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