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