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