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