Use dcerpc_call_value structure to fetch request/response frame numbers
[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.55 2002/02/14 05:25:52 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 const value_string community_vals[] = {
496         { BGP_COMM_NO_EXPORT,           "NO_EXPORT" },
497         { BGP_COMM_NO_ADVERTISE,        "NO_ADVERTISE" },
498         { BGP_COMM_NO_EXPORT_SUBCONFED, "NO_EXPORT_SUBCONFED" },
499         { 0,                            NULL }
500 };
501
502 static void
503 dissect_bgp_open(tvbuff_t *tvb, int offset, proto_tree *tree)
504 {
505     struct bgp_open bgpo;      /* BGP OPEN message      */
506     int             hlen;      /* message length        */
507     u_int           i;         /* tmp                   */
508     int             ptype;     /* parameter type        */
509     int             plen;      /* parameter length      */
510     int             ctype;     /* capability type       */
511     int             clen;      /* capability length     */
512     int             cend;      /* capabilities end      */
513     int             ostart;    /* options start         */
514     int             oend;      /* options end           */
515     int             p;         /* tvb offset counter    */
516     proto_item      *ti;       /* tree item             */
517     proto_tree      *subtree;  /* subtree for options   */
518     proto_tree      *subtree1; /* subtree for an option */
519     proto_tree      *subtree2; /* subtree for an option */
520     proto_tree      *subtree3; /* subtree for an option */
521     guint8          orfnum;    /* number of ORFs */
522     guint8          orftype;        /* ORF Type */
523     guint8          orfsendrecv;    /* ORF Send/Receive */
524
525     /* snarf OPEN message */
526     tvb_memcpy(tvb, bgpo.bgpo_marker, offset, BGP_MIN_OPEN_MSG_SIZE);
527     hlen = ntohs(bgpo.bgpo_len);
528
529     proto_tree_add_text(tree, tvb,
530         offset + offsetof(struct bgp_open, bgpo_version), 1,
531         "Version: %u", bgpo.bgpo_version);
532     proto_tree_add_text(tree, tvb,
533         offset + offsetof(struct bgp_open, bgpo_myas), 2,
534         "My AS: %u", ntohs(bgpo.bgpo_myas));
535     proto_tree_add_text(tree, tvb,
536         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
537         "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
538     proto_tree_add_text(tree, tvb,
539         offset + offsetof(struct bgp_open, bgpo_id), 4,
540         "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
541     proto_tree_add_text(tree, tvb,
542         offset + offsetof(struct bgp_open, bgpo_optlen), 1,
543         "Optional parameters length: %u %s", bgpo.bgpo_optlen,
544         (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
545
546     /* optional parameters */
547     if (bgpo.bgpo_optlen > 0) {
548         /* add a subtree and setup some offsets */
549         ostart = offset + BGP_MIN_OPEN_MSG_SIZE;
550         ti = proto_tree_add_text(tree, tvb, ostart, bgpo.bgpo_optlen,
551              "Optional parameters");
552         subtree = proto_item_add_subtree(ti, ett_bgp_options);
553         p = offset + ostart;
554         oend = p + bgpo.bgpo_optlen;
555
556         /* step through all of the optional parameters */
557         while (p < oend) {
558
559             /* grab the type and length */
560             ptype = tvb_get_guint8(tvb, p++);
561             plen = tvb_get_guint8(tvb, p++);
562
563             /* check the type */
564             switch (ptype) {
565             case BGP_OPTION_AUTHENTICATION:
566                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
567                     "Authentication information (%u %s)", plen,
568                     (plen == 1) ? "byte" : "bytes");
569                 break;
570             case BGP_OPTION_CAPABILITY:
571                 /* grab the capability code */
572                 cend = p - 1 + plen;
573                 ctype = tvb_get_guint8(tvb, p++);
574                 clen = tvb_get_guint8(tvb, p++);
575                 ti = proto_tree_add_text(subtree, tvb, p - 4,
576                      2 + plen, "Capabilities Advertisement (%u bytes)",
577                      2 + plen);
578                 subtree1 = proto_item_add_subtree(ti, ett_bgp_option);
579                 proto_tree_add_text(subtree1, tvb, p - 4,
580                      1, "Parameter type: Capabilities (2)");
581                 proto_tree_add_text(subtree1, tvb, p - 3,
582                      1, "Parameter length: %u %s", plen,
583                      (plen == 1) ? "byte" : "bytes");
584                 p -= 2;
585
586                 /* step through all of the capabilities */
587                 while (p < cend) {
588                     ctype = tvb_get_guint8(tvb, p++);
589                     clen = tvb_get_guint8(tvb, p++);
590
591                     /* check the capability type */
592                     switch (ctype) {
593                     case BGP_CAPABILITY_RESERVED:
594                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
595                              2 + clen, "Reserved capability (%u %s)", 2 + clen,
596                              (clen == 1) ? "byte" : "bytes");
597                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
598                         proto_tree_add_text(subtree2, tvb, p - 2,
599                              1, "Capability code: Reserved (0)");
600                         proto_tree_add_text(subtree2, tvb, p - 1,
601                              1, "Capability length: %u %s", clen,
602                              (clen == 1) ? "byte" : "bytes");
603                         if (clen != 0) {
604                             proto_tree_add_text(subtree2, tvb, p,
605                                  clen, "Capability value: Unknown");
606                         }
607                         p += clen;
608                         break;
609                     case BGP_CAPABILITY_MULTIPROTOCOL:
610                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
611                              2 + clen,
612                              "Multiprotocol extensions capability (%u %s)",
613                              2 + clen, (clen == 1) ? "byte" : "bytes");
614                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
615                         proto_tree_add_text(subtree2, tvb, p - 2,
616                              1, "Capability code: Multiprotocol extensions (%d)",
617                              ctype);
618                         if (clen != 4) {
619                             proto_tree_add_text(subtree2, tvb, p - 1,
620                                  1, "Capability length: Invalid");
621                             proto_tree_add_text(subtree2, tvb, p,
622                                  clen, "Capability value: Unknown");
623                         }
624                         else {
625                             proto_tree_add_text(subtree2, tvb, p - 1,
626                                  1, "Capability length: %u %s", clen,
627                                  (clen == 1) ? "byte" : "bytes");
628                             ti = proto_tree_add_text(subtree2, tvb, p,
629                                  clen, "Capability value");
630                             subtree3 = proto_item_add_subtree(ti,
631                                        ett_bgp_option);
632                             /* AFI */
633                             i = tvb_get_ntohs(tvb, p);
634                             proto_tree_add_text(subtree3, tvb, p,
635                                  2, "Address family identifier: %s (%u)",
636                                  val_to_str(i, afn_vals, "Unknown"), i);
637                             p += 2;
638                             /* Reserved */
639                             proto_tree_add_text(subtree3, tvb, p,
640                                  1, "Reserved: 1 byte");
641                             p++;
642                             /* SAFI */
643                             i = tvb_get_guint8(tvb, p);
644                             proto_tree_add_text(subtree3, tvb, p,
645                                  1, "Subsequent address family identifier: %s (%u)",
646                                  val_to_str(i, bgpattr_nlri_safi,
647                                     i >= 128 ? "Vendor specific" : "Unknown"), i);
648                             p++;
649                         }
650                         break;
651                     case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
652                     case BGP_CAPABILITY_ROUTE_REFRESH:
653                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
654                              2 + clen, "Route refresh capability (%u %s)", 2 + clen,
655                              (clen == 1) ? "byte" : "bytes");
656                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
657                         proto_tree_add_text(subtree2, tvb, p - 2,
658                              1, "Capability code: Route refresh (%d)", ctype);
659                         if (clen != 0) {
660                             proto_tree_add_text(subtree2, tvb, p,
661                                  clen, "Capability value: Invalid");
662                         }
663                         else {
664                             proto_tree_add_text(subtree2, tvb, p - 1,
665                                  1, "Capability length: %u %s", clen,
666                                  (clen == 1) ? "byte" : "bytes");
667                         }
668                         p += clen;
669                         break;
670                     case BGP_CAPABILITY_COOPERATIVE_ROUTE_FILTERING:
671                         ti = proto_tree_add_text(subtree1, tvb, p - 2,
672                              2 + clen,
673                              "Cooperative route filtering capability (%u %s)",
674                              2 + clen, (clen == 1) ? "byte" : "bytes");
675                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
676                         proto_tree_add_text(subtree2, tvb, p - 2,
677                              1, "Capability code: Cooperative route filtering (%d)",
678                              ctype);
679                         proto_tree_add_text(subtree2, tvb, p - 1,
680                              1, "Capability length: %u %s", clen,
681                              (clen == 1) ? "byte" : "bytes");
682                         ti = proto_tree_add_text(subtree2, tvb, p,
683                              clen, "Capability value");
684                         subtree3 = proto_item_add_subtree(ti, ett_bgp_option);
685                         /* AFI */
686                         i = tvb_get_ntohs(tvb, p);
687                         proto_tree_add_text(subtree3, tvb, p,
688                              2, "Address family identifier: %s (%u)",
689                              val_to_str(i, afn_vals, "Unknown"), i);
690                         p += 2;
691                         /* Reserved */
692                         proto_tree_add_text(subtree3, tvb, p, 
693                              1, "Reserved: 1 byte");
694                         p++;
695                         /* SAFI */
696                         i = tvb_get_guint8(tvb, p);
697                         proto_tree_add_text(subtree3, tvb, p,
698                              1, "Subsequent address family identifier: %s (%u)",
699                              val_to_str(i, bgpattr_nlri_safi,
700                              i >= 128 ? "Vendor specific" : "Unknown"), i);
701                         p++;
702                         /* Number of ORFs */
703                         orfnum = tvb_get_guint8(tvb, p);
704                         proto_tree_add_text(subtree3, tvb, p,
705                                             1, "Number of ORFs: %u", orfnum);
706                         p++;
707                         for (i=0; i<orfnum; i++) {
708                             /* ORF Type */
709                             orftype = tvb_get_guint8(tvb, p);
710                             proto_tree_add_text(subtree3, tvb, p,
711                                 1, "ORF Type: %s (%u)",
712                                 val_to_str(orftype, orf_type_vals,"Unknown"),
713                                 orftype);
714                             p++;
715                             /* Send/Receive */
716                             orfsendrecv = tvb_get_guint8(tvb, p);
717                             proto_tree_add_text(subtree3, tvb, p,
718                                 1, "Send/Receive: %s (%u)",
719                                 val_to_str(orfsendrecv, orf_send_recv_vals, 
720                                 "Uknown"), orfsendrecv);
721                             p++;
722                         }
723                         break;
724                     /* unknown capability */
725                     default:
726                         ti = proto_tree_add_text(subtree, tvb, p - 2,
727                              2 + clen, "Unknown capability (%u %s)", 2 + clen,
728                              (clen == 1) ? "byte" : "bytes");
729                         subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
730                         proto_tree_add_text(subtree2, tvb, p - 2,
731                              1, "Capability code: %s (%d)",
732                              ctype >= 128 ? "Private use" : "Unknown", ctype);
733                         proto_tree_add_text(subtree2, tvb, p - 1,
734                              1, "Capability length: %u %s", clen,
735                              (clen == 1) ? "byte" : "bytes");
736                         if (clen != 0) {
737                             proto_tree_add_text(subtree2, tvb, p,
738                                  clen, "Capability value: Unknown");
739                         }
740                         p += clen;
741                         break;
742                     }
743                 }
744                 break;
745             default:
746                 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
747                     "Unknown optional parameter");
748                 break;
749             }
750         }
751     }
752 }
753
754 /*
755  * Dissect a BGP UPDATE message.
756  */
757 static void
758 dissect_bgp_update(tvbuff_t *tvb, int offset, proto_tree *tree)
759  {
760     struct bgp_attr bgpa;                       /* path attributes          */
761     int             hlen;                       /* message length           */
762     gint            o;                          /* packet offset            */
763     gint            q;                          /* tmp                      */
764     gint            end;                        /* message end              */
765     gint            ext_com;                    /* EXTENDED COMMUNITY type  */
766     int             len;                        /* tmp                      */
767     int             advance;                    /* tmp                      */
768     proto_item      *ti;                        /* tree item                */
769     proto_tree      *subtree;                   /* subtree for attributes   */
770     proto_tree      *subtree2;                  /* subtree for attributes   */
771     proto_tree      *subtree3;                  /* subtree for attributes   */
772     proto_tree      *as_paths_tree;             /* subtree for AS_PATHs     */
773     proto_tree      *as_path_tree;              /* subtree for AS_PATH      */
774     proto_tree      *communities_tree;          /* subtree for COMMUNITIES  */
775     proto_tree      *community_tree;            /* subtree for a community  */
776     proto_tree      *cluster_list_tree;         /* subtree for CLUSTER_LIST */
777     int             i, j;                       /* tmp                      */
778     guint8          length;                     /* AS_PATH length           */
779     guint8          type;                       /* AS_PATH type             */
780     char            *as_path_str = NULL;        /* AS_PATH string           */
781     char            *communities_str = NULL;    /* COMMUNITIES string       */
782     char            *cluster_list_str = NULL;   /* CLUSTER_LIST string      */
783     char            *ext_com_str = NULL;        /* EXTENDED COMMUNITY list  */
784     char            junk_buf[256];              /* tmp                      */
785     guint8          ipaddr[4];                  /* IPv4 address             */
786
787     hlen = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
788     o = offset + BGP_HEADER_SIZE;
789
790     /* check for withdrawals */
791     len = tvb_get_ntohs(tvb, o);
792     proto_tree_add_text(tree, tvb, o, 2,
793         "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
794     o += 2;
795
796     /* parse unfeasible prefixes */
797     if (len > 0) {
798         ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
799         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
800
801         /* parse each prefixes */
802         end = o + len;
803         while (o < end) {
804             i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
805             proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
806             o += i;
807         }
808     }
809     else {
810         o += len;
811     }
812     /* check for advertisements */
813     len = tvb_get_ntohs(tvb, o);
814     proto_tree_add_text(tree, tvb, o, 2, "Total path attribute length: %u %s",
815             len, (len == 1) ? "byte" : "bytes");
816
817     /* path attributes */
818     if (len > 0) {
819         ti = proto_tree_add_text(tree, tvb, o + 2, len, "Path attributes");
820         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
821         i = 2;
822         while (i < len) {
823             int alen, aoff;
824             char *msg;
825             guint16 af;
826             guint8 saf;
827             int off, snpa;
828             int nexthop_len;
829
830             tvb_memcpy(tvb, (guint8 *)&bgpa, o + i, sizeof(bgpa));
831             /* check for the Extended Length bit */
832             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
833                 alen = tvb_get_ntohs(tvb, o + i + sizeof(bgpa));
834                 aoff = sizeof(bgpa) + 2;
835             } else {
836                 alen = tvb_get_guint8(tvb, o + i + sizeof(bgpa));
837                 aoff = sizeof(bgpa) + 1;
838             }
839
840             /* This is kind of ugly - similar code appears twice, but it
841                helps browsing attrs.                                      */
842             /* the first switch prints things in the title of the subtree */
843             switch (bgpa.bgpa_type) {
844             case BGPTYPE_ORIGIN:
845                 if (alen != 1)
846                     goto default_attribute_top;
847                 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
848                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
849                         "%s: %s (%u %s)",
850                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
851                         msg, alen + aoff, (alen + aoff == 1) ? "byte" :
852                         "bytes");
853                 break;
854             case BGPTYPE_AS_PATH:
855                 /* (o + i + aoff) =
856                    (o + current attribute + aoff bytes to first tuple) */
857                 q = o + i + aoff;
858                 end = q + alen;
859                 /* must be freed by second switch!                         */
860                 /* "alen * 6" (5 digits + space) should be a good estimate
861                    of how long the AS path string could be                 */
862                 as_path_str = malloc((alen + 1) * 6);
863                 if (as_path_str == NULL) break;
864                 as_path_str[0] = '\0';
865
866                 /* snarf each AS path */
867                 while (q < end) {
868                     type = tvb_get_guint8(tvb, q++);
869                     if (type == AS_SET) {
870                         snprintf(as_path_str, 2, "{");
871                     }
872                     else if (type == AS_CONFED_SET) {
873                         snprintf(as_path_str, 2, "[");
874                     }
875                     else if (type == AS_CONFED_SEQUENCE) {
876                         snprintf(as_path_str, 2, "(");
877                     }
878                     length = tvb_get_guint8(tvb, q++);
879
880                     /* snarf each value in path */
881                     for (j = 0; j < length; j++) {
882                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
883                                 (type == AS_SET || type == AS_CONFED_SET)
884                                 ? ", " : " ");
885                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
886                         q += 2;
887                     }
888
889                     /* cleanup end of string */
890                     if (type == AS_SET) {
891                         as_path_str[strlen(as_path_str) - 2] = '}';
892                     }
893                     else if (type == AS_CONFED_SET) {
894                         as_path_str[strlen(as_path_str) - 2] = ']';
895                     }
896                     else if (type == AS_CONFED_SEQUENCE) {
897                         as_path_str[strlen(as_path_str) - 1] = ')';
898                     }
899                     else {
900                         as_path_str[strlen(as_path_str) - 1] = '\0';
901                     }
902                 }
903
904                 /* check for empty AS_PATH */
905                 if (alen == 0)
906                     strncpy(as_path_str, "empty", 6);
907
908                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
909                         "%s: %s (%u %s)",
910                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
911                         as_path_str, alen + aoff,
912                         (alen + aoff == 1) ? "byte" : "bytes");
913                 break;
914             case BGPTYPE_NEXT_HOP:
915                 if (alen != 4)
916                     goto default_attribute_top;
917                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
918                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
919                         "%s: %s (%u %s)",
920                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
921                         ip_to_str(ipaddr), alen + aoff, (alen + aoff == 1)
922                         ? "byte" : "bytes");
923                 break;
924             case BGPTYPE_MULTI_EXIT_DISC:
925                 if (alen != 4)
926                     goto default_attribute_top;
927                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
928                         "%s: %u (%u %s)",
929                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
930                         tvb_get_ntohl(tvb, o + i + aoff), alen + aoff,
931                         (alen + aoff == 1) ? "byte" : "bytes");
932                 break;
933             case BGPTYPE_LOCAL_PREF:
934                 if (alen != 4)
935                     goto default_attribute_top;
936                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
937                         "%s: %u (%u %s)",
938                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
939                         tvb_get_ntohl(tvb, o + i + aoff), alen + aoff,
940                         (alen + aoff == 1) ? "byte" : "bytes");
941                 break;
942             case BGPTYPE_ATOMIC_AGGREGATE:
943                 if (alen != 0)
944                     goto default_attribute_top;
945                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
946                         "%s (%u %s)",
947                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
948                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
949                 break;
950             case BGPTYPE_AGGREGATOR:
951                 if (alen != 6)
952                     goto default_attribute_top;
953                 tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
954                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
955                         "%s: AS: %u origin: %s (%u %s)",
956                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
957                         tvb_get_ntohs(tvb, o + i + aoff),
958                         ip_to_str(ipaddr), alen + aoff,
959                         (alen + aoff == 1) ? "byte" : "bytes");
960                 break;
961             case BGPTYPE_COMMUNITIES:
962                 if (alen % 4 != 0)
963                     goto default_attribute_top;
964
965                 /* (o + i + aoff) =
966                    (o + current attribute + aoff bytes to first tuple) */
967                 q = o + i + aoff;
968                 end = q + alen;
969                 /* must be freed by second switch!                          */
970                 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be
971                    a good estimate of how long the communities string could
972                    be                                                       */
973                 communities_str = malloc((alen + 1) * 12);
974                 if (communities_str == NULL) break;
975                 communities_str[0] = '\0';
976                 memset(junk_buf, 0, sizeof(junk_buf));
977
978                 /* snarf each community */
979                 while (q < end) {
980                     /* check for well-known communities */
981                     if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
982                         strncpy(junk_buf, "NO_EXPORT ", 10);
983                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
984                         strncpy(junk_buf, "NO_ADVERTISE ", 13);
985                     else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
986                         strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
987                     else {
988                         snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
989                                 tvb_get_ntohs(tvb, q),
990                                 tvb_get_ntohs(tvb, q + 2));
991                     }
992                     q += 4;
993
994                     strncat(communities_str, junk_buf, sizeof(junk_buf));
995                 }
996                 /* cleanup end of string */
997                 communities_str[strlen(communities_str) - 1] = '\0';
998
999                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
1000                         "%s: %s (%u %s)",
1001                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1002                         communities_str, alen + aoff,
1003                         (alen + aoff == 1) ? "byte" : "bytes");
1004                 break;
1005             case BGPTYPE_ORIGINATOR_ID:
1006                 if (alen != 4)
1007                     goto default_attribute_top;
1008                 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1009                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
1010                         "%s: %s (%u %s)",
1011                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1012                         ip_to_str(ipaddr), alen + aoff, (alen + aoff == 1)
1013                         ? "byte" : "bytes");
1014                 break;
1015             case BGPTYPE_CLUSTER_LIST:
1016                 if (alen % 4 != 0)
1017                     goto default_attribute_top;
1018
1019                 /* (o + i + aoff) =
1020                    (o + current attribute + aoff bytes to first tuple) */
1021                 q = o + i + aoff;
1022                 end = q + alen;
1023                 /* must be freed by second switch!                          */
1024                 /* "alen * 16" (12 digits, 3 dots + space ) should be
1025                    a good estimate of how long the cluster_list string could
1026                    be                                                       */
1027                 cluster_list_str = malloc((alen + 1) * 16);
1028                 if (cluster_list_str == NULL) break;
1029                 cluster_list_str[0] = '\0';
1030                 memset(junk_buf, 0, sizeof(junk_buf));
1031
1032                 /* snarf each cluster list */
1033                 tvb_memcpy(tvb, ipaddr, q, 4);
1034                 while (q < end) {
1035                     snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(ipaddr));
1036                     strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
1037                     q += 4;
1038                 }
1039                 /* cleanup end of string */
1040                 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
1041
1042                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
1043                         "%s: %s (%u %s)",
1044                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1045                         cluster_list_str, alen + aoff,
1046                         (alen + aoff == 1) ? "byte" : "bytes");
1047                 break;
1048             case BGPTYPE_EXTENDED_COMMUNITY:
1049                 if (alen %8 != 0)
1050                     goto default_attribute_top;
1051
1052                 /* (o + i + aoff) =
1053                    (o + current attribute + aoff bytes to first tuple) */
1054                 q = o + i + aoff;
1055                 end = q + alen;
1056                 ext_com_str = malloc((alen / 8)*MAX_SIZE_OF_EXT_COM_NAMES);
1057                 if (ext_com_str == NULL) break;
1058                 ext_com_str[0] = '\0';
1059                 while (q < end) {
1060                         ext_com = tvb_get_ntohs(tvb, q);
1061                         snprintf(junk_buf, sizeof(junk_buf), "%s", val_to_str(ext_com,bgpext_com_type,"Unknown"));
1062                         strncat(ext_com_str, junk_buf, sizeof(junk_buf));
1063                         q = q + 8;
1064                         if (q < end) strncat(ext_com_str, ",", 1);
1065                 }
1066                 ti = proto_tree_add_text(subtree,tvb,o+i,alen+aoff,
1067                         "%s: %s (%u %s)",
1068                         val_to_str(bgpa.bgpa_type,bgpattr_type,"Unknown"),
1069                         ext_com_str, alen + aoff,
1070                         (alen + aoff == 1) ? "byte" : "bytes");
1071                 free(ext_com_str);
1072                 break;
1073
1074             default:
1075             default_attribute_top:
1076                 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
1077                         "%s (%u %s)",
1078                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1079                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
1080             } /* end of first switch */
1081             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
1082
1083             /* figure out flags */
1084             junk_buf[0] = '\0';
1085             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
1086                  strncat(junk_buf, "Optional, ", 10);
1087             }
1088             else {
1089                  strncat(junk_buf, "Well-known, ", 12);
1090             }
1091             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
1092                  strncat(junk_buf, "Transitive, ", 12);
1093             }
1094             else {
1095                  strncat(junk_buf, "Non-transitive, ", 16);
1096             }
1097             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
1098                  strncat(junk_buf, "Partial, ", 9);
1099             }
1100             else {
1101                  strncat(junk_buf, "Complete, ", 10);
1102             }
1103             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
1104                  strncat(junk_buf, "Extended Length, ", 17);
1105             }
1106             /* stomp last ", " */
1107             j = strlen(junk_buf);
1108             junk_buf[j - 2] = '\0';
1109             ti = proto_tree_add_text(subtree2, tvb,
1110                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1111                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
1112             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
1113
1114             /* add flag bitfield subtrees */
1115             proto_tree_add_text(subtree3, tvb,
1116                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1117                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1118                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
1119             proto_tree_add_text(subtree3, tvb,
1120                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1121                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1122                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
1123                         "Non-transitive"));
1124             proto_tree_add_text(subtree3, tvb,
1125                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1126                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1127                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
1128             proto_tree_add_text(subtree3, tvb,
1129                     o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
1130                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
1131                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
1132                         "Regular length"));
1133
1134             proto_tree_add_text(subtree2, tvb,
1135                     o + i + offsetof(struct bgp_attr, bgpa_type), 1,
1136                     "Type code: %s (%u)",
1137                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
1138                     bgpa.bgpa_type);
1139
1140             proto_tree_add_text(subtree2, tvb, o + i + sizeof(bgpa),
1141                     aoff - sizeof(bgpa), "Length: %d %s", alen,
1142                     (alen == 1) ? "byte" : "bytes");
1143
1144             /* the second switch prints things in the actual subtree of each
1145                attribute                                                     */
1146             switch (bgpa.bgpa_type) {
1147             case BGPTYPE_ORIGIN:
1148                 if (alen != 1) {
1149                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1150                             "Origin (invalid): %u %s", alen,
1151                              (alen == 1) ? "byte" : "bytes");
1152                 } else {
1153                     msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
1154                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1155                             "Origin: %s (%u)", msg, tvb_get_guint8(tvb, o + i + aoff));
1156                 }
1157                 break;
1158             case BGPTYPE_AS_PATH:
1159                 /* check for empty AS_PATH */
1160                 if (alen == 0) {
1161                     free(as_path_str);
1162                     break;
1163                 }
1164
1165                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1166                         "AS path: %s", as_path_str);
1167                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1168
1169                 /* (o + i + aoff) =
1170                    (o + current attribute + aoff bytes to first tuple) */
1171                 q = o + i + aoff;
1172                 end = q + alen;
1173
1174                 /* snarf each AS path tuple, we have to step through each one
1175                    again to make a separate subtree so we can't just reuse
1176                    as_path_str from above */
1177                 while (q < end) {
1178                     as_path_str[0] = '\0';
1179                     type = tvb_get_guint8(tvb, q++);
1180                     if (type == AS_SET) {
1181                         snprintf(as_path_str, 2, "{");
1182                     }
1183                     else if (type == AS_CONFED_SET) {
1184                         snprintf(as_path_str, 2, "[");
1185                     }
1186                     else if (type == AS_CONFED_SEQUENCE) {
1187                         snprintf(as_path_str, 2, "(");
1188                     }
1189                     length = tvb_get_guint8(tvb, q++);
1190
1191                     /* snarf each value in path, we're just going to reuse
1192                        as_path_str since we already have it malloced       */
1193                     for (j = 0; j < length; j++) {
1194                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
1195                                 (type == AS_SET || type == AS_CONFED_SET)
1196                                 ? ", " : " ");
1197                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1198                         q += 2;
1199                     }
1200
1201                     /* cleanup end of string */
1202                     if (type == AS_SET) {
1203                         as_path_str[strlen(as_path_str) - 2] = '}';
1204                     }
1205                     else if (type == AS_CONFED_SET) {
1206                         as_path_str[strlen(as_path_str) - 2] = ']';
1207                     }
1208                     else if (type == AS_CONFED_SEQUENCE) {
1209                         as_path_str[strlen(as_path_str) - 1] = ')';
1210                     }
1211                     else {
1212                         as_path_str[strlen(as_path_str) - 1] = '\0';
1213                     }
1214
1215                     /* length here means number of ASs, ie length * 2 bytes */
1216                     ti = proto_tree_add_text(as_paths_tree, tvb,
1217                             q - length * 2 - 2,
1218                             length * 2 + 2, "AS path segment: %s", as_path_str);
1219                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
1220                     proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 2,
1221                             1, "Path segment type: %s (%u)",
1222                             val_to_str(type, as_segment_type, "Unknown"), type);
1223                     proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 1,
1224                             1, "Path segment length: %u %s", length,
1225                             (length == 1) ? "AS" : "ASs");
1226
1227                     /* backup and reprint path segment value(s) only */
1228                     q -= 2 * length;
1229                     as_path_str[0] = '\0';
1230                     for (j = 0; j < length; j++) {
1231                         snprintf(junk_buf, sizeof(junk_buf), "%u ", tvb_get_ntohs(tvb, q));
1232                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
1233                         q += 2;
1234                     }
1235                     as_path_str[strlen(as_path_str) - 1] = '\0';
1236
1237                     proto_tree_add_text(as_path_tree, tvb, q - length * 2,
1238                             length * 2, "Path segment value: %s", as_path_str);
1239                 }
1240
1241                 free(as_path_str);
1242                 break;
1243             case BGPTYPE_NEXT_HOP:
1244                 if (alen != 4) {
1245                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1246                             "Next hop (invalid): %u %s", alen,
1247                             (alen == 1) ? "byte" : "bytes");
1248                 } else {
1249                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1250                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1251                             "Next hop: %s", ip_to_str(ipaddr));
1252                 }
1253                 break;
1254             case BGPTYPE_MULTI_EXIT_DISC:
1255                 if (alen != 4) {
1256                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1257                             "Multiple exit discriminator (invalid): %u %s",
1258                             alen, (alen == 1) ? "byte" : "bytes");
1259                 } else {
1260                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1261                             "Multiple exit discriminator: %u",
1262                             tvb_get_ntohl(tvb, o + i + aoff));
1263                 }
1264                 break;
1265             case BGPTYPE_LOCAL_PREF:
1266                 if (alen != 4) {
1267                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1268                             "Local preference (invalid): %u %s", alen,
1269                              (alen == 1) ? "byte" : "bytes");
1270                 } else {
1271                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1272                             "Local preference: %u", tvb_get_ntohl(tvb, o + i + aoff));
1273                 }
1274                 break;
1275             case BGPTYPE_ATOMIC_AGGREGATE:
1276                 if (alen != 0) {
1277                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1278                             "Atomic aggregate (invalid): %u %s", alen,
1279                             (alen == 1) ? "byte" : "bytes");
1280                 }
1281                 break;
1282             case BGPTYPE_AGGREGATOR:
1283                 if (alen != 6) {
1284                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1285                             "Aggregator (invalid): %u %s", alen,
1286                             (alen == 1) ? "byte" : "bytes");
1287                 } else {
1288                     proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1289                             "Aggregator AS: %u", tvb_get_ntohs(tvb, o + i + aoff));
1290                     tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
1291                     proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 4,
1292                             "Aggregator origin: %s",
1293                             ip_to_str(ipaddr));
1294                 }
1295                 break;
1296             case BGPTYPE_COMMUNITIES:
1297                 if (alen % 4 != 0) {
1298                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1299                             "Communities (invalid): %u %s", alen,
1300                             (alen == 1) ? "byte" : "bytes");
1301                     free(communities_str);
1302                     break;
1303                 }
1304
1305                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1306                         "Communities: %s", communities_str);
1307                 communities_tree = proto_item_add_subtree(ti,
1308                         ett_bgp_communities);
1309
1310                 /* (o + i + aoff) =
1311                    (o + current attribute + aoff bytes to first tuple) */
1312                 q = o + i + aoff;
1313                 end = q + alen;
1314
1315                 /* snarf each community */
1316                 while (q < end) {
1317                     /* check for reserved values */
1318                     guint32 community = tvb_get_ntohl(tvb, q);
1319                     if ((community & 0xFFFF0000) == FOURHEX0 ||
1320                          (community & 0xFFFF0000) == FOURHEXF) {
1321                         proto_tree_add_text(communities_tree, tvb,
1322                                q - 3 + aoff, 4,
1323                                "Community: %s (0x%08x)",
1324                                val_to_str(community, community_vals, "(reserved)"),
1325                                community);
1326                     }
1327                     else {
1328                         ti = proto_tree_add_text(communities_tree, tvb,
1329                                 q - 3 + aoff, 4, "Community: %u:%u",
1330                                 tvb_get_ntohs(tvb, q), tvb_get_ntohs(tvb, q + 2));
1331                         community_tree = proto_item_add_subtree(ti,
1332                             ett_bgp_communities);
1333                         proto_tree_add_text(community_tree, tvb, q - 3 + aoff,
1334                                 2, "Community AS: %u", tvb_get_ntohs(tvb, q));
1335                         proto_tree_add_text(community_tree, tvb, q - 1 + aoff,
1336                                 2, "Community value: %u", tvb_get_ntohs(tvb, q + 2));
1337                     }
1338
1339                     q += 4;
1340                 }
1341
1342                 free(communities_str);
1343                 break;
1344             case BGPTYPE_ORIGINATOR_ID:
1345                 if (alen != 4) {
1346                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1347                             "Originator identifier (invalid): %u %s", alen,
1348                             (alen == 1) ? "byte" : "bytes");
1349                 } else {
1350                     tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1351                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1352                             "Originator identifier: %s",
1353                             ip_to_str(ipaddr));
1354                 }
1355                 break;
1356            case BGPTYPE_MP_REACH_NLRI:
1357                 /*
1358                  * RFC 2545 specifies that there may be more than one
1359                  * address in the MP_REACH_NLRI attribute in section
1360                  * 3, "Constructing the Next Hop field".
1361                  *
1362                  * Yes, RFC 2858 says you can't do that, and, yes, RFC
1363                  * 2858 obsoletes RFC 2283, which says you can do that,
1364                  * but that doesn't mean we shouldn't dissect packets
1365                  * that conform to RFC 2283 but not RFC 2858, as some
1366                  * device on the network might implement the 2283-style
1367                  * BGP extensions rather than RFC 2858-style extensions.
1368                  */
1369                 af = tvb_get_ntohs(tvb, o + i + aoff);
1370                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1371                     "Address family: %s (%u)",
1372                     val_to_str(af, afn_vals, "Unknown"), af);
1373                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1374                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1375                     "Subsequent address family identifier: %s (%u)",
1376                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1377                     saf);
1378                 nexthop_len = tvb_get_guint8(tvb, o + i + aoff + 3);
1379                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3, 1,
1380                         "Next hop network address (%d %s)",
1381                         nexthop_len, plurality(nexthop_len, "byte", "bytes"));
1382                 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_nhna);
1383                 j = 0;
1384                 while (j < nexthop_len) {
1385                     advance = mp_addr_to_str(af, saf, tvb, o + i + aoff + 4 + j,
1386                         junk_buf, sizeof(junk_buf)) ;
1387                     if (j + advance > nexthop_len)
1388                             break;
1389                     proto_tree_add_text(subtree3, tvb,o + i + aoff + 4 + j,
1390                         advance, "Next hop: %s (%u)", junk_buf, advance);
1391                     j += advance;
1392                 }
1393                 alen -= nexthop_len + 4;
1394                 aoff += nexthop_len + 4 ;
1395
1396                 off = 0;
1397                 snpa = tvb_get_guint8(tvb, o + i + aoff);
1398                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1399                         "Subnetwork points of attachment: %u", snpa);
1400                 off++;
1401                 if (snpa) {
1402                         subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_snpa);
1403                         for (/*nothing*/; snpa > 0; snpa--) {
1404                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
1405                                         "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
1406                                 off++;
1407                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
1408                                 tvb_get_guint8(tvb, o + i + aoff + off - 1),
1409                                         "SNPA (%u %s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
1410                                         (tvb_get_guint8(tvb, o + i + aoff + off - 1) == 1) ? "byte" : "bytes");
1411                                 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
1412                         }
1413                 }
1414                 alen -= off;
1415                 aoff += off;
1416
1417                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1418                         "Network layer reachability information (%u %s)",
1419                         alen, (alen == 1) ? "byte" : "bytes");
1420                 if (alen)  {
1421                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_reach_nlri);
1422
1423                         while (alen > 0) {
1424                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1425                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1426                                 alen -= advance;
1427                                 aoff += advance;
1428                         }
1429                 }
1430                 break;
1431            case BGPTYPE_MP_UNREACH_NLRI:
1432                 af = tvb_get_ntohs(tvb, o + i + aoff);
1433                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1434                     "Address family: %s (%u)",
1435                     val_to_str(af, afn_vals, "Unknown"), af);
1436                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1437                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1438                     "Subsequent address family identifier: %s (%u)",
1439                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1440                     saf);
1441                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
1442                         alen - 3, "Withdrawn routes (%u %s)", alen - 3,
1443                         (alen - 3 == 1) ? "byte" : "bytes");
1444
1445                 alen -= 3;
1446                 aoff += 3;
1447                 if (alen > 0) {
1448                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_unreach_nlri);
1449
1450                         while (alen > 0) {
1451                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1452
1453                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1454                                 alen -= advance;
1455                                 aoff += advance;
1456                         }
1457                 }
1458                 break;
1459             case BGPTYPE_CLUSTER_LIST:
1460                 if (alen % 4 != 0) {
1461                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1462                             "Cluster list (invalid): %u %s", alen,
1463                             (alen == 1) ? "byte" : "bytes");
1464                     free(cluster_list_str);
1465                     break;
1466                 }
1467
1468                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1469                         "Cluster list: %s", cluster_list_str);
1470                 cluster_list_tree = proto_item_add_subtree(ti,
1471                         ett_bgp_cluster_list);
1472
1473                 /* (o + i + aoff) =
1474                    (o + current attribute + aoff bytes to first tuple) */
1475                 q = o + i + aoff;
1476                 end = q + alen;
1477
1478                 /* snarf each cluster identifier */
1479                 while (q < end) {
1480                     tvb_memcpy(tvb, ipaddr, q, 4);
1481                     ti = proto_tree_add_text(cluster_list_tree, tvb,
1482                             q - 3 + aoff, 4, "Cluster identifier: %s",
1483                             ip_to_str(ipaddr));
1484
1485                     q += 4;
1486                 }
1487
1488                 free(cluster_list_str);
1489                 break;
1490                 case BGPTYPE_EXTENDED_COMMUNITY:
1491                 if (alen %8 != 0) {
1492                         proto_tree_add_text(subtree3, tvb, o + i + aoff, alen, "Extended community (invalid) : %u %s", alen,
1493                                 (alen == 1) ? "byte" : "bytes") ;
1494                 } else {
1495                         q = o + i + aoff ;
1496                         end = o + i + aoff + alen ;
1497                         ext_com_str = malloc(MAX_SIZE_OF_EXT_COM_NAMES+MAX_SIZE_OF_IP_ADDR_STRING*2+1) ;
1498                         if (ext_com_str == NULL) break ;
1499                         ti = proto_tree_add_text(subtree2,tvb,q,alen, "Carried Extended communities");
1500                         subtree3 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
1501
1502                         while (q < end) {
1503                           ext_com_str[0] = '\0' ;
1504                           ext_com = tvb_get_ntohs(tvb,q) ;
1505                           snprintf(junk_buf, sizeof(junk_buf), "%s", val_to_str(ext_com,bgpext_com_type,"Unknown"));
1506                           strncat(ext_com_str,junk_buf,sizeof(junk_buf));
1507                           switch (ext_com) {
1508                           case BGP_EXT_COM_RT_0:
1509                           case BGP_EXT_COM_RO_0:
1510                             snprintf(junk_buf, sizeof(junk_buf), ": %u%s%d",tvb_get_ntohs(tvb,q+2),":",tvb_get_ntohl(tvb,q+4));
1511                             break ;
1512                           case BGP_EXT_COM_RT_1:
1513                           case BGP_EXT_COM_RO_1:
1514                             tvb_memcpy(tvb,ipaddr,q+2,4);
1515                             snprintf(junk_buf, sizeof(junk_buf), ": %s%s%u",ip_to_str(ipaddr),":",tvb_get_ntohs(tvb,q+6));
1516                             break;
1517                           case BGP_EXT_COM_VPN_ORIGIN:
1518                           case BGP_EXT_COM_OSPF_RID:
1519                             tvb_memcpy(tvb,ipaddr,q+2,4);
1520                             snprintf(junk_buf, sizeof(junk_buf), ": %s",ip_to_str(ipaddr));
1521                             break;
1522                           case BGP_EXT_COM_OSPF_RTYPE: 
1523                             tvb_memcpy(tvb,ipaddr,q+2,4);
1524                             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"));
1525                                 /* print OSPF Metric type if selected */
1526                                 /* always print E2 even if not external route -- receiving router should ignore */
1527                             if ( (tvb_get_guint8(tvb,q+7)) & BGP_OSPF_RTYPE_METRIC_TYPE ) { 
1528                               strcat(junk_buf," E2");
1529                             } else if (tvb_get_guint8(tvb,q+6)==(BGP_OSPF_RTYPE_EXT ||BGP_OSPF_RTYPE_NSSA ) ) {
1530                               strcat(junk_buf, " E1");
1531                             }
1532                             break;
1533                           case BGP_EXT_COM_LINKBAND:
1534                             tvb_memcpy(tvb,ipaddr,q+2,4); /* need to check on IEEE format on all platforms */
1535                             snprintf(junk_buf, sizeof(junk_buf), ": %f bytes per second",(double)*ipaddr);
1536                             break;
1537                           default:
1538                             snprintf(junk_buf, sizeof(junk_buf), " ");
1539                             break ;
1540                           }
1541                           strncat(ext_com_str,junk_buf,sizeof(junk_buf));
1542                           proto_tree_add_text(subtree3,tvb,q,8, "%s",ext_com_str);
1543                           q = q + 8 ;
1544                         }
1545                         free(ext_com_str) ;
1546                 }
1547                 break;
1548             default:
1549                 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1550                         "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
1551                         "bytes");
1552                 break;
1553             } /* end of second switch */
1554
1555             i += alen + aoff;
1556         }
1557
1558         o += 2 + len;
1559
1560         /* NLRI */
1561         len = offset + hlen - o;
1562
1563         /* parse prefixes */
1564         if (len > 0) {
1565            ti = proto_tree_add_text(tree, tvb, o, len,
1566                    "Network layer reachability information: %u %s", len,
1567                    (len == 1) ? "byte" : "bytes");
1568             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1569             end = o + len;
1570             while (o < end) {
1571                 i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
1572                 proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
1573                 o += i;
1574             }
1575         }
1576     }
1577 }
1578
1579 /*
1580  * Dissect a BGP NOTIFICATION message.
1581  */
1582 static void
1583 dissect_bgp_notification(tvbuff_t *tvb, int offset, proto_tree *tree)
1584 {
1585     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
1586     int                     hlen;   /* message length           */
1587     char                    *p;     /* string pointer           */
1588
1589     /* snarf message */
1590     tvb_memcpy(tvb, bgpn.bgpn_marker, offset, BGP_MIN_NOTIFICATION_MSG_SIZE);
1591     hlen = ntohs(bgpn.bgpn_len);
1592
1593     /* print error code */
1594     proto_tree_add_text(tree, tvb,
1595         offset + offsetof(struct bgp_notification, bgpn_major), 1,
1596         "Error code: %s (%u)",
1597         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1598         bgpn.bgpn_major);
1599
1600     /* print error subcode */
1601     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1602      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1603         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1604             "Unknown");
1605     } else if (bgpn.bgpn_minor == 0)
1606         p = "Unspecified";
1607     else
1608         p = "Unknown";
1609     proto_tree_add_text(tree, tvb,
1610         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1611         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1612
1613     /* only print if there is optional data */
1614     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1615         proto_tree_add_text(tree, tvb, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1616             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1617     }
1618 }
1619
1620 /*
1621  * Dissect a BGP ROUTE-REFRESH message.
1622  */
1623 static void
1624 dissect_bgp_route_refresh(tvbuff_t *tvb, int offset, proto_tree *tree)
1625 {
1626     u_int        i;    /* tmp            */
1627
1628     /* AFI */
1629     i = tvb_get_ntohs(tvb, offset + BGP_HEADER_SIZE);
1630     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 2, 
1631                         "Address family identifier: %s (%u)",
1632                         val_to_str(i, afn_vals, "Unknown"), i);
1633     offset += 2;
1634     /* Reserved */
1635     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 1, 
1636                         "Reserved: 1 byte");
1637     offset++;
1638     /* SAFI */
1639     i = tvb_get_guint8(tvb, offset + BGP_HEADER_SIZE);
1640     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 1, 
1641                         "Subsequent address family identifier: %s (%u)",
1642                         val_to_str(i, bgpattr_nlri_safi,
1643                         i >= 128 ? "Vendor specific" : "Unknown"),
1644                         i);
1645 }
1646
1647 /*
1648  * Dissect a BGP packet.
1649  */
1650 static void
1651 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1652 {
1653     proto_item    *ti;           /* tree item                        */
1654     proto_tree    *bgp_tree;     /* BGP packet tree                  */
1655     proto_tree    *bgp1_tree;    /* BGP message tree                 */
1656     int           l, i;          /* tmp                              */
1657     int           found;         /* number of BGP messages in packet */
1658     static u_char marker[] = {   /* BGP message marker               */
1659         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1660         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1661     };
1662     struct bgp    bgp;           /* BGP header                       */
1663     int           hlen;          /* BGP header length                */
1664     char          *typ;          /* BGP message type                 */
1665
1666     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1667         col_set_str(pinfo->cinfo, COL_PROTOCOL, "BGP");
1668     if (check_col(pinfo->cinfo, COL_INFO))
1669         col_clear(pinfo->cinfo, COL_INFO);
1670
1671     l = tvb_reported_length(tvb);
1672     i = 0;
1673     found = -1;
1674     /* run through the TCP packet looking for BGP headers         */
1675     while (i + BGP_HEADER_SIZE <= l) {
1676         tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1677
1678         /* look for bgp header */
1679         if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1680             i++;
1681             continue;
1682         }
1683
1684         found++;
1685         hlen = ntohs(bgp.bgp_len);
1686
1687         /*
1688          * Desegmentation check.
1689          */
1690         if (bgp_desegment) {
1691             if (hlen > tvb_length_remaining(tvb, i) && pinfo->can_desegment) {
1692                 /*
1693                  * Not all of this packet is in the data we've been
1694                  * handed, but we can do reassembly on it.
1695                  *
1696                  * Tell the TCP dissector where the data for
1697                  * this message starts in the data it handed
1698                  * us, and how many more bytes we need, and
1699                  * return.
1700                  */
1701                 pinfo->desegment_offset = i;
1702                 pinfo->desegment_len = hlen - tvb_length_remaining(tvb, i);
1703                 return;
1704             }
1705         }
1706
1707         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1708
1709         if (check_col(pinfo->cinfo, COL_INFO)) {
1710             if (found == 0)
1711                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", typ);
1712             else
1713                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", typ);
1714         }
1715
1716         if (tree) {
1717             ti = proto_tree_add_item(tree, proto_bgp, tvb, i, hlen, FALSE);
1718             bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1719
1720             ti = proto_tree_add_text(bgp_tree, tvb, i, hlen, "%s", typ);
1721
1722             /* add a different tree for each message type */
1723             switch (bgp.bgp_type) {
1724             case BGP_OPEN:
1725                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1726                 break;
1727             case BGP_UPDATE:
1728                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1729                 break;
1730             case BGP_NOTIFICATION:
1731                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1732                 break;
1733             case BGP_KEEPALIVE:
1734                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1735                 break;
1736             case BGP_ROUTE_REFRESH_CISCO:
1737             case BGP_ROUTE_REFRESH:
1738                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
1739                 break;
1740             default:
1741                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1742                 break;
1743             }
1744
1745             proto_tree_add_text(bgp1_tree, tvb, i, BGP_MARKER_SIZE,
1746                 "Marker: 16 bytes");
1747
1748             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1749                 proto_tree_add_text(bgp1_tree, tvb,
1750                     i + offsetof(struct bgp, bgp_len), 2,
1751                     "Length (invalid): %u %s", hlen,
1752                     (hlen == 1) ? "byte" : "bytes");
1753             } else {
1754                 proto_tree_add_text(bgp1_tree, tvb,
1755                     i + offsetof(struct bgp, bgp_len), 2,
1756                     "Length: %u %s", hlen,
1757                     (hlen == 1) ? "byte" : "bytes");
1758             }
1759
1760             proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, tvb,
1761                                        i + offsetof(struct bgp, bgp_type), 1,
1762                                        bgp.bgp_type,
1763                                        "Type: %s (%u)", typ, bgp.bgp_type);
1764
1765             switch (bgp.bgp_type) {
1766             case BGP_OPEN:
1767                 dissect_bgp_open(tvb, i, bgp1_tree);
1768                 break;
1769             case BGP_UPDATE:
1770                 dissect_bgp_update(tvb, i, bgp1_tree);
1771                 break;
1772             case BGP_NOTIFICATION:
1773                 dissect_bgp_notification(tvb, i, bgp1_tree);
1774                 break;
1775             case BGP_KEEPALIVE:
1776                 /* no data in KEEPALIVE messages */
1777                 break;
1778             case BGP_ROUTE_REFRESH_CISCO:
1779             case BGP_ROUTE_REFRESH:
1780                 dissect_bgp_route_refresh(tvb, i, bgp1_tree);
1781                 break;
1782             default:
1783                 break;
1784             }
1785         }
1786
1787         i += hlen;
1788     }
1789 }
1790
1791 /*
1792  * Register ourselves.
1793  */
1794 void
1795 proto_register_bgp(void)
1796 {
1797
1798     static hf_register_info hf[] = {
1799       { &hf_bgp_type,
1800         { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
1801           VALS(bgptypevals), 0x0, "BGP message type", HFILL }},
1802     };
1803
1804     static gint *ett[] = {
1805       &ett_bgp,
1806       &ett_bgp_unfeas,
1807       &ett_bgp_attrs,
1808       &ett_bgp_attr,
1809       &ett_bgp_attr_flags,
1810       &ett_bgp_mp_nhna,
1811       &ett_bgp_mp_reach_nlri,
1812       &ett_bgp_mp_unreach_nlri,
1813       &ett_bgp_mp_snpa,
1814       &ett_bgp_nlri,
1815       &ett_bgp_open,
1816       &ett_bgp_update,
1817       &ett_bgp_notification,
1818       &ett_bgp_route_refresh,
1819       &ett_bgp_as_paths,
1820       &ett_bgp_communities,
1821       &ett_bgp_cluster_list,
1822       &ett_bgp_options,
1823       &ett_bgp_option,
1824       &ett_bgp_extended_communities
1825     };
1826     module_t *bgp_module;
1827
1828     proto_bgp = proto_register_protocol("Border Gateway Protocol",
1829                                         "BGP", "bgp");
1830     proto_register_field_array(proto_bgp, hf, array_length(hf));
1831     proto_register_subtree_array(ett, array_length(ett));
1832
1833     bgp_module = prefs_register_protocol(proto_bgp, NULL);
1834     prefs_register_bool_preference(bgp_module, "desegment",
1835       "Desegment all BGP messages spanning multiple TCP segments",
1836       "Whether the BGP dissector should desegment all messages spanning multiple TCP segments",
1837       &bgp_desegment);
1838 }
1839
1840 void
1841 proto_reg_handoff_bgp(void)
1842 {
1843     dissector_handle_t bgp_handle;
1844
1845     bgp_handle = create_dissector_handle(dissect_bgp, proto_bgp);
1846     dissector_add("tcp.port", BGP_TCP_PORT, bgp_handle);
1847 }