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