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