update RFC1966 (BGP route reflection) support.
[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
6  * 
7  * Supports:
8  * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9  * RFC1966 BGP Route Reflection An alternative to full mesh IBGP
10  * RFC1997 BGP Communities Attribute
11  * RFC2283 Multiprotocol Extensions for BGP-4
12  *
13  * TODO:
14  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing 
15  * RFC1965 Autonomous System Confederations for BGP 
16  * Destination Preference Attribute for BGP (work in progress)
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 NEED_SNPRINTF_H
53 # ifdef HAVE_STDARG_H
54 #  include <stdarg.h>
55 # else
56 #  include <varargs.h>
57 # endif
58 # include "snprintf.h"
59 #endif
60
61 #include <string.h>
62 #include <glib.h>
63 #include "packet.h"
64 #include "packet-bgp.h"
65 #include "packet-ipv6.h"
66
67 #ifdef HAVE_ARPA_INET_H
68 #include <arpa/inet.h>
69 #endif
70
71 static const value_string bgptypevals[] = {
72     { BGP_OPEN, "OPEN Message" },
73     { BGP_UPDATE, "UPDATE Message" },
74     { BGP_NOTIFICATION, "NOTIFICATION Message" },
75     { BGP_KEEPALIVE, "KEEPALIVE Message" },
76     { 0, NULL },
77 };
78
79 static const value_string bgpnotify_major[] = {
80     { 1, "Message Header Error" },
81     { 2, "OPEN Message Error" },
82     { 3, "UPDATE Message Error" },
83     { 4, "Hold Timer Expired" },
84     { 5, "Finite State Machine Error" },
85     { 6, "Cease" },
86     { 0, NULL },
87 };
88
89 static const value_string bgpnotify_minor_1[] = {
90     { 1, "Connection Not Synchronized" },
91     { 2, "Bad Message Length" },
92     { 3, "Bad Message Type" },
93     { 0, NULL },
94 };
95
96 static const value_string bgpnotify_minor_2[] = {
97     { 1, "Unsupported Version Number" },
98     { 2, "Bad Peer AS" },
99     { 3, "Bad BGP Identifier" },
100     { 4, "Unsupported Optional Parameter" },
101     { 5, "Authentication Failure" },
102     { 6, "Unacceptable Hold Time" },
103     { 0, NULL },
104 };
105
106 static const value_string bgpnotify_minor_3[] = {
107     { 1, "Malformed Attribute List" },
108     { 2, "Unrecognized Well-known Attribute" },
109     { 3, "Missing Well-known Attribute" },
110     { 4, "Attribute Flags Error" },
111     { 5, "Attribute Length Error" },
112     { 6, "Invalid ORIGIN Attribute" },
113     { 7, "AS Routing Loop" },
114     { 8, "Invalid NEXT_HOP Attribute" },
115     { 9, "Optional Attribute Error" },
116     { 10, "Invalid Network Field" },
117     { 11, "Malformed AS_PATH" },
118     { 0, NULL },
119 };
120
121 static const value_string *bgpnotify_minor[] = {
122     NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
123 };
124
125 static const value_string bgpattr_origin[] = {
126     { 0, "IGP" },
127     { 1, "EGP" },
128     { 2, "INCOMPLETE" },
129     { 0, NULL },
130 };
131
132 static const value_string as_segment_type[] = {
133     { 1, "AS_SET" },
134     { 2, "AS_SEQUENCE" },
135     { 3, "AS_CONFED_SET" },
136     { 4, "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,
271         offset + offsetof(struct bgp_open, bgpo_version), 1,
272         "Version: %u", bgpo.bgpo_version);
273     proto_tree_add_text(tree,
274         offset + offsetof(struct bgp_open, bgpo_myas), 2,
275         "My AS: %u", ntohs(bgpo.bgpo_myas));
276     proto_tree_add_text(tree,
277         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
278         "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
279     proto_tree_add_text(tree,
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,
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,
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, 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, 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, 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, p - pd, 2, "Total path attribute length: %u %s", 
359             len, (len == 1) ? "byte" : "bytes");
360
361     /* path attributes */
362 /* --- move --- */
363     if (len > 0) {
364         ti = proto_tree_add_text(tree, p - pd + 2, len, "Path attributes");
365         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
366         i = 2;
367         while (i < len) {
368             int alen, aoff;
369             char *msg;
370             guint16 af;
371             int off, snpa;
372
373             memcpy(&bgpa, &p[i], sizeof(bgpa));
374             /* check for the Extended Length bit */
375             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
376                 alen = pntohs(&p[i + sizeof(bgpa)]);
377                 aoff = sizeof(bgpa) + 2;
378             } else {
379                 alen = p[i + sizeof(bgpa)];
380                 aoff = sizeof(bgpa) + 1;
381             }
382             
383             /* This is kind of ugly - similar code appears twice, but it 
384                helps browsing attrs.                                      */
385             /* the first switch prints things in the title of the subtree */
386             switch (bgpa.bgpa_type) {
387             case BGPTYPE_ORIGIN:
388                 if (alen != 1)
389                     goto default_attribute_top;
390                 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
391                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
392                         "%s: %s (%u %s)",
393                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
394                         msg, alen + aoff, (alen + aoff == 1) ? "byte" : 
395                         "bytes");
396                 break;
397             case BGPTYPE_AS_PATH:
398                 /* (p + i + 3) =
399                    (p + current attribute + 3 bytes to first tuple) */ 
400                 end = p + alen + i + 3;
401                 q = p + i + 3;
402                 /* must be freed by second switch!                         */
403                 /* "alen * 6" (5 digits + space) should be a good estimate
404                    of how long the AS path string could be                 */
405                 as_path_str = malloc((alen + 1) * 6);
406                 if (as_path_str == NULL) break;
407                 as_path_str[0] = '\0';
408    
409                 /* snarf each AS path */
410                 while (q < end) {
411                     type = *q++;
412                     if (type == AS_SET) {
413                         snprintf(as_path_str, 2, "{");
414                     }
415                     length = *q++;
416
417                     /* ignore confederation types until we support them */
418                     if (type == AS_CONFED_SET || type == AS_CONFED_SEQUENCE) {
419                         q += length;
420                         break;
421                     }
422
423                     /* snarf each value in path */
424                     for (j = 0; j < length; j++) {
425                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q), 
426                                 (type == AS_SET) ? ", " : " ");
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 {
436                         as_path_str[strlen(as_path_str) - 1] = '\0';
437                     }
438                 }
439
440                 /* check for empty AS_PATH */
441                 if (alen == 0)
442                     strncpy(as_path_str, "empty", 6);
443
444                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
445                         "%s: %s (%u %s)",
446                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
447                         as_path_str, alen + aoff,
448                         (alen + aoff == 1) ? "byte" : "bytes");
449                 break;
450             case BGPTYPE_NEXT_HOP:
451                 if (alen != 4)
452                     goto default_attribute_top;
453                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
454                         "%s: %s (%u %s)",
455                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
456                         ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
457                         ? "byte" : "bytes");
458                 break;
459             case BGPTYPE_MULTI_EXIT_DISC:
460                 if (alen != 4)
461                     goto default_attribute_top;
462                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
463                         "%s: %u (%u %s)",
464                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
465                         pntohl(&p[i + aoff]), alen + aoff,
466                         (alen + aoff == 1) ? "byte" : "bytes");
467                 break;
468             case BGPTYPE_LOCAL_PREF:
469                 if (alen != 4)
470                     goto default_attribute_top;
471                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
472                         "%s: %u (%u %s)",
473                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
474                         pntohl(&p[i + aoff]), alen + aoff,
475                         (alen + aoff == 1) ? "byte" : "bytes");
476                 break;
477             case BGPTYPE_ATOMIC_AGGREGATE:
478                 if (alen != 0) 
479                     goto default_attribute_top;
480                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
481                         "%s (%u %s)",
482                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
483                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
484                 break;
485             case BGPTYPE_AGGREGATOR:
486                 if (alen != 6) 
487                     goto default_attribute_top;
488                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
489                         "%s: AS: %u origin: %s (%u %s)",
490                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
491                         pntohs(&p[i + aoff]),
492                         ip_to_str(&p[i + aoff + 2]), alen + aoff, 
493                         (alen + aoff == 1) ? "byte" : "bytes");
494                 break;
495             case BGPTYPE_COMMUNITIES:
496                 if (alen % 4 != 0)
497                     goto default_attribute_top;
498
499                 /* (p + i + 3) =
500                    (p + current attribute + 3 bytes to first tuple) */ 
501                 end = p + alen + i + 3;
502                 q = p + i + 3;
503                 /* must be freed by second switch!                          */
504                 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be 
505                    a good estimate of how long the communities string could 
506                    be                                                       */
507                 communities_str = malloc((alen + 1) * 12);
508                 if (communities_str == NULL) break;
509                 communities_str[0] = '\0';
510                 memset(junk_buf, 0, sizeof(junk_buf)); 
511
512                 /* snarf each community */
513                 while (q < end) {
514                     /* check for well-known communities */
515                     if (pntohl(q) == BGP_COMM_NO_EXPORT)
516                         strncpy(junk_buf, "NO_EXPORT ", 10);
517                     else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
518                         strncpy(junk_buf, "NO_ADVERTISE ", 13);
519                     else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
520                         strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
521                     else {
522                         snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
523                                 pntohs(q), 
524                                 pntohs(q + 2));
525                     }
526                     q += 4; 
527  
528                     strncat(communities_str, junk_buf, sizeof(junk_buf));
529                 }
530                 /* cleanup end of string */
531                 communities_str[strlen(communities_str) - 1] = '\0';
532
533                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
534                         "%s: %s (%u %s)",
535                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
536                         communities_str, alen + aoff,
537                         (alen + aoff == 1) ? "byte" : "bytes");
538                 break;
539             case BGPTYPE_ORIGINATOR_ID:
540                 if (alen != 4)
541                     goto default_attribute_top;
542                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
543                         "%s: %s (%u %s)",
544                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
545                         ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
546                         ? "byte" : "bytes");
547                 break;
548             case BGPTYPE_CLUSTER_LIST:
549                 if (alen % 4 != 0)
550                     goto default_attribute_top;
551
552                 /* (p + i + 3) =
553                    (p + current attribute + 3 bytes to first tuple) */ 
554                 end = p + alen + i + 3;
555                 q = p + i + 3;
556                 /* must be freed by second switch!                          */
557                 /* "alen * 16" (12 digits, 3 dots + space ) should be 
558                    a good estimate of how long the cluster_list string could 
559                    be                                                       */
560                 cluster_list_str = malloc((alen + 1) * 16);
561                 if (cluster_list_str == NULL) break;
562                 cluster_list_str[0] = '\0';
563                 memset(junk_buf, 0, sizeof(junk_buf)); 
564
565                 /* snarf each cluster list */
566                 while (q < end) {
567                     snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(q));
568                     strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
569                     q += 4; 
570                 }
571                 /* cleanup end of string */
572                 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
573
574                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
575                         "%s: %s (%u %s)",
576                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
577                         cluster_list_str, alen + aoff,
578                         (alen + aoff == 1) ? "byte" : "bytes");
579                 break;
580             default:
581             default_attribute_top:
582                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
583                         "%s (%u %s)",
584                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
585                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
586             } /* end of first switch */
587             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
588
589             /* figure out flags */
590             junk_buf[0] = '\0';
591             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
592                  strncat(junk_buf, "Optional, ", 10);
593             }
594             else {
595                  strncat(junk_buf, "Well-known, ", 12);
596             }
597             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
598                  strncat(junk_buf, "Transitive, ", 12);
599             }
600             else {
601                  strncat(junk_buf, "Non-transitive, ", 16);
602             }
603             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
604                  strncat(junk_buf, "Partial, ", 9);
605             }
606             else {
607                  strncat(junk_buf, "Complete, ", 10);
608             }
609             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
610                  strncat(junk_buf, "Extended Length, ", 17);
611             }
612             /* stomp last ", " */
613             j = strlen(junk_buf);
614             junk_buf[j - 2] = '\0';
615             ti = proto_tree_add_text(subtree2,
616                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
617                     "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
618             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
619
620             /* add flag bitfield subtrees */
621             proto_tree_add_text(subtree3,
622                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
623                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
624                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
625             proto_tree_add_text(subtree3,
626                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
627                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
628                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive", 
629                         "Non-transitive"));
630             proto_tree_add_text(subtree3,
631                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
632                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
633                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
634             proto_tree_add_text(subtree3,
635                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
636                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
637                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length", 
638                         "Regular length"));
639
640             proto_tree_add_text(subtree2,
641                     p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
642                     "Type code: %s (%u)",
643                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
644                     bgpa.bgpa_type);
645             
646             proto_tree_add_text(subtree2, p - pd + i + sizeof(bgpa), 
647                     aoff - sizeof(bgpa), "Length: %d %s", alen, 
648                     (alen == 1) ? "byte" : "bytes");
649
650             /* the second switch prints things in the actual subtree of each 
651                attribute                                                     */ 
652             switch (bgpa.bgpa_type) {
653             case BGPTYPE_ORIGIN:
654                 if (alen != 1) {
655                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
656                             "Origin (invalid): %u %s", alen,
657                              (alen == 1) ? "byte" : "bytes");
658                 } else {
659                     msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
660                     proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
661                             "Origin: %s (%u)", msg, p[i + aoff]);
662                 }
663                 break;
664             case BGPTYPE_AS_PATH:
665                 /* check for empty AS_PATH */
666                 if (alen == 0) {
667                     free(as_path_str);
668                     break;
669                 }
670
671                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
672                         "AS path: %s", as_path_str);
673                 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
674
675                 /* (p + i + 3) =
676                    (p + current attribute + 3 bytes to first tuple) */ 
677                 end = p + alen + i + 3;
678                 q = p + i + 3;
679    
680                 /* snarf each AS path tuple */
681                 while (q < end) {
682                     as_path_str[0] = '\0';
683                     type = *q++;
684                     if (type == AS_SET) {
685                         snprintf(as_path_str, 2, "{");
686                     }
687                     length = *q++;
688
689                     /* ignore confederation types until we support them */
690                     if (type == AS_CONFED_SET || type == AS_CONFED_SEQUENCE) {
691                         q += length;
692                         break;
693                     }
694
695                     /* snarf each value in path, we're just going to reuse 
696                        as_path_str since we already have it malloced       */
697                     for (j = 0; j < length; j++) {
698                         snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
699                                 (type == AS_SET) ? ", " : " ");
700                         strncat(as_path_str, junk_buf, sizeof(junk_buf));
701                         q += 2;
702                     }
703
704                     /* cleanup end of string */
705                     if (type == AS_SET) {
706                         as_path_str[strlen(as_path_str) - 2] = '}';
707                     }
708                     else {
709                         as_path_str[strlen(as_path_str) - 1] = '\0';
710                     }
711
712                     /* length here means number of ASs, ie length * 2 bytes */
713                     ti = proto_tree_add_text(as_paths_tree, 
714                             q - pd - length * 2 - 2,
715                             length * 2 + 2, "AS path segment: %s", as_path_str);
716                     as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
717                     proto_tree_add_text(as_path_tree, q - pd - length * 2 - 2,
718                             1, "Path segment type: %s (%u)",
719                             val_to_str(type, as_segment_type, "Unknown"), type);
720                     proto_tree_add_text(as_path_tree, q - pd - length * 2 - 1, 
721                             1, "Path segment length: %u %s", length,
722                             (length == 1) ? "AS" : "ASs");
723                     proto_tree_add_text(as_path_tree, q - pd - length * 2, 
724                             length * 2, "Path segment value: %s", as_path_str);
725                 }
726
727                 free(as_path_str);
728                 break;
729             case BGPTYPE_NEXT_HOP:
730                 if (alen != 4) {
731                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
732                             "Next hop (invalid): %u %s", alen,
733                             (alen == 1) ? "byte" : "bytes");
734                 } else {
735                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
736                             "Next hop: %s", ip_to_str(&p[i + aoff]));
737                 }
738                 break;
739             case BGPTYPE_MULTI_EXIT_DISC:
740                 if (alen != 4) {
741                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
742                             "Multiple exit discriminator (invalid): %u %s",
743                             alen, (alen == 1) ? "byte" : "bytes");
744                 } else {
745                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
746                             "Multiple exit discriminator: %u",
747                             pntohl(&p[i + aoff]));
748                 }
749                 break;
750             case BGPTYPE_LOCAL_PREF:
751                 if (alen != 4) {
752                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
753                             "Local preference (invalid): %u %s", alen,
754                              (alen == 1) ? "byte" : "bytes");
755                 } else {
756                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
757                             "Local preference: %u", pntohl(&p[i + aoff]));
758                 }
759                 break;
760             case BGPTYPE_ATOMIC_AGGREGATE:
761                 if (alen != 0) {
762                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
763                             "Atomic aggregate (invalid): %u %s", alen,
764                             (alen == 1) ? "byte" : "bytes");    
765                 }
766                 break;
767             case BGPTYPE_AGGREGATOR:
768                 if (alen != 6) {
769                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
770                             "Aggregator (invalid): %u %s", alen,
771                             (alen == 1) ? "byte" : "bytes");
772                 } else {
773                     proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
774                             "Aggregator AS: %u", pntohs(&p[i + aoff]));
775                     proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 4,
776                             "Aggregator origin: %s",
777                             ip_to_str(&p[i + aoff + 2]));
778                 }
779                 break;
780             case BGPTYPE_COMMUNITIES:
781                 if (alen % 4 != 0) {
782                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen, 
783                             "Communities (invalid): %u %s", alen,
784                             (alen == 1) ? "byte" : "bytes");
785                     free(communities_str);
786                     break;
787                 }
788
789                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
790                         "Communities: %s", communities_str);
791                 communities_tree = proto_item_add_subtree(ti, 
792                         ett_bgp_communities);
793
794                 /* (p + i + 3) =
795                    (p + current attribute + 3 bytes to first tuple) */
796                 end = p + alen + i + 3;
797                 q = p + i + 3;
798
799                 /* snarf each community */
800                 while (q < end) {
801                     /* check for reserved values */
802                     if (pntohs(q) == FOURHEX0 || pntohs(q) == FOURHEXF) {
803                         /* check for well-known communities */
804                         if (pntohl(q) == BGP_COMM_NO_EXPORT)
805                             proto_tree_add_text(communities_tree, 
806                                    q - pd - 3 + aoff, 4, 
807                                    "Community: NO_EXPORT (0x%x)", pntohl(q));
808                         else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
809                             proto_tree_add_text(communities_tree, 
810                                    q - pd - 3 + aoff, 4, 
811                                    "Community: NO_ADVERTISE (0x%x)", pntohl(q));
812                         else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
813                             proto_tree_add_text(communities_tree, 
814                                     q - pd - 3 + aoff, 4, 
815                                     "Community: NO_EXPORT_SUBCONFED (0x%x)",
816                                     pntohl(q));
817                         else
818                             proto_tree_add_text(communities_tree, 
819                                     q - pd - 3 + aoff, 4, 
820                                     "Community (reserved): 0x%x", pntohl(q));
821                     }
822                     else {
823
824                         ti = proto_tree_add_text(communities_tree,
825                                 q - pd - 3 + aoff, 4, "Community: %u:%u", 
826                                 pntohs(q), pntohs(q + 2));
827                         community_tree = proto_item_add_subtree(ti, 
828                             ett_bgp_communities);
829                         proto_tree_add_text(community_tree, q - pd - 3 + aoff,
830                                 2, "Community AS: %u", pntohs(q));
831                         proto_tree_add_text(community_tree, q - pd - 1 + aoff, 
832                                 2, "Community value: %u", pntohs(q + 2));
833                     }
834
835                     q += 4;
836                 }
837
838                 free(communities_str);
839                 break;
840             case BGPTYPE_ORIGINATOR_ID:
841                 if (alen != 4) {
842                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
843                             "Originator identifier (invalid): %u %s", alen,
844                             (alen == 1) ? "byte" : "bytes");
845                 } else {
846                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
847                             "Originator identifier: %s",
848                             ip_to_str(&p[i + aoff]));
849                 }
850                 break;
851             case BGPTYPE_MP_REACH_NLRI:
852                 af = pntohs(&p[i + aoff]);
853                 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
854                     "Address family: %s (%u)",
855                     val_to_str(af, afnumber, "Unknown"), af);
856                 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
857                     "Subsequent address family identifier: %s (%u)",
858                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
859                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
860                     p[i + aoff + 2]);
861                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3, 1,
862                         "Next hop network address (%d %s)",
863                         p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" : 
864                         "bytes");
865                 if (af == AFNUM_INET || af == AFNUM_INET6) {
866                     int j, advance;
867                     const char *s;
868
869                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
870
871                     j = 0;
872                     while (j < p[i + aoff + 3]) {
873                         if (af == AFNUM_INET)
874                             advance = 4;
875                         else if (af == AFNUM_INET6)
876                             advance = 16;
877                         else
878                             break;
879                         if (j + advance > p[i + aoff + 3])
880                             break;
881
882                         if (af == AFNUM_INET)
883                             s = ip_to_str(&p[i + aoff + 4 + j]);
884                         else {
885                             s = ip6_to_str((struct e_in6_addr *)
886                                 &p[i + aoff + 4 + j]);
887                         }
888                         proto_tree_add_text(subtree3,
889                             p - pd + i + aoff + 4 + j, advance,
890                             "Next hop: %s", s);
891                         j += advance;
892                     }
893                 }
894
895                 alen -= (p[i + aoff + 3] + 4);
896                 aoff += (p[i + aoff + 3] + 4);
897                 off = 0;
898                 snpa = p[i + aoff];
899                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
900                         "Subnetwork points of attachment: %u", snpa);
901                 off++;
902                 if (snpa)
903                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
904                 for (/*nothing*/; snpa > 0; snpa--) {
905                     proto_tree_add_text(subtree3, p - pd + i + aoff + off, 1,
906                         "SNPA length: %u", p[i + aoff + off]);
907                     off++;
908                     proto_tree_add_text(subtree3, p - pd + i + aoff + off,
909                         p[i + aoff + off - 1],
910                         "SNPA (%u %s)", p[i + aoff + off - 1],
911                         (p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
912                     off += p[i + aoff + off - 1];
913                 }
914
915                 alen -= off;
916                 aoff += off;
917                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
918                         "Network layer reachability information (%u %s)",
919                         alen, (alen == 1) ? "byte" : "bytes");
920                 if (alen)
921                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
922                 while (alen > 0) {
923                     int advance;
924                     char buf[256];
925
926                     if (af == AFNUM_INET) {
927                         advance = decode_prefix4(&p[i + aoff], buf,
928                             sizeof(buf));
929                     } else if (af == AFNUM_INET6) {
930                         advance = decode_prefix6(&p[i + aoff], buf,
931                             sizeof(buf));
932                     } else
933                         break;
934                     if (advance < 0)
935                         break;
936                     if (alen < advance)
937                         break;
938                     proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
939                         "Network layer reachability information: %s", buf);
940
941                     alen -= advance;
942                     aoff += advance;
943                 }
944
945                 break;
946             case BGPTYPE_MP_UNREACH_NLRI:
947                 af = pntohs(&p[i + aoff]);      
948                 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
949                     "Address family: %s (%u)",
950                     val_to_str(af, afnumber, "Unknown"), af);
951                 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
952                     "Subsequent address family identifier: %s (%u)",
953                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
954                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
955                     p[i + aoff + 2]);
956                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3,
957                         alen - 3, "Withdrawn routes (%u %s)", alen - 3,
958                         (alen - 3 == 1) ? "byte" : "bytes");
959
960                 alen -= 3;
961                 aoff += 3;
962                 if (alen > 0)
963                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
964                 while (alen > 0) {
965                     int advance;
966                     char buf[256];
967
968                     if (af == AFNUM_INET) {
969                         advance = decode_prefix4(&p[i + aoff], buf,
970                             sizeof(buf));
971                     } else if (af == AFNUM_INET6) {
972                         advance = decode_prefix6(&p[i + aoff], buf,
973                             sizeof(buf));
974                     } else
975                         break;
976                     if (advance < 0)
977                         break;
978                     if (alen < advance)
979                         break;
980                     proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
981                         "Withdrawn route: %s", buf);
982
983                     alen -= advance;
984                     aoff += advance;
985                 }
986
987                 break;
988             case BGPTYPE_CLUSTER_LIST:
989                 if (alen % 4 != 0) {
990                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen, 
991                             "Cluster list (invalid): %u %s", alen,
992                             (alen == 1) ? "byte" : "bytes");
993                     free(cluster_list_str);
994                     break;
995                 }
996
997                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
998                         "Cluster list: %s", cluster_list_str);
999                 cluster_list_tree = proto_item_add_subtree(ti, 
1000                         ett_bgp_cluster_list);
1001
1002                 /* (p + i + 3) =
1003                    (p + current attribute + 3 bytes to first tuple) */
1004                 end = p + alen + i + 3;
1005                 q = p + i + 3;
1006
1007                 /* snarf each cluster identifier */
1008                 while (q < end) {
1009                     ti = proto_tree_add_text(cluster_list_tree,
1010                             q - pd - 3 + aoff, 4, "Cluster identifier: %s", 
1011                             ip_to_str(q));
1012
1013                     q += 4;
1014                 }
1015
1016                 free(cluster_list_str);
1017                 break;
1018             default:
1019                 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
1020                         "Unknown (%d %s)", alen, (alen == 1) ? "byte" : 
1021                         "bytes");
1022                 break;
1023             } /* end of second switch */
1024
1025             i += alen + aoff;
1026         }
1027 /* --- move --- */
1028         p += 2 + len;
1029
1030         /* NLRI */
1031         len = hlen - (p - &pd[offset]);
1032
1033         /* parse prefixes */
1034         if (len > 0) {
1035            ti = proto_tree_add_text(tree, p - pd, len,
1036                    "Network layer reachability information: %u %s", len,
1037                    (len == 1) ? "byte" : "bytes");
1038             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1039             end = p + len;
1040             while (p < end) {
1041                 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
1042                 proto_tree_add_text(subtree, p - pd, i, "%s", junk_buf);
1043                 p += i;
1044             }
1045         }
1046     }
1047 }
1048
1049 /*
1050  * Dissect a BGP NOTIFICATION message.
1051  */
1052 static void
1053 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
1054     proto_tree *tree)
1055 {
1056     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
1057     int                     hlen;   /* message length           */
1058     char                    *p;     /* string pointer           */
1059
1060     /* snarf message */
1061     memcpy(&bgpn, &pd[offset], sizeof(bgpn));
1062     hlen = ntohs(bgpn.bgpn_len);
1063
1064     /* print error code */
1065     proto_tree_add_text(tree,
1066         offset + offsetof(struct bgp_notification, bgpn_major), 1,
1067         "Error code: %s (%u)",
1068         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1069         bgpn.bgpn_major);
1070
1071     /* print error subcode */
1072     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1073      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1074         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1075             "Unknown");
1076     } else if (bgpn.bgpn_minor == 0)
1077         p = "Unspecified";
1078     else
1079         p = "Unknown";
1080     proto_tree_add_text(tree,
1081         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1082         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1083
1084     /* only print if there is optional data */
1085     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1086         proto_tree_add_text(tree, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1087             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1088     }
1089 }
1090
1091 /*
1092  * Dissect a BGP packet.
1093  */
1094 void
1095 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1096 {
1097     proto_item    *ti;           /* tree item                        */
1098     proto_tree    *bgp_tree;     /* BGP packet tree                  */
1099     proto_tree    *bgp1_tree;    /* BGP message tree                 */
1100     const u_char  *p;            /* packet offset pointer            */
1101     int           l, i;          /* tmp                              */
1102     int           found;         /* number of BGP messages in packet */
1103     static u_char marker[] = {   /* BGP message marker               */
1104         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1105         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1106     };
1107     struct bgp    bgp;           /* BGP header                       */
1108     int           hlen;          /* BGP header length                */
1109     char          *typ;          /* BGP message type                 */
1110
1111     if (check_col(fd, COL_PROTOCOL))
1112         col_add_str(fd, COL_PROTOCOL, "BGP");
1113
1114     p = &pd[offset];
1115     l = END_OF_FRAME;
1116     i = 0;
1117     found = -1;
1118     /* run through the TCP packet looking for BGP headers         */
1119     /* this is done twice, but this way each message type can be 
1120        printed in the COL_INFO field                              */
1121     while (i < l) {
1122         /* look for bgp header */
1123         if (p[i] != 0xff) {
1124             i++;
1125             continue;
1126         }
1127         CHECK_SIZE(i, sizeof(marker), l);
1128         if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1129             i++;
1130             continue;
1131         }
1132
1133         memcpy(&bgp, &p[i], sizeof(bgp));
1134         found++;
1135         hlen = ntohs(bgp.bgp_len);
1136         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1137
1138         if (check_col(fd, COL_INFO)) {
1139             if (found == 0) 
1140                 col_add_fstr(fd, COL_INFO, "%s", typ);
1141             else
1142                 col_append_fstr(fd, COL_INFO, ", %s", typ);
1143         }
1144
1145         i += hlen;
1146     }
1147
1148     if (tree) {
1149         ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
1150                     "Border Gateway Protocol");
1151         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1152
1153         p = &pd[offset];
1154         l = END_OF_FRAME;
1155         i = 0;
1156         /* now, run through the TCP packet again, this time dissect */
1157         /* each message that we find */
1158         while (i < l) {
1159             /* look for bgp header */
1160             if (p[i] != 0xff) {
1161                 i++;
1162                 continue;
1163             }
1164             CHECK_SIZE(i, sizeof(marker), l);
1165             if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1166                 i++;
1167                 continue;
1168             }
1169
1170             memcpy(&bgp, &p[i], sizeof(bgp));
1171             hlen = ntohs(bgp.bgp_len);
1172             typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1173             if (END_OF_FRAME < hlen) {
1174                 ti = proto_tree_add_text(bgp_tree, offset + i, END_OF_FRAME,
1175                             "%s (truncated)", typ);
1176             } else {
1177                 ti = proto_tree_add_text(bgp_tree, offset + i, hlen,
1178                             "%s", typ);
1179             }
1180             /* add a different tree for each message type */
1181             switch (bgp.bgp_type) {
1182             case BGP_OPEN:
1183                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1184                 break;
1185             case BGP_UPDATE:
1186                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1187                 break;
1188             case BGP_NOTIFICATION:
1189                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1190                 break;
1191             case BGP_KEEPALIVE:
1192                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1193                 break;
1194             default:
1195                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1196                 break;
1197             }
1198
1199             proto_tree_add_text(bgp1_tree, offset + i, BGP_MARKER_SIZE,
1200                 "Marker: 16 bytes");
1201                             
1202             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1203                 proto_tree_add_text(bgp1_tree,
1204                     offset + i + offsetof(struct bgp, bgp_len), 2,
1205                     "Length (invalid): %u %s", hlen, 
1206                     (hlen == 1) ? "byte" : "bytes");
1207             } else {
1208                 proto_tree_add_text(bgp1_tree,
1209                     offset + i + offsetof(struct bgp, bgp_len), 2,
1210                     "Length: %u %s", hlen, 
1211                     (hlen == 1) ? "byte" : "bytes");
1212             }
1213
1214             proto_tree_add_text(bgp1_tree,
1215                 offset + i + offsetof(struct bgp, bgp_type), 1,
1216                 "Type: %s (%u)", typ, bgp.bgp_type);
1217
1218             CHECK_SIZE(i, hlen, l);
1219
1220             /* handle each message type */
1221             switch (bgp.bgp_type) {
1222             case BGP_OPEN:
1223                 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
1224                 break;
1225             case BGP_UPDATE:
1226                 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
1227                 break;
1228             case BGP_NOTIFICATION:
1229                 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
1230                 break;
1231             case BGP_KEEPALIVE:
1232                 /* no data in KEEPALIVE messages */
1233                 break;
1234             default:
1235                 break;
1236             }
1237
1238             i += hlen;
1239         }
1240     }
1241 }
1242
1243 /*
1244  * Register ourselves.
1245  */
1246 void
1247 proto_register_bgp(void)
1248 {
1249     static gint *ett[] = {
1250       &ett_bgp,
1251       &ett_bgp_unfeas,
1252       &ett_bgp_attrs,
1253       &ett_bgp_attr,
1254       &ett_bgp_attr_flags,
1255       &ett_bgp_mp_reach_nlri,
1256       &ett_bgp_mp_unreach_nlri,
1257       &ett_bgp_nlri,
1258       &ett_bgp_open,
1259       &ett_bgp_update,
1260       &ett_bgp_notification,
1261       &ett_bgp_as_paths,
1262       &ett_bgp_communities,
1263       &ett_bgp_cluster_list,
1264     };
1265
1266     proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
1267     proto_register_subtree_array(ett, array_length(ett));
1268 }