- fix potential buffer overflow problems.
[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.26 2000/08/13 14:08:02 deniel Exp $
6  * 
7  * Supports:
8  * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9  * RFC1965 Autonomous System Confederations for BGP 
10  * RFC1966 BGP Route Reflection An alternative to full mesh IBGP
11  * RFC1997 BGP Communities Attribute
12  * RFC2283 Multiprotocol Extensions for BGP-4
13  *
14  * TODO:
15  * Destination Preference Attribute for BGP (work in progress)
16  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing 
17  *
18  * Ethereal - Network traffic analyzer
19  * By Gerald Combs <gerald@zing.org>
20  * Copyright 1998 Gerald Combs
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License
24  * as published by the Free Software Foundation; either version 2
25  * of the License, or (at your option) any later version.
26  * 
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  * 
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  */
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <stdio.h>
42 #include <stdlib.h>
43
44 #ifdef HAVE_SYS_TYPES_H
45 # include <sys/types.h>
46 #endif
47
48 #ifdef HAVE_NETINET_IN_H
49 # include <netinet/in.h>
50 #endif
51
52 #ifdef HAVE_ARPA_INET_H
53 #include <arpa/inet.h>
54 #endif
55
56 #include <string.h>
57 #include <glib.h>
58
59 #ifdef NEED_SNPRINTF_H
60 # include "snprintf.h"
61 #endif
62
63 #include "packet.h"
64 #include "packet-bgp.h"
65 #include "packet-ipv6.h"
66
67 #define TCP_PORT_BGP                    179
68
69 static const value_string bgptypevals[] = {
70     { BGP_OPEN, "OPEN Message" },
71     { BGP_UPDATE, "UPDATE Message" },
72     { BGP_NOTIFICATION, "NOTIFICATION Message" },
73     { BGP_KEEPALIVE, "KEEPALIVE Message" },
74     { 0, NULL },
75 };
76
77 static const value_string bgpnotify_major[] = {
78     { 1, "Message Header Error" },
79     { 2, "OPEN Message Error" },
80     { 3, "UPDATE Message Error" },
81     { 4, "Hold Timer Expired" },
82     { 5, "Finite State Machine Error" },
83     { 6, "Cease" },
84     { 0, NULL },
85 };
86
87 static const value_string bgpnotify_minor_1[] = {
88     { 1, "Connection Not Synchronized" },
89     { 2, "Bad Message Length" },
90     { 3, "Bad Message Type" },
91     { 0, NULL },
92 };
93
94 static const value_string bgpnotify_minor_2[] = {
95     { 1, "Unsupported Version Number" },
96     { 2, "Bad Peer AS" },
97     { 3, "Bad BGP Identifier" },
98     { 4, "Unsupported Optional Parameter" },
99     { 5, "Authentication Failure" },
100     { 6, "Unacceptable Hold Time" },
101     { 0, NULL },
102 };
103
104 static const value_string bgpnotify_minor_3[] = {
105     { 1, "Malformed Attribute List" },
106     { 2, "Unrecognized Well-known Attribute" },
107     { 3, "Missing Well-known Attribute" },
108     { 4, "Attribute Flags Error" },
109     { 5, "Attribute Length Error" },
110     { 6, "Invalid ORIGIN Attribute" },
111     { 7, "AS Routing Loop" },
112     { 8, "Invalid NEXT_HOP Attribute" },
113     { 9, "Optional Attribute Error" },
114     { 10, "Invalid Network Field" },
115     { 11, "Malformed AS_PATH" },
116     { 0, NULL },
117 };
118
119 static const value_string *bgpnotify_minor[] = {
120     NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
121 };
122
123 static const value_string bgpattr_origin[] = {
124     { 0, "IGP" },
125     { 1, "EGP" },
126     { 2, "INCOMPLETE" },
127     { 0, NULL },
128 };
129
130 static const value_string as_segment_type[] = {
131     { 1, "AS_SET" },
132     { 2, "AS_SEQUENCE" },
133 /* This is wrong according to the RFC... in the Zebra code they say that
134    cisco reversed it.  Packet traces seem to agree.                      */
135     { 4, "AS_CONFED_SET" },
136     { 3, "AS_CONFED_SEQUENCE" },
137     { 0, NULL },
138 };
139
140 static const value_string bgpattr_type[] = {
141     { BGPTYPE_ORIGIN, "ORIGIN" },
142     { BGPTYPE_AS_PATH, "AS_PATH" },
143     { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
144     { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
145     { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
146     { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
147     { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
148     { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
149     { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
150     { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
151     { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
152     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
153     { 0, NULL },
154 };
155
156 /* Subsequent address family identifier, RFC2283 section 7 */
157 static const value_string bgpattr_nlri_safi[] = {
158     { 0, "Reserved" },
159     { 1, "Unicast" },
160     { 2, "Multicast" },
161     { 3, "Unicast+Multicast" },
162     { 0, NULL },
163 };
164
165 static const value_string afnumber[] = {
166     { 0, "Reserved" },
167     { AFNUM_INET, "IPv4" },
168     { AFNUM_INET6, "IPv6" },
169     { AFNUM_NSAP, "NSAP" },
170     { AFNUM_HDLC, "HDLC" },
171     { AFNUM_BBN1822, "BBN 1822" },
172     { AFNUM_802, "802" },
173     { AFNUM_E163, "E.163" },
174     { AFNUM_E164, "E.164" },
175     { AFNUM_F69, "F.69" },
176     { AFNUM_X121, "X.121" },
177     { AFNUM_IPX, "IPX" },
178     { AFNUM_ATALK, "Appletalk" },
179     { AFNUM_DECNET, "Decnet IV" },
180     { AFNUM_BANYAN, "Banyan Vines" },
181     { AFNUM_E164NSAP, "E.164 with NSAP subaddress" },
182     { 65535, "Reserved" },
183     { 0, NULL },
184 };
185
186 static int proto_bgp = -1;
187
188 static gint ett_bgp = -1;
189 static gint ett_bgp_unfeas = -1;
190 static gint ett_bgp_attrs = -1;
191 static gint ett_bgp_attr = -1;
192 static gint ett_bgp_attr_flags = -1;
193 static gint ett_bgp_mp_reach_nlri = -1;
194 static gint ett_bgp_mp_unreach_nlri = -1;
195 static gint ett_bgp_nlri = -1;
196 static gint ett_bgp_open = -1;
197 static gint ett_bgp_update = -1;
198 static gint ett_bgp_notification = -1;
199 static gint ett_bgp_as_paths = -1;
200 static gint ett_bgp_communities = -1;
201 static gint ett_bgp_cluster_list = -1;
202
203 /*
204  * Decode an IPv4 prefix.
205  */
206 static int
207 decode_prefix4(const u_char *pd, char *buf, int buflen)
208 {
209     guint8 addr[4];   /* IP address                         */
210     int    plen;      /* prefix length                      */
211     int    length;    /* number of octets needed for prefix */
212
213     /* snarf length */
214     plen = pd[0];
215     if (plen < 0 || 32 < plen)
216         return -1;
217     length = (plen + 7) / 8;
218
219     /* snarf prefix */
220     memset(addr, 0, sizeof(addr));
221     memcpy(addr, &pd[1], length);
222     if (plen % 8)
223         addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
224
225     /* hand back a formatted string */
226     snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
227     return(1 + length);
228 }
229
230 /*
231  * Decode an IPv6 prefix.
232  */
233 static int
234 decode_prefix6(const u_char *pd, char *buf, int buflen)
235 {
236     struct e_in6_addr addr;     /* IPv6 address                       */
237     int               plen;     /* prefix length                      */
238     int               length;   /* number of octets needed for prefix */
239
240     /* snarf length */
241     plen = pd[0];
242     if (plen < 0 || 128 < plen)
243         return -1;
244     length = (plen + 7) / 8;
245
246     /* snarf prefix */
247     memset(&addr, 0, sizeof(addr));
248     memcpy(&addr, &pd[1], length);
249     if (plen % 8)
250         addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
251
252     /* hand back a formatted string */
253     snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
254     return(1 + length);
255 }
256
257 /*
258  * Dissect a BGP OPEN message.
259  */
260 static void
261 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
262 {
263     struct bgp_open bgpo;   /* BGP OPEN message   */
264     int             hlen;   /* message length     */
265
266     /* snarf OPEN message */
267     memcpy(&bgpo, &pd[offset], sizeof(bgpo));
268     hlen = ntohs(bgpo.bgpo_len);
269
270     proto_tree_add_text(tree, NullTVB,
271         offset + offsetof(struct bgp_open, bgpo_version), 1,
272         "Version: %u", bgpo.bgpo_version);
273     proto_tree_add_text(tree, NullTVB,
274         offset + offsetof(struct bgp_open, bgpo_myas), 2,
275         "My AS: %u", ntohs(bgpo.bgpo_myas));
276     proto_tree_add_text(tree, NullTVB,
277         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
278         "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
279     proto_tree_add_text(tree, NullTVB,
280         offset + offsetof(struct bgp_open, bgpo_id), 4,
281         "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
282     proto_tree_add_text(tree, NullTVB,
283         offset + offsetof(struct bgp_open, bgpo_optlen), 1,
284         "Optional parameters length: %u %s", bgpo.bgpo_optlen,
285         (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
286
287     if (hlen > sizeof(struct bgp_open)) {
288         int openoff;
289         openoff = ((char *)&bgpo.bgpo_optlen - (char *)&bgpo) + 1;
290         proto_tree_add_text(tree, NullTVB,
291             offset + openoff, hlen - openoff,
292             "Optional parameters");
293     }
294 }
295
296 /*
297  * Dissect a BGP UPDATE message.
298  */
299 static void
300 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
301     proto_tree *tree)
302  {
303     struct bgp bgp;                             /* BGP header               */
304     struct bgp_attr bgpa;                       /* path attributes          */
305     int             hlen;                       /* message length           */
306     const u_char    *p;                         /* packet offset pointer    */
307     const u_char    *q;                         /* tmp                      */
308     const u_char    *end;                       /* message end              */
309     int             len;                        /* tmp                      */
310     proto_item      *ti;                        /* tree item                */
311     proto_tree      *subtree;                   /* subtree for attibutes    */ 
312     proto_tree      *subtree2;                  /* subtree for attibutes    */ 
313     proto_tree      *subtree3;                  /* subtree for attibutes    */
314     proto_tree      *as_paths_tree;             /* subtree for AS_PATHs     */
315     proto_tree      *as_path_tree;              /* subtree for AS_PATH      */
316     proto_tree      *communities_tree;          /* subtree for COMMUNITIES  */
317     proto_tree      *community_tree;            /* subtree for a community  */
318     proto_tree      *cluster_list_tree;         /* subtree for CLUSTER_LIST */
319     int             i, j;                       /* tmp                      */
320     guint8          length;                     /* AS_PATH length           */
321     guint8          type;                       /* AS_PATH type             */
322     char            *as_path_str = NULL;        /* AS_PATH string           */
323     char            *communities_str = NULL;    /* COMMUNITIES string       */
324     char            *cluster_list_str = NULL;   /* CLUSTER_LIST string      */
325     char            junk_buf[256];              /* tmp                      */
326
327
328     /* snarf UPDATE message */
329     memcpy(&bgp, &pd[offset], sizeof(bgp));
330     hlen = ntohs(bgp.bgp_len);
331     p = &pd[offset + BGP_HEADER_SIZE];  /*XXX*/
332
333     /* check for withdrawals */
334     len = pntohs(p);
335     proto_tree_add_text(tree, NullTVB, p - pd, 2, 
336         "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
337     p += 2;
338
339     /* parse unfeasible prefixes */
340     if (len > 0) {
341         ti = proto_tree_add_text(tree, NullTVB, p - pd, len, "Withdrawn routes:");
342         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
343
344         /* parse each prefixes */
345         end = p + len;
346         while (p < end) {
347             i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
348             proto_tree_add_text(subtree, NullTVB, p - pd, i, "%s", junk_buf);
349             p += i;
350         }
351     }
352     else {
353         p += len;
354     }
355
356     /* check for advertisements */
357     len = pntohs(p);
358     proto_tree_add_text(tree, NullTVB, p - pd, 2, "Total path attribute length: %u %s", 
359             len, (len == 1) ? "byte" : "bytes");
360
361     /* path attributes */
362     if (len > 0) {
363         ti = proto_tree_add_text(tree, NullTVB, p - pd + 2, len, "Path attributes");
364         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
365         i = 2;
366         while (i < len) {
367             int alen, aoff;
368             char *msg;
369             guint16 af;
370             int off, snpa;
371
372             memcpy(&bgpa, &p[i], sizeof(bgpa));
373             /* check for the Extended Length bit */
374             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
375                 alen = pntohs(&p[i + sizeof(bgpa)]);
376                 aoff = sizeof(bgpa) + 2;
377             } else {
378                 alen = p[i + sizeof(bgpa)];
379                 aoff = sizeof(bgpa) + 1;
380             }
381             
382             /* This is kind of ugly - similar code appears twice, but it 
383                helps browsing attrs.                                      */
384             /* the first switch prints things in the title of the subtree */
385             switch (bgpa.bgpa_type) {
386             case BGPTYPE_ORIGIN:
387                 if (alen != 1)
388                     goto default_attribute_top;
389                 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
390                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
391                         "%s: %s (%u %s)",
392                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
393                         msg, alen + aoff, (alen + aoff == 1) ? "byte" : 
394                         "bytes");
395                 break;
396             case BGPTYPE_AS_PATH:
397                 /* (p + i + 3) =
398                    (p + current attribute + 3 bytes to first tuple) */ 
399                 end = p + alen + i + 3;
400                 q = p + i + 3;
401                 /* must be freed by second switch!                         */
402                 /* "alen * 6" (5 digits + space) should be a good estimate
403                    of how long the AS path string could be                 */
404                 as_path_str = malloc((alen + 1) * 6);
405                 if (as_path_str == NULL) break;
406                 as_path_str[0] = '\0';
407    
408                 /* snarf each AS path */
409                 while (q < end) {
410                     type = *q++;
411                     if (type == AS_SET) {
412                         snprintf(as_path_str, 2, "{");
413                     }
414                     else if (type == AS_CONFED_SET) {
415                         snprintf(as_path_str, 2, "[");
416                     }
417                     else if (type == AS_CONFED_SEQUENCE) {
418                         snprintf(as_path_str, 2, "(");
419                     }
420                     length = *q++;
421
422                     /* snarf each value in path */
423                     for (j = 0; j < length; j++) {
424                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q), 
425                                 (type == AS_SET || type == AS_CONFED_SET) 
426                                 ? ", " : " ");
427                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
428                         q += 2;
429                     }
430                    
431                     /* cleanup end of string */
432                     if (type == AS_SET) {
433                         as_path_str[strlen(as_path_str) - 2] = '}';
434                     }
435                     else if (type == AS_CONFED_SET) {
436                         as_path_str[strlen(as_path_str) - 2] = ']';
437                     }
438                     else if (type == AS_CONFED_SEQUENCE) {
439                         as_path_str[strlen(as_path_str) - 1] = ')';
440                     }
441                     else {
442                         as_path_str[strlen(as_path_str) - 1] = '\0';
443                     }
444                 }
445
446                 /* check for empty AS_PATH */
447                 if (alen == 0)
448                     strncpy(as_path_str, "empty", 6);
449
450                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
451                         "%s: %s (%u %s)",
452                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
453                         as_path_str, alen + aoff,
454                         (alen + aoff == 1) ? "byte" : "bytes");
455                 break;
456             case BGPTYPE_NEXT_HOP:
457                 if (alen != 4)
458                     goto default_attribute_top;
459                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
460                         "%s: %s (%u %s)",
461                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
462                         ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
463                         ? "byte" : "bytes");
464                 break;
465             case BGPTYPE_MULTI_EXIT_DISC:
466                 if (alen != 4)
467                     goto default_attribute_top;
468                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
469                         "%s: %u (%u %s)",
470                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
471                         pntohl(&p[i + aoff]), alen + aoff,
472                         (alen + aoff == 1) ? "byte" : "bytes");
473                 break;
474             case BGPTYPE_LOCAL_PREF:
475                 if (alen != 4)
476                     goto default_attribute_top;
477                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
478                         "%s: %u (%u %s)",
479                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
480                         pntohl(&p[i + aoff]), alen + aoff,
481                         (alen + aoff == 1) ? "byte" : "bytes");
482                 break;
483             case BGPTYPE_ATOMIC_AGGREGATE:
484                 if (alen != 0) 
485                     goto default_attribute_top;
486                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
487                         "%s (%u %s)",
488                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
489                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
490                 break;
491             case BGPTYPE_AGGREGATOR:
492                 if (alen != 6) 
493                     goto default_attribute_top;
494                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
495                         "%s: AS: %u origin: %s (%u %s)",
496                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
497                         pntohs(&p[i + aoff]),
498                         ip_to_str(&p[i + aoff + 2]), alen + aoff, 
499                         (alen + aoff == 1) ? "byte" : "bytes");
500                 break;
501             case BGPTYPE_COMMUNITIES:
502                 if (alen % 4 != 0)
503                     goto default_attribute_top;
504
505                 /* (p + i + 3) =
506                    (p + current attribute + 3 bytes to first tuple) */ 
507                 end = p + alen + i + 3;
508                 q = p + i + 3;
509                 /* must be freed by second switch!                          */
510                 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be 
511                    a good estimate of how long the communities string could 
512                    be                                                       */
513                 communities_str = malloc((alen + 1) * 12);
514                 if (communities_str == NULL) break;
515                 communities_str[0] = '\0';
516                 memset(junk_buf, 0, sizeof(junk_buf)); 
517
518                 /* snarf each community */
519                 while (q < end) {
520                     /* check for well-known communities */
521                     if (pntohl(q) == BGP_COMM_NO_EXPORT)
522                         strncpy(junk_buf, "NO_EXPORT ", 10);
523                     else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
524                         strncpy(junk_buf, "NO_ADVERTISE ", 13);
525                     else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
526                         strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
527                     else {
528                         snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
529                                 pntohs(q), 
530                                 pntohs(q + 2));
531                     }
532                     q += 4; 
533  
534                     strncat(communities_str, junk_buf, sizeof(junk_buf));
535                 }
536                 /* cleanup end of string */
537                 communities_str[strlen(communities_str) - 1] = '\0';
538
539                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
540                         "%s: %s (%u %s)",
541                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
542                         communities_str, alen + aoff,
543                         (alen + aoff == 1) ? "byte" : "bytes");
544                 break;
545             case BGPTYPE_ORIGINATOR_ID:
546                 if (alen != 4)
547                     goto default_attribute_top;
548                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
549                         "%s: %s (%u %s)",
550                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
551                         ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
552                         ? "byte" : "bytes");
553                 break;
554             case BGPTYPE_CLUSTER_LIST:
555                 if (alen % 4 != 0)
556                     goto default_attribute_top;
557
558                 /* (p + i + 3) =
559                    (p + current attribute + 3 bytes to first tuple) */ 
560                 end = p + alen + i + 3;
561                 q = p + i + 3;
562                 /* must be freed by second switch!                          */
563                 /* "alen * 16" (12 digits, 3 dots + space ) should be 
564                    a good estimate of how long the cluster_list string could 
565                    be                                                       */
566                 cluster_list_str = malloc((alen + 1) * 16);
567                 if (cluster_list_str == NULL) break;
568                 cluster_list_str[0] = '\0';
569                 memset(junk_buf, 0, sizeof(junk_buf)); 
570
571                 /* snarf each cluster list */
572                 while (q < end) {
573                     snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(q));
574                     strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
575                     q += 4; 
576                 }
577                 /* cleanup end of string */
578                 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
579
580                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
581                         "%s: %s (%u %s)",
582                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
583                         cluster_list_str, alen + aoff,
584                         (alen + aoff == 1) ? "byte" : "bytes");
585                 break;
586             default:
587             default_attribute_top:
588                 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
589                         "%s (%u %s)",
590                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
591                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
592             } /* end of first switch */
593             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
594
595             /* figure out flags */
596             junk_buf[0] = '\0';
597             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
598                  strncat(junk_buf, "Optional, ", 10);
599             }
600             else {
601                  strncat(junk_buf, "Well-known, ", 12);
602             }
603             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
604                  strncat(junk_buf, "Transitive, ", 12);
605             }
606             else {
607                  strncat(junk_buf, "Non-transitive, ", 16);
608             }
609             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
610                  strncat(junk_buf, "Partial, ", 9);
611             }
612             else {
613                  strncat(junk_buf, "Complete, ", 10);
614             }
615             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
616                  strncat(junk_buf, "Extended Length, ", 17);
617             }
618             /* stomp last ", " */
619             j = strlen(junk_buf);
620             junk_buf[j - 2] = '\0';
621             ti = proto_tree_add_text(subtree2, NullTVB,
622                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
623                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
624             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
625
626             /* add flag bitfield subtrees */
627             proto_tree_add_text(subtree3, NullTVB,
628                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
629                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
630                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
631             proto_tree_add_text(subtree3, NullTVB,
632                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
633                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
634                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive", 
635                         "Non-transitive"));
636             proto_tree_add_text(subtree3, NullTVB,
637                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
638                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
639                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
640             proto_tree_add_text(subtree3, NullTVB,
641                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
642                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
643                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length", 
644                         "Regular length"));
645
646             proto_tree_add_text(subtree2, NullTVB,
647                     p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
648                     "Type code: %s (%u)",
649                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
650                     bgpa.bgpa_type);
651             
652             proto_tree_add_text(subtree2, NullTVB, p - pd + i + sizeof(bgpa), 
653                     aoff - sizeof(bgpa), "Length: %d %s", alen, 
654                     (alen == 1) ? "byte" : "bytes");
655
656             /* the second switch prints things in the actual subtree of each 
657                attribute                                                     */ 
658             switch (bgpa.bgpa_type) {
659             case BGPTYPE_ORIGIN:
660                 if (alen != 1) {
661                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
662                             "Origin (invalid): %u %s", alen,
663                              (alen == 1) ? "byte" : "bytes");
664                 } else {
665                     msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
666                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 1,
667                             "Origin: %s (%u)", msg, p[i + aoff]);
668                 }
669                 break;
670             case BGPTYPE_AS_PATH:
671                 /* check for empty AS_PATH */
672                 if (alen == 0) {
673                     free(as_path_str);
674                     break;
675                 }
676
677                 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
678                         "AS path: %s", as_path_str);
679                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
680
681                 /* (p + i + 3) =
682                    (p + current attribute + 3 bytes to first tuple) */ 
683                 end = p + alen + i + 3;
684                 q = p + i + 3;
685    
686                 /* snarf each AS path tuple, we have to step through each one
687                    again to make a separate subtree so we can't just reuse
688                    as_path_str from above */
689                 while (q < end) {
690                     as_path_str[0] = '\0';
691                     type = *q++;
692                     if (type == AS_SET) {
693                         snprintf(as_path_str, 2, "{");
694                     }
695                     else if (type == AS_CONFED_SET) {
696                         snprintf(as_path_str, 2, "[");
697                     }
698                     else if (type == AS_CONFED_SEQUENCE) {
699                         snprintf(as_path_str, 2, "(");
700                     }
701                     length = *q++;
702
703                     /* snarf each value in path, we're just going to reuse 
704                        as_path_str since we already have it malloced       */
705                     for (j = 0; j < length; j++) {
706                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
707                                 (type == AS_SET || type == AS_CONFED_SET) 
708                                 ? ", " : " ");
709                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
710                         q += 2;
711                     }
712
713                     /* cleanup end of string */
714                     if (type == AS_SET) {
715                         as_path_str[strlen(as_path_str) - 2] = '}';
716                     }
717                     else if (type == AS_CONFED_SET) {
718                         as_path_str[strlen(as_path_str) - 2] = ']';
719                     }
720                     else if (type == AS_CONFED_SEQUENCE) {
721                         as_path_str[strlen(as_path_str) - 1] = ')';
722                     }
723                     else {
724                         as_path_str[strlen(as_path_str) - 1] = '\0';
725                     }
726
727                     /* length here means number of ASs, ie length * 2 bytes */
728                     ti = proto_tree_add_text(as_paths_tree, NullTVB, 
729                             q - pd - length * 2 - 2,
730                             length * 2 + 2, "AS path segment: %s", as_path_str);
731                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
732                     proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2 - 2,
733                             1, "Path segment type: %s (%u)",
734                             val_to_str(type, as_segment_type, "Unknown"), type);
735                     proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2 - 1, 
736                             1, "Path segment length: %u %s", length,
737                             (length == 1) ? "AS" : "ASs");
738
739                     /* backup and reprint path segment value(s) only */
740                     q -= 2 * length;
741                     as_path_str[0] = '\0';
742                     for (j = 0; j < length; j++) {
743                         snprintf(junk_buf, sizeof(junk_buf), "%u ", pntohs(q));
744                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
745                         q += 2;
746                     }
747                     as_path_str[strlen(as_path_str) - 1] = '\0';
748
749                     proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2, 
750                             length * 2, "Path segment value: %s", as_path_str);
751                 }
752
753                 free(as_path_str);
754                 break;
755             case BGPTYPE_NEXT_HOP:
756                 if (alen != 4) {
757                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
758                             "Next hop (invalid): %u %s", alen,
759                             (alen == 1) ? "byte" : "bytes");
760                 } else {
761                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
762                             "Next hop: %s", ip_to_str(&p[i + aoff]));
763                 }
764                 break;
765             case BGPTYPE_MULTI_EXIT_DISC:
766                 if (alen != 4) {
767                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
768                             "Multiple exit discriminator (invalid): %u %s",
769                             alen, (alen == 1) ? "byte" : "bytes");
770                 } else {
771                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
772                             "Multiple exit discriminator: %u",
773                             pntohl(&p[i + aoff]));
774                 }
775                 break;
776             case BGPTYPE_LOCAL_PREF:
777                 if (alen != 4) {
778                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
779                             "Local preference (invalid): %u %s", alen,
780                              (alen == 1) ? "byte" : "bytes");
781                 } else {
782                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
783                             "Local preference: %u", pntohl(&p[i + aoff]));
784                 }
785                 break;
786             case BGPTYPE_ATOMIC_AGGREGATE:
787                 if (alen != 0) {
788                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
789                             "Atomic aggregate (invalid): %u %s", alen,
790                             (alen == 1) ? "byte" : "bytes");    
791                 }
792                 break;
793             case BGPTYPE_AGGREGATOR:
794                 if (alen != 6) {
795                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
796                             "Aggregator (invalid): %u %s", alen,
797                             (alen == 1) ? "byte" : "bytes");
798                 } else {
799                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
800                             "Aggregator AS: %u", pntohs(&p[i + aoff]));
801                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 4,
802                             "Aggregator origin: %s",
803                             ip_to_str(&p[i + aoff + 2]));
804                 }
805                 break;
806             case BGPTYPE_COMMUNITIES:
807                 if (alen % 4 != 0) {
808                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen, 
809                             "Communities (invalid): %u %s", alen,
810                             (alen == 1) ? "byte" : "bytes");
811                     free(communities_str);
812                     break;
813                 }
814
815                 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
816                         "Communities: %s", communities_str);
817                 communities_tree = proto_item_add_subtree(ti, 
818                         ett_bgp_communities);
819
820                 /* (p + i + 3) =
821                    (p + current attribute + 3 bytes to first tuple) */
822                 end = p + alen + i + 3;
823                 q = p + i + 3;
824
825                 /* snarf each community */
826                 while (q < end) {
827                     /* check for reserved values */
828                     if (pntohs(q) == FOURHEX0 || pntohs(q) == FOURHEXF) {
829                         /* check for well-known communities */
830                         if (pntohl(q) == BGP_COMM_NO_EXPORT)
831                             proto_tree_add_text(communities_tree, NullTVB, 
832                                    q - pd - 3 + aoff, 4, 
833                                    "Community: NO_EXPORT (0x%x)", pntohl(q));
834                         else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
835                             proto_tree_add_text(communities_tree, NullTVB, 
836                                    q - pd - 3 + aoff, 4, 
837                                    "Community: NO_ADVERTISE (0x%x)", pntohl(q));
838                         else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
839                             proto_tree_add_text(communities_tree, NullTVB, 
840                                     q - pd - 3 + aoff, 4, 
841                                     "Community: NO_EXPORT_SUBCONFED (0x%x)",
842                                     pntohl(q));
843                         else
844                             proto_tree_add_text(communities_tree, NullTVB, 
845                                     q - pd - 3 + aoff, 4, 
846                                     "Community (reserved): 0x%x", pntohl(q));
847                     }
848                     else {
849
850                         ti = proto_tree_add_text(communities_tree, NullTVB,
851                                 q - pd - 3 + aoff, 4, "Community: %u:%u", 
852                                 pntohs(q), pntohs(q + 2));
853                         community_tree = proto_item_add_subtree(ti, 
854                             ett_bgp_communities);
855                         proto_tree_add_text(community_tree, NullTVB, q - pd - 3 + aoff,
856                                 2, "Community AS: %u", pntohs(q));
857                         proto_tree_add_text(community_tree, NullTVB, q - pd - 1 + aoff, 
858                                 2, "Community value: %u", pntohs(q + 2));
859                     }
860
861                     q += 4;
862                 }
863
864                 free(communities_str);
865                 break;
866             case BGPTYPE_ORIGINATOR_ID:
867                 if (alen != 4) {
868                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
869                             "Originator identifier (invalid): %u %s", alen,
870                             (alen == 1) ? "byte" : "bytes");
871                 } else {
872                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
873                             "Originator identifier: %s",
874                             ip_to_str(&p[i + aoff]));
875                 }
876                 break;
877             case BGPTYPE_MP_REACH_NLRI:
878                 af = pntohs(&p[i + aoff]);
879                 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
880                     "Address family: %s (%u)",
881                     val_to_str(af, afnumber, "Unknown"), af);
882                 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 1,
883                     "Subsequent address family identifier: %s (%u)",
884                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
885                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
886                     p[i + aoff + 2]);
887                 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 3, 1,
888                         "Next hop network address (%d %s)",
889                         p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" : 
890                         "bytes");
891                 if (af == AFNUM_INET || af == AFNUM_INET6) {
892                     int j, advance;
893                     const char *s;
894
895                     subtree3 = proto_item_add_subtree(ti, 
896                             ett_bgp_mp_reach_nlri);
897
898                     j = 0;
899                     while (j < p[i + aoff + 3]) {
900                         if (af == AFNUM_INET)
901                             advance = 4;
902                         else if (af == AFNUM_INET6)
903                             advance = 16;
904                         else
905                             break;
906                         if (j + advance > p[i + aoff + 3])
907                             break;
908
909                         if (af == AFNUM_INET)
910                             s = ip_to_str(&p[i + aoff + 4 + j]);
911                         else {
912                             s = ip6_to_str((struct e_in6_addr *)
913                                 &p[i + aoff + 4 + j]);
914                         }
915                         proto_tree_add_text(subtree3, NullTVB,
916                             p - pd + i + aoff + 4 + j, advance,
917                             "Next hop: %s", s);
918                         j += advance;
919                     }
920                 }
921
922                 alen -= (p[i + aoff + 3] + 4);
923                 aoff += (p[i + aoff + 3] + 4);
924                 off = 0;
925                 snpa = p[i + aoff];
926                 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 1,
927                         "Subnetwork points of attachment: %u", snpa);
928                 off++;
929                 if (snpa)
930                     subtree3 = proto_item_add_subtree(ti, 
931                             ett_bgp_mp_reach_nlri);
932                 for (/*nothing*/; snpa > 0; snpa--) {
933                     proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff + off, 1,
934                         "SNPA length: %u", p[i + aoff + off]);
935                     off++;
936                     proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff + off,
937                         p[i + aoff + off - 1],
938                         "SNPA (%u %s)", p[i + aoff + off - 1],
939                         (p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
940                     off += p[i + aoff + off - 1];
941                 }
942
943                 alen -= off;
944                 aoff += off;
945                 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
946                         "Network layer reachability information (%u %s)",
947                         alen, (alen == 1) ? "byte" : "bytes");
948                 if (alen)
949                     subtree3 = proto_item_add_subtree(ti, 
950                             ett_bgp_mp_unreach_nlri);
951                 while (alen > 0) {
952                     int advance;
953                     char buf[256];
954
955                     if (af == AFNUM_INET) {
956                         advance = decode_prefix4(&p[i + aoff], buf,
957                             sizeof(buf));
958                     } else if (af == AFNUM_INET6) {
959                         advance = decode_prefix6(&p[i + aoff], buf,
960                             sizeof(buf));
961                     } else
962                         break;
963                     if (advance < 0)
964                         break;
965                     if (alen < advance)
966                         break;
967                     proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff, advance,
968                         "Network layer reachability information: %s", buf);
969
970                     alen -= advance;
971                     aoff += advance;
972                 }
973
974                 break;
975             case BGPTYPE_MP_UNREACH_NLRI:
976                 af = pntohs(&p[i + aoff]);      
977                 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
978                     "Address family: %s (%u)",
979                     val_to_str(af, afnumber, "Unknown"), af);
980                 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 1,
981                     "Subsequent address family identifier: %s (%u)",
982                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
983                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
984                     p[i + aoff + 2]);
985                 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 3,
986                         alen - 3, "Withdrawn routes (%u %s)", alen - 3,
987                         (alen - 3 == 1) ? "byte" : "bytes");
988
989                 alen -= 3;
990                 aoff += 3;
991                 if (alen > 0)
992                     subtree3 = proto_item_add_subtree(ti, 
993                             ett_bgp_mp_unreach_nlri);
994                 while (alen > 0) {
995                     int advance;
996                     char buf[256];
997
998                     if (af == AFNUM_INET) {
999                         advance = decode_prefix4(&p[i + aoff], buf,
1000                             sizeof(buf));
1001                     } else if (af == AFNUM_INET6) {
1002                         advance = decode_prefix6(&p[i + aoff], buf,
1003                             sizeof(buf));
1004                     } else
1005                         break;
1006                     if (advance < 0)
1007                         break;
1008                     if (alen < advance)
1009                         break;
1010                     proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff, advance,
1011                         "Withdrawn route: %s", buf);
1012
1013                     alen -= advance;
1014                     aoff += advance;
1015                 }
1016
1017                 break;
1018             case BGPTYPE_CLUSTER_LIST:
1019                 if (alen % 4 != 0) {
1020                     proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen, 
1021                             "Cluster list (invalid): %u %s", alen,
1022                             (alen == 1) ? "byte" : "bytes");
1023                     free(cluster_list_str);
1024                     break;
1025                 }
1026
1027                 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1028                         "Cluster list: %s", cluster_list_str);
1029                 cluster_list_tree = proto_item_add_subtree(ti, 
1030                         ett_bgp_cluster_list);
1031
1032                 /* (p + i + 3) =
1033                    (p + current attribute + 3 bytes to first tuple) */
1034                 end = p + alen + i + 3;
1035                 q = p + i + 3;
1036
1037                 /* snarf each cluster identifier */
1038                 while (q < end) {
1039                     ti = proto_tree_add_text(cluster_list_tree, NullTVB,
1040                             q - pd - 3 + aoff, 4, "Cluster identifier: %s", 
1041                             ip_to_str(q));
1042
1043                     q += 4;
1044                 }
1045
1046                 free(cluster_list_str);
1047                 break;
1048             default:
1049                 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1050                         "Unknown (%d %s)", alen, (alen == 1) ? "byte" : 
1051                         "bytes");
1052                 break;
1053             } /* end of second switch */
1054
1055             i += alen + aoff;
1056         }
1057         p += 2 + len;
1058
1059         /* NLRI */
1060         len = hlen - (p - &pd[offset]);
1061
1062         /* parse prefixes */
1063         if (len > 0) {
1064            ti = proto_tree_add_text(tree, NullTVB, p - pd, len,
1065                    "Network layer reachability information: %u %s", len,
1066                    (len == 1) ? "byte" : "bytes");
1067             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1068             end = p + len;
1069             while (p < end) {
1070                 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
1071                 proto_tree_add_text(subtree, NullTVB, p - pd, i, "%s", junk_buf);
1072                 p += i;
1073             }
1074         }
1075     }
1076 }
1077
1078 /*
1079  * Dissect a BGP NOTIFICATION message.
1080  */
1081 static void
1082 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
1083     proto_tree *tree)
1084 {
1085     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
1086     int                     hlen;   /* message length           */
1087     char                    *p;     /* string pointer           */
1088
1089     /* snarf message */
1090     memcpy(&bgpn, &pd[offset], sizeof(bgpn));
1091     hlen = ntohs(bgpn.bgpn_len);
1092
1093     /* print error code */
1094     proto_tree_add_text(tree, NullTVB,
1095         offset + offsetof(struct bgp_notification, bgpn_major), 1,
1096         "Error code: %s (%u)",
1097         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1098         bgpn.bgpn_major);
1099
1100     /* print error subcode */
1101     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1102      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1103         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1104             "Unknown");
1105     } else if (bgpn.bgpn_minor == 0)
1106         p = "Unspecified";
1107     else
1108         p = "Unknown";
1109     proto_tree_add_text(tree, NullTVB,
1110         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1111         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1112
1113     /* only print if there is optional data */
1114     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1115         proto_tree_add_text(tree, NullTVB, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1116             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1117     }
1118 }
1119
1120 /*
1121  * Dissect a BGP packet.
1122  */
1123 static void
1124 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1125 {
1126     proto_item    *ti;           /* tree item                        */
1127     proto_tree    *bgp_tree;     /* BGP packet tree                  */
1128     proto_tree    *bgp1_tree;    /* BGP message tree                 */
1129     const u_char  *p;            /* packet offset pointer            */
1130     int           l, i;          /* tmp                              */
1131     int           found;         /* number of BGP messages in packet */
1132     static u_char marker[] = {   /* BGP message marker               */
1133         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1134         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1135     };
1136     struct bgp    bgp;           /* BGP header                       */
1137     int           hlen;          /* BGP header length                */
1138     char          *typ;          /* BGP message type                 */
1139
1140     OLD_CHECK_DISPLAY_AS_DATA(proto_bgp, pd, offset, fd, tree);
1141
1142     if (check_col(fd, COL_PROTOCOL))
1143         col_add_str(fd, COL_PROTOCOL, "BGP");
1144
1145     p = &pd[offset];
1146     l = END_OF_FRAME;
1147     i = 0;
1148     found = -1;
1149     /* run through the TCP packet looking for BGP headers         */
1150     /* this is done twice, but this way each message type can be 
1151        printed in the COL_INFO field                              */
1152     while (i < l) {
1153         /* look for bgp header */
1154         if (p[i] != 0xff) {
1155             i++;
1156             continue;
1157         }
1158         CHECK_SIZE(i, sizeof(marker), l);
1159         if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1160             i++;
1161             continue;
1162         }
1163
1164         memcpy(&bgp, &p[i], sizeof(bgp));
1165         found++;
1166         hlen = ntohs(bgp.bgp_len);
1167         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1168
1169         if (check_col(fd, COL_INFO)) {
1170             if (found == 0) 
1171                 col_add_fstr(fd, COL_INFO, "%s", typ);
1172             else
1173                 col_append_fstr(fd, COL_INFO, ", %s", typ);
1174         }
1175
1176         i += hlen;
1177     }
1178
1179     if (tree) {
1180         ti = proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME,
1181                     "Border Gateway Protocol");
1182         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1183
1184         p = &pd[offset];
1185         l = END_OF_FRAME;
1186         i = 0;
1187         /* now, run through the TCP packet again, this time dissect */
1188         /* each message that we find */
1189         while (i < l) {
1190             /* look for bgp header */
1191             if (p[i] != 0xff) {
1192                 i++;
1193                 continue;
1194             }
1195             CHECK_SIZE(i, sizeof(marker), l);
1196             if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1197                 i++;
1198                 continue;
1199             }
1200
1201             memcpy(&bgp, &p[i], sizeof(bgp));
1202             hlen = ntohs(bgp.bgp_len);
1203             typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1204             if (END_OF_FRAME < hlen) {
1205                 ti = proto_tree_add_text(bgp_tree, NullTVB, offset + i, END_OF_FRAME,
1206                             "%s (truncated)", typ);
1207             } else {
1208                 ti = proto_tree_add_text(bgp_tree, NullTVB, offset + i, hlen,
1209                             "%s", typ);
1210             }
1211             /* add a different tree for each message type */
1212             switch (bgp.bgp_type) {
1213             case BGP_OPEN:
1214                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1215                 break;
1216             case BGP_UPDATE:
1217                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1218                 break;
1219             case BGP_NOTIFICATION:
1220                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1221                 break;
1222             case BGP_KEEPALIVE:
1223                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1224                 break;
1225             default:
1226                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1227                 break;
1228             }
1229
1230             proto_tree_add_text(bgp1_tree, NullTVB, offset + i, BGP_MARKER_SIZE,
1231                 "Marker: 16 bytes");
1232                             
1233             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1234                 proto_tree_add_text(bgp1_tree, NullTVB,
1235                     offset + i + offsetof(struct bgp, bgp_len), 2,
1236                     "Length (invalid): %u %s", hlen, 
1237                     (hlen == 1) ? "byte" : "bytes");
1238             } else {
1239                 proto_tree_add_text(bgp1_tree, NullTVB,
1240                     offset + i + offsetof(struct bgp, bgp_len), 2,
1241                     "Length: %u %s", hlen, 
1242                     (hlen == 1) ? "byte" : "bytes");
1243             }
1244
1245             proto_tree_add_text(bgp1_tree, NullTVB,
1246                 offset + i + offsetof(struct bgp, bgp_type), 1,
1247                 "Type: %s (%u)", typ, bgp.bgp_type);
1248
1249             CHECK_SIZE(i, hlen, l);
1250
1251             /* handle each message type */
1252             switch (bgp.bgp_type) {
1253             case BGP_OPEN:
1254                 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
1255                 break;
1256             case BGP_UPDATE:
1257                 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
1258                 break;
1259             case BGP_NOTIFICATION:
1260                 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
1261                 break;
1262             case BGP_KEEPALIVE:
1263                 /* no data in KEEPALIVE messages */
1264                 break;
1265             default:
1266                 break;
1267             }
1268
1269             i += hlen;
1270         }
1271     }
1272 }
1273
1274 /*
1275  * Register ourselves.
1276  */
1277 void
1278 proto_register_bgp(void)
1279 {
1280     static gint *ett[] = {
1281       &ett_bgp,
1282       &ett_bgp_unfeas,
1283       &ett_bgp_attrs,
1284       &ett_bgp_attr,
1285       &ett_bgp_attr_flags,
1286       &ett_bgp_mp_reach_nlri,
1287       &ett_bgp_mp_unreach_nlri,
1288       &ett_bgp_nlri,
1289       &ett_bgp_open,
1290       &ett_bgp_update,
1291       &ett_bgp_notification,
1292       &ett_bgp_as_paths,
1293       &ett_bgp_communities,
1294       &ett_bgp_cluster_list,
1295     };
1296
1297     proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
1298     proto_register_subtree_array(ett, array_length(ett));
1299 }
1300
1301 void
1302 proto_reg_handoff_bgp(void)
1303 {
1304     old_dissector_add("tcp.port", TCP_PORT_BGP, dissect_bgp);
1305 }