Removed trailing whitespaces from .h and .c files using the
[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.66 2002/08/27 19:12:35 guy Exp $
6  *
7  * Supports:
8  * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9  * RFC1965 Autonomous System Confederations for BGP
10  * RFC1997 BGP Communities Attribute
11  * RFC2547 BGP/MPLS VPNs
12  * RFC2796 BGP Route Reflection An alternative to full mesh IBGP
13  * RFC2842 Capabilities Advertisement with BGP-4
14  * RFC2858 Multiprotocol Extensions for BGP-4
15  * RFC2918 Route Refresh Capability for BGP-4
16  * RFC3107 Carrying Label Information in BGP-4
17  * Draft Ramahandra on Extended Communities Extentions
18  *
19  * TODO:
20  * Destination Preference Attribute for BGP (work in progress)
21  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
22  *
23  * Ethereal - Network traffic analyzer
24  * By Gerald Combs <gerald@ethereal.com>
25  * Copyright 1998 Gerald Combs
26  *
27  * This program is free software; you can redistribute it and/or
28  * modify it under the terms of the GNU General Public License
29  * as published by the Free Software Foundation; either version 2
30  * of the License, or (at your option) any later version.
31  *
32  * This program is distributed in the hope that it will be useful,
33  * but WITHOUT ANY WARRANTY; without even the implied warranty of
34  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35  * GNU General Public License for more details.
36  *
37  * You should have received a copy of the GNU General Public License
38  * along with this program; if not, write to the Free Software
39  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
40  */
41
42 #ifdef HAVE_CONFIG_H
43 # include "config.h"
44 #endif
45
46 #include <stdio.h>
47 #include <stdlib.h>
48
49 #include <string.h>
50 #include <glib.h>
51
52 #ifdef NEED_SNPRINTF_H
53 # include "snprintf.h"
54 #endif
55
56 #include <epan/packet.h>
57 #include "packet-bgp.h"
58 #include "packet-ipv6.h"
59 #include "afn.h"
60 #include "prefs.h"
61
62 static const value_string bgptypevals[] = {
63     { BGP_OPEN, "OPEN Message" },
64     { BGP_UPDATE, "UPDATE Message" },
65     { BGP_NOTIFICATION, "NOTIFICATION Message" },
66     { BGP_KEEPALIVE, "KEEPALIVE Message" },
67     { BGP_ROUTE_REFRESH, "ROUTE-REFRESH Message" },
68     { BGP_ROUTE_REFRESH_CISCO, "Cisco ROUTE-REFRESH Message" },
69     { 0, NULL },
70 };
71
72 static const value_string bgpnotify_major[] = {
73     { 1, "Message Header Error" },
74     { 2, "OPEN Message Error" },
75     { 3, "UPDATE Message Error" },
76     { 4, "Hold Timer Expired" },
77     { 5, "Finite State Machine Error" },
78     { 6, "Cease" },
79     { 0, NULL },
80 };
81
82 static const value_string bgpnotify_minor_1[] = {
83     { 1, "Connection Not Synchronized" },
84     { 2, "Bad Message Length" },
85     { 3, "Bad Message Type" },
86     { 0, NULL },
87 };
88
89 static const value_string bgpnotify_minor_2[] = {
90     { 1, "Unsupported Version Number" },
91     { 2, "Bad Peer AS" },
92     { 3, "Bad BGP Identifier" },
93     { 4, "Unsupported Optional Parameter" },
94     { 5, "Authentication Failure" },
95     { 6, "Unacceptable Hold Time" },
96     { 7, "Unsupported Capability" },
97     { 0, NULL },
98 };
99
100 static const value_string bgpnotify_minor_3[] = {
101     { 1, "Malformed Attribute List" },
102     { 2, "Unrecognized Well-known Attribute" },
103     { 3, "Missing Well-known Attribute" },
104     { 4, "Attribute Flags Error" },
105     { 5, "Attribute Length Error" },
106     { 6, "Invalid ORIGIN Attribute" },
107     { 7, "AS Routing Loop" },
108     { 8, "Invalid NEXT_HOP Attribute" },
109     { 9, "Optional Attribute Error" },
110     { 10, "Invalid Network Field" },
111     { 11, "Malformed AS_PATH" },
112     { 0, NULL },
113 };
114
115 static const value_string *bgpnotify_minor[] = {
116     NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
117 };
118
119 static const value_string bgpattr_origin[] = {
120     { 0, "IGP" },
121     { 1, "EGP" },
122     { 2, "INCOMPLETE" },
123     { 0, NULL },
124 };
125
126 static const value_string as_segment_type[] = {
127     { 1, "AS_SET" },
128     { 2, "AS_SEQUENCE" },
129 /* RFC1965 has the wrong values, corrected in  */
130 /* draft-ietf-idr-bgp-confed-rfc1965bis-01.txt */
131     { 4, "AS_CONFED_SET" },
132     { 3, "AS_CONFED_SEQUENCE" },
133     { 0, NULL },
134 };
135
136 static const value_string bgpattr_type[] = {
137     { BGPTYPE_ORIGIN, "ORIGIN" },
138     { BGPTYPE_AS_PATH, "AS_PATH" },
139     { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
140     { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
141     { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
142     { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
143     { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
144     { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
145     { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
146     { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
147     { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
148     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
149     { BGPTYPE_EXTENDED_COMMUNITY, "EXTENDED_COMMUNITIES" },
150     { 0, NULL },
151 };
152
153 /* Beware : See also MAX_SIZE_OF_EXT_COM_NAMES */
154 static const value_string bgpext_com_type[] = {
155     { BGP_EXT_COM_RT_0, "Route Target" },
156     { BGP_EXT_COM_RT_1, "Route Target" },
157     { BGP_EXT_COM_RO_0, "Route Origin" },
158     { BGP_EXT_COM_RO_1, "Route Origin" },
159     { BGP_EXT_COM_LINKBAND, "Link Bandwidth" },
160     { BGP_EXT_COM_VPN_ORIGIN, "OSPF Domain" },
161     { BGP_EXT_COM_OSPF_RTYPE, "OSPF Route Type" },
162     { BGP_EXT_COM_OSPF_RID, "OSPF Router ID" },
163     { BGP_EXT_COM_L2INFO, "Layer 2 Information" },
164     { 0, NULL },
165 };
166
167 static const value_string bgp_l2vpn_encaps[] = {
168     { 0,                      "Reserved"},
169     { 1,                      "Frame Relay"},
170     { 2,                      "ATM AAL5 VCC transport"},
171     { 3,                      "ATM transparent cell transport"}, 
172     { 4,                      "Ethernet VLAN"}, 
173     { 5,                      "Ethernet"}, 
174     { 6,                      "Cisco-HDLC"}, 
175     { 7,                      "PPP"}, 
176     { 8,                      "CEM"}, 
177     { 9,                      "ATM VCC cell transport"}, 
178     { 10,                     "ATM VPC cell transport"}, 
179     { 11,                     "MPLS"}, 
180     { 12,                     "VPLS"}, 
181     { 64,                     "IP-interworking"}, 
182     { 0, NULL},
183 };
184
185 static const value_string bgpext_ospf_rtype[] = {
186   { BGP_OSPF_RTYPE_RTR, "Router" },  
187   { BGP_OSPF_RTYPE_NET, "Network" },  
188   { BGP_OSPF_RTYPE_SUM, "Summary" },  
189   { BGP_OSPF_RTYPE_EXT, "External" },  
190   { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
191   { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },  
192   { 0, NULL },
193 };
194
195
196 /* MUST be resized if a longer named extended community is added */
197 #define MAX_SIZE_OF_EXT_COM_NAMES       20
198
199 /* Subsequent address family identifier, RFC2858 */
200 static const value_string bgpattr_nlri_safi[] = {
201     { 0, "Reserved" },
202     { SAFNUM_UNICAST, "Unicast" },
203     { SAFNUM_MULCAST, "Multicast" },
204     { SAFNUM_UNIMULC, "Unicast+Multicast" },
205     { SAFNUM_MPLS_LABEL, "MPLS Labeled Prefix"},
206     { SAFNUM_LAB_VPNUNICAST, "Labeled VPN Unicast" },        /* draft-rosen-rfc2547bis-03 */
207     { SAFNUM_LAB_VPNMULCAST, "Labeled VPN Multicast" },
208     { SAFNUM_LAB_VPNUNIMULC, "Labeled VPN Unicast+Multicast" },
209     { 0, NULL },
210 };
211
212 /* ORF Type, draft-ietf-idr-route-filter-04.txt */
213 static const value_string orf_type_vals[] = {
214     { 2,        "Communities ORF-Type" },
215     { 3,        "Extended Communities ORF-Type" },
216     { 128,      "Cisco PrefixList ORF-Type" },
217     { 129,      "Cisco CommunityList ORF-Type" },
218     { 130,      "Cisco Extended CommunityList ORF-Type" },
219     { 131,      "Cisco AsPathList ORF-Type" },
220     { 0,        NULL },
221 };
222
223 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
224 static const value_string orf_send_recv_vals[] = {
225     { 1,        "Receive" },
226     { 2,        "Send" },
227     { 3,        "Both" },
228     { 0,        NULL },
229 };
230
231 /* ORF Send/Receive, draft-ietf-idr-route-filter-04.txt */
232 static const value_string orf_when_vals[] = {
233     { 1,        "Immediate" },
234     { 2,        "Defer" },
235     { 0,        NULL },
236 };
237
238 static const value_string orf_entry_action_vals[] = {
239     { 0,        "Add" },
240     { 0x40,     "Remove" },
241     { 0x80,     "RemoveAll" },
242     { 0,        NULL },
243 };
244
245 static const value_string orf_entry_match_vals[] = {
246     { 0,        "Permit" },
247     { 0x20,     "Deny" },
248     { 0,        NULL },
249 };
250 /* Maximal size of an IP address string */
251 #define MAX_SIZE_OF_IP_ADDR_STRING      16
252
253 static int proto_bgp = -1;
254 static int hf_bgp_type = -1;
255
256 static gint ett_bgp = -1;
257 static gint ett_bgp_unfeas = -1;
258 static gint ett_bgp_attrs = -1;
259 static gint ett_bgp_attr = -1;
260 static gint ett_bgp_attr_flags = -1;
261 static gint ett_bgp_mp_nhna = -1;
262 static gint ett_bgp_mp_reach_nlri = -1;
263 static gint ett_bgp_mp_unreach_nlri = -1;
264 static gint ett_bgp_mp_snpa = -1;
265 static gint ett_bgp_nlri = -1;
266 static gint ett_bgp_open = -1;
267 static gint ett_bgp_update = -1;
268 static gint ett_bgp_notification = -1;
269 static gint ett_bgp_route_refresh = -1; /* ROUTE-REFRESH message tree */
270 static gint ett_bgp_as_paths = -1;
271 static gint ett_bgp_communities = -1;
272 static gint ett_bgp_cluster_list = -1;  /* cluster list tree          */
273 static gint ett_bgp_options = -1;       /* optional parameters tree   */
274 static gint ett_bgp_option = -1;        /* an optional parameter tree */
275 static gint ett_bgp_extended_communities = -1 ; /* extended communities list tree */ 
276 static gint ett_bgp_orf = -1;           /* orf (outbound route filter) tree */
277 static gint ett_bgp_orf_entry = -1;             /* orf entry tree */
278
279 /* desegmentation */
280 static gboolean bgp_desegment = TRUE;
281
282 /*
283  * Decode an IPv4 prefix.
284  */
285 static int
286 decode_prefix4(tvbuff_t *tvb, gint offset, char *buf, int buflen)
287 {
288     guint8 addr[4];   /* IP address                         */
289     int    plen;      /* prefix length                      */
290     int    length;    /* number of octets needed for prefix */
291
292     /* snarf length */
293     plen = tvb_get_guint8(tvb, offset);
294     if (plen < 0 || 32 < plen)
295         return -1;
296     length = (plen + 7) / 8;
297
298     /* snarf prefix */
299     memset(addr, 0, sizeof(addr));
300     tvb_memcpy(tvb, addr, offset + 1, length);
301     if (plen % 8)
302         addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
303
304     /* hand back a formatted string */
305     snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
306     return(1 + length);
307 }
308
309 /*
310  * Decode an IPv6 prefix.
311  */
312 static int
313 decode_prefix6(tvbuff_t *tvb, gint offset, char *buf, int buflen)
314 {
315     struct e_in6_addr addr;     /* IPv6 address                       */
316     int               plen;     /* prefix length                      */
317     int               length;   /* number of octets needed for prefix */
318
319     /* snarf length */
320     plen = tvb_get_guint8(tvb, offset);
321     if (plen < 0 || 128 < plen)
322         return -1;
323     length = (plen + 7) / 8;
324
325     /* snarf prefix */
326     memset(&addr, 0, sizeof(addr));
327     tvb_memcpy(tvb, (guint8 *)&addr, offset + 1, length);
328     if (plen % 8)
329         addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
330
331     /* hand back a formatted string */
332     snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
333     return(1 + length);
334 }
335
336
337
338 /*
339  * Decode an MPLS label stack
340  */
341 static int
342 decode_MPLS_stack(tvbuff_t *tvb, gint offset, char *buf, size_t buflen)
343 {
344     guint32     label_entry;    /* an MPLS label enrty (label + COS field + stack bit   */
345     gint        index;          /* index for the label stack                            */
346     char        junk_buf[256];  /* tmp                                                  */
347
348     index = offset ;
349     label_entry = 0x000000 ;
350
351     buf[0] = '\0' ;
352
353     while ((label_entry & 0x000001) == 0) {
354
355         label_entry = tvb_get_ntoh24(tvb, index) ;
356
357         /* withdrawn routes may contain 0 or 0x800000 in the first label */
358         if((index-offset)==0&&(label_entry==0||label_entry==0x800000)) {
359             snprintf(buf, buflen, "0 (withdrawn)");
360             return (1);
361         }
362
363         snprintf(junk_buf, sizeof(junk_buf),"%u%s", (label_entry >> 4), ((label_entry & 0x000001) == 0) ? "," : " (bottom)");
364         if (strlen(buf) + strlen(junk_buf) + 1 <= buflen)
365             strcat(buf, junk_buf);
366         index += 3 ;
367
368         if ((label_entry & 0x000001) == 0) {
369             /* real MPLS multi-label stack in BGP? - maybe later; for now, it must be a bogus packet */
370             strcpy(junk_buf, " (BOGUS: Bottom of Stack NOT set!)");
371             if (strlen(buf) + strlen(junk_buf) + 1 <= buflen)
372                 strcat(buf, junk_buf);
373             break;
374         }         
375     }
376
377     return((index - offset) / 3);
378 }
379
380 /*
381  * Decode a multiprotocol address
382  */
383
384 static int
385 mp_addr_to_str (guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *buf, int buflen)
386 {
387     int                 length;                         /* length of the address in byte */
388     guint8              ip4addr[4],ip4addr2[4];         /* IPv4 address                 */
389     guint16             rd_type;                        /* Route Distinguisher type     */
390     struct e_in6_addr   ip6addr;                        /* IPv6 address                 */
391
392     length = 0 ;
393     switch (afi) {
394         case AFNUM_INET:
395                 switch (safi) {
396                         case SAFNUM_UNICAST:
397                         case SAFNUM_MULCAST:
398                         case SAFNUM_UNIMULC:
399                         case SAFNUM_MPLS_LABEL:
400                                 length = 4 ;
401                                 tvb_memcpy(tvb, ip4addr, offset, 4);
402                                 snprintf(buf, buflen, "%s", ip_to_str(ip4addr));
403                                 break;
404                         case SAFNUM_LAB_VPNUNICAST:
405                         case SAFNUM_LAB_VPNMULCAST:
406                         case SAFNUM_LAB_VPNUNIMULC:
407                                 rd_type=tvb_get_ntohs(tvb,offset) ;
408                                 switch (rd_type) {
409                                         case FORMAT_AS2_LOC:
410                                                 length = 12;
411                                                 tvb_memcpy(tvb, ip4addr, offset + 8, 4);
412                                                 snprintf(buf, buflen, "Empty Label Stack RD=%u:%u IP=%s",
413                                                                 tvb_get_ntohs(tvb, offset + 2),
414                                                                 tvb_get_ntohl(tvb, offset + 4),
415                                                                 ip_to_str(ip4addr));
416                                                 break;
417                                         case FORMAT_IP_LOC:
418                                                 length = 12;
419                                                 tvb_memcpy(tvb, ip4addr, offset + 2, 4);   /* IP part of the RD            */
420                                                 tvb_memcpy(tvb, ip4addr2, offset +6, 4);   /* IP address of the VPN        */
421                                                 snprintf(buf, buflen, "Empty Label Stack RD=%s:%u IP=%s",
422                                                                 ip_to_str(ip4addr),
423                                                                 tvb_get_ntohs(tvb, offset + 6),
424                                                                 ip_to_str(ip4addr2));
425                                                 break ;
426                                         default:
427                                                 length = 0 ;
428                                                 snprintf(buf, buflen, "Unknown (0x%04x)labeled VPN address format",rd_type);
429                                                 break;
430                                 }
431                                 break;
432                         default:
433                             length = 0 ;
434                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
435                             break;
436                 }
437                 break;
438         case AFNUM_INET6:
439                 switch (safi) {
440                         case SAFNUM_UNICAST: /* only decode unlabeled prefixes */
441                         case SAFNUM_MULCAST:
442                         case SAFNUM_UNIMULC:
443                             length = 16 ;
444                             tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8,offset, sizeof(ip6addr));
445                             snprintf(buf, buflen, "%s", ip6_to_str(&ip6addr));
446                             break;
447                         default:
448                             length = 0 ;
449                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
450                             break;
451                 }
452                 break;
453        case AFNUM_L2VPN:
454                 switch (safi) {
455                         case SAFNUM_LAB_VPNUNICAST: /* only labeles prefixes do make sense */
456                         case SAFNUM_LAB_VPNMULCAST:
457                         case SAFNUM_LAB_VPNUNIMULC:
458                             length = 4; /* the next-hop is simply an ipv4 addr */
459                             tvb_memcpy(tvb, ip4addr, offset + 0, 4);
460                             snprintf(buf, buflen, "IP=%s",
461                                      ip_to_str(ip4addr));
462                             break;
463                         default:
464                             length = 0 ;
465                             snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
466                             break; 
467                 }
468                 break;
469         default:
470                 length = 0 ;
471                 snprintf(buf, buflen, "Unknown AFI (%u) value", afi);
472                 break;
473     }
474     return(length) ;
475 }
476
477 /*
478  * Decode a multiprotocol prefix
479  */
480 static int
481 decode_prefix_MP(guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset, char *buf, int buflen)
482 {
483     int                 length;                         /* length of the prefix in byte */
484     int                 plen;                           /* length of the prefix in bit  */
485     int                 labnum;                         /* number of labels             */
486     int                 ce_id,labblk_off;
487     guint8              ip4addr[4],ip4addr2[4];         /* IPv4 address                 */
488     guint16             rd_type;                        /* Route Distinguisher type     */
489     char                lab_stk[256];                   /* label stack                  */
490
491     length = 0 ;
492
493     switch (afi) {
494         case AFNUM_INET:
495                 switch (safi) {
496                         case SAFNUM_UNICAST:
497                         case SAFNUM_MULCAST:
498                         case SAFNUM_UNIMULC:
499                                 length = decode_prefix4(tvb, offset, buf, buflen) - 1 ;
500                                 break;
501                         case SAFNUM_MPLS_LABEL:
502                                 plen =  tvb_get_guint8(tvb,offset) ;
503                                 labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
504
505                                 offset += (1 + labnum * 3);
506                                 plen -= (labnum * 3*8);
507                                 if (plen < 0 || 32 < plen) {
508                                         length = 0 ;
509                                         break ;
510                                 }
511
512                                 length = (plen + 7) / 8;
513                                 memset(ip4addr, 0, sizeof(ip4addr));
514                                 tvb_memcpy(tvb, ip4addr, offset, length);
515                                 if (plen % 8)
516                                         ip4addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
517
518                                 snprintf(buf,buflen, "Label Stack=%s IP=%s/%d",
519                                          lab_stk,
520                                          ip_to_str(ip4addr),
521                                          plen);
522                                 length += (labnum*3) ;
523                                 break;
524
525                         case SAFNUM_LAB_VPNUNICAST:
526                         case SAFNUM_LAB_VPNMULCAST:
527                         case SAFNUM_LAB_VPNUNIMULC:
528                                 plen =  tvb_get_guint8(tvb,offset) ;
529
530                                 labnum = decode_MPLS_stack(tvb, offset + 1, lab_stk, sizeof(lab_stk));
531
532                                 offset += (1 + labnum * 3);
533                                 plen -= (labnum * 3*8);
534
535                                 rd_type=tvb_get_ntohs(tvb,offset) ;
536                                 plen -= 8*8;
537
538                                 switch (rd_type) {
539                                         case FORMAT_AS2_LOC: /* Code borrowed from the decode_prefix4 function */
540                                                 if (plen < 0 || 32 < plen) {
541                                                         length = 0 ;
542                                                         break ;
543                                                 }
544
545                                                 length = (plen + 7) / 8;
546                                                 memset(ip4addr, 0, sizeof(ip4addr));
547                                                 tvb_memcpy(tvb, ip4addr, offset + 8, length);
548                                                 if (plen % 8)
549                                                         ip4addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
550
551                                                 snprintf(buf,buflen, "Label Stack=%s RD=%u:%u, IP=%s/%d",
552                                                         lab_stk,
553                                                         tvb_get_ntohs(tvb, offset + 2),
554                                                         tvb_get_ntohl(tvb, offset + 4),
555                                                         ip_to_str(ip4addr),
556                                                         plen);
557                                                 length += (labnum * 3 + 8) ;
558                                                 break ;
559                                         case FORMAT_IP_LOC: /* Code borrowed from the decode_prefix4 function */
560                                                 tvb_memcpy(tvb, ip4addr, offset + 2, 4);
561
562                                                 if (plen < 0 || 32 < plen) {
563                                                         length = 0 ;
564                                                         break ;
565                                                 }
566
567                                                 length = (plen + 7) / 8;
568                                                 memset(ip4addr2, 0, sizeof(ip4addr2));
569                                                 tvb_memcpy(tvb, ip4addr2, offset + 8, length);
570                                                 if (plen % 8)
571                                                         ip4addr2[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
572
573                                                 snprintf(buf,buflen, "Label Stack=%s RD=%s:%u, IP=%s/%d",
574                                                         lab_stk,
575                                                         ip_to_str(ip4addr),
576                                                         tvb_get_ntohs(tvb, offset + 6),
577                                                         ip_to_str(ip4addr2),
578                                                         plen);
579                                                 length += (labnum * 3 + 8) ;
580                                                 break ;
581                                         default:
582                                                 length = 0 ;
583                                                 snprintf(buf,buflen, "Unknown labeled VPN address format");
584                                                 break;
585                                 }
586                                 break;
587                 default:
588                         length = 0 ;
589                         snprintf(buf,buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
590                         break;
591                 }
592                 break;
593         case AFNUM_INET6:
594                 switch (safi) {
595                         case SAFNUM_UNICAST:
596                         case SAFNUM_MULCAST:
597                         case SAFNUM_UNIMULC:
598                             length = decode_prefix6(tvb, offset, buf, buflen) - 1 ;
599                             break;
600                 default:
601                         length = 0 ;
602                         snprintf(buf,buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
603                         break;
604                 }
605                 break;
606        case AFNUM_L2VPN:
607                 switch (safi) {
608                         case SAFNUM_LAB_VPNUNICAST:
609                         case SAFNUM_LAB_VPNMULCAST:
610                         case SAFNUM_LAB_VPNUNIMULC:
611                                 plen =  tvb_get_ntohs(tvb,offset);
612                                 rd_type=tvb_get_ntohs(tvb,offset+2);
613                                 ce_id=tvb_get_ntohs(tvb,offset+10);
614                                 labblk_off=tvb_get_ntohs(tvb,offset+12);
615                                 labnum = decode_MPLS_stack(tvb, offset + 14, lab_stk, sizeof(lab_stk));
616  
617                                 switch (rd_type) {
618                                         case FORMAT_AS2_LOC:
619                                                 tvb_memcpy(tvb, ip4addr, offset + 6, 4);
620                                                 snprintf(buf,buflen, "RD: %u:%s, CE-ID: %u, Label-Block Offset: %u, Label Base %s",
621                                                          tvb_get_ntohs(tvb, offset + 4),
622                                                          ip_to_str(ip4addr),
623                                                          ce_id,
624                                                          labblk_off,
625                                                          lab_stk);
626                                                 break ;
627                                         case FORMAT_IP_LOC:
628                                                 tvb_memcpy(tvb, ip4addr, offset + 4, 4);
629                                                 snprintf(buf,buflen, "RD: %s:%u, CE-ID: %u, Label-Block Offset: %u, Label Base %s",
630                                                          ip_to_str(ip4addr),
631                                                          tvb_get_ntohs(tvb, offset + 8),
632                                                          ce_id,
633                                                          labblk_off,
634                                                          lab_stk);
635                                                 break ;
636                                         default:
637                                                 length = 0 ;
638                                                 snprintf(buf,buflen, "Unknown labeled VPN address format");
639                                                 break;
640                                 }
641                             /* FIXME there are subTLVs left to decode ... for now lets omit them */
642                             length=plen+1; /* should be 2 but length+1 is returned at the end */
643                             break;
644                 default:
645                         length = 0 ;
646                         snprintf(buf, buflen, "Unknown SAFI (%u) for AFI %u", safi, afi);
647                         break;
648                 }
649                 break;
650         default:
651                 length = 0 ;
652                 snprintf(buf,buflen, "Unknown AFI (%u) value", afi);
653                 break;
654     }
655     return(1 + length) ;
656 }
657
658 /*
659  * Dissect a BGP OPEN message.
660  */
661 static const value_string community_vals[] = {
662         { BGP_COMM_NO_EXPORT,           "NO_EXPORT" },
663         { BGP_COMM_NO_ADVERTISE,        "NO_ADVERTISE" },
664         { BGP_COMM_NO_EXPORT_SUBCONFED, "NO_EXPORT_SUBCONFED" },
665         { 0,                            NULL }
666 };
667
668 static void
669 dissect_bgp_open(tvbuff_t *tvb, int offset, proto_tree *tree)
670 {
671     struct bgp_open bgpo;      /* BGP OPEN message      */
672     int             hlen;      /* message length        */
673     guint           i;         /* tmp                   */
674     int             ptype;     /* parameter type        */
675     int             plen;      /* parameter length      */
676     int             ctype;     /* capability type       */
677     int             clen;      /* capability length     */
678     int             cend;      /* capabilities end      */
679     int             ostart;    /* options start         */
680     int             oend;      /* options end           */
681     int             p;         /* tvb offset counter    */
682     proto_item      *ti;       /* tree item             */
683     proto_tree      *subtree;  /* subtree for options   */
684     proto_tree      *subtree1; /* subtree for an option */
685     proto_tree      *subtree2; /* subtree for an option */
686     proto_tree      *subtree3; /* subtree for an option */
687     guint8          orfnum;    /* number of ORFs */
688     guint8          orftype;        /* ORF Type */
689     guint8          orfsendrecv;    /* ORF Send/Receive */
690
691     /* snarf OPEN message */
692     tvb_memcpy(tvb, bgpo.bgpo_marker, offset, BGP_MIN_OPEN_MSG_SIZE);
693     hlen = g_ntohs(bgpo.bgpo_len);
694
695     proto_tree_add_text(tree, tvb,
696         offset + offsetof(struct bgp_open, bgpo_version), 1,
697         "Version: %u", bgpo.bgpo_version);
698     proto_tree_add_text(tree, tvb,
699         offset + offsetof(struct bgp_open, bgpo_myas), 2,
700         "My AS: %u", g_ntohs(bgpo.bgpo_myas));
701     proto_tree_add_text(tree, tvb,
702         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
703         "Hold time: %u", g_ntohs(bgpo.bgpo_holdtime));
704     proto_tree_add_text(tree, tvb,
705         offset + offsetof(struct bgp_open, bgpo_id), 4,
706         "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
707     proto_tree_add_text(tree, tvb,
708         offset + offsetof(struct bgp_open, bgpo_optlen), 1,
709         "Optional parameters length: %u %s", bgpo.bgpo_optlen,
710         (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
711
712     /* optional parameters */
713     if (bgpo.bgpo_optlen > 0) {
714         /* add a subtree and setup some offsets */
715         ostart = offset + BGP_MIN_OPEN_MSG_SIZE;
716         ti = proto_tree_add_text(tree, tvb, ostart, bgpo.bgpo_optlen,
717              "Optional parameters");
718         subtree = proto_item_add_subtree(ti, ett_bgp_options);
719         p = offset + ostart;
720         oend = p + bgpo.bgpo_optlen;
721
722         /* step through all of the optional parameters */
723         while (p < oend) {
724
725             /* grab the type and length */
726             ptype = tvb_get_guint8(tvb, p++);
727             plen = tvb_get_guint8(tvb, p++);
728
729             /* check the type */
730             switch (ptype) {
731             case BGP_OPTION_AUTHENTICATION:
732                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
733                     "Authentication information (%u %s)", plen,
734                     (plen == 1) ? "byte" : "bytes");
735                 break;
736             case BGP_OPTION_CAPABILITY:
737                 /* grab the capability code */
738                 cend = p - 1 + plen;
739                 ctype = tvb_get_guint8(tvb, p++);
740                 clen = tvb_get_guint8(tvb, p++);
741                 ti = proto_tree_add_text(subtree, tvb, p - 4,
742                      2 + plen, "Capabilities Advertisement (%u bytes)",
743                      2 + plen);
744                 subtree1 = proto_item_add_subtree(ti, ett_bgp_option);
745                 proto_tree_add_text(subtree1, tvb, p - 4,
746                      1, "Parameter type: Capabilities (2)");
747                 proto_tree_add_text(subtree1, tvb, p - 3,
748                      1, "Parameter length: %u %s", plen,
749                      (plen == 1) ? "byte" : "bytes");
750                 p -= 2;
751
752                 /* step through all of the capabilities */
753                 while (p < cend) {
754                     ctype = tvb_get_guint8(tvb, p++);
755                     clen = tvb_get_guint8(tvb, p++);
756
757                     /* check the capability type */
758                     switch (ctype) {
759                     case BGP_CAPABILITY_RESERVED:
760                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
761                              2 + clen, "Reserved capability (%u %s)", 2 + clen,
762                              (clen == 1) ? "byte" : "bytes");
763                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
764                         proto_tree_add_text(subtree2, tvb, p - 2,
765                              1, "Capability code: Reserved (0)");
766                         proto_tree_add_text(subtree2, tvb, p - 1,
767                              1, "Capability length: %u %s", clen,
768                              (clen == 1) ? "byte" : "bytes");
769                         if (clen != 0) {
770                             proto_tree_add_text(subtree2, tvb, p,
771                                  clen, "Capability value: Unknown");
772                         }
773                         p += clen;
774                         break;
775                     case BGP_CAPABILITY_MULTIPROTOCOL:
776                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
777                              2 + clen,
778                              "Multiprotocol extensions capability (%u %s)",
779                              2 + clen, (clen == 1) ? "byte" : "bytes");
780                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
781                         proto_tree_add_text(subtree2, tvb, p - 2,
782                              1, "Capability code: Multiprotocol extensions (%d)",
783                              ctype);
784                         if (clen != 4) {
785                             proto_tree_add_text(subtree2, tvb, p - 1,
786                                  1, "Capability length: Invalid");
787                             proto_tree_add_text(subtree2, tvb, p,
788                                  clen, "Capability value: Unknown");
789                         }
790                         else {
791                             proto_tree_add_text(subtree2, tvb, p - 1,
792                                  1, "Capability length: %u %s", clen,
793                                  (clen == 1) ? "byte" : "bytes");
794                             ti = proto_tree_add_text(subtree2, tvb, p,
795                                  clen, "Capability value");
796                             subtree3 = proto_item_add_subtree(ti,
797                                        ett_bgp_option);
798                             /* AFI */
799                             i = tvb_get_ntohs(tvb, p);
800                             proto_tree_add_text(subtree3, tvb, p,
801                                  2, "Address family identifier: %s (%u)",
802                                  val_to_str(i, afn_vals, "Unknown"), i);
803                             p += 2;
804                             /* Reserved */
805                             proto_tree_add_text(subtree3, tvb, p,
806                                  1, "Reserved: 1 byte");
807                             p++;
808                             /* SAFI */
809                             i = tvb_get_guint8(tvb, p);
810                             proto_tree_add_text(subtree3, tvb, p,
811                                  1, "Subsequent address family identifier: %s (%u)",
812                                  val_to_str(i, bgpattr_nlri_safi,
813                                     i >= 128 ? "Vendor specific" : "Unknown"), i);
814                             p++;
815                         }
816                         break;
817                     case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
818                     case BGP_CAPABILITY_ROUTE_REFRESH:
819                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
820                              2 + clen, "Route refresh capability (%u %s)", 2 + clen,
821                              (clen == 1) ? "byte" : "bytes");
822                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
823                         proto_tree_add_text(subtree2, tvb, p - 2,
824                              1, "Capability code: Route refresh (%d)", ctype);
825                         if (clen != 0) {
826                             proto_tree_add_text(subtree2, tvb, p,
827                                  clen, "Capability value: Invalid");
828                         }
829                         else {
830                             proto_tree_add_text(subtree2, tvb, p - 1,
831                                  1, "Capability length: %u %s", clen,
832                                  (clen == 1) ? "byte" : "bytes");
833                         }
834                         p += clen;
835                         break;
836                     case BGP_CAPABILITY_ORF_CISCO:
837                     case BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING:
838                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
839                              2 + clen,
840                              "Cooperative route filtering capability (%u %s)",
841                              2 + clen, (clen == 1) ? "byte" : "bytes");
842                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
843                         proto_tree_add_text(subtree2, tvb, p - 2,
844                              1, "Capability code: Cooperative route filtering (%d)",
845                              ctype);
846                         proto_tree_add_text(subtree2, tvb, p - 1,
847                              1, "Capability length: %u %s", clen,
848                              (clen == 1) ? "byte" : "bytes");
849                         ti = proto_tree_add_text(subtree2, tvb, p,
850                              clen, "Capability value");
851                         subtree3 = proto_item_add_subtree(ti, ett_bgp_option);
852                         /* AFI */
853                         i = tvb_get_ntohs(tvb, p);
854                         proto_tree_add_text(subtree3, tvb, p,
855                              2, "Address family identifier: %s (%u)",
856                              val_to_str(i, afn_vals, "Unknown"), i);
857                         p += 2;
858                         /* Reserved */
859                         proto_tree_add_text(subtree3, tvb, p, 
860                              1, "Reserved: 1 byte");
861                         p++;
862                         /* SAFI */
863                         i = tvb_get_guint8(tvb, p);
864                         proto_tree_add_text(subtree3, tvb, p,
865                              1, "Subsequent address family identifier: %s (%u)",
866                              val_to_str(i, bgpattr_nlri_safi,
867                              i >= 128 ? "Vendor specific" : "Unknown"), i);
868                         p++;
869                         /* Number of ORFs */
870                         orfnum = tvb_get_guint8(tvb, p);
871                         proto_tree_add_text(subtree3, tvb, p,
872                                             1, "Number of ORFs: %u", orfnum);
873                         p++;
874                         for (i=0; i<orfnum; i++) {
875                             /* ORF Type */
876                             orftype = tvb_get_guint8(tvb, p);
877                             proto_tree_add_text(subtree3, tvb, p,
878                                 1, "ORF Type: %s (%u)",
879                                 val_to_str(orftype, orf_type_vals,"Unknown"),
880                                 orftype);
881                             p++;
882                             /* Send/Receive */
883                             orfsendrecv = tvb_get_guint8(tvb, p);
884                             proto_tree_add_text(subtree3, tvb, p,
885                                 1, "Send/Receive: %s (%u)",
886                                 val_to_str(orfsendrecv, orf_send_recv_vals, 
887                                 "Uknown"), orfsendrecv);
888                             p++;
889                         }
890                         break;
891                     /* unknown capability */
892                     default:
893                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
894                              2 + clen, "Unknown capability (%u %s)", 2 + clen,
895                              (clen == 1) ? "byte" : "bytes");
896                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
897                         proto_tree_add_text(subtree2, tvb, p - 2,
898                              1, "Capability code: %s (%d)",
899                              ctype >= 128 ? "Private use" : "Unknown", ctype);
900                         proto_tree_add_text(subtree2, tvb, p - 1,
901                              1, "Capability length: %u %s", clen,
902                              (clen == 1) ? "byte" : "bytes");
903                         if (clen != 0) {
904                             proto_tree_add_text(subtree2, tvb, p,
905                                  clen, "Capability value: Unknown");
906                         }
907                         p += clen;
908                         break;
909                     }
910                 }
911                 break;
912             default:
913                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
914                     "Unknown optional parameter");
915                 break;
916             }
917         }
918     }
919 }
920
921 /*
922  * Dissect a BGP UPDATE message.
923  */
924 static void
925 dissect_bgp_update(tvbuff_t *tvb, int offset, proto_tree *tree)
926  {
927     struct bgp_attr bgpa;                       /* path attributes          */
928     int             hlen;                       /* message length           */
929     gint            o;                          /* packet offset            */
930     gint            q;                          /* tmp                      */
931     gint            end;                        /* message end              */
932     gint            ext_com;                    /* EXTENDED COMMUNITY type  */
933     int             len;                        /* tmp                      */
934     int             advance;                    /* tmp                      */
935     proto_item      *ti;                        /* tree item                */
936     proto_tree      *subtree;                   /* subtree for attributes   */
937     proto_tree      *subtree2;                  /* subtree for attributes   */
938     proto_tree      *subtree3;                  /* subtree for attributes   */
939     proto_tree      *subtree4;                  /* subtree for attributes   */
940     proto_tree      *as_paths_tree;             /* subtree for AS_PATHs     */
941     proto_tree      *as_path_tree;              /* subtree for AS_PATH      */
942     proto_tree      *communities_tree;          /* subtree for COMMUNITIES  */
943     proto_tree      *community_tree;            /* subtree for a community  */
944     proto_tree      *cluster_list_tree;         /* subtree for CLUSTER_LIST */
945     int             i, j;                       /* tmp                      */
946     guint8          length;                     /* AS_PATH length           */
947     guint8          type;                       /* AS_PATH type             */
948     char            *as_path_str = NULL;        /* AS_PATH string           */
949     char            *communities_str = NULL;    /* COMMUNITIES string       */
950     char            *cluster_list_str = NULL;   /* CLUSTER_LIST string      */
951     char            junk_buf[256];              /* tmp                      */
952     int             junk_buf_len;               /* tmp len                  */
953     guint8          ipaddr[4];                  /* IPv4 address             */
954
955     hlen = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
956     o = offset + BGP_HEADER_SIZE;
957
958     /* check for withdrawals */
959     len = tvb_get_ntohs(tvb, o);
960     proto_tree_add_text(tree, tvb, o, 2,
961         "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
962     o += 2;
963
964     /* parse unfeasible prefixes */
965     if (len > 0) {
966         ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
967         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
968
969         /* parse each prefixes */
970         end = o + len;
971         while (o < end) {
972             i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
973             proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
974             o += i;
975         }
976     }
977     else {
978         o += len;
979     }
980     /* check for advertisements */
981     len = tvb_get_ntohs(tvb, o);
982     proto_tree_add_text(tree, tvb, o, 2, "Total path attribute length: %u %s",
983             len, (len == 1) ? "byte" : "bytes");
984
985     /* path attributes */
986     if (len > 0) {
987         ti = proto_tree_add_text(tree, tvb, o + 2, len, "Path attributes");
988         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
989         i = 2;
990         while (i < len) {
991             int alen, tlen, aoff;
992             char *msg;
993             guint16 af;
994             guint8 saf;
995             int off, snpa;
996             int nexthop_len;
997
998             tvb_memcpy(tvb, (guint8 *)&bgpa, o + i, sizeof(bgpa));
999             /* check for the Extended Length bit */
1000             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1001                 alen = tvb_get_ntohs(tvb, o + i + sizeof(bgpa));
1002                 aoff = sizeof(bgpa) + 2;
1003             } else {
1004                 alen = tvb_get_guint8(tvb, o + i + sizeof(bgpa));
1005                 aoff = sizeof(bgpa) + 1;
1006             }
1007             tlen = alen;
1008
1009             /* This is kind of ugly - similar code appears twice, but it
1010                helps browsing attrs.                                      */
1011             /* the first switch prints things in the title of the subtree */
1012             switch (bgpa.bgpa_type) {
1013             case BGPTYPE_ORIGIN:
1014                 if (tlen != 1)
1015                     goto default_attribute_top;
1016                 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1017                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1018                         "%s: %s (%u %s)",
1019                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1020                         msg, tlen + aoff, (tlen + aoff == 1) ? "byte" :
1021                         "bytes");
1022                 break;
1023             case BGPTYPE_AS_PATH:
1024                 /* (o + i + aoff) =
1025                    (o + current attribute + aoff bytes to first tuple) */
1026                 q = o + i + aoff;
1027                 end = q + tlen;
1028                 /* must be freed by second switch!                         */
1029                 /* "tlen * 6" (5 digits + space) should be a good estimate
1030                    of how long the AS path string could be                 */
1031                 as_path_str = malloc((tlen + 1) * 6);
1032                 if (as_path_str == NULL) break;
1033                 as_path_str[0] = '\0';
1034
1035                 /* snarf each AS path */
1036                 while (q < end) {
1037                     type = tvb_get_guint8(tvb, q++);
1038                     if (type == AS_SET) {
1039                         snprintf(as_path_str, 2, "{");
1040                     }
1041                     else if (type == AS_CONFED_SET) {
1042                         snprintf(as_path_str, 2, "[");
1043                     }
1044                     else if (type == AS_CONFED_SEQUENCE) {
1045                         snprintf(as_path_str, 2, "(");
1046                     }
1047                     length = tvb_get_guint8(tvb, q++);
1048
1049                     /* snarf each value in path */
1050                     for (j = 0; j < length; j++) {
1051                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
1052                                 (type == AS_SET || type == AS_CONFED_SET)
1053                                 ? ", " : " ");
1054                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1055                         q += 2;
1056                     }
1057
1058                     /* cleanup end of string */
1059                     if (type == AS_SET) {
1060                         as_path_str[strlen(as_path_str) - 2] = '}';
1061                     }
1062                     else if (type == AS_CONFED_SET) {
1063                         as_path_str[strlen(as_path_str) - 2] = ']';
1064                     }
1065                     else if (type == AS_CONFED_SEQUENCE) {
1066                         as_path_str[strlen(as_path_str) - 1] = ')';
1067                     }
1068                     else {
1069                         as_path_str[strlen(as_path_str) - 1] = '\0';
1070                     }
1071                 }
1072
1073                 /* check for empty AS_PATH */
1074                 if (tlen == 0)
1075                     strncpy(as_path_str, "empty", 6);
1076
1077                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1078                         "%s: %s (%u %s)",
1079                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1080                         as_path_str, tlen + aoff,
1081                         (tlen + aoff == 1) ? "byte" : "bytes");
1082                 break;
1083             case BGPTYPE_NEXT_HOP:
1084                 if (tlen != 4)
1085                     goto default_attribute_top;
1086                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1087                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1088                         "%s: %s (%u %s)",
1089                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1090                         ip_to_str(ipaddr), tlen + aoff, (tlen + aoff == 1)
1091                         ? "byte" : "bytes");
1092                 break;
1093             case BGPTYPE_MULTI_EXIT_DISC:
1094                 if (tlen != 4)
1095                     goto default_attribute_top;
1096                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1097                         "%s: %u (%u %s)",
1098                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1099                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1100                         (tlen + aoff == 1) ? "byte" : "bytes");
1101                 break;
1102             case BGPTYPE_LOCAL_PREF:
1103                 if (tlen != 4)
1104                     goto default_attribute_top;
1105                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1106                         "%s: %u (%u %s)",
1107                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1108                         tvb_get_ntohl(tvb, o + i + aoff), tlen + aoff,
1109                         (tlen + aoff == 1) ? "byte" : "bytes");
1110                 break;
1111             case BGPTYPE_ATOMIC_AGGREGATE:
1112                 if (tlen != 0)
1113                     goto default_attribute_top;
1114                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1115                         "%s (%u %s)",
1116                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1117                         tlen + aoff, (tlen + aoff == 1) ? "byte" : "bytes");
1118                 break;
1119             case BGPTYPE_AGGREGATOR:
1120                 if (tlen != 6)
1121                     goto default_attribute_top;
1122                 tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
1123                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1124                         "%s: AS: %u origin: %s (%u %s)",
1125                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1126                         tvb_get_ntohs(tvb, o + i + aoff),
1127                         ip_to_str(ipaddr), tlen + aoff,
1128                         (tlen + aoff == 1) ? "byte" : "bytes");
1129                 break;
1130             case BGPTYPE_COMMUNITIES:
1131                 if (tlen % 4 != 0)
1132                     goto default_attribute_top;
1133
1134                 /* (o + i + aoff) =
1135                    (o + current attribute + aoff bytes to first tuple) */
1136                 q = o + i + aoff;
1137                 end = q + tlen;
1138                 /* must be freed by second switch!                          */
1139                 /* "tlen * 12" (5 digits, a :, 5 digits + space ) should be
1140                    a good estimate of how long the communities string could
1141                    be                                                       */
1142                 communities_str = malloc((tlen + 1) * 12);
1143                 if (communities_str == NULL) break;
1144                 communities_str[0] = '\0';
1145                 memset(junk_buf, 0, sizeof(junk_buf));
1146
1147                 /* snarf each community */
1148                 while (q < end) {
1149                     /* check for well-known communities */
1150                     if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
1151                         strncpy(junk_buf, "NO_EXPORT ", 10);
1152                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
1153                         strncpy(junk_buf, "NO_ADVERTISE ", 13);
1154                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
1155                         strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
1156                     else {
1157                         snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
1158                                 tvb_get_ntohs(tvb, q),
1159                                 tvb_get_ntohs(tvb, q + 2));
1160                     }
1161                     q += 4;
1162
1163                     strncat(communities_str, junk_buf, sizeof(junk_buf));
1164                 }
1165                 /* cleanup end of string */
1166                 communities_str[strlen(communities_str) - 1] = '\0';
1167
1168                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1169                         "%s: %s (%u %s)",
1170                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1171                         communities_str, tlen + aoff,
1172                         (tlen + aoff == 1) ? "byte" : "bytes");
1173                 break;
1174             case BGPTYPE_ORIGINATOR_ID:
1175                 if (tlen != 4)
1176                     goto default_attribute_top;
1177                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1178                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1179                         "%s: %s (%u %s)",
1180                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1181                         ip_to_str(ipaddr), tlen + aoff, (tlen + aoff == 1)
1182                         ? "byte" : "bytes");
1183                 break;
1184             case BGPTYPE_CLUSTER_LIST:
1185                 if (tlen % 4 != 0)
1186                     goto default_attribute_top;
1187
1188                 /* (o + i + aoff) =
1189                    (o + current attribute + aoff bytes to first tuple) */
1190                 q = o + i + aoff;
1191                 end = q + tlen;
1192                 /* must be freed by second switch!                          */
1193                 /* "tlen * 16" (12 digits, 3 dots + space ) should be
1194                    a good estimate of how long the cluster_list string could
1195                    be                                                       */
1196                 cluster_list_str = malloc((tlen + 1) * 16);
1197                 if (cluster_list_str == NULL) break;
1198                 cluster_list_str[0] = '\0';
1199                 memset(junk_buf, 0, sizeof(junk_buf));
1200
1201                 /* snarf each cluster list */
1202                 tvb_memcpy(tvb, ipaddr, q, 4);
1203                 while (q < end) {
1204                     snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(ipaddr));
1205                     strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
1206                     q += 4;
1207                 }
1208                 /* cleanup end of string */
1209                 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
1210
1211                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1212                         "%s: %s (%u %s)",
1213                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1214                         cluster_list_str, tlen + aoff,
1215                         (tlen + aoff == 1) ? "byte" : "bytes");
1216                 break;
1217             case BGPTYPE_EXTENDED_COMMUNITY:
1218                 if (tlen %8 != 0)
1219                     break;
1220                 ti = proto_tree_add_text(subtree,tvb,o+i,tlen+aoff,
1221                         "%s: (%u %s)",
1222                         val_to_str(bgpa.bgpa_type,bgpattr_type,"Unknown"),
1223                         tlen + aoff,
1224                         (tlen + aoff == 1) ? "byte" : "bytes");
1225                 break;
1226
1227             default:
1228             default_attribute_top:
1229                 ti = proto_tree_add_text(subtree, tvb, o + i, tlen + aoff,
1230                         "%s (%u %s)",
1231                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1232                         tlen + aoff, (tlen + aoff == 1) ? "byte" : "bytes");
1233             } /* end of first switch */
1234             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
1235
1236             /* figure out flags */
1237             junk_buf[0] = '\0';
1238             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
1239                  strncat(junk_buf, "Optional, ", 10);
1240             }
1241             else {
1242                  strncat(junk_buf, "Well-known, ", 12);
1243             }
1244             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
1245                  strncat(junk_buf, "Transitive, ", 12);
1246             }
1247             else {
1248                  strncat(junk_buf, "Non-transitive, ", 16);
1249             }
1250             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
1251                  strncat(junk_buf, "Partial, ", 9);
1252             }
1253             else {
1254                  strncat(junk_buf, "Complete, ", 10);
1255             }
1256             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1257                  strncat(junk_buf, "Extended Length, ", 17);
1258             }
1259             /* stomp last ", " */
1260             j = strlen(junk_buf);
1261             junk_buf[j - 2] = '\0';
1262             ti = proto_tree_add_text(subtree2, tvb,
1263                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1264                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
1265             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
1266
1267             /* add flag bitfield subtrees */
1268             proto_tree_add_text(subtree3, tvb,
1269                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1270                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1271                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
1272             proto_tree_add_text(subtree3, tvb,
1273                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1274                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1275                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
1276                         "Non-transitive"));
1277             proto_tree_add_text(subtree3, tvb,
1278                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1279                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1280                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
1281             proto_tree_add_text(subtree3, tvb,
1282                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1283                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1284                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
1285                         "Regular length"));
1286
1287             proto_tree_add_text(subtree2, tvb,
1288                     o + i + offsetof(struct bgp_attr, bgpa_type), 1,
1289                     "Type code: %s (%u)",
1290                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1291                     bgpa.bgpa_type);
1292
1293             proto_tree_add_text(subtree2, tvb, o + i + sizeof(bgpa),
1294                     aoff - sizeof(bgpa), "Length: %d %s", tlen,
1295                     (tlen == 1) ? "byte" : "bytes");
1296
1297             /* the second switch prints things in the actual subtree of each
1298                attribute                                                     */
1299             switch (bgpa.bgpa_type) {
1300             case BGPTYPE_ORIGIN:
1301                 if (tlen != 1) {
1302                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1303                             "Origin (invalid): %u %s", tlen,
1304                              (tlen == 1) ? "byte" : "bytes");
1305                 } else {
1306                     msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1307                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1308                             "Origin: %s (%u)", msg, tvb_get_guint8(tvb, o + i + aoff));
1309                 }
1310                 break;
1311             case BGPTYPE_AS_PATH:
1312                 /* check for empty AS_PATH */
1313                 if (tlen == 0) {
1314                     free(as_path_str);
1315                     break;
1316                 }
1317
1318                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1319                         "AS path: %s", as_path_str);
1320                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1321
1322                 /* (o + i + aoff) =
1323                    (o + current attribute + aoff bytes to first tuple) */
1324                 q = o + i + aoff;
1325                 end = q + tlen;
1326
1327                 /* snarf each AS path tuple, we have to step through each one
1328                    again to make a separate subtree so we can't just reuse
1329                    as_path_str from above */
1330                 while (q < end) {
1331                     as_path_str[0] = '\0';
1332                     type = tvb_get_guint8(tvb, q++);
1333                     if (type == AS_SET) {
1334                         snprintf(as_path_str, 2, "{");
1335                     }
1336                     else if (type == AS_CONFED_SET) {
1337                         snprintf(as_path_str, 2, "[");
1338                     }
1339                     else if (type == AS_CONFED_SEQUENCE) {
1340                         snprintf(as_path_str, 2, "(");
1341                     }
1342                     length = tvb_get_guint8(tvb, q++);
1343
1344                     /* snarf each value in path, we're just going to reuse
1345                        as_path_str since we already have it malloced       */
1346                     for (j = 0; j < length; j++) {
1347                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
1348                                 (type == AS_SET || type == AS_CONFED_SET)
1349                                 ? ", " : " ");
1350                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1351                         q += 2;
1352                     }
1353
1354                     /* cleanup end of string */
1355                     if (type == AS_SET) {
1356                         as_path_str[strlen(as_path_str) - 2] = '}';
1357                     }
1358                     else if (type == AS_CONFED_SET) {
1359                         as_path_str[strlen(as_path_str) - 2] = ']';
1360                     }
1361                     else if (type == AS_CONFED_SEQUENCE) {
1362                         as_path_str[strlen(as_path_str) - 1] = ')';
1363                     }
1364                     else {
1365                         as_path_str[strlen(as_path_str) - 1] = '\0';
1366                     }
1367
1368                     /* length here means number of ASs, ie length * 2 bytes */
1369                     ti = proto_tree_add_text(as_paths_tree, tvb,
1370                             q - length * 2 - 2,
1371                             length * 2 + 2, "AS path segment: %s", as_path_str);
1372                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1373                     proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 2,
1374                             1, "Path segment type: %s (%u)",
1375                             val_to_str(type, as_segment_type, "Unknown"), type);
1376                     proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 1,
1377                             1, "Path segment length: %u %s", length,
1378                             (length == 1) ? "AS" : "ASs");
1379
1380                     /* backup and reprint path segment value(s) only */
1381                     q -= 2 * length;
1382                     as_path_str[0] = '\0';
1383                     for (j = 0; j < length; j++) {
1384                         snprintf(junk_buf, sizeof(junk_buf), "%u ", tvb_get_ntohs(tvb, q));
1385                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1386                         q += 2;
1387                     }
1388                     as_path_str[strlen(as_path_str) - 1] = '\0';
1389
1390                     proto_tree_add_text(as_path_tree, tvb, q - length * 2,
1391                             length * 2, "Path segment value: %s", as_path_str);
1392                 }
1393
1394                 free(as_path_str);
1395                 break;
1396             case BGPTYPE_NEXT_HOP:
1397                 if (tlen != 4) {
1398                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1399                             "Next hop (invalid): %u %s", tlen,
1400                             (tlen == 1) ? "byte" : "bytes");
1401                 } else {
1402                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1403                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1404                             "Next hop: %s", ip_to_str(ipaddr));
1405                 }
1406                 break;
1407             case BGPTYPE_MULTI_EXIT_DISC:
1408                 if (tlen != 4) {
1409                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1410                             "Multiple exit discriminator (invalid): %u %s",
1411                             tlen, (tlen == 1) ? "byte" : "bytes");
1412                 } else {
1413                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1414                             "Multiple exit discriminator: %u",
1415                             tvb_get_ntohl(tvb, o + i + aoff));
1416                 }
1417                 break;
1418             case BGPTYPE_LOCAL_PREF:
1419                 if (tlen != 4) {
1420                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1421                             "Local preference (invalid): %u %s", tlen,
1422                              (tlen == 1) ? "byte" : "bytes");
1423                 } else {
1424                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1425                             "Local preference: %u", tvb_get_ntohl(tvb, o + i + aoff));
1426                 }
1427                 break;
1428             case BGPTYPE_ATOMIC_AGGREGATE:
1429                 if (tlen != 0) {
1430                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1431                             "Atomic aggregate (invalid): %u %s", tlen,
1432                             (tlen == 1) ? "byte" : "bytes");
1433                 }
1434                 break;
1435             case BGPTYPE_AGGREGATOR:
1436                 if (tlen != 6) {
1437                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1438                             "Aggregator (invalid): %u %s", tlen,
1439                             (tlen == 1) ? "byte" : "bytes");
1440                 } else {
1441                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1442                             "Aggregator AS: %u", tvb_get_ntohs(tvb, o + i + aoff));
1443                     tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
1444                     proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 4,
1445                             "Aggregator origin: %s",
1446                             ip_to_str(ipaddr));
1447                 }
1448                 break;
1449             case BGPTYPE_COMMUNITIES:
1450                 if (tlen % 4 != 0) {
1451                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1452                             "Communities (invalid): %u %s", tlen,
1453                             (tlen == 1) ? "byte" : "bytes");
1454                     free(communities_str);
1455                     break;
1456                 }
1457
1458                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1459                         "Communities: %s", communities_str);
1460                 communities_tree = proto_item_add_subtree(ti,
1461                         ett_bgp_communities);
1462
1463                 /* (o + i + aoff) =
1464                    (o + current attribute + aoff bytes to first tuple) */
1465                 q = o + i + aoff;
1466                 end = q + tlen;
1467
1468                 /* snarf each community */
1469                 while (q < end) {
1470                     /* check for reserved values */
1471                     guint32 community = tvb_get_ntohl(tvb, q);
1472                     if ((community & 0xFFFF0000) == FOURHEX0 ||
1473                          (community & 0xFFFF0000) == FOURHEXF) {
1474                         proto_tree_add_text(communities_tree, tvb,
1475                                q - 3 + aoff, 4,
1476                                "Community: %s (0x%08x)",
1477                                val_to_str(community, community_vals, "(reserved)"),
1478                                community);
1479                     }
1480                     else {
1481                         ti = proto_tree_add_text(communities_tree, tvb,
1482                                 q - 3 + aoff, 4, "Community: %u:%u",
1483                                 tvb_get_ntohs(tvb, q), tvb_get_ntohs(tvb, q + 2));
1484                         community_tree = proto_item_add_subtree(ti,
1485                             ett_bgp_communities);
1486                         proto_tree_add_text(community_tree, tvb, q - 3 + aoff,
1487                                 2, "Community AS: %u", tvb_get_ntohs(tvb, q));
1488                         proto_tree_add_text(community_tree, tvb, q - 1 + aoff,
1489                                 2, "Community value: %u", tvb_get_ntohs(tvb, q + 2));
1490                     }
1491
1492                     q += 4;
1493                 }
1494
1495                 free(communities_str);
1496                 break;
1497             case BGPTYPE_ORIGINATOR_ID:
1498                 if (tlen != 4) {
1499                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1500                             "Originator identifier (invalid): %u %s", tlen,
1501                             (tlen == 1) ? "byte" : "bytes");
1502                 } else {
1503                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1504                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1505                             "Originator identifier: %s",
1506                             ip_to_str(ipaddr));
1507                 }
1508                 break;
1509            case BGPTYPE_MP_REACH_NLRI:
1510                 /*
1511                  * RFC 2545 specifies that there may be more than one
1512                  * address in the MP_REACH_NLRI attribute in section
1513                  * 3, "Constructing the Next Hop field".
1514                  *
1515                  * Yes, RFC 2858 says you can't do that, and, yes, RFC
1516                  * 2858 obsoletes RFC 2283, which says you can do that,
1517                  * but that doesn't mean we shouldn't dissect packets
1518                  * that conform to RFC 2283 but not RFC 2858, as some
1519                  * device on the network might implement the 2283-style
1520                  * BGP extensions rather than RFC 2858-style extensions.
1521                  */
1522                 af = tvb_get_ntohs(tvb, o + i + aoff);
1523                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1524                     "Address family: %s (%u)",
1525                     val_to_str(af, afn_vals, "Unknown"), af);
1526                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1527                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1528                     "Subsequent address family identifier: %s (%u)",
1529                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1530                     saf);
1531                 if (af != AFNUM_INET && af != AFNUM_INET6 && af != AFNUM_L2VPN) {
1532                     /*
1533                      * The addresses don't contain lengths, so if we
1534                      * don't understand the address family type, we
1535                      * cannot parse the subsequent addresses as we
1536                      * don't know how long they are.
1537                      *
1538                      * XXX - we should put a protocol tree item in for
1539                      * this, as an unknown blob.
1540                      */
1541                     break;
1542                 }
1543                 nexthop_len = tvb_get_guint8(tvb, o + i + aoff + 3);
1544                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3, 1,
1545                         "Next hop network address (%d %s)",
1546                         nexthop_len, plurality(nexthop_len, "byte", "bytes"));
1547                 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_nhna);
1548                 j = 0;
1549                 while (j < nexthop_len) {
1550                     advance = mp_addr_to_str(af, saf, tvb, o + i + aoff + 4 + j,
1551                         junk_buf, sizeof(junk_buf)) ;
1552                     if (advance == 0) /* catch if this is a unknown AFI type*/
1553                             break;
1554                     if (j + advance > nexthop_len)
1555                             break;
1556                     proto_tree_add_text(subtree3, tvb,o + i + aoff + 4 + j,
1557                         advance, "Next hop: %s (%u)", junk_buf, advance);
1558                     j += advance;
1559                 }
1560                 tlen -= nexthop_len + 4;
1561                 aoff += nexthop_len + 4 ;
1562
1563                 off = 0;
1564                 snpa = tvb_get_guint8(tvb, o + i + aoff);
1565                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1566                         "Subnetwork points of attachment: %u", snpa);
1567                 off++;
1568                 if (snpa) {
1569                         subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_snpa);
1570                         for (/*nothing*/; snpa > 0; snpa--) {
1571                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
1572                                         "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
1573                                 off++;
1574                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
1575                                 tvb_get_guint8(tvb, o + i + aoff + off - 1),
1576                                         "SNPA (%u %s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
1577                                         (tvb_get_guint8(tvb, o + i + aoff + off - 1) == 1) ? "byte" : "bytes");
1578                                 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
1579                         }
1580                 }
1581                 tlen -= off;
1582                 aoff += off;
1583                 
1584                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1585                         "Network layer reachability information (%u %s)",
1586                         tlen, (tlen == 1) ? "byte" : "bytes");
1587                 if (tlen)  {
1588                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_reach_nlri);
1589
1590                         while (tlen > 0) {
1591                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1592                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1593                                 tlen -= advance;
1594                                 aoff += advance;
1595                         }
1596                 }
1597                 break;
1598            case BGPTYPE_MP_UNREACH_NLRI:
1599                 af = tvb_get_ntohs(tvb, o + i + aoff);
1600                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1601                     "Address family: %s (%u)",
1602                     val_to_str(af, afn_vals, "Unknown"), af);
1603                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1604                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1605                     "Subsequent address family identifier: %s (%u)",
1606                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1607                     saf);
1608                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
1609                         tlen - 3, "Withdrawn routes (%u %s)", tlen - 3,
1610                         (tlen - 3 == 1) ? "byte" : "bytes");
1611
1612                 tlen -= 3;
1613                 aoff += 3;
1614                 if (tlen > 0) {
1615                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_unreach_nlri);
1616
1617                         while (tlen > 0) {
1618                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1619                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1620                                 tlen -= advance;
1621                                 aoff += advance;
1622                                 if (advance==1)  /* catch if this is a unknown AFI type*/
1623                                         break;
1624                         }
1625                 }
1626                 break;
1627             case BGPTYPE_CLUSTER_LIST:
1628                 if (tlen % 4 != 0) {
1629                     proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1630                             "Cluster list (invalid): %u %s", tlen,
1631                             (tlen == 1) ? "byte" : "bytes");
1632                     free(cluster_list_str);
1633                     break;
1634                 }
1635
1636                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1637                         "Cluster list: %s", cluster_list_str);
1638                 cluster_list_tree = proto_item_add_subtree(ti,
1639                         ett_bgp_cluster_list);
1640
1641                 /* (o + i + aoff) =
1642                    (o + current attribute + aoff bytes to first tuple) */
1643                 q = o + i + aoff;
1644                 end = q + tlen;
1645
1646                 /* snarf each cluster identifier */
1647                 while (q < end) {
1648                     tvb_memcpy(tvb, ipaddr, q, 4);
1649                     ti = proto_tree_add_text(cluster_list_tree, tvb,
1650                             q - 3 + aoff, 4, "Cluster identifier: %s",
1651                             ip_to_str(ipaddr));
1652
1653                     q += 4;
1654                 }
1655
1656                 free(cluster_list_str);
1657                 break;
1658                 case BGPTYPE_EXTENDED_COMMUNITY:
1659                 if (tlen %8 != 0) {
1660                         proto_tree_add_text(subtree3, tvb, o + i + aoff, tlen, "Extended community (invalid) : %u %s", tlen,
1661                                 (tlen == 1) ? "byte" : "bytes") ;
1662                 } else {
1663                         q = o + i + aoff ;
1664                         end = o + i + aoff + tlen ;
1665                         ti = proto_tree_add_text(subtree2,tvb,q,tlen, "Carried Extended communities");
1666                         subtree3 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
1667
1668                         while (q < end) {
1669                             junk_buf_len=0;
1670                             ext_com = tvb_get_ntohs(tvb,q) ;
1671                             junk_buf_len=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf), "%s",
1672                                                   val_to_str(ext_com,bgpext_com_type,"Unknown"));
1673                             switch (ext_com) {
1674                             case BGP_EXT_COM_RT_0:
1675                             case BGP_EXT_COM_RO_0:
1676                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %u%s%d",
1677                                                        tvb_get_ntohs(tvb,q+2),":",tvb_get_ntohl(tvb,q+4));
1678                                 junk_buf[junk_buf_len]='\0';
1679                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1680                                 break ;
1681                             case BGP_EXT_COM_RT_1:
1682                             case BGP_EXT_COM_RO_1:
1683                                 tvb_memcpy(tvb,ipaddr,q+2,4);
1684                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %s%s%u",
1685                                                        ip_to_str(ipaddr),":",tvb_get_ntohs(tvb,q+6));
1686                                 junk_buf[junk_buf_len]='\0';
1687                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1688                                 break;
1689                             case BGP_EXT_COM_VPN_ORIGIN:
1690                             case BGP_EXT_COM_OSPF_RID:
1691                                 tvb_memcpy(tvb,ipaddr,q+2,4);
1692                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %s",
1693                                                        ip_to_str(ipaddr));
1694                                 junk_buf[junk_buf_len]='\0';
1695                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1696                                 break;
1697                             case BGP_EXT_COM_OSPF_RTYPE: 
1698                                 tvb_memcpy(tvb,ipaddr,q+2,4);
1699                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": Area:%s %s",
1700                                          ip_to_str(ipaddr),
1701                                          val_to_str(tvb_get_guint8(tvb,q+6),bgpext_ospf_rtype,"Unknown"));
1702                                 /* print OSPF Metric type if selected */
1703                                 /* always print E2 even if not external route -- receiving router should ignore */
1704                                 if ( (tvb_get_guint8(tvb,q+7)) & BGP_OSPF_RTYPE_METRIC_TYPE ) { 
1705                                     junk_buf_len+=snprintf(junk_buf+junk_buf_len,sizeof(junk_buf)-junk_buf_len," E2");
1706                                 } else if (tvb_get_guint8(tvb,q+6)==(BGP_OSPF_RTYPE_EXT ||BGP_OSPF_RTYPE_NSSA ) ) {
1707                                     junk_buf_len+=snprintf(junk_buf+junk_buf_len,sizeof(junk_buf)-junk_buf_len," E1");
1708                                 }
1709                                 junk_buf[junk_buf_len]='\0';
1710                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1711                                 break;
1712                             case BGP_EXT_COM_LINKBAND:
1713                                 tvb_memcpy(tvb,ipaddr,q+2,4); /* need to check on IEEE format on all platforms */
1714                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, ": %.3f Mbps",
1715                                                        ((double)*ipaddr)*8/1000000);
1716                                 junk_buf[junk_buf_len]='\0';
1717                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1718                                 break;
1719                             case BGP_EXT_COM_L2INFO:
1720                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len,
1721                                                        ": %s, Control Flags: %s%s%s%s%s, MTU: %u %s",
1722                                                        val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"),
1723                                                        tvb_get_guint8(tvb,q+3) ? "" : "none",
1724                                                        tvb_get_ntohs(tvb,q+3)&0x08 ? "Q" : "",
1725                                                        tvb_get_ntohs(tvb,q+3)&0x04 ? "F" : "",
1726                                                        tvb_get_ntohs(tvb,q+3)&0x02 ? "C" : "",
1727                                                        tvb_get_ntohs(tvb,q+3)&0x01 ? "S" : "",
1728                                                        tvb_get_ntohs(tvb,q+4),
1729                                                        tvb_get_ntohs(tvb,q+4)==1 ? "byte" : "bytes");
1730                                 junk_buf[junk_buf_len]='\0';
1731                                 ti = proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1732   
1733                                 subtree4 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
1734                                 proto_tree_add_text(subtree4,tvb,q+2,1, "Encapsulation: %s",
1735                                                          val_to_str(tvb_get_guint8(tvb,q+2),bgp_l2vpn_encaps,"Unknown"));
1736                                 proto_tree_add_text(subtree4,tvb,q+3,1, "Control Flags: %s%sControl Word %s required, Sequenced delivery %s required",
1737                                                     tvb_get_ntohs(tvb,q+3)&0x08 ? "Q flag (Reserved) set" : "",
1738                                                     tvb_get_ntohs(tvb,q+3)&0x04 ? "F flag (reserved) set" : "",
1739                                                     tvb_get_ntohs(tvb,q+3)&0x02 ? "is" : "not",
1740                                                     tvb_get_ntohs(tvb,q+3)&0x01 ? "is" : "not"); 
1741                                 proto_tree_add_text(subtree4,tvb,q+4,2, "MTU: %u %s",
1742                                                     tvb_get_ntohs(tvb,q+4),
1743                                                     tvb_get_ntohs(tvb,q+4)==1 ? "byte" : "bytes");
1744                                 break;
1745                             default:
1746                                 junk_buf_len+=snprintf(junk_buf+junk_buf_len, sizeof(junk_buf)-junk_buf_len, " ");
1747                                 junk_buf[junk_buf_len]='\0';
1748                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",junk_buf);
1749                                 break ;
1750                             }
1751                             q = q + 8 ;
1752                         }
1753                 }
1754                 break;
1755             default:
1756                 proto_tree_add_text(subtree2, tvb, o + i + aoff, tlen,
1757                         "Unknown (%d %s)", tlen, (tlen == 1) ? "byte" :
1758                         "bytes");
1759                 break;
1760             } /* end of second switch */
1761
1762             i += alen + aoff;
1763         }
1764
1765         o += 2 + len;
1766
1767         /* NLRI */
1768         len = offset + hlen - o;
1769
1770         /* parse prefixes */
1771         if (len > 0) {
1772            ti = proto_tree_add_text(tree, tvb, o, len,
1773                    "Network layer reachability information: %u %s", len,
1774                    (len == 1) ? "byte" : "bytes");
1775             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1776             end = o + len;
1777             while (o < end) {
1778                 i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
1779                 proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
1780                 o += i;
1781             }
1782         }
1783     }
1784 }
1785
1786 /*
1787  * Dissect a BGP NOTIFICATION message.
1788  */
1789 static void
1790 dissect_bgp_notification(tvbuff_t *tvb, int offset, proto_tree *tree)
1791 {
1792     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
1793     int                     hlen;   /* message length           */
1794     char                    *p;     /* string pointer           */
1795
1796     /* snarf message */
1797     tvb_memcpy(tvb, bgpn.bgpn_marker, offset, BGP_MIN_NOTIFICATION_MSG_SIZE);
1798     hlen = g_ntohs(bgpn.bgpn_len);
1799
1800     /* print error code */
1801     proto_tree_add_text(tree, tvb,
1802         offset + offsetof(struct bgp_notification, bgpn_major), 1,
1803         "Error code: %s (%u)",
1804         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1805         bgpn.bgpn_major);
1806
1807     /* print error subcode */
1808     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1809      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1810         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1811             "Unknown");
1812     } else if (bgpn.bgpn_minor == 0)
1813         p = "Unspecified";
1814     else
1815         p = "Unknown";
1816     proto_tree_add_text(tree, tvb,
1817         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1818         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1819
1820     /* only print if there is optional data */
1821     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1822         proto_tree_add_text(tree, tvb, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1823             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1824     }
1825 }
1826
1827 /*
1828  * Dissect a BGP ROUTE-REFRESH message.
1829  */
1830 static void
1831 dissect_bgp_route_refresh(tvbuff_t *tvb, int offset, proto_tree *tree)
1832 {
1833     guint        i;    /* tmp            */
1834     int             p;         /* tvb offset counter    */
1835     int             pend;       /* end of list of entries for one orf type */
1836     int             hlen;       /* tvb RR msg length */
1837     proto_item      *ti;       /* tree item             */
1838     proto_item      *ti1;       /* tree item             */
1839     proto_tree      *subtree;  /* tree for orf   */
1840     proto_tree      *subtree1; /* tree for orf entry */
1841     guint8          orftype;        /* ORF Type */
1842     guint8          orfwhen;        /* ORF flag: immediate, defer */
1843     int             orflen;         /* ORF len */
1844     guint8          entryflag;      /* ORF Entry flag: action(add,del,delall) match(permit,deny) */
1845     int             entryseq;       /* ORF Entry sequence number */
1846     int             entrylen;       /* ORF Entry length */
1847     guint8          pfx_ge;         /* ORF PrefixList mask lower bound */
1848     guint8          pfx_le;         /* ORF PrefixList mask upper bound */
1849     char            pfxbuf[20];     /* ORF PrefixList prefix string buffer */
1850     int             pfx_masklen;    /* ORF PRefixList prefix mask length */
1851     
1852
1853 /* 
1854 example 1
1855  00 1c 05       hlen=28
1856  00 01 00 01    afi,safi= ipv4-unicast
1857  02 80 00 01    defer, prefix-orf, len=1
1858     80            removeall
1859 example 2
1860  00 25 05       hlen=37
1861  00 01 00 01    afi,saif= ipv4-unicast
1862  01 80 00 0a    immediate, prefix-orf, len=10
1863     00            add
1864     00 00 00 05   seqno = 5
1865     12            ge = 18
1866     18            le = 24
1867     10 07 02      prefix = 7.2.0.0/16
1868 */
1869     hlen = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
1870     p = offset + BGP_HEADER_SIZE;
1871     /* AFI */
1872     i = tvb_get_ntohs(tvb, p);
1873     proto_tree_add_text(tree, tvb, p, 2, 
1874                         "Address family identifier: %s (%u)",
1875                         val_to_str(i, afn_vals, "Unknown"), i);
1876     p += 2;
1877     /* Reserved */
1878     proto_tree_add_text(tree, tvb, p, 1, 
1879                         "Reserved: 1 byte");
1880     p++;
1881     /* SAFI */
1882     i = tvb_get_guint8(tvb, p);
1883     proto_tree_add_text(tree, tvb, p, 1, 
1884                         "Subsequent address family identifier: %s (%u)",
1885                         val_to_str(i, bgpattr_nlri_safi,
1886                         i >= 128 ? "Vendor specific" : "Unknown"),
1887                         i);
1888     p++;
1889     if ( hlen == BGP_HEADER_SIZE + 4 )
1890         return;
1891     while (p < offset + hlen) {
1892         /* ORF type */
1893         orfwhen = tvb_get_guint8(tvb, p);
1894         orftype = tvb_get_guint8(tvb, p+1);
1895         orflen = tvb_get_ntohs(tvb, p+2);
1896         ti = proto_tree_add_text(tree, tvb, p , orflen + 4 , "ORF information (%u bytes)", orflen + 4);
1897         subtree = proto_item_add_subtree(ti, ett_bgp_orf);
1898         proto_tree_add_text(subtree, tvb, p , 1, "ORF flag: %s", val_to_str(orfwhen, orf_when_vals,"UNKNOWN"));
1899         proto_tree_add_text(subtree, tvb, p+1 , 1, "ORF type: %s", val_to_str(orftype, orf_type_vals,"UNKNOWN"));
1900         proto_tree_add_text(subtree, tvb, p+2 , 2, "ORF len: %u %s", orflen, (orflen == 1) ? "byte" : "bytes");
1901         p += 4;
1902
1903         if (orftype != BGP_ORF_PREFIX_CISCO){
1904                 proto_tree_add_text(subtree, tvb, p, orflen, "ORFEntry-Unknown (%u bytes)", orflen);
1905                 p += orflen;
1906                 continue;
1907         }
1908         pend = p + orflen;
1909         while (p < pend) {
1910                 entryflag = tvb_get_guint8(tvb, p);
1911                 if ((entryflag & BGP_ORF_ACTION) == BGP_ORF_REMOVEALL) {
1912                         ti1 = proto_tree_add_text(subtree, tvb, p, 1, "ORFEntry-PrefixList (1 byte)");
1913                         subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
1914                         proto_tree_add_text(subtree1, tvb, p , 1, "RemoveAll");
1915                         p++;
1916                 } else {
1917                         entryseq = tvb_get_ntohl(tvb, p+1);
1918                         pfx_ge = tvb_get_guint8(tvb, p+5);
1919                         pfx_le = tvb_get_guint8(tvb, p+6);
1920                         /* calc len */
1921                         decode_prefix4(tvb,  p+7, pfxbuf, sizeof(pfxbuf));
1922                         pfx_masklen = tvb_get_guint8(tvb, p+7);
1923                         entrylen = 7+ 1 + (pfx_masklen+7)/8;
1924                         ti1 = proto_tree_add_text(subtree, tvb, p, entrylen, "ORFEntry-PrefixList (%u bytes)", entrylen);
1925                         subtree1 = proto_item_add_subtree(ti1, ett_bgp_orf_entry);
1926                         proto_tree_add_text(subtree1, tvb, p , 1, "ACTION: %s MATCH: %s",
1927                          val_to_str(entryflag&BGP_ORF_ACTION, orf_entry_action_vals,"UNKNOWN"), 
1928                          val_to_str(entryflag&BGP_ORF_MATCH, orf_entry_match_vals,"UNKNOWN"));
1929                         p++;
1930                         proto_tree_add_text(subtree1, tvb, p , 4, "Entry Sequence No: %u", entryseq);
1931                         p += 4;
1932                         proto_tree_add_text(subtree1, tvb, p , 1, "PrefixMask length lower bound: %u", pfx_ge);
1933                         p++;
1934                         proto_tree_add_text(subtree1, tvb, p , 1, "PrefixMask length upper bound: %u", pfx_le);
1935                         p++;
1936                         proto_tree_add_text(subtree1, tvb, p , 1 + (pfx_masklen+7)/8, "Prefix: %s", pfxbuf);
1937                         p+= 1 + (pfx_masklen+7)/8;
1938                 }
1939         }
1940     }
1941 }
1942
1943 /*
1944  * Dissect a BGP packet.
1945  */
1946 static void
1947 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1948 {
1949     proto_item    *ti;           /* tree item                        */
1950     proto_tree    *bgp_tree;     /* BGP packet tree                  */
1951     proto_tree    *bgp1_tree;    /* BGP message tree                 */
1952     int           l, i;          /* tmp                              */
1953     int           found;         /* number of BGP messages in packet */
1954     static guchar marker[] = {   /* BGP message marker               */
1955         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1956         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1957     };
1958     struct bgp    bgp;           /* BGP header                       */
1959     int           hlen;          /* BGP header length                */
1960     char          *typ;          /* BGP message type                 */
1961
1962     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1963         col_set_str(pinfo->cinfo, COL_PROTOCOL, "BGP");
1964     if (check_col(pinfo->cinfo, COL_INFO))
1965         col_clear(pinfo->cinfo, COL_INFO);
1966
1967     l = tvb_reported_length(tvb);
1968     i = 0;
1969     found = -1;
1970     /* run through the TCP packet looking for BGP headers         */
1971     while (i + BGP_HEADER_SIZE <= l) {
1972         tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1973
1974         /* look for bgp header */
1975         if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1976             i++;
1977             continue;
1978         }
1979
1980         found++;
1981         hlen = g_ntohs(bgp.bgp_len);
1982
1983         /*
1984          * Desegmentation check.
1985          */
1986         if (bgp_desegment) {
1987             if (hlen > tvb_length_remaining(tvb, i) && pinfo->can_desegment) {
1988                 /*
1989                  * Not all of this packet is in the data we've been
1990                  * handed, but we can do reassembly on it.
1991                  *
1992                  * Tell the TCP dissector where the data for
1993                  * this message starts in the data it handed
1994                  * us, and how many more bytes we need, and
1995                  * return.
1996                  */
1997                 pinfo->desegment_offset = i;
1998                 pinfo->desegment_len = hlen - tvb_length_remaining(tvb, i);
1999                 return;
2000             }
2001         }
2002
2003         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
2004
2005         if (check_col(pinfo->cinfo, COL_INFO)) {
2006             if (found == 0)
2007                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", typ);
2008             else
2009                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", typ);
2010         }
2011
2012         if (tree) {
2013             ti = proto_tree_add_item(tree, proto_bgp, tvb, i, hlen, FALSE);
2014             bgp_tree = proto_item_add_subtree(ti, ett_bgp);
2015
2016             ti = proto_tree_add_text(bgp_tree, tvb, i, hlen, "%s", typ);
2017
2018             /* add a different tree for each message type */
2019             switch (bgp.bgp_type) {
2020             case BGP_OPEN:
2021                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
2022                 break;
2023             case BGP_UPDATE:
2024                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
2025                 break;
2026             case BGP_NOTIFICATION:
2027                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
2028                 break;
2029             case BGP_KEEPALIVE:
2030                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2031                 break;
2032             case BGP_ROUTE_REFRESH_CISCO:
2033             case BGP_ROUTE_REFRESH:
2034                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
2035                 break;
2036             default:
2037                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
2038                 break;
2039             }
2040
2041             proto_tree_add_text(bgp1_tree, tvb, i, BGP_MARKER_SIZE,
2042                 "Marker: 16 bytes");
2043
2044             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
2045                 proto_tree_add_text(bgp1_tree, tvb,
2046                     i + offsetof(struct bgp, bgp_len), 2,
2047                     "Length (invalid): %u %s", hlen,
2048                     (hlen == 1) ? "byte" : "bytes");
2049             } else {
2050                 proto_tree_add_text(bgp1_tree, tvb,
2051                     i + offsetof(struct bgp, bgp_len), 2,
2052                     "Length: %u %s", hlen,
2053                     (hlen == 1) ? "byte" : "bytes");
2054             }
2055
2056             proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, tvb,
2057                                        i + offsetof(struct bgp, bgp_type), 1,
2058                                        bgp.bgp_type,
2059                                        "Type: %s (%u)", typ, bgp.bgp_type);
2060
2061             switch (bgp.bgp_type) {
2062             case BGP_OPEN:
2063                 dissect_bgp_open(tvb, i, bgp1_tree);
2064                 break;
2065             case BGP_UPDATE:
2066                 dissect_bgp_update(tvb, i, bgp1_tree);
2067                 break;
2068             case BGP_NOTIFICATION:
2069                 dissect_bgp_notification(tvb, i, bgp1_tree);
2070                 break;
2071             case BGP_KEEPALIVE:
2072                 /* no data in KEEPALIVE messages */
2073                 break;
2074             case BGP_ROUTE_REFRESH_CISCO:
2075             case BGP_ROUTE_REFRESH:
2076                 dissect_bgp_route_refresh(tvb, i, bgp1_tree);
2077                 break;
2078             default:
2079                 break;
2080             }
2081         }
2082
2083         i += hlen;
2084     }
2085 }
2086
2087 /*
2088  * Register ourselves.
2089  */
2090 void
2091 proto_register_bgp(void)
2092 {
2093
2094     static hf_register_info hf[] = {
2095       { &hf_bgp_type,
2096         { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
2097           VALS(bgptypevals), 0x0, "BGP message type", HFILL }},
2098     };
2099
2100     static gint *ett[] = {
2101       &ett_bgp,
2102       &ett_bgp_unfeas,
2103       &ett_bgp_attrs,
2104       &ett_bgp_attr,
2105       &ett_bgp_attr_flags,
2106       &ett_bgp_mp_nhna,
2107       &ett_bgp_mp_reach_nlri,
2108       &ett_bgp_mp_unreach_nlri,
2109       &ett_bgp_mp_snpa,
2110       &ett_bgp_nlri,
2111       &ett_bgp_open,
2112       &ett_bgp_update,
2113       &ett_bgp_notification,
2114       &ett_bgp_route_refresh,
2115       &ett_bgp_as_paths,
2116       &ett_bgp_communities,
2117       &ett_bgp_cluster_list,
2118       &ett_bgp_options,
2119       &ett_bgp_option,
2120       &ett_bgp_extended_communities,
2121       &ett_bgp_orf,
2122       &ett_bgp_orf_entry
2123     };
2124     module_t *bgp_module;
2125
2126     proto_bgp = proto_register_protocol("Border Gateway Protocol",
2127                                         "BGP", "bgp");
2128     proto_register_field_array(proto_bgp, hf, array_length(hf));
2129     proto_register_subtree_array(ett, array_length(ett));
2130
2131     bgp_module = prefs_register_protocol(proto_bgp, NULL);
2132     prefs_register_bool_preference(bgp_module, "desegment",
2133       "Desegment all BGP messages spanning multiple TCP segments",
2134       "Whether the BGP dissector should desegment all messages spanning multiple TCP segments",
2135       &bgp_desegment);
2136 }
2137
2138 void
2139 proto_reg_handoff_bgp(void)
2140 {
2141     dissector_handle_t bgp_handle;
2142
2143     bgp_handle = create_dissector_handle(dissect_bgp, proto_bgp);
2144     dissector_add("tcp.port", BGP_TCP_PORT, bgp_handle);
2145 }