little bit more fixes to bgp dissector.
[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.7 1999/11/02 00:11:58 itojun Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@unicom.net>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_NETINET_IN_H
38 # include <netinet/in.h>
39 #endif
40
41 #ifdef NEED_SNPRINTF_H
42 # ifdef HAVE_STDARG_H
43 #  include <stdarg.h>
44 # else
45 #  include <varargs.h>
46 # endif
47 # include "snprintf.h"
48 #endif
49
50 #include <string.h>
51 #include <glib.h>
52 #include "packet.h"
53 #include "packet-bgp.h"
54 #include "packet-ipv6.h"
55
56 static const value_string bgptypevals[] = {
57     { BGP_OPEN, "OPEN Message" },
58     { BGP_UPDATE, "UPDATE Message" },
59     { BGP_NOTIFICATION, "NOTIFICATION Message" },
60     { BGP_KEEPALIVE, "KEEPALIVE Message" },
61     { 0, NULL },
62 };
63
64 static const value_string bgpnotify_major[] = {
65     { 1, "Message Header Error" },
66     { 2, "OPEN Message Error" },
67     { 3, "UPDATE Message Error" },
68     { 4, "Hold Timer Expired" },
69     { 5, "Finite State Machine Error" },
70     { 6, "Cease" },
71     { 0, NULL },
72 };
73
74 static const value_string bgpnotify_minor_1[] = {
75     { 1, "Connection Not Synchronized" },
76     { 2, "Bad Message Length" },
77     { 3, "Bad Message Type" },
78     { 0, NULL },
79 };
80
81 static const value_string bgpnotify_minor_2[] = {
82     { 1, "Unsupported Version Number" },
83     { 2, "Bad Peer AS" },
84     { 3, "Bad BGP Identifier" },
85     { 4, "Unsupported Optional Parameter" },
86     { 5, "Authentication Failure" },
87     { 6, "Unacceptable Hold Time" },
88     { 0, NULL },
89 };
90
91 static const value_string bgpnotify_minor_3[] = {
92     { 1, "Malformed Attribute List" },
93     { 2, "Unrecognized Well-known Attribute" },
94     { 3, "Missing Well-known Attribute" },
95     { 4, "Attribute Flags Error" },
96     { 5, "Attribute Length Error" },
97     { 6, "Invalid ORIGIN Attribute" },
98     { 7, "AS Routing Loop" },
99     { 8, "Invalid NEXT_HOP Attribute" },
100     { 9, "Optional Attribute Error" },
101     { 10, "Invalid Network Field" },
102     { 11, "Malformed AS_PATH" },
103     { 0, NULL },
104 };
105
106 static const value_string *bgpnotify_minor[] = {
107     NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
108 };
109
110 static const value_string bgpattr_flags[] = {
111     { 0x80, "Optional" },
112     { 0x40, "Transitive" },
113     { 0x20, "Partial" },
114     { 0x10, "Extended length" },
115     { 0, NULL },
116 };
117
118 static const value_string bgpattr_origin[] = {
119     { 0, "IGP" },
120     { 1, "EGP" },
121     { 2, "INCOMPLETE" },
122     { 0, NULL },
123 };
124
125 static const value_string bgpattr_type[] = {
126     { BGPTYPE_ORIGIN, "ORIGIN" },
127     { BGPTYPE_AS_PATH, "AS_PATH" },
128     { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
129     { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
130     { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
131     { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
132     { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
133     { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
134     { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
135     { 0, NULL },
136 };
137
138 /* Subsequent address family identifier, RFC2283 section 7 */
139 static const value_string bgpattr_nlri_safi[] = {
140     { 0, "Reserved" },
141     { 1, "Unicast" },
142     { 2, "Multicast" },
143     { 3, "Unicast+Multicast" },
144     { 0, NULL },
145 };
146
147 static const value_string afnumber[] = {
148     { 0, "Reserved" },
149     { AFNUM_INET, "IPv4" },
150     { AFNUM_INET6, "IPv6" },
151     { AFNUM_NSAP, "NSAP" },
152     { AFNUM_HDLC, "HDLC" },
153     { AFNUM_BBN1822, "BBN 1822" },
154     { AFNUM_802, "802" },
155     { AFNUM_E163, "E.163" },
156     { AFNUM_E164, "E.164" },
157     { AFNUM_F69, "F.69" },
158     { AFNUM_X121, "X.121" },
159     { AFNUM_IPX, "IPX" },
160     { AFNUM_ATALK, "Appletalk" },
161     { AFNUM_DECNET, "Decnet IV" },
162     { AFNUM_BANYAN, "Banyan Vines" },
163     { AFNUM_E164NSAP, "E.164 with NSAP subaddress" },
164     { 65535, "Reserved" },
165     { 0, NULL },
166 };
167
168 static int proto_bgp = -1;
169
170 static int
171 decode_prefix4(const u_char *pd, char *buf, int buflen)
172 {
173     guint8 addr[4];
174     int plen;
175
176     plen = pd[0];
177     if (plen < 0 || 32 < plen)
178         return -1;
179
180     memset(addr, 0, sizeof(addr));
181     memcpy(addr, &pd[1], (plen + 7) / 8);
182     if (plen % 8)
183         addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
184     snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
185     return 1 + (plen + 7) / 8;
186 }
187
188 static int
189 decode_prefix6(const u_char *pd, char *buf, int buflen)
190 {
191     struct e_in6_addr addr;
192     int plen;
193
194     plen = pd[0];
195     if (plen < 0 || 128 < plen)
196         return -1;
197
198     memset(&addr, 0, sizeof(addr));
199     memcpy(&addr, &pd[1], (plen + 7) / 8);
200     if (plen % 8)
201         addr.s6_addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
202     snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
203     return 1 + (plen + 7) / 8;
204 }
205
206 static void
207 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
208 {
209     struct bgp_open bgpo;
210     int hlen;
211
212     memcpy(&bgpo, &pd[offset], sizeof(bgpo));
213     hlen = ntohs(bgpo.bgpo_len);
214
215     proto_tree_add_text(tree,
216         offset + offsetof(struct bgp_open, bgpo_version), 1,
217         "Version: %u", bgpo.bgpo_version);
218     proto_tree_add_text(tree,
219         offset + offsetof(struct bgp_open, bgpo_myas), 2,
220         "My AS: %u", ntohs(bgpo.bgpo_myas));
221     proto_tree_add_text(tree,
222         offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
223         "Holdtime: %u", ntohs(bgpo.bgpo_holdtime));
224     proto_tree_add_text(tree,
225         offset + offsetof(struct bgp_open, bgpo_id), 4,
226         "ID: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
227     proto_tree_add_text(tree,
228         offset + offsetof(struct bgp_open, bgpo_optlen), 1,
229         "Option length: %u", bgpo.bgpo_optlen);
230     if (hlen > sizeof(struct bgp_open)) {
231         proto_tree_add_text(tree,
232             offset + sizeof(struct bgp_open), hlen - sizeof(struct bgp_open),
233             "Option data%s");
234     }
235 }
236
237 /* NOTE: caller needs to free() the returned value. */
238 static char *
239 dissect_bgp_aspath(const u_char *pd, int len)
240 {
241     char *msg;
242     int j, n;
243     char *q;
244
245     if (len % 2)
246         return NULL;
247     msg = malloc(len / 2 * 6 + 10);
248     if (!msg)
249         return NULL;
250
251     q = msg;
252     for (j = 0; j < len; j += 2) {
253         n = sprintf(q, "%u ", ntohs(*(guint16 *)&pd[j]));
254         q += n;
255     }
256
257     /* remove the last blank */
258     q--;
259     *q = '\0';
260
261     return msg;
262 }
263
264 static void
265 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
266     proto_tree *tree)
267 {
268     struct bgp bgp;
269     struct bgp_attr bgpa;
270     int hlen;
271     const u_char *p;
272     int len;
273     proto_item *ti;
274     proto_tree *subtree, *subtree2, *subtree3;
275     int i;
276
277     memcpy(&bgp, &pd[offset], sizeof(bgp));
278     hlen = ntohs(bgp.bgp_len);
279
280     p = &pd[offset + BGP_HEADER_SIZE];  /*XXX*/
281     proto_tree_add_text(tree, p - pd, 2, 
282         "Unfeasible routes length: %d", len = ntohs(*(guint16 *)p));
283     ti = proto_tree_add_text(tree, p - pd, len,
284             "Withdrawn routes (%u bytes)", len);
285     if (len) {
286         subtree = proto_item_add_subtree(ti, ETT_BGP);
287     }
288     p += 2 + len;
289     proto_tree_add_text(tree, p - pd, 2, 
290         "Total path attribute length: %d", len = ntohs(*(guint16 *)p));
291     ti = proto_tree_add_text(tree, p - pd + 2, len,
292             "Path attributes (%u bytes)", len);
293     if (len) {
294         subtree = proto_item_add_subtree(ti, ETT_BGP);
295         i = 2;
296         while (i < len) {
297             int alen, aoff;
298             char *msg;
299             guint16 af;
300             int off, snpa;
301
302             memcpy(&bgpa, &p[i], sizeof(bgpa));
303             if (bgpa.bgpa_flags & 0x10) {
304                 alen = ntohs(*(guint16 *)&p[i + sizeof(bgpa)]);
305                 aoff = sizeof(bgpa) + 2;
306             } else {
307                 alen = p[i + sizeof(bgpa)];
308                 aoff = sizeof(bgpa) + 1;
309             }
310             
311             /*
312              * This is kind of ugly - similar code appears twice,
313              * but it helps browsing attrs.
314              */
315             switch (bgpa.bgpa_type) {
316             case BGPTYPE_ORIGIN:
317                 if (alen != 1)
318                     goto default_attribute_top;
319                 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
320                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
321                         "Attribute: %s: %s (%u bytes)",
322                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
323                         msg, alen + aoff);
324                 break;
325             case BGPTYPE_AS_PATH:
326                 if (alen % 2)
327                     goto default_attribute_top;
328                 msg = dissect_bgp_aspath(p + i + aoff, alen);
329                 if (msg == NULL)
330                     goto default_attribute_top;
331                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
332                         "Attribute: %s: %s (%u bytes)",
333                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
334                         msg, alen + aoff);
335                 free(msg);
336                 break;
337             case BGPTYPE_NEXT_HOP:
338                 if (alen != 4)
339                     goto default_attribute_top;
340                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
341                         "Attribute: %s: %s (%u bytes)",
342                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
343                         ip_to_str(&p[i + aoff]), alen + aoff);
344                 break;
345             case BGPTYPE_MULTI_EXIT_DISC:
346                 if (alen != 4)
347                     goto default_attribute_top;
348                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
349                         "Attribute: %s: %u (%u bytes)",
350                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
351                         ntohl(*(guint32 *)&p[i + aoff]),
352                         alen + aoff);
353                 break;
354             case BGPTYPE_LOCAL_PREF:
355                 if (alen != 4)
356                     goto default_attribute_top;
357                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
358                         "Attribute: %s: %u (%u bytes)",
359                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
360                         ntohl(*(guint32 *)&p[i + aoff]),
361                         alen + aoff);
362                 break;
363             case BGPTYPE_AGGREGATOR:
364                 if (alen != 6)
365                     goto default_attribute_top;
366                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
367                         "Attribute: %s: AS %u, origin %s (%u bytes)",
368                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
369                         ntohs(*(guint16 *)&p[i + aoff]),
370                         ip_to_str(&p[i + aoff + 2]), alen + aoff);
371                 break;
372             default:
373             default_attribute_top:
374                 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
375                         "Attribute: %s (%u bytes)",
376                         val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
377                         alen + aoff);
378             }
379             subtree2 = proto_item_add_subtree(ti, ETT_BGP);
380
381             ti = proto_tree_add_text(subtree2,
382                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
383                     "Flags: 0x%02x", bgpa.bgpa_flags);
384             subtree3 = proto_item_add_subtree(ti, ETT_BGP);
385             proto_tree_add_text(subtree3,
386                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
387                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
388                         0x80, 8, "Optional", "not Optional"));
389             proto_tree_add_text(subtree3,
390                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
391                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
392                         0x40, 8, "Transitive", "not Transitive"));
393             proto_tree_add_text(subtree3,
394                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
395                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
396                         0x20, 8, "Partial", "not Partial"));
397             proto_tree_add_text(subtree3,
398                     p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
399                     "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
400                         0x10, 8, "Extended length", "not Extended length"));
401
402             proto_tree_add_text(subtree2,
403                     p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
404                     "Type code: %s (0x%02x)",
405                     val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
406                     bgpa.bgpa_type);
407
408             if (bgpa.bgpa_flags & 0x10) {
409                 proto_tree_add_text(subtree2,
410                         p - pd + i + sizeof(bgpa), aoff - sizeof(bgpa),
411                         "Attribute length: %d", alen);
412             } else {
413                 proto_tree_add_text(subtree2,
414                         p - pd + i + sizeof(bgpa), aoff - sizeof(bgpa),
415                         "Attribute length: %d", alen);
416             }
417
418             switch (bgpa.bgpa_type) {
419             case BGPTYPE_ORIGIN:
420                 if (alen != 1) {
421                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
422                             "Origin: Invalid (%d bytes)", alen);
423                 } else {
424                     msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
425                     proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
426                             "Origin: %s (0x%02x)", msg, p[i + aoff]);
427                 }
428                 break;
429             case BGPTYPE_AS_PATH:
430                 if (alen % 2) {
431                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
432                             "AS path: Invalid (%d bytes)", alen);
433                 } else {
434                     msg = dissect_bgp_aspath(p + i + aoff, alen);
435                     if (msg == NULL) {
436                         proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
437                                 "AS path (%d bytes)", alen);
438                     } else {
439                         proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
440                                 "AS path: %s (%d ASes, %d bytes)",
441                                 msg, alen / 2, alen);
442                         free(msg);
443                     }
444                 }
445                 break;
446             case BGPTYPE_NEXT_HOP:
447                 if (alen != 4) {
448                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
449                             "Next hop: Invalid (%d bytes)", alen);
450                 } else {
451                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
452                             "Next hop: %s", ip_to_str(&p[i + aoff]));
453                 }
454                 break;
455             case BGPTYPE_MULTI_EXIT_DISC:
456                 if (alen != 4) {
457                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
458                             "Multi exit discriminator: Invalid (%d bytes)",
459                             alen);
460                 } else {
461                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
462                             "Multi exit discriminator: %u",
463                             ntohl(*(guint32 *)&p[i + aoff]));
464                 }
465                 break;
466             case BGPTYPE_LOCAL_PREF:
467                 if (alen != 4) {
468                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
469                             "Local preference: Invalid (%d bytes)", alen);
470                 } else {
471                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
472                             "Local preference: %u",
473                             ntohl(*(guint32 *)&p[i + aoff]));
474                 }
475                 break;
476             case BGPTYPE_ATOMIC_AGGREGATE:
477                 if (alen != 0) {
478                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
479                             "Atomic aggregate: Invalid (%d bytes)", alen);
480                 } else {
481                     proto_tree_add_text(subtree2, p - pd + i + aoff, 0,
482                             "Atomic aggregate");
483                 }
484                 break;
485             case BGPTYPE_AGGREGATOR:
486                 if (alen != 6) {
487                     proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
488                             "Aggregator: Invalid (%d bytes)", alen);
489                 } else {
490                     proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
491                             "Aggregator AS: %u",
492                             ntohs(*(guint16 *)&p[i + aoff]));
493                     proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 4,
494                             "Aggregator origin: %s",
495                             ip_to_str(&p[i + aoff + 2]));
496                 }
497                 break;
498             case BGPTYPE_MP_REACH_NLRI:
499                 af = ntohs(*(guint16 *)&p[i + aoff]);
500                 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
501                     "Address family: %s (%u)",
502                     val_to_str(af, afnumber, "Unknown"), af);
503                 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
504                     "Subsequent address family identifier: %s (%u)",
505                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
506                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
507                     p[i + aoff + 2]);
508                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3, 1,
509                         "Next hop network address (%d bytes)",
510                         p[i + aoff + 3]);
511                 if (af == AFNUM_INET || af == AFNUM_INET6) {
512                     int j, advance;
513                     const char *s;
514
515                     subtree3 = proto_item_add_subtree(ti, ETT_BGP);
516
517                     j = 0;
518                     while (j < p[i + aoff + 3]) {
519                         if (af == AFNUM_INET)
520                             advance = 4;
521                         else if (af == AFNUM_INET6)
522                             advance = 16;
523                         else
524                             break;
525                         if (j + advance > p[i + aoff + 3])
526                             break;
527
528                         if (af == AFNUM_INET)
529                             s = ip_to_str(&p[i + aoff + 4 + j]);
530                         else {
531                             s = ip6_to_str((struct e_in6_addr *)
532                                 &p[i + aoff + 4 + j]);
533                         }
534                         proto_tree_add_text(subtree3,
535                             p - pd + i + aoff + 4 + j, advance,
536                             "Next hop: %s", s);
537                         j += advance;
538                     }
539                 }
540
541                 alen -= (p[i + aoff + 3] + 4);
542                 aoff += (p[i + aoff + 3] + 4);
543                 off = 0;
544                 snpa = p[i + aoff];
545                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
546                         "Subnetwork points of attachment: %u", snpa);
547                 off++;
548                 if (snpa)
549                     subtree3 = proto_item_add_subtree(ti, ETT_BGP);
550                 for (/*nothing*/; snpa > 0; snpa--) {
551                     proto_tree_add_text(subtree3, p - pd + i + aoff + off, 1,
552                         "SNPA length: ", p[i + aoff + off]);
553                     off++;
554                     proto_tree_add_text(subtree3, p - pd + i + aoff + off,
555                         p[i + aoff + off - 1],
556                         "SNPA (%u bytes)", p[i + aoff + off - 1]);
557                     off += p[i + aoff + off - 1];
558                 }
559
560                 alen -= off;
561                 aoff += off;
562                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
563                         "Network Layer Reachability Information (%u bytes)",
564                         alen);
565                 if (alen)
566                     subtree3 = proto_item_add_subtree(ti, ETT_BGP);
567                 while (alen > 0) {
568                     int advance;
569                     char buf[256];
570
571                     if (af == AFNUM_INET) {
572                         advance = decode_prefix4(&p[i + aoff], buf,
573                             sizeof(buf));
574                     } else if (af == AFNUM_INET6) {
575                         advance = decode_prefix6(&p[i + aoff], buf,
576                             sizeof(buf));
577                     } else
578                         break;
579                     if (advance < 0)
580                         break;
581                     if (alen < advance)
582                         break;
583                     proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
584                         "Network Layer Reachability Information: %s", buf);
585
586                     alen -= advance;
587                     aoff += advance;
588                 }
589
590                 break;
591             case BGPTYPE_MP_UNREACH_NLRI:
592                 af = ntohs(*(guint16 *)&p[i + aoff]);
593                 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
594                     "Address family: %s (%u)",
595                     val_to_str(af, afnumber, "Unknown"), af);
596                 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
597                     "Subsequent address family identifier: %s (%u)",
598                     val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
599                         p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
600                     p[i + aoff + 2]);
601                 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3,
602                         alen - 3, "Withdrawn Routes (%u bytes)", alen - 3);
603
604                 alen -= 3;
605                 aoff += 3;
606                 if (alen > 0)
607                     subtree3 = proto_item_add_subtree(ti, ETT_BGP);
608                 while (alen > 0) {
609                     int advance;
610                     char buf[256];
611
612                     if (af == AFNUM_INET) {
613                         advance = decode_prefix4(&p[i + aoff], buf,
614                             sizeof(buf));
615                     } else if (af == AFNUM_INET6) {
616                         advance = decode_prefix6(&p[i + aoff], buf,
617                             sizeof(buf));
618                     } else
619                         break;
620                     if (advance < 0)
621                         break;
622                     if (alen < advance)
623                         break;
624                     proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
625                         "Withdrawn route: %s", buf);
626
627                     alen -= advance;
628                     aoff += advance;
629                 }
630
631                 break;
632             default:
633                 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
634                         "Unknown (%d bytes)", alen);
635                 break;
636             }
637
638             i += alen + aoff;
639         }
640     }
641     p += 2 + len;
642     len = hlen - (p - &pd[offset]);
643     ti = proto_tree_add_text(tree, p - pd, len,
644             "Network layer reachability information (%d bytes)", len);
645     if (len) {
646         subtree = proto_item_add_subtree(ti, ETT_BGP);
647     }
648 }
649
650 /*
651  * Dissect a BGP NOTIFICATION message.
652  */
653 static void
654 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
655     proto_tree *tree)
656 {
657     struct bgp_notification bgpn;
658     int hlen;
659     char *p;
660
661     /* snarf message */
662     memcpy(&bgpn, &pd[offset], sizeof(bgpn));
663     hlen = ntohs(bgpn.bgpn_len);
664
665     /* print error code */
666     proto_tree_add_text(tree,
667         offset + offsetof(struct bgp_notification, bgpn_major), 1,
668         "Error code: %s (%u)",
669         val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
670         bgpn.bgpn_major);
671
672     /* print error subcode */
673     if (bgpn.bgpn_major < array_length(bgpnotify_minor)
674      && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
675         p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
676             "Unknown");
677     } else if (bgpn.bgpn_minor == 0)
678         p = "Unspecified";
679     else
680         p = "Unknown";
681     proto_tree_add_text(tree,
682         offset + offsetof(struct bgp_notification, bgpn_minor), 1,
683         "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
684
685     /* only print if there is optional data */
686     if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
687         proto_tree_add_text(tree, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
688             hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
689     }
690 }
691
692 /*
693  * Dissect a BGP packet.
694  */
695 void
696 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
697 {
698     proto_item *ti;
699     proto_tree *bgp_tree;
700     proto_tree *bgp1_tree;
701     const u_char *p;
702     int l, i;
703     int found;
704     static u_char marker[] = {
705         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
706         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
707     };
708     struct bgp bgp;
709     int hlen;
710     char *typ;
711
712     if (check_col(fd, COL_PROTOCOL))
713         col_add_str(fd, COL_PROTOCOL, "BGP");
714
715     p = &pd[offset];
716     l = END_OF_FRAME;
717     i = 0;
718     found = -1;
719     /* run through the TCP packet looking for BGP headers         */
720     /* this is done twice, but this way each message type can be 
721        printed in the COL_INFO field                              */
722     while (i < l) {
723         /* look for bgp header */
724         if (p[i] != 0xff) {
725             i++;
726             continue;
727         }
728         CHECK_SIZE(i, sizeof(marker), l);
729         if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
730             i++;
731             continue;
732         }
733
734         memcpy(&bgp, &p[i], sizeof(bgp));
735         found++;
736         hlen = ntohs(bgp.bgp_len);
737         typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
738
739         if (check_col(fd, COL_INFO)) {
740             if (found == 0) 
741                 col_add_fstr(fd, COL_INFO, "%s", typ);
742             else
743                 col_append_fstr(fd, COL_INFO, ", %s", typ);
744         }
745
746         i += hlen;
747     }
748
749     if (tree) {
750         ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
751                     "Border Gateway Protocol");
752         bgp_tree = proto_item_add_subtree(ti, ETT_BGP);
753
754         p = &pd[offset];
755         l = END_OF_FRAME;
756         i = 0;
757         /* now, run through the TCP packet again, this time dissect */
758         /* each message that we find */
759         while (i < l) {
760             /* look for bgp header */
761             if (p[i] != 0xff) {
762                 i++;
763                 continue;
764             }
765             CHECK_SIZE(i, sizeof(marker), l);
766             if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
767                 i++;
768                 continue;
769             }
770
771             memcpy(&bgp, &p[i], sizeof(bgp));
772             hlen = ntohs(bgp.bgp_len);
773             typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
774             if (END_OF_FRAME < hlen) {
775                 ti = proto_tree_add_text(bgp_tree, offset + i, END_OF_FRAME,
776                             "%s (truncated)", typ);
777             } else {
778                 ti = proto_tree_add_text(bgp_tree, offset + i, hlen,
779                             "%s", typ);
780             }
781             bgp1_tree = proto_item_add_subtree(ti, ETT_BGP);
782
783             proto_tree_add_text(bgp1_tree, offset + i, BGP_MARKER_SIZE,
784                 "Marker", NULL);
785                             
786             if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
787                 proto_tree_add_text(bgp1_tree,
788                     offset + i + offsetof(struct bgp, bgp_len), 2,
789                     "Length (invalid): %u %s", hlen, 
790                     (hlen == 1) ? "byte" : "bytes");
791             } else {
792                 proto_tree_add_text(bgp1_tree,
793                     offset + i + offsetof(struct bgp, bgp_len), 2,
794                     "Length: %u %s", hlen, 
795                     (hlen == 1) ? "byte" : "bytes");
796             }
797
798             proto_tree_add_text(bgp1_tree,
799                 offset + i + offsetof(struct bgp, bgp_type), 1,
800                 "Type: %s (%u)", typ, bgp.bgp_type);
801
802             CHECK_SIZE(i, hlen, l);
803
804             /* handle each message type */
805             switch (bgp.bgp_type) {
806             case BGP_OPEN:
807                 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
808                 break;
809             case BGP_UPDATE:
810                 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
811                 break;
812             case BGP_NOTIFICATION:
813                 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
814                 break;
815             case BGP_KEEPALIVE:
816                 /* no data in KEEPALIVE messages */
817                 break;
818             default:
819                 break;
820             }
821
822             i += hlen;
823         }
824     }
825 }
826
827 /*
828  * Register ourselves.
829  */
830 void
831 proto_register_bgp(void)
832 {
833     proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
834 }