Support for filterable fields in UPDATE messages, based on changes from
[obnox/wireshark/wip.git] / packet-bgp.c
1 /* packet-bgp.c
2  * Routines for BGP packet dissection.
3  * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
4  *
5  * $Id: packet-bgp.c,v 1.76 2003/04/24 09:00:27 guy Exp $
6  *
7  * Supports:
8  * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9  * RFC1965 Autonomous System Confederations for BGP
10  * RFC1997 BGP Communities Attribute
11  * RFC2547 BGP/MPLS VPNs
12  * RFC2796 BGP Route Reflection An alternative to full mesh IBGP
13  * RFC2842 Capabilities Advertisement with BGP-4
14  * RFC2858 Multiprotocol Extensions for BGP-4
15  * RFC2918 Route Refresh Capability for BGP-4
16  * RFC3107 Carrying Label Information in BGP-4
17  * Draft Ramahandra on Extended Communities Extentions
18  * draft-ietf-idr-as4bytes-06
19  * draft-ietf-idr-dynamic-cap-03
20  *
21  * TODO:
22  * Destination Preference Attribute for BGP (work in progress)
23  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
24  *
25  * Ethereal - Network traffic analyzer
26  * By Gerald Combs <gerald@ethereal.com>
27  * Copyright 1998 Gerald Combs
28  *
29  * This program is free software; you can redistribute it and/or
30  * modify it under the terms of the GNU General Public License
31  * as published by the Free Software Foundation; either version 2
32  * of the License, or (at your option) any later version.
33  *
34  * This program is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37  * GNU General Public License for more details.
38  *
39  * You should have received a copy of the GNU General Public License
40  * along with this program; if not, write to the Free Software
41  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
42  */
43
44 #ifdef HAVE_CONFIG_H
45 # include "config.h"
46 #endif
47
48 #include <stdio.h>
49 #include <stdlib.h>
50
51 #include <string.h>
52 #include <glib.h>
53
54 #ifdef NEED_SNPRINTF_H
55 # include "snprintf.h"
56 #endif
57
58 #include <epan/packet.h>
59 #include "packet-bgp.h"
60 #include "packet-ipv6.h"
61 #include "packet-frame.h"
62 #include "afn.h"
63 #include "prefs.h"
64
65 static const value_string bgptypevals[] = {
66     { BGP_OPEN, "OPEN Message" },
67     { BGP_UPDATE, "UPDATE Message" },
68     { BGP_NOTIFICATION, "NOTIFICATION Message" },
69     { BGP_KEEPALIVE, "KEEPALIVE Message" },
70     { BGP_ROUTE_REFRESH, "ROUTE-REFRESH Message" },
71     { BGP_CAPABILITY, "CAPABILITY Message" },
72     { BGP_ROUTE_REFRESH_CISCO, "Cisco ROUTE-REFRESH Message" },
73     { 0, NULL },
74 };
75
76 static const value_string bgpnotify_major[] = {
77     { 1, "Message Header Error" },
78     { 2, "OPEN Message Error" },
79     { 3, "UPDATE Message Error" },
80     { 4, "Hold Timer Expired" },
81     { 5, "Finite State Machine Error" },
82     { 6, "Cease" },
83     { 7, "CAPABILITY Message Error" },
84     { 0, NULL },
85 };
86
87 static const value_string bgpnotify_minor_1[] = {
88     { 1, "Connection Not Synchronized" },
89     { 2, "Bad Message Length" },
90     { 3, "Bad Message Type" },
91     { 0, NULL },
92 };
93
94 static const value_string bgpnotify_minor_2[] = {
95     { 1, "Unsupported Version Number" },
96     { 2, "Bad Peer AS" },
97     { 3, "Bad BGP Identifier" },
98     { 4, "Unsupported Optional Parameter" },
99     { 5, "Authentication Failure" },
100     { 6, "Unacceptable Hold Time" },
101     { 7, "Unsupported Capability" },
102     { 0, NULL },
103 };
104
105 static const value_string bgpnotify_minor_3[] = {
106     { 1, "Malformed Attribute List" },
107     { 2, "Unrecognized Well-known Attribute" },
108     { 3, "Missing Well-known Attribute" },
109     { 4, "Attribute Flags Error" },
110     { 5, "Attribute Length Error" },
111     { 6, "Invalid ORIGIN Attribute" },
112     { 7, "AS Routing Loop" },
113     { 8, "Invalid NEXT_HOP Attribute" },
114     { 9, "Optional Attribute Error" },
115     { 10, "Invalid Network Field" },
116     { 11, "Malformed AS_PATH" },
117     { 0, NULL },
118 };
119
120 static const value_string bgpnotify_minor_7[] = {
121     { 1, "Invalid Action Value" },
122     { 2, "Invalid Capability Length" },
123     { 3, "Malformed Capability Value" },
124     { 4, "Unsopported Capability Code" },
125     { 0, NULL },
126 };
127
128 static const value_string *bgpnotify_minor[] = {
129     NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
130 };
131
132 static const value_string bgpattr_origin[] = {
133     { 0, "IGP" },
134     { 1, "EGP" },
135     { 2, "INCOMPLETE" },
136     { 0, NULL },
137 };
138
139 static const value_string as_segment_type[] = {
140     { 1, "AS_SET" },
141     { 2, "AS_SEQUENCE" },
142 /* RFC1965 has the wrong values, corrected in  */
143 /* draft-ietf-idr-bgp-confed-rfc1965bis-01.txt */
144     { 4, "AS_CONFED_SET" },
145     { 3, "AS_CONFED_SEQUENCE" },
146     { 0, NULL },
147 };
148
149 static const value_string bgpattr_type[] = {
150     { BGPTYPE_ORIGIN, "ORIGIN" },
151     { BGPTYPE_AS_PATH, "AS_PATH" },
152     { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
153     { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
154     { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
155     { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
156     { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
157     { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
158     { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
159     { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
160     { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
161     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
162     { BGPTYPE_EXTENDED_COMMUNITY, "EXTENDED_COMMUNITIES" },
163     { BGPTYPE_NEW_AS_PATH, "NEW_AS_PATH" },
164     { BGPTYPE_NEW_AGGREGATOR, "NEW_AGGREGATOR" },
165     { 0, NULL },
166 };
167
168 /* Beware : See also MAX_SIZE_OF_EXT_COM_NAMES */
169 static const value_string bgpext_com_type[] = {
170     { BGP_EXT_COM_RT_0, "Route Target" },
171     { BGP_EXT_COM_RT_1, "Route Target" },
172     { BGP_EXT_COM_RO_0, "Route Origin" },
173     { BGP_EXT_COM_RO_1, "Route Origin" },
174     { BGP_EXT_COM_LINKBAND, "Link Bandwidth" },
175     { BGP_EXT_COM_VPN_ORIGIN, "OSPF Domain" },
176     { BGP_EXT_COM_OSPF_RTYPE, "OSPF Route Type" },
177     { BGP_EXT_COM_OSPF_RID, "OSPF Router ID" },
178     { BGP_EXT_COM_L2INFO, "Layer 2 Information" },
179     { 0, NULL },
180 };
181
182 static const value_string bgp_l2vpn_encaps[] = {
183     { 0,                      "Reserved"},
184     { 1,                      "Frame Relay"},
185     { 2,                      "ATM AAL5 VCC transport"},
186     { 3,                      "ATM transparent cell transport"},
187     { 4,                      "Ethernet VLAN"},
188     { 5,                      "Ethernet"},
189     { 6,                      "Cisco-HDLC"},
190     { 7,                      "PPP"},
191     { 8,                      "CEM"},
192     { 9,                      "ATM VCC cell transport"},
193     { 10,                     "ATM VPC cell transport"},
194     { 11,                     "MPLS"},
195     { 12,                     "VPLS"},
196     { 64,                     "IP-interworking"},
197     { 0, NULL},
198 };
199
200 static const value_string bgpext_ospf_rtype[] = {
201   { BGP_OSPF_RTYPE_RTR, "Router" },
202   { BGP_OSPF_RTYPE_NET, "Network" },
203   { BGP_OSPF_RTYPE_SUM, "Summary" },
204   { BGP_OSPF_RTYPE_EXT, "External" },
205   { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
206   { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },
207   { 0, NULL },
208 };
209
210
211 /* MUST be resized if a longer named extended community is added */
212 #define MAX_SIZE_OF_EXT_COM_NAMES       20
213
214 /* Subsequent address family identifier, RFC2858 */
215 static const value_string bgpattr_nlri_safi[] = {
216     { 0, "Reserved" },
217     { SAFNUM_UNICAST, "Unicast" },
218     { SAFNUM_MULCAST, "Multicast" },
219     { SAFNUM_UNIMULC, "Unicast+Multicast" },
220     { SAFNUM_MPLS_LABEL, "Labeled Unicast"},
221     { SAFNUM_LAB_VPNUNICAST, "Labeled VPN Unicast" },        /* draft-rosen-rfc2547bis-03 */
222     { SAFNUM_LAB_VPNMULCAST, "Labeled VPN Multicast" },
223     { SAFNUM_LAB_VPNUNIMULC, "Labeled VPN Unicast+Multicast" },
224     { 0, NULL },
225 };
226
227 /* ORF Type, draft-ietf-idr-route-filter-04.txt */
228 static const value_string orf_type_vals[] = {
229     { 2,        "Communities ORF-Type" },
230     { 3,        "Extended Communities ORF-Type" },
231     { 128,      "Cisco PrefixList ORF-Type" },
232     { 129,      "Cisco CommunityList ORF-Type" },
233     { 130,      "Cisco Extended CommunityList ORF-Type" },
234     { 131,      "Cisco AsPathList ORF-Type" },
235     { 0,        NULL },
236 };
237
238 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
239 static const value_string orf_send_recv_vals[] = {
240     { 1,        "Receive" },
241     { 2,        "Send" },
242     { 3,        "Both" },
243     { 0,        NULL },
244 };
245
246 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
247 static const value_string orf_when_vals[] = {
248     { 1,        "Immediate" },
249     { 2,        "Defer" },
250     { 0,        NULL },
251 };
252
253 static const value_string orf_entry_action_vals[] = {
254     { 0,        "Add" },
255     { 0x40,     "Remove" },
256     { 0x80,     "RemoveAll" },
257     { 0,        NULL },
258 };
259
260 static const value_string orf_entry_match_vals[] = {
261     { 0,        "Permit" },
262     { 0x20,     "Deny" },
263     { 0,        NULL },
264 };
265
266 static const value_string capability_vals[] = {
267     { BGP_CAPABILITY_RESERVED, "Reserved capability" },
268     { BGP_CAPABILITY_MULTIPROTOCOL, "Multiprotocol extensions capability" },
269     { BGP_CAPABILITY_ROUTE_REFRESH, "Route refresh capability" },
270     { BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING, "Cooperative route filtering capability" },
271     { BGP_CAPABILITY_GRACEFUL_RESTART, "Graceful Restart capability" },
272     { BGP_CAPABILITY_4_OCTET_AS_NUMBER, "Support for 4-octet AS number capability" },
273     { BGP_CAPABILITY_DYNAMIC_CAPABILITY, "Support for Dynamic capability" },
274     { BGP_CAPABILITY_ROUTE_REFRESH_CISCO, "Route refresh capability" },
275     { BGP_CAPABILITY_ORF_CISCO, "Cooperative route filtering capability" },
276 };
277
278 /* Capability Message action code */
279 static const value_string bgpcap_action[] = {
280     { 0, "advertising a capability" },
281     { 1, "removing a capability" },
282     { 0, NULL },
283 };
284
285
286 /* Maximal size of an IP address string */
287 #define MAX_SIZE_OF_IP_ADDR_STRING      16
288
289 static int proto_bgp = -1;
290 static int hf_bgp_type = -1;
291 static int hf_bgp_next_hop = -1;
292 static int hf_bgp_as_path = -1;
293 static int hf_bgp_cluster_identifier = -1;
294 static int hf_bgp_community_as = -1;
295 static int hf_bgp_community_value = -1;
296 static int hf_bgp_origin = -1;
297 static int hf_bgp_cluster_list = -1;
298 static int hf_bgp_originator_id = -1;
299 static int hf_bgp_local_pref = -1;
300 static int hf_bgp_multi_exit_disc = -1;
301 static int hf_bgp_aggregator_as = -1;
302 static int hf_bgp_aggregator_origin = -1;
303 static int hf_bgp_mp_reach_nlri_ipv4_prefix = -1;
304 static int hf_bgp_mp_unreach_nlri_ipv4_prefix = -1;
305 static int hf_bgp_withdrawn_prefix = -1;
306 static int hf_bgp_nlri_prefix = -1;
307
308 static gint ett_bgp = -1;
309 static gint ett_bgp_prefix = -1;
310 static gint ett_bgp_unfeas = -1;
311 static gint ett_bgp_attrs = -1;
312 static gint ett_bgp_attr = -1;
313 static gint ett_bgp_attr_flags = -1;
314 static gint ett_bgp_mp_nhna = -1;
315 static gint ett_bgp_mp_reach_nlri = -1;
316 static gint ett_bgp_mp_unreach_nlri = -1;
317 static gint ett_bgp_mp_snpa = -1;
318 static gint ett_bgp_nlri = -1;
319 static gint ett_bgp_open = -1;
320 static gint ett_bgp_update = -1;
321 static gint ett_bgp_notification = -1;
322 static gint ett_bgp_route_refresh = -1; /* ROUTE-REFRESH message tree */
323 static gint ett_bgp_capability = -1;
324 static gint ett_bgp_as_paths = -1;
325 static gint ett_bgp_as_path_segments = -1;
326 static gint ett_bgp_communities = -1;
327 static gint ett_bgp_cluster_list = -1;  /* cluster list tree          */
328 static gint ett_bgp_options = -1;       /* optional parameters tree   */
329 static gint ett_bgp_option = -1;        /* an optional parameter tree */
330 static gint ett_bgp_extended_communities = -1 ; /* extended communities list tree */
331 static gint ett_bgp_orf = -1;           /* orf (outbound route filter) tree */
332 static gint ett_bgp_orf_entry = -1;             /* orf entry tree */
333
334 /* desegmentation */
335 static gboolean bgp_desegment = TRUE;
336
337 static gint bgp_asn_len = 0;
338
339 /*
340  * Decode an IPv4 prefix.
341  */
342 static int
343 decode_prefix4(proto_tree *tree, int hf_addr, tvbuff_t *tvb, gint offset,
344     guint16 tlen, char *tag)
345 {
346     proto_item *ti;
347     proto_tree *prefix_tree;
348     union {
349        guint8 addr_bytes[4];
350        guint32 addr;
351     } ip_addr;        /* IP address                         */
352     guint8 plen;      /* prefix length                      */
353     int    length;    /* number of octets needed for prefix */
354
355     /* snarf length */
356     plen = tvb_get_guint8(tvb, offset);
357     if (plen > 32) {
358         proto_tree_add_text(tree, tvb, offset, 1, "%s length %u invalid",
359             tag, plen);
360         return -1;
361     }
362     length = (plen + 7) / 8;
363
364     /* snarf prefix */
365     memset((void *)&ip_addr, 0, sizeof(ip_addr));
366     tvb_memcpy(tvb, ip_addr.addr_bytes, offset + 1, length);
367     if (plen % 8)
368         ip_addr.addr_bytes[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
369
370     /* put prefix into protocol tree */
371     ti = proto_tree_add_text(tree, tvb, offset,
372             tlen != 0 ? tlen : 1 + length, "%s/%u",
373         ip_to_str(ip_addr.addr_bytes), plen);
374     prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
375     proto_tree_add_text(prefix_tree, tvb, offset, 1, "%s prefix length: %u",
376         tag, plen);
377     if (hf_addr != -1) {
378         proto_tree_add_ipv4(prefix_tree, hf_addr, tvb, offset + 1, length,
379             ip_addr.addr);
380     } else {
381         proto_tree_add_text(prefix_tree, tvb, offset + 1, length,
382             "%s prefix: %s", tag, ip_to_str(ip_addr.addr_bytes));
383     }
384     return(1 + length);
385 }
386
387 /*
388  * Decode an IPv6 prefix.
389  */
390 static int
391 decode_prefix6(proto_tree *tree, int hf_addr, tvbuff_t *tvb, gint offset,
392     guint16 tlen, char *tag)
393 {
394     proto_item        *ti;
395     proto_tree        *prefix_tree;
396     struct e_in6_addr addr;     /* IPv6 address                       */
397     int               plen;     /* prefix length                      */
398     int               length;   /* number of octets needed for prefix */
399
400     /* snarf length */
401     plen = tvb_get_guint8(tvb, offset);
402     if (plen > 128) {
403         proto_tree_add_text(tree, tvb, offset, 1, "%s length %u invalid",
404             tag, plen);
405         return -1;
406     }
407     length = (plen + 7) / 8;
408
409     /* snarf prefix */
410     memset(&addr, 0, sizeof(addr));
411     tvb_memcpy(tvb, (guint8 *)&addr, offset + 1, length);
412     if (plen % 8)
413         addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
414
415     /* put prefix into protocol tree */
416     ti = proto_tree_add_text(tree, tvb, offset,
417             tlen != 0 ? tlen : 1 + length, "%s/%u",
418             ip6_to_str(&addr), plen);
419     prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
420     proto_tree_add_text(prefix_tree, tvb, offset, 1, "%s prefix length: %u",
421         tag, plen);
422     if (hf_addr != -1) {
423         proto_tree_add_ipv6(prefix_tree, hf_addr, tvb, offset + 1, length,
424             addr.s6_addr);
425     } else {
426         proto_tree_add_text(prefix_tree, tvb, offset + 1, length,
427             "%s prefix: %s", tag, ip6_to_str(&addr));
428     }
429     return(1 + length);
430 }
431
432
433
434 /*
435  * Decode an MPLS label stack
436  */
437 static int
438 decode_MPLS_stack(tvbuff_t *tvb, gint offset, char *buf, size_t buflen)
439 {
440     guint32     label_entry;    /* an MPLS label enrty (label + COS field + stack bit   */
441     gint        index;          /* index for the label stack                            */
442     char        junk_buf[256];  /* tmp                                                  */
443
444     index = offset ;
445     label_entry = 0x000000 ;
446
447     buf[0] = '\0' ;
448
449     while ((label_entry & 0x000001) == 0) {
450
451         label_entry = tvb_get_ntoh24(tvb, index) ;
452
453         /* withdrawn routes may contain 0 or 0x800000 in the first label */
454         if((index-offset)==0&&(label_entry==0||label_entry==0x800000)) {
455             snprintf(buf, buflen, "0 (withdrawn)");
456             return (1);
457         }
458
459         snprintf(junk_buf, sizeof(junk_buf),"%u%s", (label_entry >> 4), ((label_entry & 0x000001) == 0) ? "," : " (bottom)");
460         if (strlen(buf) + strlen(junk_buf) + 1 <= buflen)
461             strcat(buf, junk_buf);
462         index += 3 ;
463
464         if ((label_entry & 0x000001) == 0) {
465             /* real MPLS multi-label stack in BGP? - maybe later; for now, it must be a bogus packet */
466             strcpy(junk_buf, " (BOGUS: Bottom of Stack NOT set!)");
467             if (strlen(buf) + strlen(junk_buf) + 1 <= buflen)
468                 strcat(buf, junk_buf);
469             break;
470         }
471     }
472
473     return((index - offset) / 3);
474 }
475
476 /*
477  * Decode a multiprotocol address
478  */
479
480 static int
481 mp_addr_to_str (guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *buf, int buflen)
482 {
483     int                 length;                         /* length of the address in byte */
484     guint8              ip4addr[4],ip4addr2[4];         /* IPv4 address                 */
485     guint16             rd_type;                        /* Route Distinguisher type     */
486     struct e_in6_addr   ip6addr;                        /* IPv6 address                 */
487
488     length = 0 ;
489     switch (afi) {
490         case AFNUM_INET:
491                 switch (safi) {
492                         case SAFNUM_UNICAST:
493                         case SAFNUM_MULCAST:
494                         case SAFNUM_UNIMULC:
495                         case SAFNUM_MPLS_LABEL:
496                                 length = 4 ;
497                                 tvb_memcpy(tvb, ip4addr, offset, sizeof(ip4addr));
498                                 snprintf(buf, buflen, "%s", ip_to_str(ip4addr));
499                                 break;
500                         case SAFNUM_LAB_VPNUNICAST:
501                         case SAFNUM_LAB_VPNMULCAST:
502                         case SAFNUM_LAB_VPNUNIMULC:
503                                 rd_type=tvb_get_ntohs(tvb,offset) ;
504                                 switch (rd_type) {
505                                         case FORMAT_AS2_LOC:
506                                                 length = 8 + sizeof(ip4addr);
507                                                 tvb_memcpy(tvb, ip4addr, offset + 8, sizeof(ip4addr));   /* Next Hop */
508                                                 snprintf(buf, buflen, "Empty Label Stack RD=%u:%u IP=%s",
509                                                                 tvb_get_ntohs(tvb, offset + 2),
510                                                                 tvb_get_ntohl(tvb, offset + 4),
511                                                                 ip_to_str(ip4addr));
512                                                 break;
513                                         case FORMAT_IP_LOC:
514                                                 length = 8 + sizeof(ip4addr);
515                                                 tvb_memcpy(tvb, ip4addr, offset + 2, sizeof(ip4addr));   /* IP part of the RD            */
516                                                 tvb_memcpy(tvb, ip4addr2, offset + 8, sizeof(ip4addr));  /* Next Hop   */
517                                                 snprintf(buf, buflen, "Empty Label Stack RD=%s:%u IP=%s",
518                                                                 ip_to_str(ip4addr),
519                                                                 tvb_get_ntohs(tvb, offset + 6),
520                                                                 ip_to_str(ip4addr2));
521                                                 break ;
522                                         default:
523                                                 length = 0 ;
524                                                 snprintf(buf, buflen, "Unknown (0x%04x)labeled VPN address format",rd_type);
525                                                 break;
526                                 }
527                                 break;
528                         default:
529                             length = 0 ;
530                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
531                             break;
532                 }
533                 break;
534         case AFNUM_INET6:
535                 switch (safi) {
536                         case SAFNUM_UNICAST:
537                         case SAFNUM_MULCAST:
538                         case SAFNUM_UNIMULC:
539                             length = 16 ;
540                             tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8,offset, 16);
541                             snprintf(buf, buflen, "%s", ip6_to_str(&ip6addr));
542                             break;
543                         case SAFNUM_LAB_VPNUNICAST:
544                         case SAFNUM_LAB_VPNMULCAST:
545                         case SAFNUM_LAB_VPNUNIMULC:
546                                 rd_type=tvb_get_ntohs(tvb,offset) ;
547                                 switch (rd_type) {
548                                         case FORMAT_AS2_LOC:
549                                                 length = 8 + 16;
550                                                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, 16); /* Next Hop */
551                                                 snprintf(buf, buflen, "Empty Label Stack RD=%u:%u IP=%s",
552                                                                 tvb_get_ntohs(tvb, offset + 2),
553                                                                 tvb_get_ntohl(tvb, offset + 4),
554                                                                 ip6_to_str(&ip6addr));
555                                                 break;
556                                         case FORMAT_IP_LOC:
557                                                 length = 8 + 16;
558                                                 tvb_memcpy(tvb, ip4addr, offset + 2, sizeof(ip4addr));   /* IP part of the RD            */
559                                                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, 16); /* Next Hop */
560                                                 snprintf(buf, buflen, "Empty Label Stack RD=%s:%u IP=%s",
561                                                                 ip_to_str(ip4addr),
562                                                                 tvb_get_ntohs(tvb, offset + 6),
563                                                                 ip6_to_str(&ip6addr));
564                                                 break ;
565                                         default:
566                                                 length = 0 ;
567                                                 snprintf(buf, buflen, "Unknown (0x%04x)labeled VPN address format",rd_type);
568                                                 break;
569                                 }
570                                 break;
571                         default:
572                             length = 0 ;
573                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
574                             break;
575                 }
576                 break;
577        case AFNUM_L2VPN:
578                 switch (safi) {
579                         case SAFNUM_LAB_VPNUNICAST: /* only labeles prefixes do make sense */
580                         case SAFNUM_LAB_VPNMULCAST:
581                         case SAFNUM_LAB_VPNUNIMULC:
582                             length = 4; /* the next-hop is simply an ipv4 addr */
583                             tvb_memcpy(tvb, ip4addr, offset + 0, 4);
584                             snprintf(buf, buflen, "IP=%s",
585                                      ip_to_str(ip4addr));
586                             break;
587                         default:
588                             length = 0 ;
589                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
590                             break;
591                 }
592                 break;
593         default:
594                 length = 0 ;
595                 snprintf(buf, buflen, "Unknown AFI (%u) value", afi);
596                 break;
597     }
598     return(length) ;
599 }
600
601 /*
602  * Decode a multiprotocol prefix
603  */
604 static int
605 decode_prefix_MP(proto_tree *tree, int hf_addr4, int hf_addr6,
606     guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *tag)
607 {
608     int                 start_offset = offset;
609     proto_item          *ti;
610     proto_tree          *prefix_tree;
611     int                 total_length;       /* length of the entire item */
612     int                 length;             /* length of the prefix address, in bytes */
613     guint8              plen;               /* length of the prefix address, in bits */
614     int                 labnum;             /* number of labels             */
615     int                 ce_id,labblk_off;
616     union {
617        guint8 addr_bytes[4];
618        guint32 addr;
619     } ip4addr, ip4addr2;                    /* IPv4 address                 */
620     struct e_in6_addr   ip6addr;            /* IPv6 address                 */
621     guint16             rd_type;            /* Route Distinguisher type     */
622     char                lab_stk[256];       /* label stack                  */
623
624     switch (afi) {
625
626     case AFNUM_INET:
627         switch (safi) {
628
629         case SAFNUM_UNICAST:
630         case SAFNUM_MULCAST:
631         case SAFNUM_UNIMULC:
632             total_length = decode_prefix4(tree, hf_addr4, tvb, offset, 0, tag);
633             if (total_length < 0)
634                 return -1;
635             break;
636
637         case SAFNUM_MPLS_LABEL:
638             plen =  tvb_get_guint8(tvb, offset);
639             labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
640
641             offset += (1 + labnum * 3);
642             if (plen <= (labnum * 3*8)) {
643                 proto_tree_add_text(tree, tvb, start_offset, 1,
644                         "%s IPv4 prefix length %u invalid", tag, plen);
645                 return -1;
646             }
647             plen -= (labnum * 3*8);
648             if (plen > 32) {
649                 proto_tree_add_text(tree, tvb, start_offset, 1,
650                         "%s IPv4 prefix length %u invalid",
651                         tag, plen + (labnum * 3*8));
652                 return -1;
653             }
654
655             length = (plen + 7) / 8;
656             memset((void *)&ip4addr, 0, sizeof(ip4addr));
657             tvb_memcpy(tvb, (void *)ip4addr.addr_bytes, offset, length);
658             if (plen % 8)
659                 ip4addr.addr_bytes[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
660
661             ti = proto_tree_add_text(tree, tvb, start_offset,
662                     (offset + 1 + length) - start_offset,
663                     "Label Stack=%s IP=%s/%u",
664                     lab_stk, ip_to_str(ip4addr.addr_bytes), plen);
665             prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
666             if (hf_addr4 != -1) {
667                 proto_tree_add_ipv4(prefix_tree, hf_addr4, tvb, offset + 1,
668                         length, ip4addr.addr);
669             } else {
670                 proto_tree_add_text(prefix_tree, tvb, offset + 1, length,
671                         "%s IPv4 prefix: %s",
672                         tag, ip_to_str(ip4addr.addr_bytes));
673             }
674             total_length = (1 + labnum*3) + length;
675             break;
676
677         case SAFNUM_LAB_VPNUNICAST:
678         case SAFNUM_LAB_VPNMULCAST:
679         case SAFNUM_LAB_VPNUNIMULC:
680             plen =  tvb_get_guint8(tvb, offset);
681             labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
682
683             offset += (1 + labnum * 3);
684             if (plen <= (labnum * 3*8)) {
685                 proto_tree_add_text(tree, tvb, start_offset, 1,
686                         "%s IPv4 prefix length %u invalid", tag, plen);
687                 return -1;
688             }
689             plen -= (labnum * 3*8);
690
691             rd_type = tvb_get_ntohs(tvb, offset);
692             if (plen <= 8*8) {
693                 proto_tree_add_text(tree, tvb, start_offset, 1,
694                         "%s IPv4 prefix length %u invalid",
695                         tag, plen + (labnum * 3*8));
696                 return -1;
697             }
698             plen -= 8*8;
699
700             switch (rd_type) {
701
702             case FORMAT_AS2_LOC: /* Code borrowed from the decode_prefix4 function */
703                 if (plen > 32) {
704                     proto_tree_add_text(tree, tvb, start_offset, 1,
705                             "%s IPv4 prefix length %u invalid",
706                             tag, plen + (labnum * 3*8) + 8*8);
707                     return -1;
708                 }
709
710                 length = (plen + 7) / 8;
711                 memset(ip4addr.addr_bytes, 0, 4);
712                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 8, length);
713                 if (plen % 8)
714                     ip4addr.addr_bytes[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
715
716                 ti = proto_tree_add_text(tree, tvb, start_offset,
717                         (offset + 8 + length) - start_offset,
718                         "Label Stack=%s RD=%u:%u, IP=%s/%u",
719                         lab_stk,
720                         tvb_get_ntohs(tvb, offset + 2),
721                         tvb_get_ntohl(tvb, offset + 4),
722                         ip_to_str(ip4addr.addr_bytes), plen);
723                 prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
724                 if (hf_addr4 != -1) {
725                     proto_tree_add_ipv4(prefix_tree, hf_addr4, tvb,
726                             offset + 8, length, ip4addr.addr);
727                 } else {
728                     proto_tree_add_text(prefix_tree, tvb, offset + 8,
729                             length, "%s IPv4 prefix: %s", tag,
730                             ip_to_str(ip4addr.addr_bytes));
731                 }
732                 total_length = (1 + labnum * 3 + 8) + length;
733                 break;
734
735             case FORMAT_IP_LOC: /* Code borrowed from the decode_prefix4 function */
736                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 2, 4);
737
738                 if (plen > 32) {
739                         proto_tree_add_text(tree, tvb, start_offset, 1,
740                                 "%s IPv4 prefix length %u invalid",
741                                 tag, plen + (labnum * 3*8) + 8*8);
742                         return -1;
743                 }
744
745                 length = (plen + 7) / 8;
746                 memset((void *)&ip4addr2, 0, sizeof(ip4addr2));
747                 tvb_memcpy(tvb, ip4addr2.addr_bytes, offset + 8, length);
748                 if (plen % 8)
749                     ip4addr2.addr_bytes[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
750
751                 ti = proto_tree_add_text(tree, tvb, start_offset,
752                         (offset + 8 + length) - start_offset,
753                         "Label Stack=%s RD=%s:%u, IP=%s/%u",
754                         lab_stk,
755                         ip_to_str(ip4addr.addr_bytes),
756                         tvb_get_ntohs(tvb, offset + 6),
757                         ip_to_str(ip4addr2.addr_bytes),
758                         plen);
759                 total_length = (1 + labnum * 3 + 8) + length;
760                 break;
761
762             default:
763                 proto_tree_add_text(tree, tvb, start_offset,
764                         (offset - start_offset) + 2,
765                         "Unknown labeled VPN address format %u", rd_type);
766                 return -1;
767             }
768             break;
769
770         default:
771             proto_tree_add_text(tree, tvb, start_offset, 0,
772                     "Unknown SAFI (%u) for AFI %u", safi, afi);
773             return -1;
774         }
775         break;
776
777     case AFNUM_INET6:
778         switch (safi) {
779
780         case SAFNUM_UNICAST:
781         case SAFNUM_MULCAST:
782         case SAFNUM_UNIMULC:
783             total_length = decode_prefix6(tree, hf_addr6, tvb, offset, 0, tag);
784             if (total_length < 0)
785                 return -1;
786             break;
787
788         case SAFNUM_LAB_VPNUNICAST:
789         case SAFNUM_LAB_VPNMULCAST:
790         case SAFNUM_LAB_VPNUNIMULC:
791             plen =  tvb_get_guint8(tvb, offset);
792             labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
793
794             offset += (1 + labnum * 3);
795             if (plen <= (labnum * 3*8)) {
796                 proto_tree_add_text(tree, tvb, start_offset, 1,
797                         "%s IPv6 prefix length %u invalid", tag, plen);
798                 return -1;
799             }
800             plen -= (labnum * 3*8);
801
802             rd_type = tvb_get_ntohs(tvb,offset);
803             if (plen <= 8*8) {
804                 proto_tree_add_text(tree, tvb, start_offset, 1,
805                         "%s IPv6 prefix length %u invalid",
806                         tag, plen + (labnum * 3*8));
807                 return -1;
808             }
809             plen -= 8*8;
810
811             switch (rd_type) {
812
813             case FORMAT_AS2_LOC:
814                 if (plen > 128) {
815                     proto_tree_add_text(tree, tvb, start_offset, 1,
816                             "%s IPv6 prefix length %u invalid",
817                             tag, plen + (labnum * 3*8) + 8*8);
818                     return -1;
819                 }
820
821                 length = (plen + 7) / 8;
822                 memset(ip6addr.u6_addr.u6_addr8, 0, 16);
823                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, length);
824                 if (plen % 8)
825                     ip6addr.u6_addr.u6_addr8[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
826
827                 ti = proto_tree_add_text(tree, tvb, start_offset,
828                         (offset + 8 + length) - start_offset,
829                         "Label Stack=%s RD=%u:%u, IP=%s/%u",
830                         lab_stk,
831                         tvb_get_ntohs(tvb, offset + 2),
832                         tvb_get_ntohl(tvb, offset + 4),
833                         ip6_to_str(&ip6addr), plen);
834                 total_length = (1 + labnum * 3 + 8) + length;
835                 break;
836
837             case FORMAT_IP_LOC: 
838                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 2, 4);
839
840                 if (plen > 128) {
841                     proto_tree_add_text(tree, tvb, start_offset, 1,
842                             "%s IPv6 prefix length %u invalid",
843                             tag, plen + (labnum * 3*8) + 8*8);
844                     return -1;
845                 }
846                 length = (plen + 7) / 8;
847                 memset(ip6addr.u6_addr.u6_addr8, 0, 16);
848                 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8, offset + 8, length);
849                 if (plen % 8)
850                     ip6addr.u6_addr.u6_addr8[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
851
852                 ti = proto_tree_add_text(tree, tvb, start_offset,
853                         (offset + 8 + length) - start_offset,
854                         "Label Stack=%s RD=%s:%u, IP=%s/%u",
855                         lab_stk,
856                         ip_to_str(ip4addr.addr_bytes),
857                         tvb_get_ntohs(tvb, offset + 6),
858                         ip6_to_str(&ip6addr), plen);
859                 total_length = (1 + labnum * 3 + 8) + length;
860                 break;
861
862             default:
863                 proto_tree_add_text(tree, tvb, start_offset, 0,
864                         "Unknown labeled VPN address format %u", rd_type);
865                 return -1;
866             }
867             break;
868
869         default:
870             proto_tree_add_text(tree, tvb, start_offset, 0,
871                     "Unknown SAFI (%u) for AFI %u", safi, afi);
872             return -1;
873         }
874         break;
875
876     case AFNUM_L2VPN:
877         switch (safi) {
878
879         case SAFNUM_LAB_VPNUNICAST:
880         case SAFNUM_LAB_VPNMULCAST:
881         case SAFNUM_LAB_VPNUNIMULC:
882             plen =  tvb_get_ntohs(tvb,offset);
883             rd_type=tvb_get_ntohs(tvb,offset+2);
884             ce_id=tvb_get_ntohs(tvb,offset+10);
885             labblk_off=tvb_get_ntohs(tvb,offset+12);
886             labnum = decode_MPLS_stack(tvb, offset + 14, lab_stk, sizeof(lab_stk));
887
888             switch (rd_type) {
889
890             case FORMAT_AS2_LOC:
891                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 6, 4);
892                 proto_tree_add_text(tree, tvb, start_offset,
893                         (offset + plen + 1) - start_offset,
894                         "RD: %u:%s, CE-ID: %u, Label-Block Offset: %u, Label Base %s",
895                         tvb_get_ntohs(tvb, offset + 4),
896                         ip_to_str(ip4addr.addr_bytes),
897                         ce_id,
898                         labblk_off,
899                         lab_stk);
900                 break;
901
902             case FORMAT_IP_LOC:
903                 tvb_memcpy(tvb, ip4addr.addr_bytes, offset + 4, 4);
904                 proto_tree_add_text(tree, tvb, offset,
905                         (offset + plen + 1) - start_offset,
906                         "RD: %s:%u, CE-ID: %u, Label-Block Offset: %u, Label Base %s",
907                         ip_to_str(ip4addr.addr_bytes),
908                         tvb_get_ntohs(tvb, offset + 8),
909                         ce_id,
910                         labblk_off,
911                         lab_stk);
912                 break;
913
914             default:
915                 proto_tree_add_text(tree, tvb, start_offset,
916                         (offset - start_offset) + 2,
917                         "Unknown labeled VPN address format %u", rd_type);
918                 return -1;
919             }
920             /* FIXME there are subTLVs left to decode ... for now lets omit them */
921             total_length = plen+2;
922             break;
923
924         default:
925             proto_tree_add_text(tree, tvb, start_offset, 0,
926                     "Unknown SAFI (%u) for AFI %u", safi, afi);
927             return -1;
928         }
929         break;
930
931     default:
932         proto_tree_add_text(tree, tvb, start_offset, 0,
933                 "Unknown AFI (%u) value", afi);
934         return -1;
935     }
936     return(total_length);
937 }
938
939 /*
940  * Dissect a BGP capability.
941  */
942 static void
943 dissect_bgp_capability_item(tvbuff_t *tvb, int *p, proto_tree *tree, int ctype, int clen)
944 {
945     proto_tree *subtree;
946     proto_item *ti;
947     guint8 orfnum;       /* number of ORFs */
948     guint8 orftype;      /* ORF Type */
949     guint8 orfsendrecv;  /* ORF Send/Receive */
950     int    tclen;        /* capability length */
951     int    i;
952
953     /* check the capability type */
954     switch (ctype) {
955     case BGP_CAPABILITY_RESERVED:
956         proto_tree_add_text(tree, tvb, *p - 2, 1,
957              "Capability code: %s (%d)", val_to_str(ctype,
958              capability_vals, "Unknown capability"), ctype);
959         proto_tree_add_text(tree, tvb, *p - 1,
960              1, "Capability length: %u %s", clen,
961              (clen == 1) ? "byte" : "bytes");
962         if (clen != 0) {
963             proto_tree_add_text(tree, tvb, *p,
964                  clen, "Capability value: Unknown");
965         }
966         *p += clen;
967         break;
968     case BGP_CAPABILITY_MULTIPROTOCOL:
969         proto_tree_add_text(tree, tvb, *p - 2, 1,
970              "Capability code: %s (%d)", val_to_str(ctype,
971              capability_vals, "Unknown capability"), ctype);
972         if (clen != 4) {
973             proto_tree_add_text(tree, tvb, *p - 1,
974                  1, "Capability length: Invalid");
975             proto_tree_add_text(tree, tvb, *p,
976                  clen, "Capability value: Unknown");
977         }
978         else {
979             proto_tree_add_text(tree, tvb, *p - 1,
980                  1, "Capability length: %u %s", clen,
981                  (clen == 1) ? "byte" : "bytes");
982             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
983             subtree = proto_item_add_subtree(ti, ett_bgp_option);
984             /* AFI */
985             i = tvb_get_ntohs(tvb, *p);
986             proto_tree_add_text(subtree, tvb, *p,
987                  2, "Address family identifier: %s (%u)",
988                  val_to_str(i, afn_vals, "Unknown"), i);
989             *p += 2;
990             /* Reserved */
991             proto_tree_add_text(subtree, tvb, *p, 1, "Reserved: 1 byte");
992             (*p)++;
993             /* SAFI */
994             i = tvb_get_guint8(tvb, *p);
995             proto_tree_add_text(subtree, tvb, *p,
996                  1, "Subsequent address family identifier: %s (%u)",
997                  val_to_str(i, bgpattr_nlri_safi,
998                  i >= 128 ? "Vendor specific" : "Unknown"), i);
999             (*p)++;
1000         }
1001         break;
1002     case BGP_CAPABILITY_GRACEFUL_RESTART:
1003         proto_tree_add_text(tree, tvb, *p - 2, 1,
1004              "Capability code: %s (%d)", val_to_str(ctype,
1005              capability_vals, "Unknown capability"), ctype);
1006         if (clen < 6) {
1007             proto_tree_add_text(tree, tvb, *p,
1008                  clen, "Capability value: Invalid");
1009         }
1010         else {
1011             proto_tree_add_text(tree, tvb, *p - 1,
1012                  1, "Capability length: %u %s", clen,
1013                  (clen == 1) ? "byte" : "bytes");
1014             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1015             subtree = proto_item_add_subtree(ti, ett_bgp_option);
1016             /* Timers */
1017             i = tvb_get_ntohs(tvb, *p);
1018             proto_tree_add_text(subtree, tvb, *p,
1019                  2, "Restart Flags: [%s], Restart Time %us",
1020                  (i&0x8000) ? "R" : "none", i&0xfff);
1021             *p += 2;
1022             tclen = clen - 2;
1023             /*
1024              * what follows is alist of AFI/SAFI/flag triplets
1025              * read it until the TLV ends
1026              */
1027             while (tclen >=4) {
1028                 /* AFI */
1029                 i = tvb_get_ntohs(tvb, *p);
1030                 proto_tree_add_text(subtree, tvb, *p,
1031                      2, "Address family identifier: %s (%u)",
1032                      val_to_str(i, afn_vals, "Unknown"), i);
1033                 *p += 2;
1034                 /* SAFI */
1035                 i = tvb_get_guint8(tvb, *p);
1036                 proto_tree_add_text(subtree, tvb, *p,
1037                      1, "Subsequent address family identifier: %s (%u)",
1038                      val_to_str(i, bgpattr_nlri_safi,
1039                      i >= 128 ? "Vendor specific" : "Unknown"), i);
1040                 (*p)++;
1041                 /* flags */
1042                 i = tvb_get_guint8(tvb, *p);
1043                 proto_tree_add_text(subtree, tvb, *p, 1,
1044                      "Preserve forwarding state: %s",
1045                      (i&0x80) ? "yes" : "no");
1046                 (*p)++;
1047                 tclen-=4;
1048             }
1049         }
1050         *p += clen;
1051         break;
1052     case BGP_CAPABILITY_4_OCTET_AS_NUMBER:
1053         proto_tree_add_text(tree, tvb, *p - 2, 1,
1054              "Capability code: %s (%d)", val_to_str(ctype,
1055              capability_vals, "Unknown capability"), ctype);
1056         if (clen != 4) {
1057             proto_tree_add_text(tree, tvb, *p,
1058                  clen, "Capability value: Invalid");
1059         }
1060         else {
1061             proto_tree_add_text(tree, tvb, *p - 1,
1062                  1, "Capability length: %u %s", clen,
1063                  (clen == 1) ? "byte" : "bytes");
1064             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1065             subtree = proto_item_add_subtree(ti, ett_bgp_option);
1066             proto_tree_add_text(subtree, tvb, *p, 4,
1067                  "AS number: %d", tvb_get_ntohl(tvb, *p));
1068         }
1069         *p += clen;
1070         break;
1071     case BGP_CAPABILITY_DYNAMIC_CAPABILITY:
1072         proto_tree_add_text(tree, tvb, *p - 2, 1,
1073              "Capability code: %s (%d)", val_to_str(ctype,
1074              capability_vals, "Unknown capability"), ctype);
1075         proto_tree_add_text(tree, tvb, *p - 1, 1,
1076              "Capability length: %u %s", clen,
1077              (clen == 1) ? "byte" : "bytes");
1078         if (clen > 0) {
1079             ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1080             subtree = proto_item_add_subtree(ti, ett_bgp_option);
1081             for (i = 0; (int)i <= clen; i++) {
1082                 proto_tree_add_text(subtree, tvb, *p, 1,
1083                      "Capability code: %s (%d)", val_to_str(ctype,
1084                      capability_vals, "Unknown capability"),
1085                      tvb_get_guint8(tvb, *p));
1086                 (*p)++;
1087             }
1088         }
1089         break;
1090     case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
1091     case BGP_CAPABILITY_ROUTE_REFRESH:
1092         proto_tree_add_text(tree, tvb, *p - 2, 1,
1093              "Capability code: %s (%d)", val_to_str(ctype,
1094              capability_vals, "Unknown capability"), ctype);
1095         if (clen != 0) {
1096             proto_tree_add_text(tree, tvb, *p,
1097                  clen, "Capability value: Invalid");
1098         }
1099         else {
1100             proto_tree_add_text(tree, tvb, *p - 1,
1101                  1, "Capability length: %u %s", clen,
1102                  (clen == 1) ? "byte" : "bytes");
1103         }
1104         *p += clen;
1105         break;
1106     case BGP_CAPABILITY_ORF_CISCO:
1107     case BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING:
1108         proto_tree_add_text(tree, tvb, *p - 2, 1,
1109              "Capability code: %s (%d)", val_to_str(ctype,
1110              capability_vals, "Unknown capability"), ctype);
1111         proto_tree_add_text(tree, tvb, *p - 1,
1112              1, "Capability length: %u %s", clen,
1113              (clen == 1) ? "byte" : "bytes");
1114         ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
1115         subtree = proto_item_add_subtree(ti, ett_bgp_option);
1116         /* AFI */
1117         i = tvb_get_ntohs(tvb, *p);
1118         proto_tree_add_text(subtree, tvb, *p,
1119              2, "Address family identifier: %s (%u)",
1120              val_to_str(i, afn_vals, "Unknown"), i);
1121         *p += 2;
1122         /* Reserved */
1123         proto_tree_add_text(subtree, tvb, *p, 1, "Reserved: 1 byte");
1124         (*p)++;
1125         /* SAFI */
1126         i = tvb_get_guint8(tvb, *p);
1127         proto_tree_add_text(subtree, tvb, *p,
1128              1, "Subsequent address family identifier: %s (%u)",
1129              val_to_str(i, bgpattr_nlri_safi,
1130              i >= 128 ? "Vendor specific" : "Unknown"), i);
1131         (*p)++;
1132         /* Number of ORFs */
1133         orfnum = tvb_get_guint8(tvb, *p);
1134         proto_tree_add_text(subtree, tvb, *p, 1, "Number of ORFs: %u", orfnum);
1135         (*p)++;
1136         for (i=0; i<orfnum; i++) {
1137             /* ORF Type */
1138             orftype = tvb_get_guint8(tvb, *p);
1139             proto_tree_add_text(subtree, tvb, *p, 1, "ORF Type: %s (%u)",
1140                  val_to_str(orftype, orf_type_vals,"Unknown"), orftype);
1141             (*p)++;
1142             /* Send/Receive */
1143             orfsendrecv = tvb_get_guint8(tvb, *p);
1144             proto_tree_add_text(subtree, tvb, *p,
1145                  1, "Send/Receive: %s (%u)",
1146                  val_to_str(orfsendrecv, orf_send_recv_vals,
1147                  "Uknown"), orfsendrecv);
1148             (*p)++;
1149         }
1150         break;
1151         /* unknown capability */
1152     default:
1153         proto_tree_add_text(tree, tvb, *p - 2, 1,
1154              "Capability code: %s (%d)", val_to_str(ctype,
1155              capability_vals, "Unknown capability"), ctype);
1156         proto_tree_add_text(tree, tvb, *p - 2,
1157              1, "Capability code: %s (%d)",
1158              ctype >= 128 ? "Private use" : "Unknown", ctype);
1159         proto_tree_add_text(tree, tvb, *p - 1,
1160              1, "Capability length: %u %s", clen,
1161              (clen == 1) ? "byte" : "bytes");
1162         if (clen != 0) {
1163             proto_tree_add_text(tree, tvb, *p,
1164                  clen, "Capability value: Unknown");
1165         }
1166         *p += clen;
1167         break;
1168     }
1169 }
1170
1171
1172 /*
1173  * Dissect a BGP OPEN message.
1174  */
1175 static const value_string community_vals[] = {
1176         { BGP_COMM_NO_EXPORT,           "NO_EXPORT" },
1177         { BGP_COMM_NO_ADVERTISE,        "NO_ADVERTISE" },
1178         { BGP_COMM_NO_EXPORT_SUBCONFED, "NO_EXPORT_SUBCONFED" },
1179         { 0,                            NULL }
1180 };
1181
1182 static void
1183 dissect_bgp_open(tvbuff_t *tvb, proto_tree *tree)
1184 {
1185     struct bgp_open bgpo;      /* BGP OPEN message      */
1186     int             hlen;      /* message length        */
1187     int             ptype;     /* parameter type        */
1188     int             plen;      /* parameter length      */
1189     int             ctype;     /* capability type       */
1190     int             clen;      /* capability length     */
1191     int             cend;      /* capabilities end      */
1192     int             ostart;    /* options start         */
1193     int             oend;      /* options end           */
1194     int             p;         /* tvb offset counter    */
1195     proto_item      *ti;       /* tree item             */
1196     proto_tree      *subtree;  /* subtree for options   */
1197     proto_tree      *subtree1; /* subtree for an option */
1198     proto_tree      *subtree2; /* subtree for an option */
1199
1200     /* snarf OPEN message */
1201     tvb_memcpy(tvb, bgpo.bgpo_marker, 0, BGP_MIN_OPEN_MSG_SIZE);
1202     hlen = g_ntohs(bgpo.bgpo_len);
1203
1204     proto_tree_add_text(tree, tvb,
1205         offsetof(struct bgp_open, bgpo_version), 1,
1206         "Version: %u", bgpo.bgpo_version);
1207     proto_tree_add_text(tree, tvb,
1208         offsetof(struct bgp_open, bgpo_myas), 2,
1209         "My AS: %u", g_ntohs(bgpo.bgpo_myas));
1210     proto_tree_add_text(tree, tvb,
1211         offsetof(struct bgp_open, bgpo_holdtime), 2,
1212         "Hold time: %u", g_ntohs(bgpo.bgpo_holdtime));
1213     proto_tree_add_text(tree, tvb,
1214         offsetof(struct bgp_open, bgpo_id), 4,
1215         "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
1216     proto_tree_add_text(tree, tvb,
1217         offsetof(struct bgp_open, bgpo_optlen), 1,
1218         "Optional parameters length: %u %s", bgpo.bgpo_optlen,
1219         (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
1220
1221     /* optional parameters */
1222     if (bgpo.bgpo_optlen > 0) {
1223         /* add a subtree and setup some offsets */
1224         ostart = BGP_MIN_OPEN_MSG_SIZE;
1225         ti = proto_tree_add_text(tree, tvb, ostart, bgpo.bgpo_optlen,
1226              "Optional parameters");
1227         subtree = proto_item_add_subtree(ti, ett_bgp_options);
1228         p = ostart;
1229         oend = p + bgpo.bgpo_optlen;
1230
1231         /* step through all of the optional parameters */
1232         while (p < oend) {
1233
1234             /* grab the type and length */
1235             ptype = tvb_get_guint8(tvb, p++);
1236             plen = tvb_get_guint8(tvb, p++);
1237
1238             /* check the type */
1239             switch (ptype) {
1240             case BGP_OPTION_AUTHENTICATION:
1241                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
1242                     "Authentication information (%u %s)", plen,
1243                     (plen == 1) ? "byte" : "bytes");
1244                 break;
1245             case BGP_OPTION_CAPABILITY:
1246                 /* grab the capability code */
1247                 cend = p - 1 + plen;
1248                 ctype = tvb_get_guint8(tvb, p++);
1249                 clen = tvb_get_guint8(tvb, p++);
1250                 ti = proto_tree_add_text(subtree, tvb, p - 4,
1251                      2 + plen, "Capabilities Advertisement (%u bytes)",
1252                      2 + plen);
1253                 subtree1 = proto_item_add_subtree(ti, ett_bgp_option);
1254                 proto_tree_add_text(subtree1, tvb, p - 4,
1255                      1, "Parameter type: Capabilities (2)");
1256                 proto_tree_add_text(subtree1, tvb, p - 3,
1257                      1, "Parameter length: %u %s", plen,
1258                      (plen == 1) ? "byte" : "bytes");
1259                 p -= 2;
1260
1261                 /* step through all of the capabilities */
1262                 while (p < cend) {
1263                     ctype = tvb_get_guint8(tvb, p++);
1264                     clen = tvb_get_guint8(tvb, p++);
1265
1266                     ti = proto_tree_add_text(subtree1, tvb, p - 2,
1267                          2 + clen, "%s (%u %s)", val_to_str(ctype,
1268                          capability_vals, "Unknown capability"),
1269                          2 + clen, (clen == 1) ? "byte" : "bytes");
1270                     subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
1271                     dissect_bgp_capability_item(tvb, &p,
1272                            subtree2, ctype, clen);
1273                 }
1274                 break;
1275             default:
1276                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
1277                     "Unknown optional parameter");
1278                 break;
1279             }
1280         }
1281     }
1282 }
1283
1284 /*
1285  * Dissect a BGP UPDATE message.
1286  */
1287 static void
1288 dissect_bgp_update(tvbuff_t *tvb, proto_tree *tree)
1289 {
1290     struct bgp_attr bgpa;                       /* path attributes          */
1291     guint16         hlen;                       /* message length           */
1292     gint            o;                          /* packet offset            */
1293     gint            q;                          /* tmp                      */
1294     gint            end;                        /* message end              */
1295     guint16         ext_com;                    /* EXTENDED COMMUNITY type  */
1296     guint16         len;                        /* tmp                      */
1297     int             advance;                    /* tmp                      */
1298     proto_item      *ti;                        /* tree item                */
1299     proto_tree      *subtree;                   /* subtree for attributes   */
1300     proto_tree      *subtree2;                  /* subtree for attributes   */
1301     proto_tree      *subtree3;                  /* subtree for attributes   */
1302     proto_tree      *subtree4;                  /* subtree for attributes   */
1303     proto_tree      *as_paths_tree;             /* subtree for AS_PATHs     */
1304     proto_tree      *as_path_tree;              /* subtree for AS_PATH      */
1305     proto_tree      *as_path_segment_tree;      /* subtree for AS_PATH segments */
1306     proto_tree      *communities_tree;          /* subtree for COMMUNITIES  */
1307     proto_tree      *community_tree;            /* subtree for a community  */
1308     proto_tree      *cluster_list_tree;         /* subtree for CLUSTER_LIST */
1309     int             i, j;                       /* tmp                      */
1310     guint8          length;                     /* AS_PATH length           */
1311     guint8          type;                       /* AS_PATH type             */
1312     guint32         as_path_item;               /* item in AS_PATH segment  */
1313     char            *as_path_str = NULL;        /* AS_PATH string           */
1314     char            *communities_str = NULL;    /* COMMUNITIES string       */
1315     char            *cluster_list_str = NULL;   /* CLUSTER_LIST string      */
1316     char            junk_buf[256];              /* tmp                      */
1317     int             junk_buf_len;               /* tmp len                  */
1318     guint8          ipaddr[4];                  /* IPv4 address             */
1319     guint32         aggregator_as;
1320
1321     hlen = tvb_get_ntohs(tvb, BGP_MARKER_SIZE);
1322     o = BGP_HEADER_SIZE;
1323
1324     /* check for withdrawals */
1325     len = tvb_get_ntohs(tvb, o);
1326     proto_tree_add_text(tree, tvb, o, 2,
1327         "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
1328     o += 2;
1329
1330     /* parse unfeasible prefixes */
1331     if (len > 0) {
1332         ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
1333         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
1334
1335         /* parse each prefix */
1336         end = o + len;
1337         while (o < end) {
1338             i = decode_prefix4(subtree, hf_bgp_withdrawn_prefix, tvb, o, len,
1339                 "Withdrawn route");
1340             if (i < 0)
1341                 return;
1342             o += i;
1343         }
1344     }
1345
1346     /* check for advertisements */
1347     len = tvb_get_ntohs(tvb, o);
1348     proto_tree_add_text(tree, tvb, o, 2, "Total path attribute length: %u %s",
1349             len, (len == 1) ? "byte" : "bytes");
1350
1351     /* path attributes */
1352     if (len > 0) {
1353         ti = proto_tree_add_text(tree, tvb, o + 2, len, "Path attributes");
1354         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
1355         i = 2;
1356         while (i < len) {
1357             char    *msg;
1358             int     off;
1359             gint    k;
1360             guint16 alen, tlen, aoff; 
1361             guint16 af;
1362             guint8  saf, snpa;
1363             guint8  nexthop_len;
1364             guint8  asn_len = 0;
1365
1366             tvb_memcpy(tvb, (guint8 *)&bgpa, o + i, sizeof(bgpa));
1367             /* check for the Extended Length bit */
1368             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1369                 alen = tvb_get_ntohs(tvb, o + i + sizeof(bgpa));
1370                 aoff = sizeof(bgpa) + 2;
1371             } else {
1372                 alen = tvb_get_guint8(tvb, o + i + sizeof(bgpa));
1373                 aoff = sizeof(bgpa) + 1;
1374             }
1375             tlen = alen;
1376
1377             /* This is kind of ugly - similar code appears twice, but it
1378                helps browsing attrs.                                      */
1379             /* the first switch prints things in the title of the subtree */
1380             switch (bgpa.bgpa_type) {
1381             case BGPTYPE_ORIGIN:
1382                 if (tlen != 1)
1383                     goto default_attribute_top;
1384                 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1385                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1386                         "%s: %s (%u %s)",
1387                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1388                         msg, tlen + aoff, (tlen + aoff == 1) ? "byte" :
1389                         "bytes");
1390                 break;
1391             case BGPTYPE_AS_PATH:
1392             case BGPTYPE_NEW_AS_PATH:
1393                 /* (o + i + aoff) =
1394                    (o + current attribute + aoff bytes to first tuple) */
1395                 q = o + i + aoff;
1396                 end = q + tlen;
1397                 /* must be freed by second switch!                         */
1398                 /* "tlen * 11" (10 digits + space) should be a good estimate
1399                    of how long the AS path string could be                 */
1400                 as_path_str = malloc((tlen + 1) * 11);
1401                 if (as_path_str == NULL) break;
1402                 as_path_str[0] = '\0';
1403
1404                 /* estimate the length of the AS number */
1405                 if (bgpa.bgpa_type == BGPTYPE_NEW_AS_PATH) 
1406                     asn_len = 4;
1407                 else {
1408                     if (bgp_asn_len == 0) {
1409                         k = q;
1410                         while (k < end) {
1411                             k++;
1412                             length = tvb_get_guint8(tvb, k++);
1413                             k += length * 2;
1414                         }
1415                         asn_len = (k == end) ? 2 : 4;
1416                     }
1417                     else {
1418                         asn_len = bgp_asn_len;
1419                     }
1420                 }
1421
1422                 /* snarf each AS path */
1423                 while (q < end) {
1424                     type = tvb_get_guint8(tvb, q++);
1425                     if (strlen(as_path_str) != 0 &&
1426                         as_path_str[strlen(as_path_str) - 1] != ' ')
1427                         strcat(as_path_str, " ");
1428                     if (type == AS_SET) {
1429                         strcat(as_path_str, "{");
1430                     }
1431                     else if (type == AS_CONFED_SET) {
1432                         strcat(as_path_str, "[");
1433                     }
1434                     else if (type == AS_CONFED_SEQUENCE) {
1435                         strcat(as_path_str, "(");
1436                     }
1437                     length = tvb_get_guint8(tvb, q++);
1438
1439                     /* snarf each value in path */
1440                     for (j = 0; j < length; j++) {
1441                         snprintf(junk_buf, sizeof(junk_buf), "%u%s",
1442                                 (asn_len == 2) ?
1443                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q),
1444                                 (type == AS_SET || type == AS_CONFED_SET) ?
1445                                 ", " : " ");
1446                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1447                         q += asn_len;
1448                     }
1449
1450                     /* cleanup end of string */
1451                     if (type == AS_SET) {
1452                         as_path_str[strlen(as_path_str) - 2] = '}';
1453                         as_path_str[strlen(as_path_str) - 1] = '\0';
1454                     }
1455                     else if (type == AS_CONFED_SET) {
1456                         as_path_str[strlen(as_path_str) - 2] = ']';
1457                         as_path_str[strlen(as_path_str) - 1] = '\0';
1458                     }
1459                     else if (type == AS_CONFED_SEQUENCE) {
1460                         as_path_str[strlen(as_path_str) - 1] = ')';
1461                     }
1462                     else {
1463                         as_path_str[strlen(as_path_str) - 1] = '\0';
1464                     }
1465                 }
1466
1467                 /* check for empty AS_PATH */
1468                 if (tlen == 0)
1469                     strncpy(as_path_str, "empty", 6);
1470
1471                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1472                         "%s: %s (%u %s)",
1473                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1474                         as_path_str, tlen + aoff,
1475                         (tlen + aoff == 1) ? "byte" : "bytes");
1476                 break;
1477             case BGPTYPE_NEXT_HOP:
1478                 if (tlen != 4)
1479                     goto default_attribute_top;
1480                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1481                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1482                         "%s: %s (%u %s)",
1483                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1484                         ip_to_str(ipaddr), tlen + aoff, (tlen + aoff == 1)
1485                         ? "byte" : "bytes");
1486                 break;
1487             case BGPTYPE_MULTI_EXIT_DISC:
1488                 if (tlen != 4)
1489                     goto default_attribute_top;
1490                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1491                         "%s: %u (%u %s)",
1492                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1493                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1494                         (tlen + aoff == 1) ? "byte" : "bytes");
1495                 break;
1496             case BGPTYPE_LOCAL_PREF:
1497                 if (tlen != 4)
1498                     goto default_attribute_top;
1499                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1500                         "%s: %u (%u %s)",
1501                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1502                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1503                         (tlen + aoff == 1) ? "byte" : "bytes");
1504                 break;
1505             case BGPTYPE_ATOMIC_AGGREGATE:
1506                 if (tlen != 0)
1507                     goto default_attribute_top;
1508                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1509                         "%s (%u %s)",
1510                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1511                         tlen + aoff, (tlen + aoff == 1) ? "byte" : "bytes");
1512                 break;
1513             case BGPTYPE_AGGREGATOR:
1514                 if (tlen != 6 && tlen != 8)
1515                     goto default_attribute_top;
1516             case BGPTYPE_NEW_AGGREGATOR:
1517                 if (bgpa.bgpa_type == BGPTYPE_NEW_AGGREGATOR && tlen != 8)
1518                     goto default_attribute_top;
1519                 asn_len = tlen - 4;
1520                 tvb_memcpy(tvb, ipaddr, o + i + aoff + asn_len, 4);
1521                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1522                         "%s: AS: %u origin: %s (%u %s)",
1523                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1524                         (asn_len == 2) ? tvb_get_ntohs(tvb, o + i + aoff) :
1525                         tvb_get_ntohl(tvb, o + i + aoff),
1526                         ip_to_str(ipaddr), tlen + aoff,
1527                         (tlen + aoff == 1) ? "byte" : "bytes");
1528                 break;
1529             case BGPTYPE_COMMUNITIES:
1530                 if (tlen % 4 != 0)
1531                     goto default_attribute_top;
1532
1533                 /* (o + i + aoff) =
1534                    (o + current attribute + aoff bytes to first tuple) */
1535                 q = o + i + aoff;
1536                 end = q + tlen;
1537                 /* must be freed by second switch!                          */
1538                 /* "tlen * 12" (5 digits, a :, 5 digits + space ) should be
1539                    a good estimate of how long the communities string could
1540                    be                                                       */
1541                 communities_str = malloc((tlen + 1) * 12);
1542                 if (communities_str == NULL) break;
1543                 communities_str[0] = '\0';
1544                 memset(junk_buf, 0, sizeof(junk_buf));
1545
1546                 /* snarf each community */
1547                 while (q < end) {
1548                     /* check for well-known communities */
1549                     if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
1550                         strncpy(junk_buf, "NO_EXPORT ", 10);
1551                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
1552                         strncpy(junk_buf, "NO_ADVERTISE ", 13);
1553                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
1554                         strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
1555                     else {
1556                         snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
1557                                 tvb_get_ntohs(tvb, q),
1558                                 tvb_get_ntohs(tvb, q + 2));
1559                     }
1560                     q += 4;
1561
1562                     strncat(communities_str, junk_buf, sizeof(junk_buf));
1563                 }
1564                 /* cleanup end of string */
1565                 communities_str[strlen(communities_str) - 1] = '\0';
1566
1567                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1568                         "%s: %s (%u %s)",
1569                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1570                         communities_str, tlen + aoff,
1571                         (tlen + aoff == 1) ? "byte" : "bytes");
1572                 break;
1573             case BGPTYPE_ORIGINATOR_ID:
1574                 if (tlen != 4)
1575                     goto default_attribute_top;
1576                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1577                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1578                         "%s: %s (%u %s)",
1579                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1580                         ip_to_str(ipaddr), tlen + aoff, (tlen + aoff == 1)
1581                         ? "byte" : "bytes");
1582                 break;
1583             case BGPTYPE_CLUSTER_LIST:
1584                 if (tlen % 4 != 0)
1585                     goto default_attribute_top;
1586
1587                 /* (o + i + aoff) =
1588                    (o + current attribute + aoff bytes to first tuple) */
1589                 q = o + i + aoff;
1590                 end = q + tlen;
1591                 /* must be freed by second switch!                          */
1592                 /* "tlen * 16" (12 digits, 3 dots + space ) should be
1593                    a good estimate of how long the cluster_list string could
1594                    be                                                       */
1595                 cluster_list_str = malloc((tlen + 1) * 16);
1596                 if (cluster_list_str == NULL) break;
1597                 cluster_list_str[0] = '\0';
1598                 memset(junk_buf, 0, sizeof(junk_buf));
1599
1600                 /* snarf each cluster list */
1601                 tvb_memcpy(tvb, ipaddr, q, 4);
1602                 while (q < end) {
1603                     snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(ipaddr));
1604                     strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
1605                     q += 4;
1606                 }
1607                 /* cleanup end of string */
1608                 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
1609
1610                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1611                         "%s: %s (%u %s)",
1612                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1613                         cluster_list_str, tlen + aoff,
1614                         (tlen + aoff == 1) ? "byte" : "bytes");
1615                 break;
1616             case BGPTYPE_EXTENDED_COMMUNITY:
1617                 if (tlen %8 != 0)
1618                     break;
1619                 ti = proto_tree_add_text(subtree,tvb,o+i,tlen+aoff,
1620                         "%s: (%u %s)",
1621                         val_to_str(bgpa.bgpa_type,bgpattr_type,"Unknown"),
1622                         tlen + aoff,
1623                         (tlen + aoff == 1) ? "byte" : "bytes");
1624                 break;
1625
1626             default:
1627             default_attribute_top:
1628                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1629                         "%s (%u %s)",
1630                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1631                         tlen + aoff, (tlen + aoff == 1) ? "byte" : "bytes");
1632             } /* end of first switch */
1633             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
1634
1635             /* figure out flags */
1636             junk_buf[0] = '\0';
1637             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
1638                  strncat(junk_buf, "Optional, ", 10);
1639             }
1640             else {
1641                  strncat(junk_buf, "Well-known, ", 12);
1642             }
1643             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
1644                  strncat(junk_buf, "Transitive, ", 12);
1645             }
1646             else {
1647                  strncat(junk_buf, "Non-transitive, ", 16);
1648             }
1649             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
1650                  strncat(junk_buf, "Partial, ", 9);
1651             }
1652             else {
1653                  strncat(junk_buf, "Complete, ", 10);
1654             }
1655             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1656                  strncat(junk_buf, "Extended Length, ", 17);
1657             }
1658             /* stomp last ", " */
1659             j = strlen(junk_buf);
1660             junk_buf[j - 2] = '\0';
1661             ti = proto_tree_add_text(subtree2, tvb,
1662                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1663                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
1664             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
1665
1666             /* add flag bitfield subtrees */
1667             proto_tree_add_text(subtree3, tvb,
1668                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1669                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1670                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
1671             proto_tree_add_text(subtree3, tvb,
1672                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1673                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1674                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
1675                         "Non-transitive"));
1676             proto_tree_add_text(subtree3, tvb,
1677                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1678                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1679                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
1680             proto_tree_add_text(subtree3, tvb,
1681                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1682                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1683                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
1684                         "Regular length"));
1685
1686             proto_tree_add_text(subtree2, tvb,
1687                     o + i + offsetof(struct bgp_attr, bgpa_type), 1,
1688                     "Type code: %s (%u)",
1689                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1690                     bgpa.bgpa_type);
1691
1692             proto_tree_add_text(subtree2, tvb, o + i + sizeof(bgpa),
1693                     aoff - sizeof(bgpa), "Length: %d %s", tlen,
1694                     (tlen == 1) ? "byte" : "bytes");
1695
1696             /* the second switch prints things in the actual subtree of each
1697                attribute                                                     */
1698             switch (bgpa.bgpa_type) {
1699             case BGPTYPE_ORIGIN:
1700                 if (tlen != 1) {
1701                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1702                             "Origin (invalid): %u %s", tlen,
1703                              (tlen == 1) ? "byte" : "bytes");
1704                 } else {
1705                     proto_tree_add_item(subtree2, hf_bgp_origin, tvb,
1706                             o + i + aoff, 1, FALSE);
1707                 }
1708                 break;
1709             case BGPTYPE_AS_PATH:
1710             case BGPTYPE_NEW_AS_PATH:
1711                 /* check for empty AS_PATH */
1712                 if (tlen == 0) {
1713                     free(as_path_str);
1714                     break;
1715                 }
1716
1717                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1718                         "AS path: %s", as_path_str);
1719                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1720
1721                 /* (o + i + aoff) =
1722                    (o + current attribute + aoff bytes to first tuple) */
1723                 q = o + i + aoff;
1724                 end = q + tlen;
1725
1726                 /* snarf each AS path tuple, we have to step through each one
1727                    again to make a separate subtree so we can't just reuse
1728                    as_path_str from above */
1729                 while (q < end) {
1730                     as_path_str[0] = '\0';
1731                     type = tvb_get_guint8(tvb, q++);
1732                     if (type == AS_SET) {
1733                         snprintf(as_path_str, 2, "{");
1734                     }
1735                     else if (type == AS_CONFED_SET) {
1736                         snprintf(as_path_str, 2, "[");
1737                     }
1738                     else if (type == AS_CONFED_SEQUENCE) {
1739                         snprintf(as_path_str, 2, "(");
1740                     }
1741                     length = tvb_get_guint8(tvb, q++);
1742
1743                     /* snarf each value in path, we're just going to reuse
1744                        as_path_str since we already have it malloced       */
1745                     for (j = 0; j < length; j++) {
1746                         snprintf(junk_buf, sizeof(junk_buf), "%u%s",
1747                                 (asn_len == 2) ? 
1748                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q),
1749                                 (type == AS_SET || type == AS_CONFED_SET) ? ", " : " ");
1750                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1751                         q += asn_len;
1752                     }
1753
1754                     /* cleanup end of string */
1755                     if (type == AS_SET) {
1756                         as_path_str[strlen(as_path_str) - 2] = '}';
1757                     }
1758                     else if (type == AS_CONFED_SET) {
1759                         as_path_str[strlen(as_path_str) - 2] = ']';
1760                     }
1761                     else if (type == AS_CONFED_SEQUENCE) {
1762                         as_path_str[strlen(as_path_str) - 1] = ')';
1763                     }
1764                     else {
1765                         as_path_str[strlen(as_path_str) - 1] = '\0';
1766                     }
1767
1768                     /* length here means number of ASs, ie length * 2 bytes */
1769                     ti = proto_tree_add_text(as_paths_tree, tvb,
1770                             q - length * asn_len - 2,
1771                             length * asn_len + 2, "AS path segment: %s", as_path_str);
1772                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1773                     proto_tree_add_text(as_path_tree, tvb, q - length * asn_len - 2,
1774                             1, "Path segment type: %s (%u)",
1775                             val_to_str(type, as_segment_type, "Unknown"), type);
1776                     proto_tree_add_text(as_path_tree, tvb, q - length * asn_len - 1,
1777                             1, "Path segment length: %u %s", length,
1778                             (length == 1) ? "AS" : "ASs");
1779
1780                     /* backup and reprint path segment value(s) only */
1781                     q -= asn_len * length;
1782                     ti = proto_tree_add_text(as_path_tree, tvb, q,
1783                             length * asn_len, "Path segment value:");
1784                     as_path_segment_tree = proto_item_add_subtree(ti,
1785                             ett_bgp_as_path_segments);
1786                     for (j = 0; j < length; j++) {
1787                         as_path_item = (asn_len == 2) ? 
1788                                 tvb_get_ntohs(tvb, q) : tvb_get_ntohl(tvb, q);
1789                         proto_item_append_text(ti, " %u", as_path_item);
1790                         proto_tree_add_uint_hidden(as_path_tree, hf_bgp_as_path, tvb,
1791                             q, asn_len, as_path_item);
1792                         q += asn_len;
1793                     }
1794                 }
1795
1796                 free(as_path_str);
1797                 break;
1798             case BGPTYPE_NEXT_HOP:
1799                 if (tlen != 4) {
1800                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1801                             "Next hop (invalid): %u %s", tlen,
1802                             (tlen == 1) ? "byte" : "bytes");
1803                 } else {
1804                     proto_tree_add_item(subtree2, hf_bgp_next_hop, tvb,
1805                             o + i + aoff, tlen, FALSE);
1806                 }
1807                 break;
1808             case BGPTYPE_MULTI_EXIT_DISC:
1809                 if (tlen != 4) {
1810                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1811                             "Multiple exit discriminator (invalid): %u %s",
1812                             tlen, (tlen == 1) ? "byte" : "bytes");
1813                 } else {
1814                     proto_tree_add_item(subtree2, hf_bgp_multi_exit_disc, tvb,
1815                             o + i + aoff, tlen, FALSE);
1816                 }
1817                 break;
1818             case BGPTYPE_LOCAL_PREF:
1819                 if (tlen != 4) {
1820                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1821                             "Local preference (invalid): %u %s", tlen,
1822                              (tlen == 1) ? "byte" : "bytes");
1823                 } else {
1824                     proto_tree_add_uint(subtree2, hf_bgp_local_pref, tvb,
1825                             o + i + aoff, tlen, FALSE);
1826                 }
1827                 break;
1828             case BGPTYPE_ATOMIC_AGGREGATE:
1829                 if (tlen != 0) {
1830                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1831                             "Atomic aggregate (invalid): %u %s", tlen,
1832                             (tlen == 1) ? "byte" : "bytes");
1833                 }
1834                 break;
1835             case BGPTYPE_AGGREGATOR:
1836                 if (tlen != 6 && tlen != 8) {
1837                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1838                             "Aggregator (invalid): %u %s", tlen,
1839                             (tlen == 1) ? "byte" : "bytes");
1840                     break;
1841                 }
1842             case BGPTYPE_NEW_AGGREGATOR:
1843                 if (bgpa.bgpa_type == BGPTYPE_NEW_AGGREGATOR && tlen != 8)
1844                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1845                             "Aggregator (invalid): %u %s", tlen,
1846                             (tlen == 1) ? "byte" : "bytes");
1847                 else {
1848                     asn_len = tlen - 4;
1849                     aggregator_as = (asn_len == 2) ?
1850                             tvb_get_ntohs(tvb, o + i + aoff) :
1851                             tvb_get_ntohl(tvb, o + i + aoff);
1852                     proto_tree_add_uint(subtree2, hf_bgp_aggregator_as, tvb,
1853                             o + i + aoff, asn_len, aggregator_as);
1854                     proto_tree_add_item(subtree2, hf_bgp_aggregator_origin, tvb,
1855                         o + i + aoff + asn_len, 4, FALSE);
1856                 }
1857                 break;
1858             case BGPTYPE_COMMUNITIES:
1859                 if (tlen % 4 != 0) {
1860                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1861                             "Communities (invalid): %u %s", tlen,
1862                             (tlen == 1) ? "byte" : "bytes");
1863                     free(communities_str);
1864                     break;
1865                 }
1866
1867                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1868                         "Communities: %s", communities_str);
1869                 communities_tree = proto_item_add_subtree(ti,
1870                         ett_bgp_communities);
1871
1872                 /* (o + i + aoff) =
1873                    (o + current attribute + aoff bytes to first tuple) */
1874                 q = o + i + aoff;
1875                 end = q + tlen;
1876
1877                 /* snarf each community */
1878                 while (q < end) {
1879                     /* check for reserved values */
1880                     guint32 community = tvb_get_ntohl(tvb, q);
1881                     if ((community & 0xFFFF0000) == FOURHEX0 ||
1882                          (community & 0xFFFF0000) == FOURHEXF) {
1883                         proto_tree_add_text(communities_tree, tvb,
1884                                q - 3 + aoff, 4,
1885                                "Community: %s (0x%08x)",
1886                                val_to_str(community, community_vals, "(reserved)"),
1887                                community);
1888                     }
1889                     else {
1890                         ti = proto_tree_add_text(communities_tree, tvb,
1891                                 q - 3 + aoff, 4, "Community: %u:%u",
1892                                 tvb_get_ntohs(tvb, q), tvb_get_ntohs(tvb, q + 2));
1893                         community_tree = proto_item_add_subtree(ti,
1894                             ett_bgp_communities);
1895                         proto_tree_add_item(community_tree, hf_bgp_community_as,
1896                             tvb, q - 3 + aoff, 2, FALSE);
1897                         proto_tree_add_item(community_tree, hf_bgp_community_value,
1898                             tvb, q - 1 + aoff, 2, FALSE);
1899                     }
1900
1901                     q += 4;
1902                 }
1903
1904                 free(communities_str);
1905                 break;
1906             case BGPTYPE_ORIGINATOR_ID:
1907                 if (tlen != 4) {
1908                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1909                             "Originator identifier (invalid): %u %s", tlen,
1910                             (tlen == 1) ? "byte" : "bytes");
1911                 } else {
1912                     proto_tree_add_item(subtree2, hf_bgp_originator_id, tvb,
1913                             o + i + aoff, tlen, FALSE);
1914                 }
1915                 break;
1916            case BGPTYPE_MP_REACH_NLRI:
1917                 /*
1918                  * RFC 2545 specifies that there may be more than one
1919                  * address in the MP_REACH_NLRI attribute in section
1920                  * 3, "Constructing the Next Hop field".
1921                  *
1922                  * Yes, RFC 2858 says you can't do that, and, yes, RFC
1923                  * 2858 obsoletes RFC 2283, which says you can do that,
1924                  * but that doesn't mean we shouldn't dissect packets
1925                  * that conform to RFC 2283 but not RFC 2858, as some
1926                  * device on the network might implement the 2283-style
1927                  * BGP extensions rather than RFC 2858-style extensions.
1928                  */
1929                 af = tvb_get_ntohs(tvb, o + i + aoff);
1930                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1931                     "Address family: %s (%u)",
1932                     val_to_str(af, afn_vals, "Unknown"), af);
1933                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1934                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1935                     "Subsequent address family identifier: %s (%u)",
1936                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1937                     saf);
1938                 if (af != AFNUM_INET && af != AFNUM_INET6 && af != AFNUM_L2VPN) {
1939                     /*
1940                      * The addresses don't contain lengths, so if we
1941                      * don't understand the address family type, we
1942                      * cannot parse the subsequent addresses as we
1943                      * don't know how long they are.
1944                      *
1945                      * XXX - we should put a protocol tree item in for
1946                      * this, as an unknown blob.
1947                      */
1948                     break;
1949                 }
1950                 nexthop_len = tvb_get_guint8(tvb, o + i + aoff + 3);
1951                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
1952                         nexthop_len + 1,
1953                         "Next hop network address (%d %s)",
1954                         nexthop_len, plurality(nexthop_len, "byte", "bytes"));
1955                 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_nhna);
1956                 j = 0;
1957                 while (j < nexthop_len) {
1958                     advance = mp_addr_to_str(af, saf, tvb, o + i + aoff + 4 + j,
1959                         junk_buf, sizeof(junk_buf)) ;
1960                     if (advance == 0) /* catch if this is a unknown AFI type*/
1961                             break;
1962                     if (j + advance > nexthop_len)
1963                             break;
1964                     proto_tree_add_text(subtree3, tvb,o + i + aoff + 4 + j,
1965                         advance, "Next hop: %s (%u)", junk_buf, advance);
1966                     j += advance;
1967                 }
1968                 tlen -= nexthop_len + 4;
1969                 aoff += nexthop_len + 4 ;
1970
1971                 off = 0;
1972                 snpa = tvb_get_guint8(tvb, o + i + aoff);
1973                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1974                         "Subnetwork points of attachment: %u", snpa);
1975                 off++;
1976                 if (snpa) {
1977                         subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_snpa);
1978                         for (/*nothing*/; snpa > 0; snpa--) {
1979                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
1980                                         "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
1981                                 off++;
1982                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
1983                                 tvb_get_guint8(tvb, o + i + aoff + off - 1),
1984                                         "SNPA (%u %s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
1985                                         (tvb_get_guint8(tvb, o + i + aoff + off - 1) == 1) ? "byte" : "bytes");
1986                                 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
1987                         }
1988                 }
1989                 tlen -= off;
1990                 aoff += off;
1991
1992                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1993                         "Network layer reachability information (%u %s)",
1994                         tlen, (tlen == 1) ? "byte" : "bytes");
1995                 if (tlen)  {
1996                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_reach_nlri);
1997
1998                         while (tlen > 0) {
1999                                 advance = decode_prefix_MP(subtree3,
2000                                     hf_bgp_mp_reach_nlri_ipv4_prefix,
2001                                     -1,
2002                                     af, saf,
2003                                     tvb, o + i + aoff, "MP Reach NLRI");
2004                                 if (advance < 0)
2005                                     break;
2006                                 tlen -= advance;
2007                                 aoff += advance;
2008                         }
2009                 }
2010                 break;
2011            case BGPTYPE_MP_UNREACH_NLRI:
2012                 af = tvb_get_ntohs(tvb, o + i + aoff);
2013                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
2014                     "Address family: %s (%u)",
2015                     val_to_str(af, afn_vals, "Unknown"), af);
2016                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
2017                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
2018                     "Subsequent address family identifier: %s (%u)",
2019                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
2020                     saf);
2021                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
2022                         tlen - 3, "Withdrawn routes (%u %s)", tlen - 3,
2023                         (tlen - 3 == 1) ? "byte" : "bytes");
2024
2025                 tlen -= 3;
2026                 aoff += 3;
2027                 if (tlen > 0) {
2028                     subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_unreach_nlri);
2029
2030                     while (tlen > 0) {
2031                         advance = decode_prefix_MP(subtree3,
2032                                 hf_bgp_mp_unreach_nlri_ipv4_prefix,
2033                                 -1,
2034                                 af, saf,
2035                                 tvb, o + i + aoff, "MP Unreach NLRI");
2036                         if (advance < 0)
2037                             break;
2038                         tlen -= advance;
2039                         aoff += advance;
2040                     }
2041                 }
2042                 break;
2043             case BGPTYPE_CLUSTER_LIST:
2044                 if (tlen % 4 != 0) {
2045                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2046                             "Cluster list (invalid): %u %s", tlen,
2047                             (tlen == 1) ? "byte" : "bytes");
2048                     free(cluster_list_str);
2049                     break;
2050                 }
2051
2052                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2053                         "Cluster list: %s", cluster_list_str);
2054                 cluster_list_tree = proto_item_add_subtree(ti,
2055                         ett_bgp_cluster_list);
2056
2057                 /* (o + i + aoff) =
2058                    (o + current attribute + aoff bytes to first tuple) */
2059                 q = o + i + aoff;
2060                 end = q + tlen;
2061
2062                 /* snarf each cluster identifier */
2063                 while (q < end) {
2064                     proto_tree_add_item(cluster_list_tree, hf_bgp_cluster_list,
2065                             tvb, q - 3 + aoff, 4, FALSE);
2066                     q += 4;
2067                 }
2068
2069                 free(cluster_list_str);
2070                 break;
2071             case BGPTYPE_EXTENDED_COMMUNITY:
2072                 if (tlen %8 != 0) {
2073                         proto_tree_add_text(subtree3, tvb, o + i + aoff, tlen, "Extended community (invalid) : %u %s", tlen,
2074                                 (tlen == 1) ? "byte" : "bytes") ;
2075                 } else {
2076                         q = o + i + aoff ;
2077                         end = o + i + aoff + tlen ;
2078                         ti = proto_tree_add_text(subtree2,tvb,q,tlen, "Carried Extended communities");
2079                         subtree3 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
2080
2081                         while (q < end) {
2082                             junk_buf_len=0;
2083                             ext_com = tvb_get_ntohs(tvb,q) ;
2084                             junk_buf_len=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf), "%s",
2085                                                   val_to_str(ext_com,bgpext_com_type,"Unknown"));
2086                             switch (ext_com) {
2087                             case BGP_EXT_COM_RT_0:
2088                             case BGP_EXT_COM_RO_0:
2089                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %u%s%d",
2090                                                        tvb_get_ntohs(tvb,q+2),":",tvb_get_ntohl(tvb,q+4));
2091                                 junk_buf[junk_buf_len]='\0';
2092                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2093                                 break ;
2094                             case BGP_EXT_COM_RT_1:
2095                             case BGP_EXT_COM_RO_1:
2096                                 tvb_memcpy(tvb,ipaddr,q+2,4);
2097                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %s%s%u",
2098                                                        ip_to_str(ipaddr),":",tvb_get_ntohs(tvb,q+6));
2099                                 junk_buf[junk_buf_len]='\0';
2100                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2101                                 break;
2102                             case BGP_EXT_COM_VPN_ORIGIN:
2103                             case BGP_EXT_COM_OSPF_RID:
2104                                 tvb_memcpy(tvb,ipaddr,q+2,4);
2105                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %s",
2106                                                        ip_to_str(ipaddr));
2107                                 junk_buf[junk_buf_len]='\0';
2108                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2109                                 break;
2110                             case BGP_EXT_COM_OSPF_RTYPE:
2111                                 tvb_memcpy(tvb,ipaddr,q+2,4);
2112                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": Area:%s %s",
2113                                          ip_to_str(ipaddr),
2114                                          val_to_str(tvb_get_guint8(tvb,q+6),bgpext_ospf_rtype,"Unknown"));
2115                                 /* print OSPF Metric type if selected */
2116                                 /* always print E2 even if not external route -- receiving router should ignore */
2117                                 if ( (tvb_get_guint8(tvb,q+7)) & BGP_OSPF_RTYPE_METRIC_TYPE ) {
2118                                     junk_buf_len+=snprintf(junk_buf+junk_buf_len,sizeof(junk_buf)-junk_buf_len," E2");
2119                                 } else if (tvb_get_guint8(tvb,q+6)==(BGP_OSPF_RTYPE_EXT ||BGP_OSPF_RTYPE_NSSA ) ) {
2120                                     junk_buf_len+=snprintf(junk_buf+junk_buf_len,sizeof(junk_buf)-junk_buf_len," E1");
2121                                 }
2122                                 junk_buf[junk_buf_len]='\0';
2123                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2124                                 break;
2125                             case BGP_EXT_COM_LINKBAND:
2126                                 tvb_memcpy(tvb,ipaddr,q+2,4); /* need to check on IEEE format on all platforms */
2127                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %.3f Mbps",
2128                                                        ((double)*ipaddr)*8/1000000);
2129                                 junk_buf[junk_buf_len]='\0';
2130                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2131                                 break;
2132                             case BGP_EXT_COM_L2INFO:
2133                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len,
2134                                                        ": %s, Control Flags: %s%s%s%s%s, MTU: %u %s",
2135                                                        val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"),
2136                                                        tvb_get_guint8(tvb,q+3) ? "" : "none",
2137                                                        tvb_get_ntohs(tvb,q+3)&0x08 ? "Q" : "",
2138                                                        tvb_get_ntohs(tvb,q+3)&0x04 ? "F" : "",
2139                                                        tvb_get_ntohs(tvb,q+3)&0x02 ? "C" : "",
2140                                                        tvb_get_ntohs(tvb,q+3)&0x01 ? "S" : "",
2141                                                        tvb_get_ntohs(tvb,q+4),
2142                                                        tvb_get_ntohs(tvb,q+4)==1 ? "byte" : "bytes");
2143                                 junk_buf[junk_buf_len]='\0';
2144                                 ti = proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2145
2146                                 subtree4 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
2147                                 proto_tree_add_text(subtree4,tvb,q+2,1, "Encapsulation: %s",
2148                                                          val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"));
2149                                 proto_tree_add_text(subtree4,tvb,q+3,1, "Control Flags: %s%sControl Word %s required, Sequenced delivery %s required",
2150                                                     tvb_get_ntohs(tvb,q+3)&0x08 ? "Q flag (Reserved) set" : "",
2151                                                     tvb_get_ntohs(tvb,q+3)&0x04 ? "F flag (reserved) set" : "",
2152                                                     tvb_get_ntohs(tvb,q+3)&0x02 ? "is" : "not",
2153                                                     tvb_get_ntohs(tvb,q+3)&0x01 ? "is" : "not");
2154                                 proto_tree_add_text(subtree4,tvb,q+4,2, "MTU: %u %s",
2155                                                     tvb_get_ntohs(tvb,q+4),
2156                                                     tvb_get_ntohs(tvb,q+4)==1 ? "byte" : "bytes");
2157                                 break;
2158                             default:
2159                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, " ");
2160                                 junk_buf[junk_buf_len]='\0';
2161                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
2162                                 break ;
2163                             }
2164                             q = q + 8 ;
2165                         }
2166                 }
2167                 break;
2168             default:
2169                 proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
2170                         "Unknown (%d %s)", tlen, (tlen == 1) ? "byte" :
2171                         "bytes");
2172                 break;
2173             } /* end of second switch */
2174
2175             i += alen + aoff;
2176         }
2177
2178         o += 2 + len;
2179
2180         /* NLRI */
2181         len = hlen - o;
2182
2183         /* parse prefixes */
2184         if (len > 0) {
2185             ti = proto_tree_add_text(tree, tvb, o, len,
2186                    "Network layer reachability information: %u %s", len,
2187                    (len == 1) ? "byte" : "bytes");
2188             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
2189             end = o + len;
2190             while (o < end) {
2191                 i = decode_prefix4(subtree, hf_bgp_nlri_prefix, tvb, o, 0,
2192                     "NLRI");
2193                 if (i < 0)
2194                     return;
2195                 o += i;
2196             }
2197         }
2198     }
2199 }
2200
2201 /*
2202  * Dissect a BGP NOTIFICATION message.
2203  */
2204 static void
2205 dissect_bgp_notification(tvbuff_t *tvb, proto_tree *tree)
2206 {
2207     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
2208     int                     hlen;   /* message length           */
2209     char                    *p;     /* string pointer           */
2210
2211     /* snarf message */
2212     tvb_memcpy(tvb, bgpn.bgpn_marker, 0, BGP_MIN_NOTIFICATION_MSG_SIZE);
2213     hlen = g_ntohs(bgpn.bgpn_len);
2214
2215     /* print error code */
2216     proto_tree_add_text(tree, tvb,
2217         offsetof(struct bgp_notification, bgpn_major), 1,
2218         "Error code: %s (%u)",
2219         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
2220         bgpn.bgpn_major);
2221
2222     /* print error subcode */
2223     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
2224      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
2225         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
2226             "Unknown");
2227     } else if (bgpn.bgpn_minor == 0)
2228         p = "Unspecified";
2229     else
2230         p = "Unknown";
2231     proto_tree_add_text(tree, tvb,
2232         offsetof(struct bgp_notification, bgpn_minor), 1,
2233         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
2234
2235     /* only print if there is optional data */
2236     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
2237         proto_tree_add_text(tree, tvb, BGP_MIN_NOTIFICATION_MSG_SIZE,
2238             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
2239     }
2240 }
2241
2242 /*
2243  * Dissect a BGP ROUTE-REFRESH message.
2244  */
2245 static void
2246 dissect_bgp_route_refresh(tvbuff_t *tvb, proto_tree *tree)
2247 {
2248     guint16         i;    /* tmp            */
2249     int             p;         /* tvb offset counter    */
2250     int             pend;       /* end of list of entries for one orf type */
2251     guint16         hlen;       /* tvb RR msg length */
2252     proto_item      *ti;       /* tree item             */
2253     proto_item      *ti1;       /* tree item             */
2254     proto_tree      *subtree;  /* tree for orf   */
2255     proto_tree      *subtree1; /* tree for orf entry */
2256     guint8          orftype;        /* ORF Type */
2257     guint8          orfwhen;        /* ORF flag: immediate, defer */
2258     guint16         orflen;         /* ORF len */
2259     guint8          entryflag;      /* ORF Entry flag: action(add,del,delall) match(permit,deny) */
2260     guint32         entryseq;       /* ORF Entry sequence number */
2261     int             entrylen;       /* ORF Entry length */
2262     guint8          pfx_ge;         /* ORF PrefixList mask lower bound */
2263     guint8          pfx_le;         /* ORF PrefixList mask upper bound */
2264     int             advance;        /* tmp                      */
2265
2266
2267 /*
2268 example 1
2269  00 1c 05       hlen=28
2270  00 01 00 01    afi,safi= ipv4-unicast
2271  02 80 00 01    defer, prefix-orf, len=1
2272     80            removeall
2273 example 2
2274  00 25 05       hlen=37
2275  00 01 00 01    afi,saif= ipv4-unicast
2276  01 80 00 0a    immediate, prefix-orf, len=10
2277     00            add
2278     00 00 00 05   seqno = 5
2279     12            ge = 18
2280     18            le = 24
2281     10 07 02      prefix = 7.2.0.0/16
2282 */
2283     hlen = tvb_get_ntohs(tvb, BGP_MARKER_SIZE);
2284     p = BGP_HEADER_SIZE;
2285     /* AFI */
2286     i = tvb_get_ntohs(tvb, p);
2287     proto_tree_add_text(tree, tvb, p, 2,
2288                         "Address family identifier: %s (%u)",
2289                         val_to_str(i, afn_vals, "Unknown"), i);
2290     p += 2;
2291     /* Reserved */
2292     proto_tree_add_text(tree, tvb, p, 1,
2293                         "Reserved: 1 byte");
2294     p++;
2295     /* SAFI */
2296     i = tvb_get_guint8(tvb, p);
2297     proto_tree_add_text(tree, tvb, p, 1,
2298                         "Subsequent address family identifier: %s (%u)",
2299                         val_to_str(i, bgpattr_nlri_safi,
2300                         i >= 128 ? "Vendor specific" : "Unknown"),
2301                         i);
2302     p++;
2303     if ( hlen == BGP_HEADER_SIZE + 4 )
2304         return;
2305     while (p < hlen) {
2306         /* ORF type */
2307         orfwhen = tvb_get_guint8(tvb, p);
2308         orftype = tvb_get_guint8(tvb, p+1);
2309         orflen = tvb_get_ntohs(tvb, p+2);
2310         ti = proto_tree_add_text(tree, tvb, p , orflen + 4 , "ORF information (%u bytes)", orflen + 4);
2311         subtree = proto_item_add_subtree(ti, ett_bgp_orf);
2312         proto_tree_add_text(subtree, tvb, p , 1, "ORF flag: %s", val_to_str(orfwhen, orf_when_vals,"UNKNOWN"));
2313         proto_tree_add_text(subtree, tvb, p+1 , 1, "ORF type: %s", val_to_str(orftype, orf_type_vals,"UNKNOWN"));
2314         proto_tree_add_text(subtree, tvb, p+2 , 2, "ORF len: %u %s", orflen, (orflen == 1) ? "byte" : "bytes");
2315         p += 4;
2316
2317         if (orftype != BGP_ORF_PREFIX_CISCO) {
2318             proto_tree_add_text(subtree, tvb, p, orflen,
2319                     "ORFEntry-Unknown (%u bytes)", orflen);
2320             p += orflen;
2321             continue;
2322         }
2323         pend = p + orflen;
2324         while (p < pend) {
2325             entryflag = tvb_get_guint8(tvb, p);
2326             if ((entryflag & BGP_ORF_ACTION) == BGP_ORF_REMOVEALL) {
2327                 ti1 = proto_tree_add_text(subtree, tvb, p, 1,
2328                         "ORFEntry-PrefixList (1 byte)");
2329                 subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
2330                 proto_tree_add_text(subtree1, tvb, p , 1, "RemoveAll");
2331                 p++;
2332             } else {
2333                 ti1 = proto_tree_add_text(subtree, tvb, p, -1,
2334                         "ORFEntry-PrefixList");
2335                 subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
2336                 proto_tree_add_text(subtree1, tvb, p, 1,
2337                         "ACTION: %s MATCH: %s",
2338                         val_to_str(entryflag&BGP_ORF_ACTION,
2339                             orf_entry_action_vals, "UNKNOWN"),
2340                         val_to_str(entryflag&BGP_ORF_MATCH,
2341                             orf_entry_match_vals, "UNKNOWN"));
2342                 p++;
2343                 entryseq = tvb_get_ntohl(tvb, p);
2344                 proto_tree_add_text(subtree1, tvb, p, 4,
2345                         "Entry Sequence No: %u", entryseq);
2346                 p += 4;
2347                 pfx_ge = tvb_get_guint8(tvb, p);
2348                 proto_tree_add_text(subtree1, tvb, p, 1,
2349                         "PrefixMask length lower bound: %u", pfx_ge);
2350                 p++;
2351                 pfx_le = tvb_get_guint8(tvb, p);
2352                 proto_tree_add_text(subtree1, tvb, p, 1,
2353                         "PrefixMask length upper bound: %u", pfx_le);
2354                 p++;
2355
2356                 advance = decode_prefix4(subtree1, -1, tvb, p, 0, "ORF");
2357                 if (advance < 0)
2358                         break;
2359                 entrylen = 7 + 1 + advance;
2360
2361                 proto_item_append_text(ti1, " (%u bytes)", entrylen);
2362                 proto_item_set_len(ti1, entrylen);
2363                 p += advance;
2364             }
2365         }
2366     }
2367 }
2368
2369 /*
2370  * Dissect a BGP CAPABILITY message.
2371  */
2372 static void
2373 dissect_bgp_capability(tvbuff_t *tvb, proto_tree *tree)
2374 {
2375     int offset = 0;
2376     proto_item *ti;
2377     proto_tree *subtree;
2378     guint8  action;
2379     int ctype;
2380     int clen;
2381     int mend;
2382
2383     mend = offset + tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
2384     offset += BGP_HEADER_SIZE;
2385     /* step through all of the capabilities */
2386     while (offset < mend) {
2387         action = tvb_get_guint8(tvb, offset++);
2388         ctype  = tvb_get_guint8(tvb, offset++);
2389         clen   = tvb_get_guint8(tvb, offset++);
2390
2391         ti = proto_tree_add_text(tree, tvb, offset - 2, 2 + clen, 
2392              "%s (%u %s)", val_to_str(ctype, capability_vals,
2393              "Unknown capability"), 2 + clen, (clen == 1) ? "byte" : "bytes");
2394         subtree = proto_item_add_subtree(ti, ett_bgp_option);
2395         proto_tree_add_text(subtree, tvb, offset-2, 1, "Action: %d (%s)",
2396             action, val_to_str(action, bgpcap_action, "Invalid action value"));
2397         dissect_bgp_capability_item(tvb, &offset, subtree, ctype, clen);
2398     }
2399 }
2400
2401 static void
2402 dissect_bgp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2403     gboolean first)
2404 {
2405     guint16       bgp_len;       /* Message length             */
2406     guint8        bgp_type;      /* Message type               */
2407     char          *typ;          /* Message type (string)      */
2408     proto_item    *ti;           /* tree item                        */
2409     proto_tree    *bgp_tree;     /* BGP packet tree                  */
2410     proto_tree    *bgp1_tree;    /* BGP message tree                 */
2411
2412     bgp_len = tvb_get_ntohs(tvb, BGP_MARKER_SIZE);
2413     bgp_type = tvb_get_guint8(tvb, BGP_MARKER_SIZE + 2);
2414     typ = val_to_str(bgp_type, bgptypevals, "Unknown message type (0x%02x)");
2415
2416     if (check_col(pinfo->cinfo, COL_INFO)) {
2417         if (first)
2418             col_add_fstr(pinfo->cinfo, COL_INFO, "%s", typ);
2419         else
2420             col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", typ);
2421     }
2422
2423     if (tree) {
2424         ti = proto_tree_add_item(tree, proto_bgp, tvb, 0, -1, FALSE);
2425         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
2426
2427         ti = proto_tree_add_text(bgp_tree, tvb, 0, -1, "%s", typ);
2428
2429         /* add a different tree for each message type */
2430         switch (bgp_type) {
2431         case BGP_OPEN:
2432             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
2433             break;
2434         case BGP_UPDATE:
2435             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
2436             break;
2437         case BGP_NOTIFICATION:
2438             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
2439             break;
2440         case BGP_KEEPALIVE:
2441             bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2442             break;
2443         case BGP_ROUTE_REFRESH_CISCO:
2444         case BGP_ROUTE_REFRESH:
2445             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
2446             break;
2447         case BGP_CAPABILITY:
2448             bgp1_tree = proto_item_add_subtree(ti, ett_bgp_capability);
2449             break;
2450         default:
2451             bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2452             break;
2453         }
2454
2455         proto_tree_add_text(bgp1_tree, tvb, 0, BGP_MARKER_SIZE,
2456                             "Marker: 16 bytes");
2457
2458         if (bgp_len < BGP_HEADER_SIZE || bgp_len > BGP_MAX_PACKET_SIZE) {
2459             proto_tree_add_text(bgp1_tree, tvb, BGP_MARKER_SIZE, 2,
2460                                 "Length (invalid): %u %s", bgp_len,
2461                                 (bgp_len == 1) ? "byte" : "bytes");
2462             return;
2463         } else {
2464             proto_tree_add_text(bgp1_tree, tvb, BGP_MARKER_SIZE, 2,
2465                                 "Length: %u %s", bgp_len,
2466                                 (bgp_len == 1) ? "byte" : "bytes");
2467         }
2468
2469         proto_tree_add_uint(bgp1_tree, hf_bgp_type, tvb,
2470                                    BGP_MARKER_SIZE + 2, 1,
2471                                    bgp_type);
2472
2473         switch (bgp_type) {
2474         case BGP_OPEN:
2475             dissect_bgp_open(tvb, bgp1_tree);
2476             break;
2477         case BGP_UPDATE:
2478             dissect_bgp_update(tvb, bgp1_tree);
2479             break;
2480         case BGP_NOTIFICATION:
2481             dissect_bgp_notification(tvb, bgp1_tree);
2482             break;
2483         case BGP_KEEPALIVE:
2484             /* no data in KEEPALIVE messages */
2485             break;
2486         case BGP_ROUTE_REFRESH_CISCO:
2487         case BGP_ROUTE_REFRESH:
2488             dissect_bgp_route_refresh(tvb, bgp1_tree);
2489             break;
2490         case BGP_CAPABILITY:
2491             dissect_bgp_capability(tvb, bgp1_tree);
2492             break;
2493         default:
2494             break;
2495         }
2496     }
2497 }
2498
2499 /*
2500  * Dissect a BGP packet.
2501  */
2502 static void
2503 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2504 {
2505     volatile int  offset = 0;   /* offset into the tvbuff           */
2506     gint          reported_length_remaining;
2507     guint8        bgp_marker[BGP_MARKER_SIZE];    /* Marker (should be all ones */
2508     static guchar marker[] = {   /* BGP message marker               */
2509         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2510         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2511     };
2512     proto_item    *ti;           /* tree item                        */
2513     proto_tree    *bgp_tree;     /* BGP packet tree                  */
2514     guint16       bgp_len;       /* Message length             */
2515     int           offset_before;
2516     guint         length_remaining;
2517     guint         length;
2518     volatile gboolean first = TRUE;  /* TRUE for the first BGP message in packet */
2519     tvbuff_t      *next_tvb;
2520
2521     if (check_col(pinfo->cinfo, COL_PROTOCOL))
2522         col_set_str(pinfo->cinfo, COL_PROTOCOL, "BGP");
2523     if (check_col(pinfo->cinfo, COL_INFO))
2524         col_clear(pinfo->cinfo, COL_INFO);
2525
2526     /*
2527      * Scan through the TCP payload looking for a BGP marker.
2528      */
2529     while ((reported_length_remaining = tvb_reported_length_remaining(tvb, offset))
2530                 != 0) {
2531         /*
2532          * "reported_length_remaining" is the number of bytes of TCP payload
2533          * remaining.  If it's more than the length of a BGP marker,
2534          * we check only the number of bytes in a BGP marker.
2535          */
2536         if (reported_length_remaining > BGP_MARKER_SIZE)
2537             reported_length_remaining = BGP_MARKER_SIZE;
2538
2539         /*
2540          * OK, is there a BGP marker starting at the specified offset -
2541          * or, at least, the beginning of a BGP marker running to the end
2542          * of the TCP payload?
2543          *
2544          * This will throw an exception if the frame is short; that's what
2545          * we want.
2546          */
2547         tvb_memcpy(tvb, bgp_marker, offset, reported_length_remaining);
2548         if (memcmp(bgp_marker, marker, reported_length_remaining) == 0) {
2549             /*
2550              * Yes - stop scanning and start processing BGP packets.
2551              */
2552             break;
2553         }
2554
2555         /*
2556          * No - keep scanning through the tvbuff to try to find a marker.
2557          */
2558         offset++;
2559     }
2560
2561     /*
2562      * If we skipped any bytes, mark it as a BGP continuation.
2563      */
2564     if (offset > 0) {
2565         ti = proto_tree_add_item(tree, proto_bgp, tvb, 0, -1, FALSE);
2566         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
2567
2568         proto_tree_add_text(bgp_tree, tvb, 0, offset, "Continuation");
2569     }
2570
2571     /*
2572      * Now process the BGP packets in the TCP payload.
2573      *
2574      * XXX - perhaps "tcp_dissect_pdus()" should take a starting
2575      * offset, in which case we can replace the loop below with
2576      * a call to "tcp_dissect_pdus()".
2577      */
2578     while (tvb_reported_length_remaining(tvb, offset) != 0) {
2579         /*
2580          * This will throw an exception if we don't have any data left.
2581          * That's what we want.  (See "tcp_dissect_pdus()", which is
2582          * similar.)
2583          */
2584         length_remaining = tvb_ensure_length_remaining(tvb, offset);
2585
2586         /*
2587          * Can we do reassembly?
2588          */
2589         if (bgp_desegment && pinfo->can_desegment) {
2590             /*
2591              * Yes - would a BGP header starting at this offset be split
2592              * across segment boundaries?
2593              */
2594             if (length_remaining < BGP_HEADER_SIZE) {
2595                 /*
2596                  * Yes.  Tell the TCP dissector where the data for this
2597                  * message starts in the data it handed us, and how many
2598                  * more bytes we need, and return.
2599                  */
2600                 pinfo->desegment_offset = offset;
2601                 pinfo->desegment_len = BGP_HEADER_SIZE - length_remaining;
2602                 return;
2603             }
2604         }
2605
2606         /*
2607          * Get the length and type from the BGP header.
2608          */
2609         bgp_len = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
2610         if (bgp_len < BGP_HEADER_SIZE) {
2611             /*
2612              * The BGP length doesn't include the BGP header; report that
2613              * as an error.
2614              * Report this as an error.
2615              */
2616             show_reported_bounds_error(tvb, pinfo, tree);
2617             return;
2618         }
2619
2620         /*
2621          * Can we do reassembly?
2622          */
2623         if (bgp_desegment && pinfo->can_desegment) {
2624             /*
2625              * Yes - is the PDU split across segment boundaries?
2626              */
2627             if (length_remaining < bgp_len) {
2628                 /*
2629                  * Yes.  Tell the TCP dissector where the data for this
2630                  * message starts in the data it handed us, and how many
2631                  * more bytes we need, and return.
2632                  */
2633                 pinfo->desegment_offset = offset;
2634                 pinfo->desegment_len = bgp_len - length_remaining;
2635                 return;
2636             }
2637         }
2638
2639         /*
2640          * Construct a tvbuff containing the amount of the payload we have
2641          * available.  Make its reported length the amount of data in the PDU.
2642          *
2643          * XXX - if reassembly isn't enabled. the subdissector will throw a
2644          * BoundsError exception, rather than a ReportedBoundsError exception.
2645          * We really want a tvbuff where the length is "length", the reported
2646          * length is "plen", and the "if the snapshot length were infinite"
2647          * length is the minimum of the reported length of the tvbuff handed
2648          * to us and "plen", with a new type of exception thrown if the offset
2649          * is within the reported length but beyond that third length, with
2650          * that exception getting the "Unreassembled Packet" error.
2651          */
2652         length = length_remaining;
2653         if (length > bgp_len)
2654             length = bgp_len;
2655         next_tvb = tvb_new_subset(tvb, offset, length, bgp_len);
2656
2657         /*
2658          * Dissect the PDU.
2659          *
2660          * Catch the ReportedBoundsError exception; if this particular message
2661          * happens to get a ReportedBoundsError exception, that doesn't mean
2662          * that we should stop dissecting PDUs within this frame or chunk of
2663          * reassembled data.
2664          *
2665          * If it gets a BoundsError, we can stop, as there's nothing more to
2666          * see, so we just re-throw it.
2667          */
2668         TRY {
2669             dissect_bgp_pdu(next_tvb, pinfo, tree, first);
2670         }
2671         CATCH(BoundsError) {
2672             RETHROW;
2673         }
2674         CATCH(ReportedBoundsError) {
2675             show_reported_bounds_error(tvb, pinfo, tree);
2676         }
2677         ENDTRY;
2678
2679         first = FALSE;
2680
2681         /*
2682          * Step to the next PDU.
2683          * Make sure we don't overflow.
2684          */
2685         offset_before = offset;
2686         offset += bgp_len;
2687         if (offset <= offset_before)
2688             break;
2689     }
2690 }
2691
2692 /*
2693  * Register ourselves.
2694  */
2695 void
2696 proto_register_bgp(void)
2697 {
2698
2699     static hf_register_info hf[] = {
2700       { &hf_bgp_type,
2701         { "Type", "bgp.type", FT_UINT8, BASE_DEC,
2702           VALS(bgptypevals), 0x0, "BGP message type", HFILL }},
2703       { &hf_bgp_aggregator_as,
2704         { "Aggregator AS", "bgp.aggregator_as", FT_UINT16, BASE_DEC,
2705           NULL, 0x0, "", HFILL}},
2706       { &hf_bgp_aggregator_origin,
2707         { "Aggregator origin", "bgp.aggregator_origin", FT_IPv4, BASE_NONE,
2708           NULL, 0x0, "", HFILL}}, 
2709       { &hf_bgp_as_path,
2710         { "AS Path", "bgp.as_path", FT_UINT16, BASE_DEC,
2711           NULL, 0x0, "", HFILL}},
2712       { &hf_bgp_cluster_identifier,
2713         { "Cluster identifier", "bgp.cluster_identifier", FT_IPv4, BASE_NONE,
2714           NULL, 0x0, "", HFILL}},
2715       { &hf_bgp_community_as,
2716         { "Community AS", "bgp.community_as", FT_UINT16, BASE_DEC,
2717           NULL, 0x0, "", HFILL}},
2718       { &hf_bgp_community_value,
2719         { "Community value", "bgp.community_value", FT_UINT16, BASE_DEC,
2720           NULL, 0x0, "", HFILL}},
2721       { &hf_bgp_local_pref,
2722         { "Local preference", "bgp.local_pref", FT_UINT32, BASE_DEC,
2723           NULL, 0x0, "", HFILL}},
2724       { &hf_bgp_mp_reach_nlri_ipv4_prefix,
2725         { "MP Reach NLRI IPv4 prefix", "bgp.mp_reach_nlri_ipv4_prefix", FT_IPv4, BASE_NONE,
2726           NULL, 0x0, "", HFILL}},
2727       { &hf_bgp_mp_unreach_nlri_ipv4_prefix,
2728         { "MP Unreach NLRI IPv4 prefix", "bgp.mp_unreach_nlri_ipv4_prefix", FT_IPv4, BASE_NONE,
2729           NULL, 0x0, "", HFILL}}, 
2730       { &hf_bgp_multi_exit_disc,
2731         { "Multiple exit discriminator", "bgp.multi_exit_disc", FT_UINT32, BASE_DEC,
2732           NULL, 0x0, "", HFILL}},
2733       { &hf_bgp_next_hop,
2734         { "Next hop", "bgp.next_hop", FT_IPv4, BASE_NONE,
2735           NULL, 0x0, "", HFILL}}, 
2736       { &hf_bgp_nlri_prefix,
2737         { "NLRI prefix", "bgp.nlri_prefix", FT_IPv4, BASE_NONE,
2738           NULL, 0x0, "", HFILL}}, 
2739       { &hf_bgp_origin,
2740         { "Origin", "bgp.origin", FT_UINT8, BASE_DEC,
2741           VALS(bgpattr_origin), 0x0, "", HFILL}},
2742       { &hf_bgp_originator_id,
2743         { "Originator identifier", "bgp.originator_id", FT_IPv4, BASE_NONE,
2744           NULL, 0x0, "", HFILL}},
2745       { &hf_bgp_withdrawn_prefix,
2746         { "Withdrawn prefix", "bgp.withdrawn_prefix", FT_IPv4, BASE_NONE,
2747           NULL, 0x0, "", HFILL}}, 
2748     };
2749
2750     static gint *ett[] = {
2751       &ett_bgp,
2752       &ett_bgp_prefix,
2753       &ett_bgp_unfeas,
2754       &ett_bgp_attrs,
2755       &ett_bgp_attr,
2756       &ett_bgp_attr_flags,
2757       &ett_bgp_mp_nhna,
2758       &ett_bgp_mp_reach_nlri,
2759       &ett_bgp_mp_unreach_nlri,
2760       &ett_bgp_mp_snpa,
2761       &ett_bgp_nlri,
2762       &ett_bgp_open,
2763       &ett_bgp_update,
2764       &ett_bgp_notification,
2765       &ett_bgp_route_refresh,
2766       &ett_bgp_capability,
2767       &ett_bgp_as_paths,
2768       &ett_bgp_as_path_segments,
2769       &ett_bgp_communities,
2770       &ett_bgp_cluster_list,
2771       &ett_bgp_options,
2772       &ett_bgp_option,
2773       &ett_bgp_extended_communities,
2774       &ett_bgp_orf,
2775       &ett_bgp_orf_entry
2776     };
2777     module_t *bgp_module;
2778     static enum_val_t asn_len[] = {
2779         {"Auto-detect", 0},
2780         {"2 octet", 2},
2781         {"4 octet", 4},
2782         {NULL, -1}
2783     };
2784
2785     proto_bgp = proto_register_protocol("Border Gateway Protocol",
2786                                         "BGP", "bgp");
2787     proto_register_field_array(proto_bgp, hf, array_length(hf));
2788     proto_register_subtree_array(ett, array_length(ett));
2789
2790     bgp_module = prefs_register_protocol(proto_bgp, NULL);
2791     prefs_register_bool_preference(bgp_module, "desegment",
2792       "Desegment all BGP messages spanning multiple TCP segments",
2793       "Whether the BGP dissector should desegment all messages spanning multiple TCP segments",
2794       &bgp_desegment);
2795     prefs_register_enum_preference(bgp_module, "asn_len",
2796       "Length of the AS number",
2797       "BGP dissector detect the length of the AS number in AS_PATH attributes automatically or manually (NOTE: Automatic detection is not 100% accurate)",
2798       &bgp_asn_len, asn_len, FALSE);
2799 }
2800
2801 void
2802 proto_reg_handoff_bgp(void)
2803 {
2804     dissector_handle_t bgp_handle;
2805
2806     bgp_handle = create_dissector_handle(dissect_bgp, proto_bgp);
2807     dissector_add("tcp.port", BGP_TCP_PORT, bgp_handle);
2808 }