2 * Routines for BGP packet dissection.
3 * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-bgp.c,v 1.31 2001/01/03 06:55:27 guy Exp $
8 * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9 * RFC1965 Autonomous System Confederations for BGP
10 * RFC1997 BGP Communities Attribute
11 * RFC2796 BGP Route Reflection An alternative to full mesh IBGP
12 * RFC2842 Capabilities Advertisement with BGP-4
13 * RFC2858 Multiprotocol Extensions for BGP-4
14 * RFC2918 Route Refresh Capability for BGP-4
17 * Destination Preference Attribute for BGP (work in progress)
18 * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
20 * Ethereal - Network traffic analyzer
21 * By Gerald Combs <gerald@zing.org>
22 * Copyright 1998 Gerald Combs
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * as published by the Free Software Foundation; either version 2
27 * of the License, or (at your option) any later version.
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
34 * You should have received a copy of the GNU General Public License
35 * along with this program; if not, write to the Free Software
36 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46 #ifdef HAVE_SYS_TYPES_H
47 # include <sys/types.h>
50 #ifdef HAVE_NETINET_IN_H
51 # include <netinet/in.h>
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
61 #ifdef NEED_SNPRINTF_H
62 # include "snprintf.h"
66 #include "packet-bgp.h"
67 #include "packet-ipv6.h"
69 static const value_string bgptypevals[] = {
70 { BGP_OPEN, "OPEN Message" },
71 { BGP_UPDATE, "UPDATE Message" },
72 { BGP_NOTIFICATION, "NOTIFICATION Message" },
73 { BGP_KEEPALIVE, "KEEPALIVE Message" },
74 { BGP_ROUTE_REFRESH, "ROUTE-REFRESH Message" },
78 static const value_string bgpnotify_major[] = {
79 { 1, "Message Header Error" },
80 { 2, "OPEN Message Error" },
81 { 3, "UPDATE Message Error" },
82 { 4, "Hold Timer Expired" },
83 { 5, "Finite State Machine Error" },
88 static const value_string bgpnotify_minor_1[] = {
89 { 1, "Connection Not Synchronized" },
90 { 2, "Bad Message Length" },
91 { 3, "Bad Message Type" },
95 static const value_string bgpnotify_minor_2[] = {
96 { 1, "Unsupported Version Number" },
98 { 3, "Bad BGP Identifier" },
99 { 4, "Unsupported Optional Parameter" },
100 { 5, "Authentication Failure" },
101 { 6, "Unacceptable Hold Time" },
102 { 7, "Unsupported Capability" },
106 static const value_string bgpnotify_minor_3[] = {
107 { 1, "Malformed Attribute List" },
108 { 2, "Unrecognized Well-known Attribute" },
109 { 3, "Missing Well-known Attribute" },
110 { 4, "Attribute Flags Error" },
111 { 5, "Attribute Length Error" },
112 { 6, "Invalid ORIGIN Attribute" },
113 { 7, "AS Routing Loop" },
114 { 8, "Invalid NEXT_HOP Attribute" },
115 { 9, "Optional Attribute Error" },
116 { 10, "Invalid Network Field" },
117 { 11, "Malformed AS_PATH" },
121 static const value_string *bgpnotify_minor[] = {
122 NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
125 static const value_string bgpattr_origin[] = {
132 static const value_string as_segment_type[] = {
134 { 2, "AS_SEQUENCE" },
135 /* RFC1965 has the wrong values, corrected in */
136 /* draft-ietf-idr-bgp-confed-rfc1965bis-01.txt */
137 { 4, "AS_CONFED_SET" },
138 { 3, "AS_CONFED_SEQUENCE" },
142 static const value_string bgpattr_type[] = {
143 { BGPTYPE_ORIGIN, "ORIGIN" },
144 { BGPTYPE_AS_PATH, "AS_PATH" },
145 { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
146 { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
147 { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
148 { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
149 { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
150 { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
151 { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
152 { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
153 { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
154 { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
158 /* Subsequent address family identifier, RFC2283 section 7 */
159 static const value_string bgpattr_nlri_safi[] = {
163 { 3, "Unicast+Multicast" },
167 static const value_string afnumber[] = {
169 { AFNUM_INET, "IPv4" },
170 { AFNUM_INET6, "IPv6" },
171 { AFNUM_NSAP, "NSAP" },
172 { AFNUM_HDLC, "HDLC" },
173 { AFNUM_BBN1822, "BBN 1822" },
174 { AFNUM_802, "802" },
175 { AFNUM_E163, "E.163" },
176 { AFNUM_E164, "E.164" },
177 { AFNUM_F69, "F.69" },
178 { AFNUM_X121, "X.121" },
179 { AFNUM_IPX, "IPX" },
180 { AFNUM_ATALK, "Appletalk" },
181 { AFNUM_DECNET, "Decnet IV" },
182 { AFNUM_BANYAN, "Banyan Vines" },
183 { AFNUM_E164NSAP, "E.164 with NSAP subaddress" },
184 { 65535, "Reserved" },
188 static int proto_bgp = -1;
189 static int hf_bgp_type = -1;
191 static gint ett_bgp = -1;
192 static gint ett_bgp_unfeas = -1;
193 static gint ett_bgp_attrs = -1;
194 static gint ett_bgp_attr = -1;
195 static gint ett_bgp_attr_flags = -1;
196 static gint ett_bgp_mp_reach_nlri = -1;
197 static gint ett_bgp_mp_unreach_nlri = -1;
198 static gint ett_bgp_nlri = -1;
199 static gint ett_bgp_open = -1;
200 static gint ett_bgp_update = -1;
201 static gint ett_bgp_notification = -1;
202 static gint ett_bgp_route_refresh = -1; /* ROUTE-REFRESH message tree */
203 static gint ett_bgp_as_paths = -1;
204 static gint ett_bgp_communities = -1;
205 static gint ett_bgp_cluster_list = -1; /* cluster list tree */
206 static gint ett_bgp_options = -1; /* optional parameters tree */
207 static gint ett_bgp_option = -1; /* an optional parameter tree */
210 * Decode an IPv4 prefix.
213 decode_prefix4(const u_char *pd, char *buf, int buflen)
215 guint8 addr[4]; /* IP address */
216 int plen; /* prefix length */
217 int length; /* number of octets needed for prefix */
221 if (plen < 0 || 32 < plen)
223 length = (plen + 7) / 8;
226 memset(addr, 0, sizeof(addr));
227 memcpy(addr, &pd[1], length);
229 addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
231 /* hand back a formatted string */
232 snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
237 * Decode an IPv6 prefix.
240 decode_prefix6(const u_char *pd, char *buf, int buflen)
242 struct e_in6_addr addr; /* IPv6 address */
243 int plen; /* prefix length */
244 int length; /* number of octets needed for prefix */
248 if (plen < 0 || 128 < plen)
250 length = (plen + 7) / 8;
253 memset(&addr, 0, sizeof(addr));
254 memcpy(&addr, &pd[1], length);
256 addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
258 /* hand back a formatted string */
259 snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
264 * Dissect a BGP OPEN message.
267 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
269 struct bgp_open bgpo; /* BGP OPEN message */
270 int hlen; /* message length */
272 int ptype; /* parameter type */
273 int plen; /* parameter length */
274 int ctype; /* capability type */
275 int clen; /* capability length */
276 int ostart; /* options start */
277 const u_char *oend; /* options end */
278 const u_char *p; /* packet offset pointer */
279 proto_item *ti; /* tree item */
280 proto_tree *subtree; /* subtree for options */
281 proto_tree *subtree2; /* subtree for an option */
282 proto_tree *subtree3; /* subtree for an option */
284 /* snarf OPEN message */
285 memcpy(&bgpo, &pd[offset], sizeof(bgpo));
286 hlen = ntohs(bgpo.bgpo_len);
288 proto_tree_add_text(tree, NullTVB,
289 offset + offsetof(struct bgp_open, bgpo_version), 1,
290 "Version: %u", bgpo.bgpo_version);
291 proto_tree_add_text(tree, NullTVB,
292 offset + offsetof(struct bgp_open, bgpo_myas), 2,
293 "My AS: %u", ntohs(bgpo.bgpo_myas));
294 proto_tree_add_text(tree, NullTVB,
295 offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
296 "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
297 proto_tree_add_text(tree, NullTVB,
298 offset + offsetof(struct bgp_open, bgpo_id), 4,
299 "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
300 proto_tree_add_text(tree, NullTVB,
301 offset + offsetof(struct bgp_open, bgpo_optlen), 1,
302 "Optional parameters length: %u %s", bgpo.bgpo_optlen,
303 (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
305 /* optional parameters */
306 if (bgpo.bgpo_optlen > 0) {
307 /* add a subtree and setup some offsets */
308 ostart = offset + sizeof(bgpo) - 3;
309 ti = proto_tree_add_text(tree, NullTVB, ostart, bgpo.bgpo_optlen,
310 "Optional parameters");
311 subtree = proto_item_add_subtree(ti, ett_bgp_options);
313 oend = p + bgpo.bgpo_optlen;
315 /* step through all of the optional parameters */
318 /* grab the type and length */
324 case BGP_OPTION_AUTHENTICATION:
325 proto_tree_add_text(subtree, NullTVB, p - pd - 2, 2 + plen,
326 "Authentication information (%u %s)", plen,
327 (plen == 1) ? "byte" : "bytes");
329 case BGP_OPTION_CAPABILITY:
330 /* grab the capability code */
334 /* check the capability type */
336 case BGP_CAPABILITY_RESERVED:
337 ti = proto_tree_add_text(subtree, NullTVB, p - pd - 4,
338 2 + plen, "Reserved capability (%u %s)", 2 + plen,
339 (plen == 1) ? "byte" : "bytes");
340 subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
341 proto_tree_add_text(subtree2, NullTVB, p - pd - 4,
342 1, "Parameter type: Capabilities (2)");
343 proto_tree_add_text(subtree2, NullTVB, p - pd - 3,
344 1, "Parameter length: %u %s", plen,
345 (plen == 1) ? "byte" : "bytes");
346 proto_tree_add_text(subtree2, NullTVB, p - pd - 2,
347 1, "Capability code: Reserved (0)");
348 proto_tree_add_text(subtree2, NullTVB, p - pd - 1,
349 1, "Capability length: %u %s", clen,
350 (clen == 1) ? "byte" : "bytes");
352 proto_tree_add_text(subtree2, NullTVB, p - pd,
353 clen, "Capability value: Unknown");
357 case BGP_CAPABILITY_MULTIPROTOCOL:
358 ti = proto_tree_add_text(subtree, NullTVB, p - pd - 4,
360 "Multiprotocol extensions capability (%u %s)",
361 2 + plen, (plen == 1) ? "byte" : "bytes");
362 subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
363 proto_tree_add_text(subtree2, NullTVB, p - pd - 4,
364 1, "Parameter type: Capabilities (2)");
365 proto_tree_add_text(subtree2, NullTVB, p - pd - 3,
366 1, "Parameter length: %u %s", plen,
367 (plen == 1) ? "byte" : "bytes");
368 proto_tree_add_text(subtree2, NullTVB, p - pd - 2,
369 1, "Capability code: Multiprotocol extensions (%d)",
372 proto_tree_add_text(subtree2, NullTVB, p - pd - 1,
373 1, "Capability length: Invalid");
374 proto_tree_add_text(subtree2, NullTVB, p - pd,
375 clen, "Capability value: Unknown");
378 proto_tree_add_text(subtree2, NullTVB, p - pd - 1,
379 1, "Capability length: %u %s", clen,
380 (clen == 1) ? "byte" : "bytes");
381 ti = proto_tree_add_text(subtree2, NullTVB, p - pd,
382 clen, "Capability value");
383 subtree3 = proto_item_add_subtree(ti,
387 proto_tree_add_text(subtree3, NullTVB, p - pd,
388 2, "Address family identifier: %s (%u)",
389 val_to_str(i, afnumber, "Unknown"), i);
392 proto_tree_add_text(subtree3, NullTVB, p - pd,
393 1, "Reserved: 1 byte");
397 proto_tree_add_text(subtree3, NullTVB, p - pd,
398 1, "Subsequent address family identifier: %s (%u)",
399 val_to_str(i, bgpattr_nlri_safi,
400 i >= 128 ? "Vendor specific" : "Unknown"), i);
404 case BGP_CAPABILITY_ROUTE_REFRESH:
405 ti = proto_tree_add_text(subtree, NullTVB, p - pd - 4,
406 2 + plen, "Route refresh capability (%u %s)", 2 + plen,
407 (plen == 1) ? "byte" : "bytes");
408 subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
409 proto_tree_add_text(subtree2, NullTVB, p - pd - 4,
410 1, "Parameter type: Capabilities (2)");
411 proto_tree_add_text(subtree2, NullTVB, p - pd - 3,
412 1, "Parameter length: %u %s", plen,
413 (plen == 1) ? "byte" : "bytes");
414 proto_tree_add_text(subtree2, NullTVB, p - pd - 2,
415 1, "Capability code: Route refresh (%d)", ctype);
417 proto_tree_add_text(subtree2, NullTVB, p - pd,
418 clen, "Capability value: Invalid");
421 proto_tree_add_text(subtree2, NullTVB, p - pd - 1,
422 1, "Capability length: %u %s", clen,
423 (clen == 1) ? "byte" : "bytes");
427 /* unknown capability */
429 ti = proto_tree_add_text(subtree, NullTVB, p - pd - 4,
430 2 + plen, "Unknown capability (%u %s)", 2 + plen,
431 (plen == 1) ? "byte" : "bytes");
432 subtree2 = proto_item_add_subtree(ti, ett_bgp_option);
433 proto_tree_add_text(subtree2, NullTVB, p - pd - 4,
434 1, "Parameter type: Capabilities (2)");
435 proto_tree_add_text(subtree2, NullTVB, p - pd - 3,
436 1, "Parameter length: %u %s", plen,
437 (plen == 1) ? "byte" : "bytes");
438 proto_tree_add_text(subtree2, NullTVB, p - pd - 2,
439 1, "Capability code: %s (%d)",
440 ctype >= 128 ? "Private use" : "Unknown", ctype);
441 proto_tree_add_text(subtree2, NullTVB, p - pd - 1,
442 1, "Capability length: %u %s", clen,
443 (clen == 1) ? "byte" : "bytes");
445 proto_tree_add_text(subtree2, NullTVB, p - pd,
446 clen, "Capability value: Unknown");
453 proto_tree_add_text(subtree, NullTVB, p - pd - 2, 2 + plen,
454 "Unknown optional parameter");
462 * Dissect a BGP UPDATE message.
465 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
468 struct bgp bgp; /* BGP header */
469 struct bgp_attr bgpa; /* path attributes */
470 int hlen; /* message length */
471 const u_char *p; /* packet offset pointer */
472 const u_char *q; /* tmp */
473 const u_char *end; /* message end */
475 proto_item *ti; /* tree item */
476 proto_tree *subtree; /* subtree for attibutes */
477 proto_tree *subtree2; /* subtree for attibutes */
478 proto_tree *subtree3; /* subtree for attibutes */
479 proto_tree *as_paths_tree; /* subtree for AS_PATHs */
480 proto_tree *as_path_tree; /* subtree for AS_PATH */
481 proto_tree *communities_tree; /* subtree for COMMUNITIES */
482 proto_tree *community_tree; /* subtree for a community */
483 proto_tree *cluster_list_tree; /* subtree for CLUSTER_LIST */
485 guint8 length; /* AS_PATH length */
486 guint8 type; /* AS_PATH type */
487 char *as_path_str = NULL; /* AS_PATH string */
488 char *communities_str = NULL; /* COMMUNITIES string */
489 char *cluster_list_str = NULL; /* CLUSTER_LIST string */
490 char junk_buf[256]; /* tmp */
493 /* snarf UPDATE message */
494 memcpy(&bgp, &pd[offset], sizeof(bgp));
495 hlen = ntohs(bgp.bgp_len);
496 p = &pd[offset + BGP_HEADER_SIZE]; /*XXX*/
498 /* check for withdrawals */
500 proto_tree_add_text(tree, NullTVB, p - pd, 2,
501 "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
504 /* parse unfeasible prefixes */
506 ti = proto_tree_add_text(tree, NullTVB, p - pd, len, "Withdrawn routes:");
507 subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
509 /* parse each prefixes */
512 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
513 proto_tree_add_text(subtree, NullTVB, p - pd, i, "%s", junk_buf);
521 /* check for advertisements */
523 proto_tree_add_text(tree, NullTVB, p - pd, 2, "Total path attribute length: %u %s",
524 len, (len == 1) ? "byte" : "bytes");
526 /* path attributes */
528 ti = proto_tree_add_text(tree, NullTVB, p - pd + 2, len, "Path attributes");
529 subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
537 memcpy(&bgpa, &p[i], sizeof(bgpa));
538 /* check for the Extended Length bit */
539 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
540 alen = pntohs(&p[i + sizeof(bgpa)]);
541 aoff = sizeof(bgpa) + 2;
543 alen = p[i + sizeof(bgpa)];
544 aoff = sizeof(bgpa) + 1;
547 /* This is kind of ugly - similar code appears twice, but it
548 helps browsing attrs. */
549 /* the first switch prints things in the title of the subtree */
550 switch (bgpa.bgpa_type) {
553 goto default_attribute_top;
554 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
555 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
557 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
558 msg, alen + aoff, (alen + aoff == 1) ? "byte" :
561 case BGPTYPE_AS_PATH:
563 (p + current attribute + 3 bytes to first tuple) */
564 end = p + alen + i + 3;
566 /* must be freed by second switch! */
567 /* "alen * 6" (5 digits + space) should be a good estimate
568 of how long the AS path string could be */
569 as_path_str = malloc((alen + 1) * 6);
570 if (as_path_str == NULL) break;
571 as_path_str[0] = '\0';
573 /* snarf each AS path */
576 if (type == AS_SET) {
577 snprintf(as_path_str, 2, "{");
579 else if (type == AS_CONFED_SET) {
580 snprintf(as_path_str, 2, "[");
582 else if (type == AS_CONFED_SEQUENCE) {
583 snprintf(as_path_str, 2, "(");
587 /* snarf each value in path */
588 for (j = 0; j < length; j++) {
589 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
590 (type == AS_SET || type == AS_CONFED_SET)
592 strncat(as_path_str, junk_buf, sizeof(junk_buf));
596 /* cleanup end of string */
597 if (type == AS_SET) {
598 as_path_str[strlen(as_path_str) - 2] = '}';
600 else if (type == AS_CONFED_SET) {
601 as_path_str[strlen(as_path_str) - 2] = ']';
603 else if (type == AS_CONFED_SEQUENCE) {
604 as_path_str[strlen(as_path_str) - 1] = ')';
607 as_path_str[strlen(as_path_str) - 1] = '\0';
611 /* check for empty AS_PATH */
613 strncpy(as_path_str, "empty", 6);
615 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
617 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
618 as_path_str, alen + aoff,
619 (alen + aoff == 1) ? "byte" : "bytes");
621 case BGPTYPE_NEXT_HOP:
623 goto default_attribute_top;
624 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
626 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
627 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
630 case BGPTYPE_MULTI_EXIT_DISC:
632 goto default_attribute_top;
633 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
635 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
636 pntohl(&p[i + aoff]), alen + aoff,
637 (alen + aoff == 1) ? "byte" : "bytes");
639 case BGPTYPE_LOCAL_PREF:
641 goto default_attribute_top;
642 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
644 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
645 pntohl(&p[i + aoff]), alen + aoff,
646 (alen + aoff == 1) ? "byte" : "bytes");
648 case BGPTYPE_ATOMIC_AGGREGATE:
650 goto default_attribute_top;
651 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
653 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
654 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
656 case BGPTYPE_AGGREGATOR:
658 goto default_attribute_top;
659 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
660 "%s: AS: %u origin: %s (%u %s)",
661 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
662 pntohs(&p[i + aoff]),
663 ip_to_str(&p[i + aoff + 2]), alen + aoff,
664 (alen + aoff == 1) ? "byte" : "bytes");
666 case BGPTYPE_COMMUNITIES:
668 goto default_attribute_top;
671 (p + current attribute + 3 bytes to first tuple) */
672 end = p + alen + i + 3;
674 /* must be freed by second switch! */
675 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be
676 a good estimate of how long the communities string could
678 communities_str = malloc((alen + 1) * 12);
679 if (communities_str == NULL) break;
680 communities_str[0] = '\0';
681 memset(junk_buf, 0, sizeof(junk_buf));
683 /* snarf each community */
685 /* check for well-known communities */
686 if (pntohl(q) == BGP_COMM_NO_EXPORT)
687 strncpy(junk_buf, "NO_EXPORT ", 10);
688 else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
689 strncpy(junk_buf, "NO_ADVERTISE ", 13);
690 else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
691 strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
693 snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
699 strncat(communities_str, junk_buf, sizeof(junk_buf));
701 /* cleanup end of string */
702 communities_str[strlen(communities_str) - 1] = '\0';
704 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
706 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
707 communities_str, alen + aoff,
708 (alen + aoff == 1) ? "byte" : "bytes");
710 case BGPTYPE_ORIGINATOR_ID:
712 goto default_attribute_top;
713 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
715 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
716 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
719 case BGPTYPE_CLUSTER_LIST:
721 goto default_attribute_top;
724 (p + current attribute + 3 bytes to first tuple) */
725 end = p + alen + i + 3;
727 /* must be freed by second switch! */
728 /* "alen * 16" (12 digits, 3 dots + space ) should be
729 a good estimate of how long the cluster_list string could
731 cluster_list_str = malloc((alen + 1) * 16);
732 if (cluster_list_str == NULL) break;
733 cluster_list_str[0] = '\0';
734 memset(junk_buf, 0, sizeof(junk_buf));
736 /* snarf each cluster list */
738 snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(q));
739 strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
742 /* cleanup end of string */
743 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
745 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
747 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
748 cluster_list_str, alen + aoff,
749 (alen + aoff == 1) ? "byte" : "bytes");
752 default_attribute_top:
753 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
755 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
756 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
757 } /* end of first switch */
758 subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
760 /* figure out flags */
762 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
763 strncat(junk_buf, "Optional, ", 10);
766 strncat(junk_buf, "Well-known, ", 12);
768 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
769 strncat(junk_buf, "Transitive, ", 12);
772 strncat(junk_buf, "Non-transitive, ", 16);
774 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
775 strncat(junk_buf, "Partial, ", 9);
778 strncat(junk_buf, "Complete, ", 10);
780 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
781 strncat(junk_buf, "Extended Length, ", 17);
783 /* stomp last ", " */
784 j = strlen(junk_buf);
785 junk_buf[j - 2] = '\0';
786 ti = proto_tree_add_text(subtree2, NullTVB,
787 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
788 "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
789 subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
791 /* add flag bitfield subtrees */
792 proto_tree_add_text(subtree3, NullTVB,
793 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
794 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
795 BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
796 proto_tree_add_text(subtree3, NullTVB,
797 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
798 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
799 BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
801 proto_tree_add_text(subtree3, NullTVB,
802 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
803 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
804 BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
805 proto_tree_add_text(subtree3, NullTVB,
806 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
807 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
808 BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
811 proto_tree_add_text(subtree2, NullTVB,
812 p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
813 "Type code: %s (%u)",
814 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
817 proto_tree_add_text(subtree2, NullTVB, p - pd + i + sizeof(bgpa),
818 aoff - sizeof(bgpa), "Length: %d %s", alen,
819 (alen == 1) ? "byte" : "bytes");
821 /* the second switch prints things in the actual subtree of each
823 switch (bgpa.bgpa_type) {
826 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
827 "Origin (invalid): %u %s", alen,
828 (alen == 1) ? "byte" : "bytes");
830 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
831 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 1,
832 "Origin: %s (%u)", msg, p[i + aoff]);
835 case BGPTYPE_AS_PATH:
836 /* check for empty AS_PATH */
842 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
843 "AS path: %s", as_path_str);
844 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
847 (p + current attribute + 3 bytes to first tuple) */
848 end = p + alen + i + 3;
851 /* snarf each AS path tuple, we have to step through each one
852 again to make a separate subtree so we can't just reuse
853 as_path_str from above */
855 as_path_str[0] = '\0';
857 if (type == AS_SET) {
858 snprintf(as_path_str, 2, "{");
860 else if (type == AS_CONFED_SET) {
861 snprintf(as_path_str, 2, "[");
863 else if (type == AS_CONFED_SEQUENCE) {
864 snprintf(as_path_str, 2, "(");
868 /* snarf each value in path, we're just going to reuse
869 as_path_str since we already have it malloced */
870 for (j = 0; j < length; j++) {
871 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
872 (type == AS_SET || type == AS_CONFED_SET)
874 strncat(as_path_str, junk_buf, sizeof(junk_buf));
878 /* cleanup end of string */
879 if (type == AS_SET) {
880 as_path_str[strlen(as_path_str) - 2] = '}';
882 else if (type == AS_CONFED_SET) {
883 as_path_str[strlen(as_path_str) - 2] = ']';
885 else if (type == AS_CONFED_SEQUENCE) {
886 as_path_str[strlen(as_path_str) - 1] = ')';
889 as_path_str[strlen(as_path_str) - 1] = '\0';
892 /* length here means number of ASs, ie length * 2 bytes */
893 ti = proto_tree_add_text(as_paths_tree, NullTVB,
894 q - pd - length * 2 - 2,
895 length * 2 + 2, "AS path segment: %s", as_path_str);
896 as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
897 proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2 - 2,
898 1, "Path segment type: %s (%u)",
899 val_to_str(type, as_segment_type, "Unknown"), type);
900 proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2 - 1,
901 1, "Path segment length: %u %s", length,
902 (length == 1) ? "AS" : "ASs");
904 /* backup and reprint path segment value(s) only */
906 as_path_str[0] = '\0';
907 for (j = 0; j < length; j++) {
908 snprintf(junk_buf, sizeof(junk_buf), "%u ", pntohs(q));
909 strncat(as_path_str, junk_buf, sizeof(junk_buf));
912 as_path_str[strlen(as_path_str) - 1] = '\0';
914 proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2,
915 length * 2, "Path segment value: %s", as_path_str);
920 case BGPTYPE_NEXT_HOP:
922 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
923 "Next hop (invalid): %u %s", alen,
924 (alen == 1) ? "byte" : "bytes");
926 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
927 "Next hop: %s", ip_to_str(&p[i + aoff]));
930 case BGPTYPE_MULTI_EXIT_DISC:
932 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
933 "Multiple exit discriminator (invalid): %u %s",
934 alen, (alen == 1) ? "byte" : "bytes");
936 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
937 "Multiple exit discriminator: %u",
938 pntohl(&p[i + aoff]));
941 case BGPTYPE_LOCAL_PREF:
943 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
944 "Local preference (invalid): %u %s", alen,
945 (alen == 1) ? "byte" : "bytes");
947 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
948 "Local preference: %u", pntohl(&p[i + aoff]));
951 case BGPTYPE_ATOMIC_AGGREGATE:
953 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
954 "Atomic aggregate (invalid): %u %s", alen,
955 (alen == 1) ? "byte" : "bytes");
958 case BGPTYPE_AGGREGATOR:
960 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
961 "Aggregator (invalid): %u %s", alen,
962 (alen == 1) ? "byte" : "bytes");
964 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
965 "Aggregator AS: %u", pntohs(&p[i + aoff]));
966 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 4,
967 "Aggregator origin: %s",
968 ip_to_str(&p[i + aoff + 2]));
971 case BGPTYPE_COMMUNITIES:
973 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
974 "Communities (invalid): %u %s", alen,
975 (alen == 1) ? "byte" : "bytes");
976 free(communities_str);
980 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
981 "Communities: %s", communities_str);
982 communities_tree = proto_item_add_subtree(ti,
983 ett_bgp_communities);
986 (p + current attribute + 3 bytes to first tuple) */
987 end = p + alen + i + 3;
990 /* snarf each community */
992 /* check for reserved values */
993 if (pntohs(q) == FOURHEX0 || pntohs(q) == FOURHEXF) {
994 /* check for well-known communities */
995 if (pntohl(q) == BGP_COMM_NO_EXPORT)
996 proto_tree_add_text(communities_tree, NullTVB,
997 q - pd - 3 + aoff, 4,
998 "Community: NO_EXPORT (0x%x)", pntohl(q));
999 else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
1000 proto_tree_add_text(communities_tree, NullTVB,
1001 q - pd - 3 + aoff, 4,
1002 "Community: NO_ADVERTISE (0x%x)", pntohl(q));
1003 else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
1004 proto_tree_add_text(communities_tree, NullTVB,
1005 q - pd - 3 + aoff, 4,
1006 "Community: NO_EXPORT_SUBCONFED (0x%x)",
1009 proto_tree_add_text(communities_tree, NullTVB,
1010 q - pd - 3 + aoff, 4,
1011 "Community (reserved): 0x%x", pntohl(q));
1015 ti = proto_tree_add_text(communities_tree, NullTVB,
1016 q - pd - 3 + aoff, 4, "Community: %u:%u",
1017 pntohs(q), pntohs(q + 2));
1018 community_tree = proto_item_add_subtree(ti,
1019 ett_bgp_communities);
1020 proto_tree_add_text(community_tree, NullTVB, q - pd - 3 + aoff,
1021 2, "Community AS: %u", pntohs(q));
1022 proto_tree_add_text(community_tree, NullTVB, q - pd - 1 + aoff,
1023 2, "Community value: %u", pntohs(q + 2));
1029 free(communities_str);
1031 case BGPTYPE_ORIGINATOR_ID:
1033 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1034 "Originator identifier (invalid): %u %s", alen,
1035 (alen == 1) ? "byte" : "bytes");
1037 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1038 "Originator identifier: %s",
1039 ip_to_str(&p[i + aoff]));
1042 case BGPTYPE_MP_REACH_NLRI:
1043 af = pntohs(&p[i + aoff]);
1044 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
1045 "Address family: %s (%u)",
1046 val_to_str(af, afnumber, "Unknown"), af);
1047 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 1,
1048 "Subsequent address family identifier: %s (%u)",
1049 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
1050 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
1052 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 3, 1,
1053 "Next hop network address (%d %s)",
1054 p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" :
1056 if (af == AFNUM_INET || af == AFNUM_INET6) {
1060 subtree3 = proto_item_add_subtree(ti,
1061 ett_bgp_mp_reach_nlri);
1064 while (j < p[i + aoff + 3]) {
1065 if (af == AFNUM_INET)
1067 else if (af == AFNUM_INET6)
1071 if (j + advance > p[i + aoff + 3])
1074 if (af == AFNUM_INET)
1075 s = ip_to_str(&p[i + aoff + 4 + j]);
1077 s = ip6_to_str((struct e_in6_addr *)
1078 &p[i + aoff + 4 + j]);
1080 proto_tree_add_text(subtree3, NullTVB,
1081 p - pd + i + aoff + 4 + j, advance,
1087 alen -= (p[i + aoff + 3] + 4);
1088 aoff += (p[i + aoff + 3] + 4);
1091 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 1,
1092 "Subnetwork points of attachment: %u", snpa);
1095 subtree3 = proto_item_add_subtree(ti,
1096 ett_bgp_mp_reach_nlri);
1097 for (/*nothing*/; snpa > 0; snpa--) {
1098 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff + off, 1,
1099 "SNPA length: %u", p[i + aoff + off]);
1101 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff + off,
1102 p[i + aoff + off - 1],
1103 "SNPA (%u %s)", p[i + aoff + off - 1],
1104 (p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
1105 off += p[i + aoff + off - 1];
1110 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1111 "Network layer reachability information (%u %s)",
1112 alen, (alen == 1) ? "byte" : "bytes");
1114 subtree3 = proto_item_add_subtree(ti,
1115 ett_bgp_mp_unreach_nlri);
1120 if (af == AFNUM_INET) {
1121 advance = decode_prefix4(&p[i + aoff], buf,
1123 } else if (af == AFNUM_INET6) {
1124 advance = decode_prefix6(&p[i + aoff], buf,
1132 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff, advance,
1133 "Network layer reachability information: %s", buf);
1140 case BGPTYPE_MP_UNREACH_NLRI:
1141 af = pntohs(&p[i + aoff]);
1142 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
1143 "Address family: %s (%u)",
1144 val_to_str(af, afnumber, "Unknown"), af);
1145 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 1,
1146 "Subsequent address family identifier: %s (%u)",
1147 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
1148 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
1150 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 3,
1151 alen - 3, "Withdrawn routes (%u %s)", alen - 3,
1152 (alen - 3 == 1) ? "byte" : "bytes");
1157 subtree3 = proto_item_add_subtree(ti,
1158 ett_bgp_mp_unreach_nlri);
1163 if (af == AFNUM_INET) {
1164 advance = decode_prefix4(&p[i + aoff], buf,
1166 } else if (af == AFNUM_INET6) {
1167 advance = decode_prefix6(&p[i + aoff], buf,
1175 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff, advance,
1176 "Withdrawn route: %s", buf);
1183 case BGPTYPE_CLUSTER_LIST:
1184 if (alen % 4 != 0) {
1185 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1186 "Cluster list (invalid): %u %s", alen,
1187 (alen == 1) ? "byte" : "bytes");
1188 free(cluster_list_str);
1192 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1193 "Cluster list: %s", cluster_list_str);
1194 cluster_list_tree = proto_item_add_subtree(ti,
1195 ett_bgp_cluster_list);
1198 (p + current attribute + 3 bytes to first tuple) */
1199 end = p + alen + i + 3;
1202 /* snarf each cluster identifier */
1204 ti = proto_tree_add_text(cluster_list_tree, NullTVB,
1205 q - pd - 3 + aoff, 4, "Cluster identifier: %s",
1211 free(cluster_list_str);
1214 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1215 "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
1218 } /* end of second switch */
1225 len = hlen - (p - &pd[offset]);
1227 /* parse prefixes */
1229 ti = proto_tree_add_text(tree, NullTVB, p - pd, len,
1230 "Network layer reachability information: %u %s", len,
1231 (len == 1) ? "byte" : "bytes");
1232 subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1235 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
1236 proto_tree_add_text(subtree, NullTVB, p - pd, i, "%s", junk_buf);
1244 * Dissect a BGP NOTIFICATION message.
1247 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
1250 struct bgp_notification bgpn; /* BGP NOTIFICATION message */
1251 int hlen; /* message length */
1252 char *p; /* string pointer */
1255 memcpy(&bgpn, &pd[offset], sizeof(bgpn));
1256 hlen = ntohs(bgpn.bgpn_len);
1258 /* print error code */
1259 proto_tree_add_text(tree, NullTVB,
1260 offset + offsetof(struct bgp_notification, bgpn_major), 1,
1261 "Error code: %s (%u)",
1262 val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1265 /* print error subcode */
1266 if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1267 && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1268 p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1270 } else if (bgpn.bgpn_minor == 0)
1274 proto_tree_add_text(tree, NullTVB,
1275 offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1276 "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1278 /* only print if there is optional data */
1279 if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1280 proto_tree_add_text(tree, NullTVB, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1281 hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1286 * Dissect a BGP ROUTE-REFRESH message.
1289 dissect_bgp_route_refresh(const u_char *pd, int offset, frame_data *fd,
1292 const u_char *p; /* string pointer */
1296 p = &pd[offset + BGP_HEADER_SIZE];
1298 proto_tree_add_text(tree, NullTVB, offset + BGP_HEADER_SIZE, 2,
1299 "Address family identifier: %s (%u)",
1300 val_to_str(i, afnumber, "Unknown"), i);
1303 proto_tree_add_text(tree, NullTVB, offset + BGP_HEADER_SIZE + 2, 1,
1304 "Reserved: 1 byte");
1308 proto_tree_add_text(tree, NullTVB, offset + BGP_HEADER_SIZE + 3, 1,
1309 "Subsequent address family identifier: %s (%u)",
1310 val_to_str(i, bgpattr_nlri_safi,
1311 i >= 128 ? "Vendor specific" : "Unknown"),
1316 * Dissect a BGP packet.
1319 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1321 proto_item *ti; /* tree item */
1322 proto_tree *bgp_tree; /* BGP packet tree */
1323 proto_tree *bgp1_tree; /* BGP message tree */
1324 const u_char *p; /* packet offset pointer */
1326 int found; /* number of BGP messages in packet */
1327 static u_char marker[] = { /* BGP message marker */
1328 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1329 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1331 struct bgp bgp; /* BGP header */
1332 int hlen; /* BGP header length */
1333 char *typ; /* BGP message type */
1335 OLD_CHECK_DISPLAY_AS_DATA(proto_bgp, pd, offset, fd, tree);
1337 if (check_col(fd, COL_PROTOCOL))
1338 col_set_str(fd, COL_PROTOCOL, "BGP");
1344 /* run through the TCP packet looking for BGP headers */
1345 /* this is done twice, but this way each message type can be
1346 printed in the COL_INFO field */
1348 /* look for bgp header */
1353 CHECK_SIZE(i, sizeof(marker), l);
1354 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1359 memcpy(&bgp, &p[i], sizeof(bgp));
1361 hlen = ntohs(bgp.bgp_len);
1362 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1364 if (check_col(fd, COL_INFO)) {
1366 col_add_fstr(fd, COL_INFO, "%s", typ);
1368 col_append_fstr(fd, COL_INFO, ", %s", typ);
1375 ti = proto_tree_add_item(tree, proto_bgp, NullTVB, offset,
1376 END_OF_FRAME, FALSE);
1377 bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1382 /* now, run through the TCP packet again, this time dissect */
1383 /* each message that we find */
1385 /* look for bgp header */
1390 CHECK_SIZE(i, sizeof(marker), l);
1391 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1396 memcpy(&bgp, &p[i], sizeof(bgp));
1397 hlen = ntohs(bgp.bgp_len);
1398 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1399 if (END_OF_FRAME < hlen) {
1400 ti = proto_tree_add_text(bgp_tree, NullTVB, offset + i,
1401 END_OF_FRAME, "%s (truncated)", typ);
1403 ti = proto_tree_add_text(bgp_tree, NullTVB, offset + i, hlen,
1406 /* add a different tree for each message type */
1407 switch (bgp.bgp_type) {
1409 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1412 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1414 case BGP_NOTIFICATION:
1415 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1418 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1420 case BGP_ROUTE_REFRESH:
1421 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
1424 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1428 proto_tree_add_text(bgp1_tree, NullTVB, offset + i, BGP_MARKER_SIZE,
1429 "Marker: 16 bytes");
1431 if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1432 proto_tree_add_text(bgp1_tree, NullTVB,
1433 offset + i + offsetof(struct bgp, bgp_len), 2,
1434 "Length (invalid): %u %s", hlen,
1435 (hlen == 1) ? "byte" : "bytes");
1437 proto_tree_add_text(bgp1_tree, NullTVB,
1438 offset + i + offsetof(struct bgp, bgp_len), 2,
1439 "Length: %u %s", hlen,
1440 (hlen == 1) ? "byte" : "bytes");
1443 proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, NullTVB,
1445 offsetof(struct bgp, bgp_type), 1,
1447 "Type: %s (%u)", typ, bgp.bgp_type);
1449 CHECK_SIZE(i, hlen, l);
1451 /* handle each message type */
1452 switch (bgp.bgp_type) {
1454 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
1457 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
1459 case BGP_NOTIFICATION:
1460 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
1463 /* no data in KEEPALIVE messages */
1465 case BGP_ROUTE_REFRESH:
1466 dissect_bgp_route_refresh(pd, offset + i, fd, bgp1_tree);
1478 * Register ourselves.
1481 proto_register_bgp(void)
1484 static hf_register_info hf[] = {
1486 { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
1487 VALS(bgptypevals), 0x0, "BGP message type" }},
1490 static gint *ett[] = {
1495 &ett_bgp_attr_flags,
1496 &ett_bgp_mp_reach_nlri,
1497 &ett_bgp_mp_unreach_nlri,
1501 &ett_bgp_notification,
1502 &ett_bgp_route_refresh,
1504 &ett_bgp_communities,
1505 &ett_bgp_cluster_list,
1510 proto_bgp = proto_register_protocol("Border Gateway Protocol",
1512 proto_register_field_array(proto_bgp, hf, array_length(hf));
1513 proto_register_subtree_array(ett, array_length(ett));
1517 proto_reg_handoff_bgp(void)
1519 old_dissector_add("tcp.port", BGP_TCP_PORT, dissect_bgp);