Zero-length arrays are a GCC extension, and some compilers don't support
[metze/wireshark/wip.git] / packet-bgp.c
1 /* packet-bgp.c
2  * Routines for BGP packet dissection.
3  * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
4  *
5  * $Id: packet-bgp.c,v 1.10 1999/11/16 11:42:26 guy Exp $
6  * 
7  * Supports:
8  * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9  * RFC2283 Multiprotocol Extensions for BGP-4
10  *
11  * TODO:
12  * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing 
13  * RFC1965 Autonomous System Confederations for BGP 
14  * RFC1997 BGP Communities Attribute
15  * RFC1998 An Application of the BGP Community Attribute in Multi-home Routing 
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_flags[] = {
123     { 0x80, "Optional" },
124     { 0x40, "Transitive" },
125     { 0x20, "Partial" },
126     { 0x10, "Extended length" },
127     { 0, NULL },
128 };
129
130 static const value_string bgpattr_origin[] = {
131     { 0, "IGP" },
132     { 1, "EGP" },
133     { 2, "INCOMPLETE" },
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_MP_REACH_NLRI, "MP_REACH_NLRI" },
146     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
147     { 0, NULL },
148 };
149
150 /* Subsequent address family identifier, RFC2283 section 7 */
151 static const value_string bgpattr_nlri_safi[] = {
152     { 0, "Reserved" },
153     { 1, "Unicast" },
154     { 2, "Multicast" },
155     { 3, "Unicast+Multicast" },
156     { 0, NULL },
157 };
158
159 static const value_string afnumber[] = {
160     { 0, "Reserved" },
161     { AFNUM_INET, "IPv4" },
162     { AFNUM_INET6, "IPv6" },
163     { AFNUM_NSAP, "NSAP" },
164     { AFNUM_HDLC, "HDLC" },
165     { AFNUM_BBN1822, "BBN 1822" },
166     { AFNUM_802, "802" },
167     { AFNUM_E163, "E.163" },
168     { AFNUM_E164, "E.164" },
169     { AFNUM_F69, "F.69" },
170     { AFNUM_X121, "X.121" },
171     { AFNUM_IPX, "IPX" },
172     { AFNUM_ATALK, "Appletalk" },
173     { AFNUM_DECNET, "Decnet IV" },
174     { AFNUM_BANYAN, "Banyan Vines" },
175     { AFNUM_E164NSAP, "E.164 with NSAP subaddress" },
176     { 65535, "Reserved" },
177     { 0, NULL },
178 };
179
180 static int proto_bgp = -1;
181
182 static gint ett_bgp = -1;
183 static gint ett_bgp_unfeas = -1;
184 static gint ett_bgp_attrs = -1;
185 static gint ett_bgp_attr = -1;
186 static gint ett_bgp_attr_flags = -1;
187 static gint ett_bgp_mp_reach_nlri = -1;
188 static gint ett_bgp_mp_unreach_nlri = -1;
189 static gint ett_bgp_nlri = -1;
190 static gint ett_bgp_open = -1;
191 static gint ett_bgp_update = -1;
192 static gint ett_bgp_notification = -1;
193
194 /*
195  * Decode an IPv4 prefix.
196  */
197 static int
198 decode_prefix4(const u_char *pd, char *buf, int buflen)
199 {
200     guint8 addr[4];
201     int plen;
202
203     plen = pd[0];
204     if (plen < 0 || 32 < plen)
205         return -1;
206
207     memset(addr, 0, sizeof(addr));
208     memcpy(addr, &pd[1], (plen + 7) / 8);
209     if (plen % 8)
210         addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
211     snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
212     return 1 + (plen + 7) / 8;
213 }
214
215 /*
216  * Decode an IPv6 prefix.
217  */
218 static int
219 decode_prefix6(const u_char *pd, char *buf, int buflen)
220 {
221     struct e_in6_addr addr;
222     int plen;
223
224     plen = pd[0];
225     if (plen < 0 || 128 < plen)
226         return -1;
227
228     memset(&addr, 0, sizeof(addr));
229     memcpy(&addr, &pd[1], (plen + 7) / 8);
230     if (plen % 8)
231         addr.s6_addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
232     snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
233     return 1 + (plen + 7) / 8;
234 }
235
236 /*
237  * Dissect a BGP OPEN message.
238  */
239 static void
240 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
241 {
242     struct bgp_open bgpo;   /* BGP OPEN message   */
243     int hlen;               /* message length     */
244
245     /* snarf OPEN message */
246     memcpy(&bgpo, &pd[offset], sizeof(bgpo));
247     hlen = ntohs(bgpo.bgpo_len);
248
249     proto_tree_add_text(tree,
250         offset + offsetof(struct bgp_open, bgpo_version), 1,
251         "Version: %u", bgpo.bgpo_version);
252     proto_tree_add_text(tree,
253         offset + offsetof(struct bgp_open, bgpo_myas), 2,
254         "My AS: %u", ntohs(bgpo.bgpo_myas));
255     proto_tree_add_text(tree,
256         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
257         "Hold Time: %u", ntohs(bgpo.bgpo_holdtime));
258     proto_tree_add_text(tree,
259         offset + offsetof(struct bgp_open, bgpo_id), 4,
260         "BGP Identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
261     proto_tree_add_text(tree,
262         offset + offsetof(struct bgp_open, bgpo_optlen), 1,
263         "Optional Parameters Length: %u %s", bgpo.bgpo_optlen,
264         (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
265
266     if (hlen > sizeof(struct bgp_open)) {
267         proto_tree_add_text(tree,
268             offset + sizeof(struct bgp_open), hlen - sizeof(struct bgp_open),
269             "Optional Parameters");
270     }
271 }
272
273 /*
274  * Dissect a BGP UPDATE message.
275  */
276 static void
277 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
278     proto_tree *tree)
279 {
280     struct bgp      bgp;
281     struct bgp_attr bgpa;
282     int             hlen;
283     const u_char    *p;
284     const u_char    *q;
285     const u_char    *end;
286     int             len;
287     proto_item      *ti;
288     proto_tree      *subtree;     
289     proto_tree      *subtree2; 
290     proto_tree      *subtree3;
291     int             i;
292     int             j;
293     guint8          length;
294     guint8          type;
295     struct in_addr  prefix;
296     char            *as_path_str = NULL;
297     char junk_buf[10];
298
299     /* snarf UPDATE message */
300     memcpy(&bgp, &pd[offset], sizeof(bgp));
301     hlen = ntohs(bgp.bgp_len);
302     p = &pd[offset + BGP_HEADER_SIZE];  /*XXX*/
303
304     /* check for withdrawals */
305     len = ntohs(*(guint16 *)p);
306     proto_tree_add_text(tree, p - pd, 2, 
307         "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
308     if (len > 0) {
309         ti = proto_tree_add_text(tree, p - pd, len, "Withdrawn routes:");
310         /* TODO: unfeasible */
311         subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
312     }
313     p += 2 + len;
314
315     /* check for advertisements */
316     len = ntohs(*(guint16 *)p);
317     proto_tree_add_text(tree, p - pd, 2, "Total path attribute length: %u %s", 
318             len, (len == 1) ? "byte" : "bytes");
319
320     /* path attributes */
321 /* --- move --- */
322     if (len > 0) {
323         ti = proto_tree_add_text(tree, p - pd + 2, len, "Path attributes");
324         subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
325         i = 2;
326         while (i < len) {
327             int alen, aoff;
328             char *msg;
329             guint16 af;
330             int off, snpa;
331
332             memcpy(&bgpa, &p[i], sizeof(bgpa));
333             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
334                 alen = ntohs(*(guint16 *)&p[i + sizeof(bgpa)]);
335                 aoff = sizeof(bgpa) + 2;
336             } else {
337                 alen = p[i + sizeof(bgpa)];
338                 aoff = sizeof(bgpa) + 1;
339             }
340             
341             /*
342              * This is kind of ugly - similar code appears twice,
343              * but it helps browsing attrs.
344              */
345             switch (bgpa.bgpa_type) {
346             case BGPTYPE_ORIGIN:
347                 if (alen != 1)
348                     goto default_attribute_top;
349                 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
350                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
351                         "%s: %s (%u %s)",
352                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
353                         msg, alen + aoff, (alen + aoff == 1) ? "byte" : 
354                         "bytes");
355                 break;
356             case BGPTYPE_AS_PATH:
357                 /* (p + i + 3) =
358                    (p + current attribute + 3 bytes to first tuple) */ 
359                 end = p + alen + i + 3;
360                 q = p + i + 3;
361                 /* must be freed by second case                           */
362                 /* "alen * 6" (5 digits + space) should be a good estimate
363                    of how long the AS path string could be                 */
364                 as_path_str = malloc(alen * 6);
365                 memset(as_path_str, '\0', alen * 6);
366                 if (as_path_str == NULL) break;
367    
368                 /* snarf each AS path */
369                 while (q < end) {
370                     type = *q++;
371                     if (type == AS_SET) {
372                         sprintf(as_path_str, "{");
373                     }
374                     length = *q++;
375
376                     /* snarf each value in path */
377                     for (j = 0; j < length; j++) {
378                         sprintf(junk_buf, "%u%c", pntohs(q), 
379                                 (type == AS_SET) ? ',' : ' ');
380                         strcat(as_path_str, junk_buf);
381                         q += 2;
382                     }
383                    
384                     /* cleanup end of string */
385                     if (type == AS_SET) {
386                         as_path_str[strlen(as_path_str) - 1] = '}';
387                         as_path_str[strlen(as_path_str) + 1] = '\0';
388                     }
389                     else {
390                         as_path_str[strlen(as_path_str) - 1] = '\0';
391                     }
392                 }
393
394                 if (as_path_str[0] == '\0')
395                     goto default_attribute_top;
396                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
397                         "%s: %s (%u %s)",
398                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
399                         as_path_str, alen + aoff, (alen + aoff == 1) ? "byte" :
400                         "bytes");
401                 break;
402             case BGPTYPE_NEXT_HOP:
403                 if (alen != 4)
404                     goto default_attribute_top;
405                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
406                         "%s: %s (%u %s)",
407                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
408                         ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
409                         ? "byte" : "bytes");
410                 break;
411             case BGPTYPE_MULTI_EXIT_DISC:
412                 if (alen != 4)
413                     goto default_attribute_top;
414                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
415                         "%s: %u (%u %s)",
416                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
417                         ntohl(*(guint32 *)&p[i + aoff]), alen + aoff, 
418                         (alen + aoff == 1) ? "byte" : "bytes");
419                 break;
420             case BGPTYPE_LOCAL_PREF:
421                 if (alen != 4)
422                     goto default_attribute_top;
423                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
424                         "%s: %u (%u %s)",
425                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
426                         ntohl(*(guint32 *)&p[i + aoff]), alen + aoff,
427                         (alen + aoff == 1) ? "byte" : "bytes");
428                 break;
429             case BGPTYPE_ATOMIC_AGGREGATE:
430                 if (alen != 0) 
431                     goto default_attribute_top;
432                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
433                         "%s: (%u %s)",
434                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
435                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
436                 break;
437             default:
438             default_attribute_top:
439                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
440                         "%s (%u %s)",
441                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
442                         alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
443             }
444             subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
445
446             /* figure out flags */
447             ti = proto_tree_add_text(subtree2,
448                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
449                     "Flags: 0x%02x", bgpa.bgpa_flags);
450             subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
451             proto_tree_add_text(subtree3,
452                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
453                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
454                         BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
455             proto_tree_add_text(subtree3,
456                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
457                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
458                         BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive", 
459                         "Non-transitive"));
460             proto_tree_add_text(subtree3,
461                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
462                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
463                         BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
464             proto_tree_add_text(subtree3,
465                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
466                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
467                         BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length", 
468                         "Regular length"));
469
470             proto_tree_add_text(subtree2,
471                     p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
472                     "Type code: %s (%u)",
473                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
474                     bgpa.bgpa_type);
475             
476             /* check for the Extended Length bit */
477             if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
478                 proto_tree_add_text(subtree2,
479                         p - pd + i + sizeof(bgpa), aoff - sizeof(bgpa),
480                         "Length: %d %s", alen, 
481                         (alen == 1) ? "byte" : "bytes");
482             } else {
483                 proto_tree_add_text(subtree2,
484                         p - pd + i + sizeof(bgpa), aoff - sizeof(bgpa),
485                         "Length: %d %s", alen,
486                         (alen == 1) ? "byte" : "bytes");
487             }
488
489             switch (bgpa.bgpa_type) {
490             case BGPTYPE_ORIGIN:
491                 if (alen != 1) {
492                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
493                             "Origin (invalid): %u %s", alen,
494                              (alen == 1) ? "byte" : "bytes");
495                 } else {
496                     msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
497                     proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
498                             "Origin: %s (%u)", msg, p[i + aoff]);
499                 }
500                 break;
501             case BGPTYPE_AS_PATH:
502                 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
503                         "AS path: %s (%u %s)", as_path_str, alen, 
504                         (alen == 1) ? "byte" : "bytes");
505                 free(as_path_str);
506                 break;
507             case BGPTYPE_NEXT_HOP:
508                 if (alen != 4) {
509                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
510                             "Next hop (invalid): %u %s", alen,
511                             (alen == 1) ? "byte" : "bytes");
512                 } else {
513                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
514                             "Next hop: %s", ip_to_str(&p[i + aoff]));
515                 }
516                 break;
517             case BGPTYPE_MULTI_EXIT_DISC:
518                 if (alen != 4) {
519                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
520                             "Multi exit discriminator (invalid): %u %s",
521                             alen, (alen == 1) ? "byte" : "bytes");
522                 } else {
523                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
524                             "Multi exit discriminator: %u",
525                             ntohl(*(guint32 *)&p[i + aoff]));
526                 }
527                 break;
528             case BGPTYPE_LOCAL_PREF:
529                 if (alen != 4) {
530                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
531                             "Local preference (invalid): %u %s", alen,
532                              (alen == 1) ? "byte" : "bytes");
533                 } else {
534                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
535                             "Local preference: %u",
536                             ntohl(*(guint32 *)&p[i + aoff]));
537                 }
538                 break;
539             case BGPTYPE_ATOMIC_AGGREGATE:
540                 if (alen != 0) {
541                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
542                             "Atomic aggregate (invalid): %u %s", alen,
543                             (alen == 1) ? "byte" : "bytes");
544                 } else {
545                     proto_tree_add_text(subtree2, p - pd + i + aoff, 0,
546                             "Atomic aggregate");
547                 }
548                 break;
549             case BGPTYPE_AGGREGATOR:
550                 if (alen != 6) {
551                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
552                             "Aggregator (invalid): %u %s", alen,
553                             (alen == 1) ? "byte" : "bytes");
554                 } else {
555                     proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
556                             "Aggregator AS: %u",
557                             ntohs(*(guint16 *)&p[i + aoff]));
558                     proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 4,
559                             "Aggregator origin: %s",
560                             ip_to_str(&p[i + aoff + 2]));
561                 }
562                 break;
563             case BGPTYPE_MP_REACH_NLRI:
564                 af = ntohs(*(guint16 *)&p[i + aoff]);
565                 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
566                     "Address family: %s (%u)",
567                     val_to_str(af, afnumber, "Unknown"), af);
568                 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
569                     "Subsequent address family identifier: %s (%u)",
570                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
571                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
572                     p[i + aoff + 2]);
573                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3, 1,
574                         "Next hop network address (%d %s)",
575                         p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" : 
576                         "bytes");
577                 if (af == AFNUM_INET || af == AFNUM_INET6) {
578                     int j, advance;
579                     const char *s;
580
581                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
582
583                     j = 0;
584                     while (j < p[i + aoff + 3]) {
585                         if (af == AFNUM_INET)
586                             advance = 4;
587                         else if (af == AFNUM_INET6)
588                             advance = 16;
589                         else
590                             break;
591                         if (j + advance > p[i + aoff + 3])
592                             break;
593
594                         if (af == AFNUM_INET)
595                             s = ip_to_str(&p[i + aoff + 4 + j]);
596                         else {
597                             s = ip6_to_str((struct e_in6_addr *)
598                                 &p[i + aoff + 4 + j]);
599                         }
600                         proto_tree_add_text(subtree3,
601                             p - pd + i + aoff + 4 + j, advance,
602                             "Next hop: %s", s);
603                         j += advance;
604                     }
605                 }
606
607                 alen -= (p[i + aoff + 3] + 4);
608                 aoff += (p[i + aoff + 3] + 4);
609                 off = 0;
610                 snpa = p[i + aoff];
611                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
612                         "Subnetwork points of attachment: %u", snpa);
613                 off++;
614                 if (snpa)
615                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
616                 for (/*nothing*/; snpa > 0; snpa--) {
617                     proto_tree_add_text(subtree3, p - pd + i + aoff + off, 1,
618                         "SNPA length: ", p[i + aoff + off]);
619                     off++;
620                     proto_tree_add_text(subtree3, p - pd + i + aoff + off,
621                         p[i + aoff + off - 1],
622                         "SNPA (%u %s)", p[i + aoff + off - 1],
623                         (p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
624                     off += p[i + aoff + off - 1];
625                 }
626
627                 alen -= off;
628                 aoff += off;
629                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
630                         "Network Layer Reachability Information (%u %s)",
631                         alen, (alen == 1) ? "byte" : "bytes");
632                 if (alen)
633                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
634                 while (alen > 0) {
635                     int advance;
636                     char buf[256];
637
638                     if (af == AFNUM_INET) {
639                         advance = decode_prefix4(&p[i + aoff], buf,
640                             sizeof(buf));
641                     } else if (af == AFNUM_INET6) {
642                         advance = decode_prefix6(&p[i + aoff], buf,
643                             sizeof(buf));
644                     } else
645                         break;
646                     if (advance < 0)
647                         break;
648                     if (alen < advance)
649                         break;
650                     proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
651                         "Network Layer Reachability Information: %s", buf);
652
653                     alen -= advance;
654                     aoff += advance;
655                 }
656
657                 break;
658             case BGPTYPE_MP_UNREACH_NLRI:
659                 af = ntohs(*(guint16 *)&p[i + aoff]);
660                 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
661                     "Address family: %s (%u)",
662                     val_to_str(af, afnumber, "Unknown"), af);
663                 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
664                     "Subsequent address family identifier: %s (%u)",
665                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
666                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
667                     p[i + aoff + 2]);
668                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3,
669                         alen - 3, "Withdrawn Routes (%u %s)", alen - 3,
670                         (alen - 3 == 1) ? "byte" : "bytes");
671
672                 alen -= 3;
673                 aoff += 3;
674                 if (alen > 0)
675                     subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
676                 while (alen > 0) {
677                     int advance;
678                     char buf[256];
679
680                     if (af == AFNUM_INET) {
681                         advance = decode_prefix4(&p[i + aoff], buf,
682                             sizeof(buf));
683                     } else if (af == AFNUM_INET6) {
684                         advance = decode_prefix6(&p[i + aoff], buf,
685                             sizeof(buf));
686                     } else
687                         break;
688                     if (advance < 0)
689                         break;
690                     if (alen < advance)
691                         break;
692                     proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
693                         "Withdrawn route: %s", buf);
694
695                     alen -= advance;
696                     aoff += advance;
697                 }
698
699                 break;
700             default:
701                 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
702                         "Unknown (%d %s)", alen, (alen == 1) ? "byte" : 
703                         "bytes");
704                 break;
705             }
706
707             i += alen + aoff;
708         }
709 /* --- move --- */
710         p += 2 + len;
711
712         /* NLRI */
713         len = hlen - (p - &pd[offset]);
714         ti = proto_tree_add_text(tree, p - pd, len,
715                 "Network layer reachability information: %u %s", len,
716                 (len == 1) ? "byte" : "bytes");
717
718         if (len > 0) {
719             subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
720
721             /* parse prefixes */
722             end = p + len;
723             while (p < end) {
724                 memset(&prefix, 0, sizeof(prefix));
725                 /* snarf length */
726                 length = *p;
727                 i = convert_prefix(length);
728                 p++;
729                 /* snarf prefix */
730                 memcpy(&prefix, p, i);
731                 proto_tree_add_text(subtree, p - pd - 1, i + 1, "%s/%d", 
732                         inet_ntoa(prefix), length);
733                 p += i;
734             }
735         }
736     }
737 }
738
739 /*
740  * Dissect a BGP NOTIFICATION message.
741  */
742 static void
743 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
744     proto_tree *tree)
745 {
746     struct bgp_notification bgpn;   /* BGP NOTIFICATION message */
747     int hlen;                       /* message length           */
748     char *p;                        /* string pointer           */
749
750     /* snarf message */
751     memcpy(&bgpn, &pd[offset], sizeof(bgpn));
752     hlen = ntohs(bgpn.bgpn_len);
753
754     /* print error code */
755     proto_tree_add_text(tree,
756         offset + offsetof(struct bgp_notification, bgpn_major), 1,
757         "Error code: %s (%u)",
758         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
759         bgpn.bgpn_major);
760
761     /* print error subcode */
762     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
763      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
764         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
765             "Unknown");
766     } else if (bgpn.bgpn_minor == 0)
767         p = "Unspecified";
768     else
769         p = "Unknown";
770     proto_tree_add_text(tree,
771         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
772         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
773
774     /* only print if there is optional data */
775     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
776         proto_tree_add_text(tree, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
777             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
778     }
779 }
780
781 /*
782  * Dissect a BGP packet.
783  */
784 void
785 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
786 {
787     proto_item *ti;              /* tree item                        */
788     proto_tree *bgp_tree;        /* BGP packet tree                  */
789     proto_tree *bgp1_tree;       /* BGP message tree                 */
790     const u_char *p;             /* packet offset pointer            */
791     int l, i;                    /* tmp                              */
792     int found;                   /* number of BGP messages in packet */
793     static u_char marker[] = {   /* BGP message marker               */
794         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
795         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
796     };
797     struct bgp bgp;               /* BGP header                      */
798     int hlen;                     /* BGP header length               */
799     char *typ;                    /* BGP message type                */
800
801     if (check_col(fd, COL_PROTOCOL))
802         col_add_str(fd, COL_PROTOCOL, "BGP");
803
804     p = &pd[offset];
805     l = END_OF_FRAME;
806     i = 0;
807     found = -1;
808     /* run through the TCP packet looking for BGP headers         */
809     /* this is done twice, but this way each message type can be 
810        printed in the COL_INFO field                              */
811     while (i < l) {
812         /* look for bgp header */
813         if (p[i] != 0xff) {
814             i++;
815             continue;
816         }
817         CHECK_SIZE(i, sizeof(marker), l);
818         if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
819             i++;
820             continue;
821         }
822
823         memcpy(&bgp, &p[i], sizeof(bgp));
824         found++;
825         hlen = ntohs(bgp.bgp_len);
826         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
827
828         if (check_col(fd, COL_INFO)) {
829             if (found == 0) 
830                 col_add_fstr(fd, COL_INFO, "%s", typ);
831             else
832                 col_append_fstr(fd, COL_INFO, ", %s", typ);
833         }
834
835         i += hlen;
836     }
837
838     if (tree) {
839         ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
840                     "Border Gateway Protocol");
841         bgp_tree = proto_item_add_subtree(ti, ett_bgp);
842
843         p = &pd[offset];
844         l = END_OF_FRAME;
845         i = 0;
846         /* now, run through the TCP packet again, this time dissect */
847         /* each message that we find */
848         while (i < l) {
849             /* look for bgp header */
850             if (p[i] != 0xff) {
851                 i++;
852                 continue;
853             }
854             CHECK_SIZE(i, sizeof(marker), l);
855             if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
856                 i++;
857                 continue;
858             }
859
860             memcpy(&bgp, &p[i], sizeof(bgp));
861             hlen = ntohs(bgp.bgp_len);
862             typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
863             if (END_OF_FRAME < hlen) {
864                 ti = proto_tree_add_text(bgp_tree, offset + i, END_OF_FRAME,
865                             "%s (truncated)", typ);
866             } else {
867                 ti = proto_tree_add_text(bgp_tree, offset + i, hlen,
868                             "%s", typ);
869             }
870             /* add a different tree for each message type */
871             switch (bgp.bgp_type) {
872             case BGP_OPEN:
873                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
874                 break;
875             case BGP_UPDATE:
876                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
877                 break;
878             case BGP_NOTIFICATION:
879                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
880                 break;
881             case BGP_KEEPALIVE:
882                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
883                 break;
884             default:
885                 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
886                 break;
887             }
888
889             proto_tree_add_text(bgp1_tree, offset + i, BGP_MARKER_SIZE,
890                 "Marker", NULL);
891                             
892             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
893                 proto_tree_add_text(bgp1_tree,
894                     offset + i + offsetof(struct bgp, bgp_len), 2,
895                     "Length (invalid): %u %s", hlen, 
896                     (hlen == 1) ? "byte" : "bytes");
897             } else {
898                 proto_tree_add_text(bgp1_tree,
899                     offset + i + offsetof(struct bgp, bgp_len), 2,
900                     "Length: %u %s", hlen, 
901                     (hlen == 1) ? "byte" : "bytes");
902             }
903
904             proto_tree_add_text(bgp1_tree,
905                 offset + i + offsetof(struct bgp, bgp_type), 1,
906                 "Type: %s (%u)", typ, bgp.bgp_type);
907
908             CHECK_SIZE(i, hlen, l);
909
910             /* handle each message type */
911             switch (bgp.bgp_type) {
912             case BGP_OPEN:
913                 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
914                 break;
915             case BGP_UPDATE:
916                 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
917                 break;
918             case BGP_NOTIFICATION:
919                 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
920                 break;
921             case BGP_KEEPALIVE:
922                 /* no data in KEEPALIVE messages */
923                 break;
924             default:
925                 break;
926             }
927
928             i += hlen;
929         }
930     }
931 }
932
933 /*
934  * Register ourselves.
935  */
936 void
937 proto_register_bgp(void)
938 {
939     static gint *ett[] = {
940       &ett_bgp,
941       &ett_bgp_unfeas,
942       &ett_bgp_attrs,
943       &ett_bgp_attr,
944       &ett_bgp_attr_flags,
945       &ett_bgp_mp_reach_nlri,
946       &ett_bgp_mp_unreach_nlri,
947       &ett_bgp_nlri,
948       &ett_bgp_open,
949       &ett_bgp_update,
950       &ett_bgp_notification,
951     };
952
953     proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
954     proto_register_subtree_array(ett, array_length(ett));
955 }