2 * Routines for BGP packet dissection.
3 * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-bgp.c,v 1.34 2001/04/17 21:25:13 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(tvbuff_t *tvb, gint offset, char *buf, int buflen)
215 guint8 addr[4]; /* IP address */
216 int plen; /* prefix length */
217 int length; /* number of octets needed for prefix */
220 plen = tvb_get_guint8(tvb, offset);
221 if (plen < 0 || 32 < plen)
223 length = (plen + 7) / 8;
226 memset(addr, 0, sizeof(addr));
227 tvb_memcpy(tvb, addr, offset + 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(tvbuff_t *tvb, gint offset, 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 */
247 plen = tvb_get_guint8(tvb, offset);
248 if (plen < 0 || 128 < plen)
250 length = (plen + 7) / 8;
253 memset(&addr, 0, sizeof(addr));
254 tvb_memcpy(tvb, (guint8 *)&addr, offset + 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(tvbuff_t *tvb, int offset, 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 int oend; /* options end */
278 int p; /* tvb offset counter */
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 tvb_memcpy(tvb, bgpo.bgpo_marker, offset, BGP_MIN_OPEN_MSG_SIZE);
286 hlen = ntohs(bgpo.bgpo_len);
288 proto_tree_add_text(tree, tvb,
289 offset + offsetof(struct bgp_open, bgpo_version), 1,
290 "Version: %u", bgpo.bgpo_version);
291 proto_tree_add_text(tree, tvb,
292 offset + offsetof(struct bgp_open, bgpo_myas), 2,
293 "My AS: %u", ntohs(bgpo.bgpo_myas));
294 proto_tree_add_text(tree, tvb,
295 offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
296 "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
297 proto_tree_add_text(tree, tvb,
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, tvb,
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 + BGP_MIN_OPEN_MSG_SIZE;
309 ti = proto_tree_add_text(tree, tvb, 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 */
319 ptype = tvb_get_guint8(tvb, p++);
320 plen = tvb_get_guint8(tvb, p++);
324 case BGP_OPTION_AUTHENTICATION:
325 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
326 "Authentication information (%u %s)", plen,
327 (plen == 1) ? "byte" : "bytes");
329 case BGP_OPTION_CAPABILITY:
330 /* grab the capability code */
331 ctype = tvb_get_guint8(tvb, p++);
332 clen = tvb_get_guint8(tvb, p++);
334 /* check the capability type */
336 case BGP_CAPABILITY_RESERVED:
337 ti = proto_tree_add_text(subtree, tvb, p - 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, tvb, p - 4,
342 1, "Parameter type: Capabilities (2)");
343 proto_tree_add_text(subtree2, tvb, p - 3,
344 1, "Parameter length: %u %s", plen,
345 (plen == 1) ? "byte" : "bytes");
346 proto_tree_add_text(subtree2, tvb, p - 2,
347 1, "Capability code: Reserved (0)");
348 proto_tree_add_text(subtree2, tvb, p - 1,
349 1, "Capability length: %u %s", clen,
350 (clen == 1) ? "byte" : "bytes");
352 proto_tree_add_text(subtree2, tvb, p,
353 clen, "Capability value: Unknown");
357 case BGP_CAPABILITY_MULTIPROTOCOL:
358 ti = proto_tree_add_text(subtree, tvb, p - 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, tvb, p - 4,
364 1, "Parameter type: Capabilities (2)");
365 proto_tree_add_text(subtree2, tvb, p - 3,
366 1, "Parameter length: %u %s", plen,
367 (plen == 1) ? "byte" : "bytes");
368 proto_tree_add_text(subtree2, tvb, p - 2,
369 1, "Capability code: Multiprotocol extensions (%d)",
372 proto_tree_add_text(subtree2, tvb, p - 1,
373 1, "Capability length: Invalid");
374 proto_tree_add_text(subtree2, tvb, p,
375 clen, "Capability value: Unknown");
378 proto_tree_add_text(subtree2, tvb, p - 1,
379 1, "Capability length: %u %s", clen,
380 (clen == 1) ? "byte" : "bytes");
381 ti = proto_tree_add_text(subtree2, tvb, p,
382 clen, "Capability value");
383 subtree3 = proto_item_add_subtree(ti,
386 i = tvb_get_ntohs(tvb, p);
387 proto_tree_add_text(subtree3, tvb, p,
388 2, "Address family identifier: %s (%u)",
389 val_to_str(i, afnumber, "Unknown"), i);
392 proto_tree_add_text(subtree3, tvb, p,
393 1, "Reserved: 1 byte");
396 i = tvb_get_guint8(tvb, p);
397 proto_tree_add_text(subtree3, tvb, p,
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, tvb, p - 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, tvb, p - 4,
410 1, "Parameter type: Capabilities (2)");
411 proto_tree_add_text(subtree2, tvb, p - 3,
412 1, "Parameter length: %u %s", plen,
413 (plen == 1) ? "byte" : "bytes");
414 proto_tree_add_text(subtree2, tvb, p - 2,
415 1, "Capability code: Route refresh (%d)", ctype);
417 proto_tree_add_text(subtree2, tvb, p,
418 clen, "Capability value: Invalid");
421 proto_tree_add_text(subtree2, tvb, p - 1,
422 1, "Capability length: %u %s", clen,
423 (clen == 1) ? "byte" : "bytes");
427 /* unknown capability */
429 ti = proto_tree_add_text(subtree, tvb, p - 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, tvb, p - 4,
434 1, "Parameter type: Capabilities (2)");
435 proto_tree_add_text(subtree2, tvb, p - 3,
436 1, "Parameter length: %u %s", plen,
437 (plen == 1) ? "byte" : "bytes");
438 proto_tree_add_text(subtree2, tvb, p - 2,
439 1, "Capability code: %s (%d)",
440 ctype >= 128 ? "Private use" : "Unknown", ctype);
441 proto_tree_add_text(subtree2, tvb, p - 1,
442 1, "Capability length: %u %s", clen,
443 (clen == 1) ? "byte" : "bytes");
445 proto_tree_add_text(subtree2, tvb, p,
446 clen, "Capability value: Unknown");
453 proto_tree_add_text(subtree, tvb, p - 2, 2 + plen,
454 "Unknown optional parameter");
462 * Dissect a BGP UPDATE message.
465 dissect_bgp_update(tvbuff_t *tvb, int offset, proto_tree *tree)
467 struct bgp_attr bgpa; /* path attributes */
468 int hlen; /* message length */
469 gint o; /* packet offset */
471 gint end; /* message end */
473 proto_item *ti; /* tree item */
474 proto_tree *subtree; /* subtree for attibutes */
475 proto_tree *subtree2; /* subtree for attibutes */
476 proto_tree *subtree3; /* subtree for attibutes */
477 proto_tree *as_paths_tree; /* subtree for AS_PATHs */
478 proto_tree *as_path_tree; /* subtree for AS_PATH */
479 proto_tree *communities_tree; /* subtree for COMMUNITIES */
480 proto_tree *community_tree; /* subtree for a community */
481 proto_tree *cluster_list_tree; /* subtree for CLUSTER_LIST */
483 guint8 length; /* AS_PATH length */
484 guint8 type; /* AS_PATH type */
485 char *as_path_str = NULL; /* AS_PATH string */
486 char *communities_str = NULL; /* COMMUNITIES string */
487 char *cluster_list_str = NULL; /* CLUSTER_LIST string */
488 char junk_buf[256]; /* tmp */
489 guint8 ipaddr[4]; /* IPv4 address */
490 struct e_in6_addr ip6addr; /* IPv6 address */
492 hlen = tvb_get_ntohs(tvb, offset + BGP_MARKER_SIZE);
493 o = offset + BGP_HEADER_SIZE;
495 /* check for withdrawals */
496 len = tvb_get_ntohs(tvb, o);
497 proto_tree_add_text(tree, tvb, o, 2,
498 "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
501 /* parse unfeasible prefixes */
503 ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
504 subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
506 /* parse each prefixes */
509 i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
510 proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
518 /* check for advertisements */
519 len = tvb_get_ntohs(tvb, o);
520 proto_tree_add_text(tree, tvb, o, 2, "Total path attribute length: %u %s",
521 len, (len == 1) ? "byte" : "bytes");
523 /* path attributes */
525 ti = proto_tree_add_text(tree, tvb, o + 2, len, "Path attributes");
526 subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
534 tvb_memcpy(tvb, (guint8 *)&bgpa, o + i, sizeof(bgpa));
535 /* check for the Extended Length bit */
536 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
537 alen = tvb_get_ntohs(tvb, o + i + sizeof(bgpa));
538 aoff = sizeof(bgpa) + 2;
540 alen = tvb_get_guint8(tvb, o + i + sizeof(bgpa));
541 aoff = sizeof(bgpa) + 1;
544 /* This is kind of ugly - similar code appears twice, but it
545 helps browsing attrs. */
546 /* the first switch prints things in the title of the subtree */
547 switch (bgpa.bgpa_type) {
550 goto default_attribute_top;
551 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
552 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
554 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
555 msg, alen + aoff, (alen + aoff == 1) ? "byte" :
558 case BGPTYPE_AS_PATH:
560 (o + current attribute + 3 bytes to first tuple) */
561 end = o + alen + i + 3;
563 /* must be freed by second switch! */
564 /* "alen * 6" (5 digits + space) should be a good estimate
565 of how long the AS path string could be */
566 as_path_str = malloc((alen + 1) * 6);
567 if (as_path_str == NULL) break;
568 as_path_str[0] = '\0';
570 /* snarf each AS path */
572 type = tvb_get_guint8(tvb, q++);
573 if (type == AS_SET) {
574 snprintf(as_path_str, 2, "{");
576 else if (type == AS_CONFED_SET) {
577 snprintf(as_path_str, 2, "[");
579 else if (type == AS_CONFED_SEQUENCE) {
580 snprintf(as_path_str, 2, "(");
582 length = tvb_get_guint8(tvb, q++);
584 /* snarf each value in path */
585 for (j = 0; j < length; j++) {
586 snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
587 (type == AS_SET || type == AS_CONFED_SET)
589 strncat(as_path_str, junk_buf, sizeof(junk_buf));
593 /* cleanup end of string */
594 if (type == AS_SET) {
595 as_path_str[strlen(as_path_str) - 2] = '}';
597 else if (type == AS_CONFED_SET) {
598 as_path_str[strlen(as_path_str) - 2] = ']';
600 else if (type == AS_CONFED_SEQUENCE) {
601 as_path_str[strlen(as_path_str) - 1] = ')';
604 as_path_str[strlen(as_path_str) - 1] = '\0';
608 /* check for empty AS_PATH */
610 strncpy(as_path_str, "empty", 6);
612 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
614 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
615 as_path_str, alen + aoff,
616 (alen + aoff == 1) ? "byte" : "bytes");
618 case BGPTYPE_NEXT_HOP:
620 goto default_attribute_top;
621 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
622 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
624 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
625 ip_to_str(ipaddr), alen + aoff, (alen + aoff == 1)
628 case BGPTYPE_MULTI_EXIT_DISC:
630 goto default_attribute_top;
631 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
633 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
634 tvb_get_ntohl(tvb, o + i + aoff), alen + aoff,
635 (alen + aoff == 1) ? "byte" : "bytes");
637 case BGPTYPE_LOCAL_PREF:
639 goto default_attribute_top;
640 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
642 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
643 tvb_get_ntohl(tvb, o + i + aoff), alen + aoff,
644 (alen + aoff == 1) ? "byte" : "bytes");
646 case BGPTYPE_ATOMIC_AGGREGATE:
648 goto default_attribute_top;
649 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
651 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
652 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
654 case BGPTYPE_AGGREGATOR:
656 goto default_attribute_top;
657 tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
658 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
659 "%s: AS: %u origin: %s (%u %s)",
660 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
661 tvb_get_ntohs(tvb, o + i + aoff),
662 ip_to_str(ipaddr), alen + aoff,
663 (alen + aoff == 1) ? "byte" : "bytes");
665 case BGPTYPE_COMMUNITIES:
667 goto default_attribute_top;
670 (o + current attribute + 3 bytes to first tuple) */
671 end = o + alen + i + 3;
673 /* must be freed by second switch! */
674 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be
675 a good estimate of how long the communities string could
677 communities_str = malloc((alen + 1) * 12);
678 if (communities_str == NULL) break;
679 communities_str[0] = '\0';
680 memset(junk_buf, 0, sizeof(junk_buf));
682 /* snarf each community */
684 /* check for well-known communities */
685 if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
686 strncpy(junk_buf, "NO_EXPORT ", 10);
687 else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
688 strncpy(junk_buf, "NO_ADVERTISE ", 13);
689 else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
690 strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
692 snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
693 tvb_get_ntohs(tvb, q),
694 tvb_get_ntohs(tvb, q + 2));
698 strncat(communities_str, junk_buf, sizeof(junk_buf));
700 /* cleanup end of string */
701 communities_str[strlen(communities_str) - 1] = '\0';
703 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
705 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
706 communities_str, alen + aoff,
707 (alen + aoff == 1) ? "byte" : "bytes");
709 case BGPTYPE_ORIGINATOR_ID:
711 goto default_attribute_top;
712 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
713 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
715 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
716 ip_to_str(ipaddr), alen + aoff, (alen + aoff == 1)
719 case BGPTYPE_CLUSTER_LIST:
721 goto default_attribute_top;
724 (o + current attribute + 3 bytes to first tuple) */
725 end = o + 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 */
737 tvb_memcpy(tvb, ipaddr, q, 4);
739 snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(ipaddr));
740 strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
743 /* cleanup end of string */
744 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
746 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
748 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
749 cluster_list_str, alen + aoff,
750 (alen + aoff == 1) ? "byte" : "bytes");
753 default_attribute_top:
754 ti = proto_tree_add_text(subtree, tvb, o + i, alen + aoff,
756 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
757 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
758 } /* end of first switch */
759 subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
761 /* figure out flags */
763 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
764 strncat(junk_buf, "Optional, ", 10);
767 strncat(junk_buf, "Well-known, ", 12);
769 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
770 strncat(junk_buf, "Transitive, ", 12);
773 strncat(junk_buf, "Non-transitive, ", 16);
775 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
776 strncat(junk_buf, "Partial, ", 9);
779 strncat(junk_buf, "Complete, ", 10);
781 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
782 strncat(junk_buf, "Extended Length, ", 17);
784 /* stomp last ", " */
785 j = strlen(junk_buf);
786 junk_buf[j - 2] = '\0';
787 ti = proto_tree_add_text(subtree2, tvb,
788 o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
789 "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
790 subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
792 /* add flag bitfield subtrees */
793 proto_tree_add_text(subtree3, tvb,
794 o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
795 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
796 BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
797 proto_tree_add_text(subtree3, tvb,
798 o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
799 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
800 BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
802 proto_tree_add_text(subtree3, tvb,
803 o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
804 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
805 BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
806 proto_tree_add_text(subtree3, tvb,
807 o + i + offsetof(struct bgp_attr, bgpa_flags), 1,
808 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
809 BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
812 proto_tree_add_text(subtree2, tvb,
813 o + i + offsetof(struct bgp_attr, bgpa_type), 1,
814 "Type code: %s (%u)",
815 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
818 proto_tree_add_text(subtree2, tvb, o + i + sizeof(bgpa),
819 aoff - sizeof(bgpa), "Length: %d %s", alen,
820 (alen == 1) ? "byte" : "bytes");
822 /* the second switch prints things in the actual subtree of each
824 switch (bgpa.bgpa_type) {
827 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
828 "Origin (invalid): %u %s", alen,
829 (alen == 1) ? "byte" : "bytes");
831 msg = val_to_str(tvb_get_guint8(tvb, o + i + aoff), bgpattr_origin, "Unknown");
832 proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
833 "Origin: %s (%u)", msg, tvb_get_guint8(tvb, o + i + aoff));
836 case BGPTYPE_AS_PATH:
837 /* check for empty AS_PATH */
843 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
844 "AS path: %s", as_path_str);
845 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
848 (o + current attribute + 3 bytes to first tuple) */
849 end = o + alen + i + 3;
852 /* snarf each AS path tuple, we have to step through each one
853 again to make a separate subtree so we can't just reuse
854 as_path_str from above */
856 as_path_str[0] = '\0';
857 type = tvb_get_guint8(tvb, q++);
858 if (type == AS_SET) {
859 snprintf(as_path_str, 2, "{");
861 else if (type == AS_CONFED_SET) {
862 snprintf(as_path_str, 2, "[");
864 else if (type == AS_CONFED_SEQUENCE) {
865 snprintf(as_path_str, 2, "(");
867 length = tvb_get_guint8(tvb, q++);
869 /* snarf each value in path, we're just going to reuse
870 as_path_str since we already have it malloced */
871 for (j = 0; j < length; j++) {
872 snprintf(junk_buf, sizeof(junk_buf), "%u%s", tvb_get_ntohs(tvb, q),
873 (type == AS_SET || type == AS_CONFED_SET)
875 strncat(as_path_str, junk_buf, sizeof(junk_buf));
879 /* cleanup end of string */
880 if (type == AS_SET) {
881 as_path_str[strlen(as_path_str) - 2] = '}';
883 else if (type == AS_CONFED_SET) {
884 as_path_str[strlen(as_path_str) - 2] = ']';
886 else if (type == AS_CONFED_SEQUENCE) {
887 as_path_str[strlen(as_path_str) - 1] = ')';
890 as_path_str[strlen(as_path_str) - 1] = '\0';
893 /* length here means number of ASs, ie length * 2 bytes */
894 ti = proto_tree_add_text(as_paths_tree, tvb,
896 length * 2 + 2, "AS path segment: %s", as_path_str);
897 as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
898 proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 2,
899 1, "Path segment type: %s (%u)",
900 val_to_str(type, as_segment_type, "Unknown"), type);
901 proto_tree_add_text(as_path_tree, tvb, q - length * 2 - 1,
902 1, "Path segment length: %u %s", length,
903 (length == 1) ? "AS" : "ASs");
905 /* backup and reprint path segment value(s) only */
907 as_path_str[0] = '\0';
908 for (j = 0; j < length; j++) {
909 snprintf(junk_buf, sizeof(junk_buf), "%u ", tvb_get_ntohs(tvb, q));
910 strncat(as_path_str, junk_buf, sizeof(junk_buf));
913 as_path_str[strlen(as_path_str) - 1] = '\0';
915 proto_tree_add_text(as_path_tree, tvb, q - length * 2,
916 length * 2, "Path segment value: %s", as_path_str);
921 case BGPTYPE_NEXT_HOP:
923 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
924 "Next hop (invalid): %u %s", alen,
925 (alen == 1) ? "byte" : "bytes");
927 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
928 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
929 "Next hop: %s", ip_to_str(ipaddr));
932 case BGPTYPE_MULTI_EXIT_DISC:
934 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
935 "Multiple exit discriminator (invalid): %u %s",
936 alen, (alen == 1) ? "byte" : "bytes");
938 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
939 "Multiple exit discriminator: %u",
940 tvb_get_ntohl(tvb, o + i + aoff));
943 case BGPTYPE_LOCAL_PREF:
945 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
946 "Local preference (invalid): %u %s", alen,
947 (alen == 1) ? "byte" : "bytes");
949 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
950 "Local preference: %u", tvb_get_ntohl(tvb, o + i + aoff));
953 case BGPTYPE_ATOMIC_AGGREGATE:
955 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
956 "Atomic aggregate (invalid): %u %s", alen,
957 (alen == 1) ? "byte" : "bytes");
960 case BGPTYPE_AGGREGATOR:
962 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
963 "Aggregator (invalid): %u %s", alen,
964 (alen == 1) ? "byte" : "bytes");
966 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
967 "Aggregator AS: %u", tvb_get_ntohs(tvb, o + i + aoff));
968 tvb_memcpy(tvb, ipaddr, o + i + aoff + 2, 4);
969 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 4,
970 "Aggregator origin: %s",
974 case BGPTYPE_COMMUNITIES:
976 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
977 "Communities (invalid): %u %s", alen,
978 (alen == 1) ? "byte" : "bytes");
979 free(communities_str);
983 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
984 "Communities: %s", communities_str);
985 communities_tree = proto_item_add_subtree(ti,
986 ett_bgp_communities);
989 (o + current attribute + 3 bytes to first tuple) */
990 end = o + alen + i + 3;
993 /* snarf each community */
995 /* check for reserved values */
996 if (tvb_get_ntohs(tvb, q) == FOURHEX0 || tvb_get_ntohs(tvb, q) == FOURHEXF) {
997 /* check for well-known communities */
998 if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT)
999 proto_tree_add_text(communities_tree, tvb,
1001 "Community: NO_EXPORT (0x%x)", tvb_get_ntohl(tvb, q));
1002 else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_ADVERTISE)
1003 proto_tree_add_text(communities_tree, tvb,
1005 "Community: NO_ADVERTISE (0x%x)", pntohl(q));
1006 else if (tvb_get_ntohl(tvb, q) == BGP_COMM_NO_EXPORT_SUBCONFED)
1007 proto_tree_add_text(communities_tree, tvb,
1009 "Community: NO_EXPORT_SUBCONFED (0x%x)",
1010 tvb_get_ntohl(tvb, q));
1012 proto_tree_add_text(communities_tree, tvb,
1014 "Community (reserved): 0x%x", tvb_get_ntohl(tvb, q));
1018 ti = proto_tree_add_text(communities_tree, tvb,
1019 q - 3 + aoff, 4, "Community: %u:%u",
1020 tvb_get_ntohs(tvb, q), tvb_get_ntohs(tvb, q + 2));
1021 community_tree = proto_item_add_subtree(ti,
1022 ett_bgp_communities);
1023 proto_tree_add_text(community_tree, tvb, q - 3 + aoff,
1024 2, "Community AS: %u", tvb_get_ntohs(tvb, q));
1025 proto_tree_add_text(community_tree, tvb, q - 1 + aoff,
1026 2, "Community value: %u", tvb_get_ntohs(tvb, q + 2));
1032 free(communities_str);
1034 case BGPTYPE_ORIGINATOR_ID:
1036 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1037 "Originator identifier (invalid): %u %s", alen,
1038 (alen == 1) ? "byte" : "bytes");
1040 tvb_memcpy(tvb, ipaddr, o + i + aoff, 4);
1041 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1042 "Originator identifier: %s",
1046 case BGPTYPE_MP_REACH_NLRI:
1047 af = tvb_get_ntohs(tvb, o + i + aoff);
1048 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1049 "Address family: %s (%u)",
1050 val_to_str(af, afnumber, "Unknown"), af);
1051 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1052 "Subsequent address family identifier: %s (%u)",
1053 val_to_str(tvb_get_guint8(tvb, o + i + aoff + 2), bgpattr_nlri_safi,
1054 tvb_get_guint8(tvb, o + i + aoff + 2) >= 128 ? "Vendor specific" : "Unknown"),
1055 tvb_get_guint8(tvb, o + i + aoff + 2));
1056 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3, 1,
1057 "Next hop network address (%d %s)",
1058 tvb_get_guint8(tvb, o + i + aoff + 3),
1059 (tvb_get_guint8(tvb, o + i + aoff + 3) == 1) ? "byte" : "bytes");
1060 if (af == AFNUM_INET || af == AFNUM_INET6) {
1064 subtree3 = proto_item_add_subtree(ti,
1065 ett_bgp_mp_reach_nlri);
1068 while (j < tvb_get_guint8(tvb, o + i + aoff + 3)) {
1069 if (af == AFNUM_INET)
1071 else if (af == AFNUM_INET6)
1075 if (j + advance > tvb_get_guint8(tvb, o + i + aoff + 3))
1078 if (af == AFNUM_INET) {
1079 tvb_memcpy(tvb, ipaddr, o + i + aoff + 4 + j, 4);
1080 s = ip_to_str(ipaddr);
1082 tvb_memcpy(tvb, ip6addr.u6_addr.u6_addr8,
1083 o + i + aoff + 4 + j, sizeof ip6addr);
1084 s = ip6_to_str(&ip6addr);
1086 proto_tree_add_text(subtree3, tvb,
1087 o + i + aoff + 4 + j, advance,
1093 alen -= tvb_get_guint8(tvb, o + i + aoff + 3) + 4;
1094 aoff += tvb_get_guint8(tvb, o + i + aoff + 3) + 4;
1096 snpa = tvb_get_guint8(tvb, o + i + aoff);
1097 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, 1,
1098 "Subnetwork points of attachment: %u", snpa);
1101 subtree3 = proto_item_add_subtree(ti,
1102 ett_bgp_mp_reach_nlri);
1103 for (/*nothing*/; snpa > 0; snpa--) {
1104 proto_tree_add_text(subtree3, tvb, o + i + aoff + off, 1,
1105 "SNPA length: %u", tvb_get_guint8(tvb, o + i + aoff + off));
1107 proto_tree_add_text(subtree3, tvb, o + i + aoff + off,
1108 tvb_get_guint8(tvb, o + i + aoff + off - 1),
1109 "SNPA (%u %s)", tvb_get_guint8(tvb, o + i + aoff + off - 1),
1110 (tvb_get_guint8(tvb, o + i + aoff + off - 1) == 1) ? "byte" : "bytes");
1111 off += tvb_get_guint8(tvb, o + i + aoff + off - 1);
1116 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1117 "Network layer reachability information (%u %s)",
1118 alen, (alen == 1) ? "byte" : "bytes");
1120 subtree3 = proto_item_add_subtree(ti,
1121 ett_bgp_mp_unreach_nlri);
1126 if (af == AFNUM_INET) {
1127 advance = decode_prefix4(tvb, o + i + aoff, buf,
1129 } else if (af == AFNUM_INET6) {
1130 advance = decode_prefix6(tvb, o + i + aoff, buf,
1138 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance,
1139 "Network layer reachability information: %s", buf);
1146 case BGPTYPE_MP_UNREACH_NLRI:
1147 af = tvb_get_ntohs(tvb, o + i + aoff);
1148 proto_tree_add_text(subtree2, tvb, o + i + aoff, 2,
1149 "Address family: %s (%u)",
1150 val_to_str(af, afnumber, "Unknown"), af);
1151 proto_tree_add_text(subtree2, tvb, o + i + aoff + 2, 1,
1152 "Subsequent address family identifier: %s (%u)",
1153 val_to_str(tvb_get_guint8(tvb, o + i + aoff + 2), bgpattr_nlri_safi,
1154 tvb_get_guint8(tvb, o + i + aoff + 2) >= 128 ? "Vendor specific" : "Unknown"),
1155 tvb_get_guint8(tvb, o + i + aoff + 2));
1156 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff + 3,
1157 alen - 3, "Withdrawn routes (%u %s)", alen - 3,
1158 (alen - 3 == 1) ? "byte" : "bytes");
1163 subtree3 = proto_item_add_subtree(ti,
1164 ett_bgp_mp_unreach_nlri);
1169 if (af == AFNUM_INET) {
1170 advance = decode_prefix4(tvb, o + i + aoff, buf,
1172 } else if (af == AFNUM_INET6) {
1173 advance = decode_prefix6(tvb, o + i + aoff, buf,
1181 proto_tree_add_text(subtree3, tvb, o + i + aoff, advance,
1182 "Withdrawn route: %s", buf);
1189 case BGPTYPE_CLUSTER_LIST:
1190 if (alen % 4 != 0) {
1191 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1192 "Cluster list (invalid): %u %s", alen,
1193 (alen == 1) ? "byte" : "bytes");
1194 free(cluster_list_str);
1198 ti = proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1199 "Cluster list: %s", cluster_list_str);
1200 cluster_list_tree = proto_item_add_subtree(ti,
1201 ett_bgp_cluster_list);
1204 (p + current attribute + 3 bytes to first tuple) */
1205 end = o + alen + i + 3;
1208 /* snarf each cluster identifier */
1210 tvb_memcpy(tvb, ipaddr, q, 4);
1211 ti = proto_tree_add_text(cluster_list_tree, tvb,
1212 q - 3 + aoff, 4, "Cluster identifier: %s",
1218 free(cluster_list_str);
1221 proto_tree_add_text(subtree2, tvb, o + i + aoff, alen,
1222 "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
1225 } /* end of second switch */
1232 len = offset + hlen - o;
1234 /* parse prefixes */
1236 ti = proto_tree_add_text(tree, tvb, o, len,
1237 "Network layer reachability information: %u %s", len,
1238 (len == 1) ? "byte" : "bytes");
1239 subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1242 i = decode_prefix4(tvb, o, junk_buf, sizeof(junk_buf));
1243 proto_tree_add_text(subtree, tvb, o, i, "%s", junk_buf);
1251 * Dissect a BGP NOTIFICATION message.
1254 dissect_bgp_notification(tvbuff_t *tvb, int offset, proto_tree *tree)
1256 struct bgp_notification bgpn; /* BGP NOTIFICATION message */
1257 int hlen; /* message length */
1258 char *p; /* string pointer */
1261 tvb_memcpy(tvb, bgpn.bgpn_marker, offset, BGP_MIN_NOTIFICATION_MSG_SIZE);
1262 hlen = ntohs(bgpn.bgpn_len);
1264 /* print error code */
1265 proto_tree_add_text(tree, tvb,
1266 offset + offsetof(struct bgp_notification, bgpn_major), 1,
1267 "Error code: %s (%u)",
1268 val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1271 /* print error subcode */
1272 if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1273 && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1274 p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1276 } else if (bgpn.bgpn_minor == 0)
1280 proto_tree_add_text(tree, tvb,
1281 offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1282 "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1284 /* only print if there is optional data */
1285 if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1286 proto_tree_add_text(tree, tvb, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1287 hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1292 * Dissect a BGP ROUTE-REFRESH message.
1295 dissect_bgp_route_refresh(tvbuff_t *tvb, int offset, proto_tree *tree)
1300 i = tvb_get_ntohs(tvb, offset + BGP_HEADER_SIZE);
1301 proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE, 2,
1302 "Address family identifier: %s (%u)",
1303 val_to_str(i, afnumber, "Unknown"), i);
1306 proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE + 2, 1,
1307 "Reserved: 1 byte");
1310 i = tvb_get_guint8(tvb, offset);
1311 proto_tree_add_text(tree, tvb, offset + BGP_HEADER_SIZE + 3, 1,
1312 "Subsequent address family identifier: %s (%u)",
1313 val_to_str(i, bgpattr_nlri_safi,
1314 i >= 128 ? "Vendor specific" : "Unknown"),
1319 * Dissect a BGP packet.
1322 dissect_bgp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1324 proto_item *ti; /* tree item */
1325 proto_tree *bgp_tree; /* BGP packet tree */
1326 proto_tree *bgp1_tree; /* BGP message tree */
1328 int found; /* number of BGP messages in packet */
1329 static u_char marker[] = { /* BGP message marker */
1330 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1331 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1333 struct bgp bgp; /* BGP header */
1334 int hlen; /* BGP header length */
1335 char *typ; /* BGP message type */
1337 pinfo->current_proto = "BGP";
1338 if (check_col(pinfo->fd, COL_PROTOCOL))
1339 col_set_str(pinfo->fd, COL_PROTOCOL, "BGP");
1340 if (check_col(pinfo->fd, COL_INFO))
1341 col_clear(pinfo->fd, COL_INFO);
1343 l = tvb_length(tvb);
1346 /* run through the TCP packet looking for BGP headers */
1347 /* this is done twice, but this way each message type can be
1348 printed in the COL_INFO field */
1349 while (i + BGP_HEADER_SIZE <= l) {
1350 tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1352 /* look for bgp header */
1353 if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1359 hlen = ntohs(bgp.bgp_len);
1360 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1362 if (check_col(pinfo->fd, COL_INFO)) {
1364 col_add_fstr(pinfo->fd, COL_INFO, "%s", typ);
1366 col_append_fstr(pinfo->fd, COL_INFO, ", %s", typ);
1373 ti = proto_tree_add_item(tree, proto_bgp, tvb, 0,
1375 bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1378 /* now, run through the TCP packet again, this time dissect */
1379 /* each message that we find */
1380 while (i + BGP_HEADER_SIZE <= l) {
1381 tvb_memcpy(tvb, bgp.bgp_marker, i, BGP_HEADER_SIZE);
1383 /* look for bgp header */
1384 if (memcmp(bgp.bgp_marker, marker, sizeof(marker)) != 0) {
1389 hlen = ntohs(bgp.bgp_len);
1390 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1392 ti = proto_tree_add_text(bgp_tree, tvb, i,
1393 l, "%s (truncated)", typ);
1395 ti = proto_tree_add_text(bgp_tree, tvb, i, hlen,
1398 /* add a different tree for each message type */
1399 switch (bgp.bgp_type) {
1401 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1404 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1406 case BGP_NOTIFICATION:
1407 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1410 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1412 case BGP_ROUTE_REFRESH:
1413 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_route_refresh);
1416 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1420 proto_tree_add_text(bgp1_tree, tvb, i, BGP_MARKER_SIZE,
1421 "Marker: 16 bytes");
1423 if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1424 proto_tree_add_text(bgp1_tree, tvb,
1425 i + offsetof(struct bgp, bgp_len), 2,
1426 "Length (invalid): %u %s", hlen,
1427 (hlen == 1) ? "byte" : "bytes");
1429 proto_tree_add_text(bgp1_tree, tvb,
1430 i + offsetof(struct bgp, bgp_len), 2,
1431 "Length: %u %s", hlen,
1432 (hlen == 1) ? "byte" : "bytes");
1435 proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, tvb,
1436 i + offsetof(struct bgp, bgp_type), 1,
1438 "Type: %s (%u)", typ, bgp.bgp_type);
1440 switch (bgp.bgp_type) {
1442 dissect_bgp_open(tvb, i, bgp1_tree);
1445 dissect_bgp_update(tvb, i, bgp1_tree);
1447 case BGP_NOTIFICATION:
1448 dissect_bgp_notification(tvb, i, bgp1_tree);
1451 /* no data in KEEPALIVE messages */
1453 case BGP_ROUTE_REFRESH:
1454 dissect_bgp_route_refresh(tvb, i, bgp1_tree);
1466 * Register ourselves.
1469 proto_register_bgp(void)
1472 static hf_register_info hf[] = {
1474 { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
1475 VALS(bgptypevals), 0x0, "BGP message type" }},
1478 static gint *ett[] = {
1483 &ett_bgp_attr_flags,
1484 &ett_bgp_mp_reach_nlri,
1485 &ett_bgp_mp_unreach_nlri,
1489 &ett_bgp_notification,
1490 &ett_bgp_route_refresh,
1492 &ett_bgp_communities,
1493 &ett_bgp_cluster_list,
1498 proto_bgp = proto_register_protocol("Border Gateway Protocol",
1500 proto_register_field_array(proto_bgp, hf, array_length(hf));
1501 proto_register_subtree_array(ett, array_length(ett));
1505 proto_reg_handoff_bgp(void)
1507 dissector_add("tcp.port", BGP_TCP_PORT, dissect_bgp, proto_bgp);