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