And explain why the fact that RFC 2858 says you can't do what RFC 2545
[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.43 2001/07/03 02:49:38 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                 /*
1289                  * RFC 2545 specifies that there may be more than one
1290                  * address in the MP_REACH_NLRI attribute in section
1291                  * 3, "Constructing the Next Hop field".
1292                  *
1293                  * Yes, RFC 2858 says you can't do that, and, yes, RFC
1294                  * 2858 obsoletes RFC 2283, which says you can do that,
1295                  * but that doesn't mean we shouldn't dissect packets
1296                  * that conform to RFC 2283 but not RFC 2858, as some
1297                  * device on the network might implement the 2283-style
1298                  * BGP extensions rather than RFC 2858-style extensions.
1299                  */
1300                 af = tvb_get_ntohs(tvb, o + i + aoff);
1301                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1302                     "Address family: %s (%u)",
1303                     val_to_str(af, afnumber, "Unknown"), af);
1304                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1305                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1306                     "Subsequent address family identifier: %s (%u)",
1307                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1308                     saf);
1309                 nexthop_len = tvb_get_guint8(tvb, o + i + aoff + 3);
1310                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3, 1,
1311                         "Next hop network address (%d %s)",
1312                         nexthop_len, plurality(nexthop_len, "byte", "bytes"));
1313                 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_nhna);
1314                 j = 0;
1315                 while (j < nexthop_len) {
1316                     advance = mp_addr_to_str(af, saf, tvb, o + i + aoff + 4 + j,
1317                         junk_buf, sizeof(junk_buf)) ;
1318                     if (j + advance > nexthop_len)
1319                             break;
1320                     proto_tree_add_text(subtree3, tvb,o + i + aoff + 4 + j,
1321                         advance, "Next hop: %s (%u)", junk_buf, advance);
1322                     j += advance;
1323                 }
1324                 alen -= nexthop_len + 4;
1325                 aoff += nexthop_len + 4 ;
1326
1327                 off = 0;
1328                 snpa = tvb_get_guint8(tvb, o + i + aoff);
1329                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1330                         "Subnetwork points of attachment: %u", snpa);
1331                 off++;
1332                 if (snpa) {
1333                         subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_snpa);
1334                         for (/*nothing*/; snpa > 0; snpa--) {
1335                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
1336                                         "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
1337                                 off++;
1338                                 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
1339                                 tvb_get_guint8(tvb, o + i + aoff + off - 1),
1340                                         "SNPA (%u %s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
1341                                         (tvb_get_guint8(tvb, o + i + aoff + off - 1) == 1) ? "byte" : "bytes");
1342                                 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
1343                         }
1344                 }
1345                 alen -= off;
1346                 aoff += off;
1347
1348                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1349                         "Network layer reachability information (%u %s)",
1350                         alen, (alen == 1) ? "byte" : "bytes");
1351                 if (alen)  {
1352                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_reach_nlri);
1353
1354                         while (alen > 0) {
1355                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1356                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1357                                 alen -= advance;
1358                                 aoff += advance;
1359                         }
1360                 }
1361                 break;
1362            case BGPTYPE_MP_UNREACH_NLRI:
1363                 af = tvb_get_ntohs(tvb, o + i + aoff);
1364                 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1365                     "Address family: %s (%u)",
1366                     val_to_str(af, afnumber, "Unknown"), af);
1367                 saf = tvb_get_guint8(tvb, o + i + aoff + 2) ;
1368                 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1369                     "Subsequent address family identifier: %s (%u)",
1370                     val_to_str(saf, bgpattr_nlri_safi, saf >= 128 ? "Vendor specific" : "Unknown"),
1371                     saf);
1372                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
1373                         alen - 3, "Withdrawn routes (%u %s)", alen - 3,
1374                         (alen - 3 == 1) ? "byte" : "bytes");
1375
1376                 alen -= 3;
1377                 aoff += 3;
1378                 if (alen > 0) {
1379                         subtree3 = proto_item_add_subtree(ti,ett_bgp_mp_unreach_nlri);
1380
1381                         while (alen > 0) {
1382                                 advance = decode_prefix_MP(af, saf, tvb, o + i + aoff , junk_buf, sizeof(junk_buf)) ;
1383
1384                                 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance, "%s", junk_buf) ;
1385                                 alen -= advance;
1386                                 aoff += advance;
1387                         }
1388                 }
1389                 break;
1390             case BGPTYPE_CLUSTER_LIST:
1391                 if (alen % 4 != 0) {
1392                     proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1393                             "Cluster list (invalid): %u %s", alen,
1394                             (alen == 1) ? "byte" : "bytes");
1395                     free(cluster_list_str);
1396                     break;
1397                 }
1398
1399                 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1400                         "Cluster list: %s", cluster_list_str);
1401                 cluster_list_tree = proto_item_add_subtree(ti,
1402                         ett_bgp_cluster_list);
1403
1404                 /* (p + i + 3) =
1405                    (p + current attribute + 3 bytes to first tuple) */
1406                 end = o + alen + i + 3;
1407                 q = o + i + 3;
1408
1409                 /* snarf each cluster identifier */
1410                 while (q < end) {
1411                     tvb_memcpy(tvb, ipaddr, q, 4);
1412                     ti = proto_tree_add_text(cluster_list_tree, tvb,
1413                             q - 3 + aoff, 4, "Cluster identifier: %s",
1414                             ip_to_str(ipaddr));
1415
1416                     q += 4;
1417                 }
1418
1419                 free(cluster_list_str);
1420                 break;
1421                 case BGPTYPE_EXTENDED_COMMUNITY:
1422                 if (alen %8 != 0) {
1423                         proto_tree_add_text(subtree3, tvb, o + i + aoff, alen, "Extended community (invalid) : %u %s", alen,
1424                                 (alen == 1) ? "byte" : "bytes") ;
1425                 } else {
1426                         q = o + i + aoff ;
1427                         end = o + i + aoff + alen ;
1428                         ext_com_str = malloc(MAX_SIZE_OF_EXT_COM_NAMES+MAX_SIZE_OF_IP_ADDR_STRING*2+1) ;
1429                         if (ext_com_str == NULL) break ;
1430                         ti = proto_tree_add_text(subtree2,tvb,q,alen, "Carried Extended communities");
1431                         subtree3 = proto_item_add_subtree(ti,ett_bgp_extended_communities) ;
1432
1433                         while (q < end) {
1434                                 ext_com_str[0] = '\0' ;
1435                                 ext_com = tvb_get_ntohs(tvb,q) ;
1436                                 snprintf(junk_buf, sizeof(junk_buf), "%s", val_to_str(ext_com,bgpext_com_type,"Unknown"));
1437                                 strncat(ext_com_str,junk_buf,sizeof(junk_buf));
1438                                 switch (ext_com) {
1439                                         case BGP_EXT_COM_RT_0:
1440                                         case BGP_EXT_COM_RO_0:
1441                                                 snprintf(junk_buf, sizeof(junk_buf), ": %u%s%d",tvb_get_ntohs(tvb,q+2),":",tvb_get_ntohl(tvb,q+4));
1442                                                 break ;
1443                                         case BGP_EXT_COM_RT_1:
1444                                         case BGP_EXT_COM_RO_1:
1445                                                 tvb_memcpy(tvb,ipaddr,q+2,4);
1446                                                 snprintf(junk_buf, sizeof(junk_buf), ": %s%s%u",ip_to_str(ipaddr),":",tvb_get_ntohs(tvb,q+6));
1447                                                 break ;
1448                                         default:
1449                                                 snprintf(junk_buf, sizeof(junk_buf), " ");
1450                                                 break ;
1451                                         }
1452                                 strncat(ext_com_str,junk_buf,sizeof(junk_buf));
1453                                 proto_tree_add_text(subtree3,tvb,q,8, "%s",ext_com_str);
1454                                 q = q + 8 ;
1455                         }
1456                         free(ext_com_str) ;
1457                 }
1458                 break;
1459             default:
1460                 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1461                         "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
1462                         "bytes");
1463                 break;
1464             } /* end of second switch */
1465
1466             i += alen + aoff;
1467         }
1468
1469         o += 2 + len;
1470
1471         /* NLRI */
1472         len = offset + hlen - o;
1473
1474         /* parse prefixes */
1475         if (len > 0) {
1476            ti = proto_tree_add_text(tree, tvb, o, len,
1477                    "Network layer reachability information: %u %s", len,
1478                    (len == 1) ? "byte" : "bytes");
1479             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1480             end = o + len;
1481             while (o < end) {
1482                 i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
1483                 proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
1484                 o += i;
1485             }
1486         }
1487     }
1488 }
1489
1490 /*
1491  * Dissect a BGP NOTIFICATION message.
1492  */
1493 static void
1494 dissect_bgp_notification(tvbuff_t *tvb, int offset, proto_tree *tree)
1495 {
1496     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
1497     int                     hlen;   /* message length           */
1498     char                    *p;     /* string pointer           */
1499
1500     /* snarf message */
1501     tvb_memcpy(tvb, bgpn.bgpn_marker, offset, BGP_MIN_NOTIFICATION_MSG_SIZE);
1502     hlen = ntohs(bgpn.bgpn_len);
1503
1504     /* print error code */
1505     proto_tree_add_text(tree, tvb,
1506         offset + offsetof(struct bgp_notification, bgpn_major), 1,
1507         "Error code: %s (%u)",
1508         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1509         bgpn.bgpn_major);
1510
1511     /* print error subcode */
1512     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1513      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1514         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1515             "Unknown");
1516     } else if (bgpn.bgpn_minor == 0)
1517         p = "Unspecified";
1518     else
1519         p = "Unknown";
1520     proto_tree_add_text(tree, tvb,
1521         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1522         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1523
1524     /* only print if there is optional data */
1525     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1526         proto_tree_add_text(tree, tvb, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1527             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1528     }
1529 }
1530
1531 /*
1532  * Dissect a BGP ROUTE-REFRESH message.
1533  */
1534 static void
1535 dissect_bgp_route_refresh(tvbuff_t *tvb, int offset, proto_tree *tree)
1536 {
1537     u_int        i;    /* tmp            */
1538
1539     /* AFI */
1540     i = tvb_get_ntohs(tvb, offset + BGP_HEADER_SIZE);
1541     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 2, 
1542                         "Address family identifier: %s (%u)",
1543                         val_to_str(i, afnumber, "Unknown"), i);
1544     offset += 2;
1545     /* Reserved */
1546     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE + 2, 1, 
1547                         "Reserved: 1 byte");
1548     offset++;
1549     /* SAFI */
1550     i = tvb_get_guint8(tvb, offset);
1551     proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE + 3, 1, 
1552                         "Subsequent address family identifier: %s (%u)",
1553                         val_to_str(i, bgpattr_nlri_safi,
1554                         i >= 128 ? "Vendor specific" : "Unknown"),
1555                         i);
1556 }
1557
1558 /*
1559  * Dissect a BGP packet.
1560  */
1561 static void
1562 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1563 {
1564     proto_item    *ti;           /* tree item                        */
1565     proto_tree    *bgp_tree;     /* BGP packet tree                  */
1566     proto_tree    *bgp1_tree;    /* BGP message tree                 */
1567     int           l, i;          /* tmp                              */
1568     int           found;         /* number of BGP messages in packet */
1569     static u_char marker[] = {   /* BGP message marker               */
1570         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1571         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1572     };
1573     struct bgp    bgp;           /* BGP header                       */
1574     int           hlen;          /* BGP header length                */
1575     char          *typ;          /* BGP message type                 */
1576
1577     if (check_col(pinfo->fd, COL_PROTOCOL))
1578         col_set_str(pinfo->fd, COL_PROTOCOL, "BGP");
1579     if (check_col(pinfo->fd, COL_INFO))
1580         col_clear(pinfo->fd, COL_INFO);
1581
1582     l = tvb_length(tvb);
1583     i = 0;
1584     found = -1;
1585     /* run through the TCP packet looking for BGP headers         */
1586     /* this is done twice, but this way each message type can be 
1587        printed in the COL_INFO field                              */
1588     while (i + BGP_HEADER_SIZE <= l) {
1589         tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1590
1591         /* look for bgp header */
1592         if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1593             i++;
1594             continue;
1595         }
1596
1597         found++;
1598         hlen = ntohs(bgp.bgp_len);
1599         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1600
1601         if (check_col(pinfo->fd, COL_INFO)) {
1602             if (found == 0)
1603                 col_add_fstr(pinfo->fd, COL_INFO, "%s", typ);
1604             else
1605                 col_append_fstr(pinfo->fd, COL_INFO, ", %s", typ);
1606         }
1607
1608         i += hlen;
1609     }
1610
1611     if (tree) {
1612         ti = proto_tree_add_item(tree, proto_bgp, tvb, 0,
1613                                  l, FALSE);
1614         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1615
1616         i = 0;
1617         /* now, run through the TCP packet again, this time dissect */
1618         /* each message that we find */
1619         while (i + BGP_HEADER_SIZE <= l) {
1620             tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1621
1622             /* look for bgp header */
1623             if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1624                 i++;
1625                 continue;
1626             }
1627
1628             hlen = ntohs(bgp.bgp_len);
1629             typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1630             if (l < hlen) {
1631                 ti = proto_tree_add_text(bgp_tree, tvb, i,
1632                      l, "%s (truncated)", typ);
1633             } else {
1634                 ti = proto_tree_add_text(bgp_tree, tvb, i, hlen,
1635                             "%s", typ);
1636             }
1637             /* add a different tree for each message type */
1638             switch (bgp.bgp_type) {
1639             case BGP_OPEN:
1640                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1641                 break;
1642             case BGP_UPDATE:
1643                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1644                 break;
1645             case BGP_NOTIFICATION:
1646                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1647                 break;
1648             case BGP_KEEPALIVE:
1649                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1650                 break;
1651             case BGP_ROUTE_REFRESH_CISCO:
1652             case BGP_ROUTE_REFRESH:
1653                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
1654                 break;
1655             default:
1656                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1657                 break;
1658             }
1659
1660             proto_tree_add_text(bgp1_tree, tvb, i, BGP_MARKER_SIZE,
1661                 "Marker: 16 bytes");
1662
1663             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1664                 proto_tree_add_text(bgp1_tree, tvb,
1665                     i + offsetof(struct bgp, bgp_len), 2,
1666                     "Length (invalid): %u %s", hlen,
1667                     (hlen == 1) ? "byte" : "bytes");
1668             } else {
1669                 proto_tree_add_text(bgp1_tree, tvb,
1670                     i + offsetof(struct bgp, bgp_len), 2,
1671                     "Length: %u %s", hlen,
1672                     (hlen == 1) ? "byte" : "bytes");
1673             }
1674
1675             proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, tvb,
1676                                        i + offsetof(struct bgp, bgp_type), 1,
1677                                        bgp.bgp_type,
1678                                        "Type: %s (%u)", typ, bgp.bgp_type);
1679
1680             switch (bgp.bgp_type) {
1681             case BGP_OPEN:
1682                 dissect_bgp_open(tvb, i, bgp1_tree);
1683                 break;
1684             case BGP_UPDATE:
1685                 dissect_bgp_update(tvb, i, bgp1_tree);
1686                 break;
1687             case BGP_NOTIFICATION:
1688                 dissect_bgp_notification(tvb, i, bgp1_tree);
1689                 break;
1690             case BGP_KEEPALIVE:
1691                 /* no data in KEEPALIVE messages */
1692                 break;
1693             case BGP_ROUTE_REFRESH_CISCO:
1694             case BGP_ROUTE_REFRESH:
1695                 dissect_bgp_route_refresh(tvb, i, bgp1_tree);
1696                 break;
1697             default:
1698                 break;
1699             }
1700
1701             i += hlen;
1702         }
1703     }
1704 }
1705
1706 /*
1707  * Register ourselves.
1708  */
1709 void
1710 proto_register_bgp(void)
1711 {
1712
1713     static hf_register_info hf[] = {
1714       { &hf_bgp_type,
1715         { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
1716           VALS(bgptypevals), 0x0, "BGP message type", HFILL }},
1717     };
1718
1719     static gint *ett[] = {
1720       &ett_bgp,
1721       &ett_bgp_unfeas,
1722       &ett_bgp_attrs,
1723       &ett_bgp_attr,
1724       &ett_bgp_attr_flags,
1725       &ett_bgp_mp_nhna,
1726       &ett_bgp_mp_reach_nlri,
1727       &ett_bgp_mp_unreach_nlri,
1728       &ett_bgp_mp_snpa,
1729       &ett_bgp_nlri,
1730       &ett_bgp_open,
1731       &ett_bgp_update,
1732       &ett_bgp_notification,
1733       &ett_bgp_route_refresh,
1734       &ett_bgp_as_paths,
1735       &ett_bgp_communities,
1736       &ett_bgp_cluster_list,
1737       &ett_bgp_options,
1738       &ett_bgp_option,
1739       &ett_bgp_extended_communities
1740     };
1741
1742     proto_bgp = proto_register_protocol("Border Gateway Protocol",
1743                                         "BGP", "bgp");
1744     proto_register_field_array(proto_bgp, hf, array_length(hf));
1745     proto_register_subtree_array(ett, array_length(ett));
1746 }
1747
1748 void
1749 proto_reg_handoff_bgp(void)
1750 {
1751     dissector_add("tcp.port", BGP_TCP_PORT, dissect_bgp, proto_bgp);
1752 }