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