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