2 * Routines for BGP packet dissection.
3 * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-bgp.c,v 1.10 1999/11/16 11:42:26 guy Exp $
8 * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9 * RFC2283 Multiprotocol Extensions for BGP-4
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)
18 * Ethereal - Network traffic analyzer
19 * By Gerald Combs <gerald@unicom.net>
20 * Copyright 1998 Gerald Combs
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.
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.
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.
44 #ifdef HAVE_SYS_TYPES_H
45 # include <sys/types.h>
48 #ifdef HAVE_NETINET_IN_H
49 # include <netinet/in.h>
52 #ifdef NEED_SNPRINTF_H
58 # include "snprintf.h"
64 #include "packet-bgp.h"
65 #include "packet-ipv6.h"
66 #include <arpa/inet.h>
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" },
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" },
86 static const value_string bgpnotify_minor_1[] = {
87 { 1, "Connection Not Synchronized" },
88 { 2, "Bad Message Length" },
89 { 3, "Bad Message Type" },
93 static const value_string bgpnotify_minor_2[] = {
94 { 1, "Unsupported Version Number" },
96 { 3, "Bad BGP Identifier" },
97 { 4, "Unsupported Optional Parameter" },
98 { 5, "Authentication Failure" },
99 { 6, "Unacceptable Hold Time" },
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" },
118 static const value_string *bgpnotify_minor[] = {
119 NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
122 static const value_string bgpattr_flags[] = {
123 { 0x80, "Optional" },
124 { 0x40, "Transitive" },
126 { 0x10, "Extended length" },
130 static const value_string bgpattr_origin[] = {
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" },
150 /* Subsequent address family identifier, RFC2283 section 7 */
151 static const value_string bgpattr_nlri_safi[] = {
155 { 3, "Unicast+Multicast" },
159 static const value_string afnumber[] = {
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" },
180 static int proto_bgp = -1;
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;
195 * Decode an IPv4 prefix.
198 decode_prefix4(const u_char *pd, char *buf, int buflen)
204 if (plen < 0 || 32 < plen)
207 memset(addr, 0, sizeof(addr));
208 memcpy(addr, &pd[1], (plen + 7) / 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;
216 * Decode an IPv6 prefix.
219 decode_prefix6(const u_char *pd, char *buf, int buflen)
221 struct e_in6_addr addr;
225 if (plen < 0 || 128 < plen)
228 memset(&addr, 0, sizeof(addr));
229 memcpy(&addr, &pd[1], (plen + 7) / 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;
237 * Dissect a BGP OPEN message.
240 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
242 struct bgp_open bgpo; /* BGP OPEN message */
243 int hlen; /* message length */
245 /* snarf OPEN message */
246 memcpy(&bgpo, &pd[offset], sizeof(bgpo));
247 hlen = ntohs(bgpo.bgpo_len);
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");
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");
274 * Dissect a BGP UPDATE message.
277 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
281 struct bgp_attr bgpa;
289 proto_tree *subtree2;
290 proto_tree *subtree3;
295 struct in_addr prefix;
296 char *as_path_str = NULL;
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*/
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");
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);
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");
320 /* path attributes */
323 ti = proto_tree_add_text(tree, p - pd + 2, len, "Path attributes");
324 subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
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;
337 alen = p[i + sizeof(bgpa)];
338 aoff = sizeof(bgpa) + 1;
342 * This is kind of ugly - similar code appears twice,
343 * but it helps browsing attrs.
345 switch (bgpa.bgpa_type) {
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,
352 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
353 msg, alen + aoff, (alen + aoff == 1) ? "byte" :
356 case BGPTYPE_AS_PATH:
358 (p + current attribute + 3 bytes to first tuple) */
359 end = p + alen + 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;
368 /* snarf each AS path */
371 if (type == AS_SET) {
372 sprintf(as_path_str, "{");
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);
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';
390 as_path_str[strlen(as_path_str) - 1] = '\0';
394 if (as_path_str[0] == '\0')
395 goto default_attribute_top;
396 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
398 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
399 as_path_str, alen + aoff, (alen + aoff == 1) ? "byte" :
402 case BGPTYPE_NEXT_HOP:
404 goto default_attribute_top;
405 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
407 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
408 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
411 case BGPTYPE_MULTI_EXIT_DISC:
413 goto default_attribute_top;
414 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
416 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
417 ntohl(*(guint32 *)&p[i + aoff]), alen + aoff,
418 (alen + aoff == 1) ? "byte" : "bytes");
420 case BGPTYPE_LOCAL_PREF:
422 goto default_attribute_top;
423 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
425 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
426 ntohl(*(guint32 *)&p[i + aoff]), alen + aoff,
427 (alen + aoff == 1) ? "byte" : "bytes");
429 case BGPTYPE_ATOMIC_AGGREGATE:
431 goto default_attribute_top;
432 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
434 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
435 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
438 default_attribute_top:
439 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
441 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
442 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
444 subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
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",
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",
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"),
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");
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");
489 switch (bgpa.bgpa_type) {
492 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
493 "Origin (invalid): %u %s", alen,
494 (alen == 1) ? "byte" : "bytes");
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]);
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");
507 case BGPTYPE_NEXT_HOP:
509 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
510 "Next hop (invalid): %u %s", alen,
511 (alen == 1) ? "byte" : "bytes");
513 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
514 "Next hop: %s", ip_to_str(&p[i + aoff]));
517 case BGPTYPE_MULTI_EXIT_DISC:
519 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
520 "Multi exit discriminator (invalid): %u %s",
521 alen, (alen == 1) ? "byte" : "bytes");
523 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
524 "Multi exit discriminator: %u",
525 ntohl(*(guint32 *)&p[i + aoff]));
528 case BGPTYPE_LOCAL_PREF:
530 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
531 "Local preference (invalid): %u %s", alen,
532 (alen == 1) ? "byte" : "bytes");
534 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
535 "Local preference: %u",
536 ntohl(*(guint32 *)&p[i + aoff]));
539 case BGPTYPE_ATOMIC_AGGREGATE:
541 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
542 "Atomic aggregate (invalid): %u %s", alen,
543 (alen == 1) ? "byte" : "bytes");
545 proto_tree_add_text(subtree2, p - pd + i + aoff, 0,
549 case BGPTYPE_AGGREGATOR:
551 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
552 "Aggregator (invalid): %u %s", alen,
553 (alen == 1) ? "byte" : "bytes");
555 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
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]));
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"),
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" :
577 if (af == AFNUM_INET || af == AFNUM_INET6) {
581 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
584 while (j < p[i + aoff + 3]) {
585 if (af == AFNUM_INET)
587 else if (af == AFNUM_INET6)
591 if (j + advance > p[i + aoff + 3])
594 if (af == AFNUM_INET)
595 s = ip_to_str(&p[i + aoff + 4 + j]);
597 s = ip6_to_str((struct e_in6_addr *)
598 &p[i + aoff + 4 + j]);
600 proto_tree_add_text(subtree3,
601 p - pd + i + aoff + 4 + j, advance,
607 alen -= (p[i + aoff + 3] + 4);
608 aoff += (p[i + aoff + 3] + 4);
611 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
612 "Subnetwork points of attachment: %u", 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]);
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];
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");
633 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
638 if (af == AFNUM_INET) {
639 advance = decode_prefix4(&p[i + aoff], buf,
641 } else if (af == AFNUM_INET6) {
642 advance = decode_prefix6(&p[i + aoff], buf,
650 proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
651 "Network Layer Reachability Information: %s", buf);
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"),
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");
675 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
680 if (af == AFNUM_INET) {
681 advance = decode_prefix4(&p[i + aoff], buf,
683 } else if (af == AFNUM_INET6) {
684 advance = decode_prefix6(&p[i + aoff], buf,
692 proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
693 "Withdrawn route: %s", buf);
701 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
702 "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
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");
719 subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
724 memset(&prefix, 0, sizeof(prefix));
727 i = convert_prefix(length);
730 memcpy(&prefix, p, i);
731 proto_tree_add_text(subtree, p - pd - 1, i + 1, "%s/%d",
732 inet_ntoa(prefix), length);
740 * Dissect a BGP NOTIFICATION message.
743 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
746 struct bgp_notification bgpn; /* BGP NOTIFICATION message */
747 int hlen; /* message length */
748 char *p; /* string pointer */
751 memcpy(&bgpn, &pd[offset], sizeof(bgpn));
752 hlen = ntohs(bgpn.bgpn_len);
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"),
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],
766 } else if (bgpn.bgpn_minor == 0)
770 proto_tree_add_text(tree,
771 offset + offsetof(struct bgp_notification, bgpn_minor), 1,
772 "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
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");
782 * Dissect a BGP packet.
785 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
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 */
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,
797 struct bgp bgp; /* BGP header */
798 int hlen; /* BGP header length */
799 char *typ; /* BGP message type */
801 if (check_col(fd, COL_PROTOCOL))
802 col_add_str(fd, COL_PROTOCOL, "BGP");
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 */
812 /* look for bgp header */
817 CHECK_SIZE(i, sizeof(marker), l);
818 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
823 memcpy(&bgp, &p[i], sizeof(bgp));
825 hlen = ntohs(bgp.bgp_len);
826 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
828 if (check_col(fd, COL_INFO)) {
830 col_add_fstr(fd, COL_INFO, "%s", typ);
832 col_append_fstr(fd, COL_INFO, ", %s", typ);
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);
846 /* now, run through the TCP packet again, this time dissect */
847 /* each message that we find */
849 /* look for bgp header */
854 CHECK_SIZE(i, sizeof(marker), l);
855 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
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);
867 ti = proto_tree_add_text(bgp_tree, offset + i, hlen,
870 /* add a different tree for each message type */
871 switch (bgp.bgp_type) {
873 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
876 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
878 case BGP_NOTIFICATION:
879 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
882 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
885 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
889 proto_tree_add_text(bgp1_tree, offset + i, BGP_MARKER_SIZE,
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");
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");
904 proto_tree_add_text(bgp1_tree,
905 offset + i + offsetof(struct bgp, bgp_type), 1,
906 "Type: %s (%u)", typ, bgp.bgp_type);
908 CHECK_SIZE(i, hlen, l);
910 /* handle each message type */
911 switch (bgp.bgp_type) {
913 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
916 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
918 case BGP_NOTIFICATION:
919 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
922 /* no data in KEEPALIVE messages */
934 * Register ourselves.
937 proto_register_bgp(void)
939 static gint *ett[] = {
945 &ett_bgp_mp_reach_nlri,
946 &ett_bgp_mp_unreach_nlri,
950 &ett_bgp_notification,
953 proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
954 proto_register_subtree_array(ett, array_length(ett));