summaryrefslogtreecommitdiffstats
path: root/usr.sbin/tcpdump/print-bgp.c
diff options
context:
space:
mode:
authorjakob <jakob@openbsd.org>2000-01-16 11:43:57 +0000
committerjakob <jakob@openbsd.org>2000-01-16 11:43:57 +0000
commit54118a9c435ae022a57e762669244bb4bd380665 (patch)
tree3e613b5a6378e5e377e1237fd376e0cb3358ef9c /usr.sbin/tcpdump/print-bgp.c
parentMobile IP support (from KAME/NetBSD) (diff)
downloadwireguard-openbsd-54118a9c435ae022a57e762669244bb4bd380665.tar.xz
wireguard-openbsd-54118a9c435ae022a57e762669244bb4bd380665.zip
BGP support (from KAME/WIDE). INET6 parts not done yet.
Diffstat (limited to 'usr.sbin/tcpdump/print-bgp.c')
-rw-r--r--usr.sbin/tcpdump/print-bgp.c720
1 files changed, 720 insertions, 0 deletions
diff --git a/usr.sbin/tcpdump/print-bgp.c b/usr.sbin/tcpdump/print-bgp.c
new file mode 100644
index 00000000000..7be61b285b8
--- /dev/null
+++ b/usr.sbin/tcpdump/print-bgp.c
@@ -0,0 +1,720 @@
+/* $OpenBSD: print-bgp.c,v 1.1 2000/01/16 11:43:57 jakob Exp $ */
+
+/*
+ * Copyright (C) 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+struct bgp {
+ u_int8_t bgp_marker[16];
+ u_int16_t bgp_len;
+ u_int8_t bgp_type;
+};
+#define BGP_SIZE 19 /* unaligned */
+
+#define BGP_OPEN 1
+#define BGP_UPDATE 2
+#define BGP_NOTIFICATION 3
+#define BGP_KEEPALIVE 4
+
+struct bgp_open {
+ u_int8_t bgpo_marker[16];
+ u_int16_t bgpo_len;
+ u_int8_t bgpo_type;
+ u_int8_t bgpo_version;
+ u_int16_t bgpo_myas;
+ u_int16_t bgpo_holdtime;
+ u_int32_t bgpo_id;
+ u_int8_t bgpo_optlen;
+ /* options should follow */
+};
+
+struct bgp_opt {
+ u_int8_t bgpopt_type;
+ u_int8_t bgpopt_len;
+ /* variable length */
+};
+
+struct bgp_notification {
+ u_int8_t bgpn_marker[16];
+ u_int16_t bgpn_len;
+ u_int8_t bgpn_type;
+ u_int8_t bgpn_major;
+ u_int8_t bgpn_minor;
+ /* data should follow */
+};
+
+struct bgp_attr {
+ u_int8_t bgpa_flags;
+ u_int8_t bgpa_type;
+ union {
+ u_int8_t len;
+ u_int16_t elen;
+ } bgpa_len;
+#define bgp_attr_len(p) \
+ (((p)->bgpa_flags & 0x10) ? \
+ ntohs((p)->bgpa_len.elen) : (p)->bgpa_len.len)
+#define bgp_attr_off(p) \
+ (((p)->bgpa_flags & 0x10) ? 4 : 3)
+};
+
+#define BGPTYPE_ORIGIN 1
+#define BGPTYPE_AS_PATH 2
+#define BGPTYPE_NEXT_HOP 3
+#define BGPTYPE_MULTI_EXIT_DISC 4
+#define BGPTYPE_LOCAL_PREF 5
+#define BGPTYPE_ATOMIC_AGGREGATE 6
+#define BGPTYPE_AGGREGATOR 7
+#define BGPTYPE_COMMUNITIES 8 /* RFC1997 */
+#define BGPTYPE_ORIGINATOR_ID 9 /* RFC1998 */
+#define BGPTYPE_CLUSTER_LIST 10 /* RFC1998 */
+#define BGPTYPE_DPA 11 /* work in progress */
+#define BGPTYPE_ADVERTISERS 12 /* RFC1863 */
+#define BGPTYPE_RCID_PATH 13 /* RFC1863 */
+#define BGPTYPE_MP_REACH_NLRI 14 /* RFC2283 */
+#define BGPTYPE_MP_UNREACH_NLRI 15 /* RFC2283 */
+
+
+static const char *bgptype[] = {
+ NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE",
+};
+#define bgp_type(x) num_or_str(bgptype, sizeof(bgptype)/sizeof(bgptype[0]), (x))
+
+static const char *bgpopt_type[] = {
+ NULL, "Authentication Information",
+};
+#define bgp_opttype(x) \
+ num_or_str(bgpopt_type, sizeof(bgpopt_type)/sizeof(bgpopt_type[0]), (x))
+
+static const char *bgpnotify_major[] = {
+ NULL, "Message Header Error",
+ "OPEN Message Error", "UPDATE Message Error",
+ "Hold Timer Expired", "Finite State Machine Error",
+ "Cease",
+};
+#define bgp_notify_major(x) \
+ num_or_str(bgpnotify_major, \
+ sizeof(bgpnotify_major)/sizeof(bgpnotify_major[0]), (x))
+
+static const char *bgpnotify_minor_1[] = {
+ NULL, "Connection Not Synchronized",
+ "Bad Message Length", "Bad Message Type",
+};
+
+static const char *bgpnotify_minor_2[] = {
+ NULL, "Unsupported Version Number",
+ "Bad Peer AS", "Bad BGP Identifier",
+ "Unsupported Optional Parameter", "Authentication Failure",
+ "Unacceptable Hold Time",
+};
+
+static const char *bgpnotify_minor_3[] = {
+ NULL, "Malformed Attribute List",
+ "Unrecognized Well-known Attribute", "Missing Well-known Attribute",
+ "Attribute Flags Error", "Attribute Length Error",
+ "Invalid ORIGIN Attribute", "AS Routing Loop",
+ "Invalid NEXT_HOP Attribute", "Optional Attribute Error",
+ "Invalid Network Field", "Malformed AS_PATH",
+};
+
+static const char **bgpnotify_minor[] = {
+ NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
+};
+static const int bgpnotify_minor_siz[] = {
+ 0, sizeof(bgpnotify_minor_1)/sizeof(bgpnotify_minor_1[0]),
+ sizeof(bgpnotify_minor_2)/sizeof(bgpnotify_minor_2[0]),
+ sizeof(bgpnotify_minor_3)/sizeof(bgpnotify_minor_3[0]),
+};
+
+static const char *bgpattr_origin[] = {
+ "IGP", "EGP", "INCOMPLETE",
+};
+#define bgp_attr_origin(x) \
+ num_or_str(bgpattr_origin, \
+ sizeof(bgpattr_origin)/sizeof(bgpattr_origin[0]), (x))
+
+static const char *bgpattr_type[] = {
+ NULL, "ORIGIN", "AS_PATH", "NEXT_HOP",
+ "MULTI_EXIT_DISC", "LOCAL_PREF", "ATOMIC_AGGREGATE", "AGGREGATOR",
+ "COMMUNITIES", "ORIGINATOR_ID", "CLUSTER_LIST", "DPA",
+ "ADVERTISERS", "RCID_PATH", "MP_REACH_NLRI", "MP_UNREACH_NLRI",
+};
+#define bgp_attr_type(x) \
+ num_or_str(bgpattr_type, \
+ sizeof(bgpattr_type)/sizeof(bgpattr_type[0]), (x))
+
+/* Subsequent address family identifier, RFC2283 section 7 */
+static const char *bgpattr_nlri_safi[] = {
+ "Reserved", "Unicast", "Multicast", "Unicast+Multicast",
+};
+#define bgp_attr_nlri_safi(x) \
+ num_or_str(bgpattr_nlri_safi, \
+ sizeof(bgpattr_nlri_safi)/sizeof(bgpattr_nlri_safi[0]), (x))
+
+/* well-known community */
+#define BGP_COMMUNITY_NO_EXPORT 0xffffff01
+#define BGP_COMMUNITY_NO_ADVERT 0xffffff02
+#define BGP_COMMUNITY_NO_EXPORT_SUBCONFED 0xffffff03
+
+/* RFC1700 address family numbers */
+#define AFNUM_INET 1
+#define AFNUM_INET6 2
+#define AFNUM_NSAP 3
+#define AFNUM_HDLC 4
+#define AFNUM_BBN1822 5
+#define AFNUM_802 6
+#define AFNUM_E163 7
+#define AFNUM_E164 8
+#define AFNUM_F69 9
+#define AFNUM_X121 10
+#define AFNUM_IPX 11
+#define AFNUM_ATALK 12
+#define AFNUM_DECNET 13
+#define AFNUM_BANYAN 14
+#define AFNUM_E164NSAP 15
+
+static const char *afnumber[] = {
+ "Reserved", "IPv4", "IPv6", "NSAP", "HDLC",
+ "BBN 1822", "802", "E.163", "E.164", "F.69",
+ "X.121", "IPX", "Appletalk", "Decnet IV", "Banyan Vines",
+ "E.164 with NSAP subaddress",
+};
+#define af_name(x) \
+ (((x) == 65535) ? afnumber[0] : \
+ num_or_str(afnumber, \
+ sizeof(afnumber)/sizeof(afnumber[0]), (x)))
+
+
+static const char *
+num_or_str(const char **table, size_t siz, int value)
+{
+ static char buf[20];
+ if (value < 0 || siz <= value || table[value] == NULL) {
+ snprintf(buf, sizeof(buf), "#%d", value);
+ return buf;
+ } else
+ return table[value];
+}
+
+static const char *
+bgp_notify_minor(int major, int minor)
+{
+ static const char **table;
+ int siz;
+ static char buf[20];
+ const char *p;
+
+ if (0 <= major
+ && major < sizeof(bgpnotify_minor)/sizeof(bgpnotify_minor[0])
+ && bgpnotify_minor[major]) {
+ table = bgpnotify_minor[major];
+ siz = bgpnotify_minor_siz[major];
+ if (0 <= minor && minor < siz && table[minor])
+ p = table[minor];
+ else
+ p = NULL;
+ } else
+ p = NULL;
+ if (p == NULL) {
+ snprintf(buf, sizeof(buf), "#%d", minor);
+ return buf;
+ } else
+ return p;
+}
+
+static int
+decode_prefix4(const u_char *pd, char *buf, int buflen)
+{
+ struct in_addr addr;
+ int plen;
+
+ plen = pd[0];
+ if (plen < 0 || 32 < plen)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ memcpy(&addr, &pd[1], (plen + 7) / 8);
+ if (plen % 8) {
+ ((u_char *)&addr)[(plen + 7) / 8 - 1] &=
+ ((0xff00 >> (plen % 8)) & 0xff);
+ }
+ snprintf(buf, buflen, "%s/%d", getname((char *)&addr), plen);
+ return 1 + (plen + 7) / 8;
+}
+
+#ifdef INET6
+static int
+decode_prefix6(const u_char *pd, char *buf, int buflen)
+{
+ struct in6_addr addr;
+ int plen;
+
+ plen = pd[0];
+ if (plen < 0 || 128 < plen)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ memcpy(&addr, &pd[1], (plen + 7) / 8);
+ if (plen % 8) {
+ addr.s6_addr[(plen + 7) / 8 - 1] &=
+ ((0xff00 >> (plen % 8)) & 0xff);
+ }
+ snprintf(buf, buflen, "%s/%d", getname6((char *)&addr), plen);
+ return 1 + (plen + 7) / 8;
+}
+#endif
+
+static void
+bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len)
+{
+ int i;
+ u_int16_t af;
+ u_int8_t safi, snpa;
+ int advance;
+ int tlen;
+ const u_char *p;
+ char buf[256];
+
+ p = dat;
+
+ switch (attr->bgpa_type) {
+ case BGPTYPE_ORIGIN:
+ if (len != 1)
+ printf(" invalid len");
+ else
+ printf(" %s", bgp_attr_origin(p[0]));
+ break;
+ case BGPTYPE_AS_PATH:
+ if (len % 2) {
+ printf(" invalid len");
+ break;
+ }
+ while (p < dat + len) {
+ /*
+ * under RFC1965, p[0] means:
+ * 1: AS_SET 2: AS_SEQUENCE
+ * 3: AS_CONFED_SET 4: AS_CONFED_SEQUENCE
+ */
+ printf(" ");
+ if (p[0] == 3 || p[0] == 4)
+ printf("confed");
+ printf("%s", (p[0] & 1) ? "{" : "");
+ for (i = 0; i < p[1]; i += 2) {
+ printf("%s%u", i == 0 ? "" : " ",
+ ntohs(*(u_int16_t *)&p[2 + i]));
+ }
+ printf("%s", (p[0] & 1) ? "}" : "");
+ p += 2 + p[1] * 2;
+ }
+ break;
+ case BGPTYPE_NEXT_HOP:
+ if (len != 4)
+ printf(" invalid len");
+ else
+ printf(" %s", getname(p));
+ break;
+ case BGPTYPE_MULTI_EXIT_DISC:
+ case BGPTYPE_LOCAL_PREF:
+ if (len != 4)
+ printf(" invalid len");
+ else
+ printf(" %u", (u_int32_t)ntohl(*(u_int32_t *)p));
+ break;
+ case BGPTYPE_ATOMIC_AGGREGATE:
+ if (len != 0)
+ printf(" invalid len");
+ break;
+ case BGPTYPE_AGGREGATOR:
+ if (len != 6) {
+ printf(" invalid len");
+ break;
+ }
+ printf(" AS #%u, origin %s", ntohs(*(u_int16_t *)p),
+ getname(p + 2));
+ break;
+ case BGPTYPE_COMMUNITIES:
+ if (len % 4) {
+ printf(" invalid len");
+ break;
+ }
+ for (i = 0; i < len; i++) {
+ u_int32_t comm;
+ comm = (u_int32_t)ntohl(*(u_int32_t *)&p[i]);
+ switch (comm) {
+ case BGP_COMMUNITY_NO_EXPORT:
+ printf(" NO_EXPORT");
+ break;
+ case BGP_COMMUNITY_NO_ADVERT:
+ printf(" NO_ADVERTISE");
+ break;
+ case BGP_COMMUNITY_NO_EXPORT_SUBCONFED:
+ printf(" NO_EXPORT_SUBCONFED");
+ break;
+ default:
+ printf(" (AS #%d value 0x%04x)",
+ (comm >> 16) & 0xffff, comm & 0xfffff);
+ break;
+ }
+ }
+ break;
+ case BGPTYPE_MP_REACH_NLRI:
+ af = ntohs(*(u_int16_t *)p);
+ safi = p[2];
+ if (safi >= 128)
+ printf(" %s vendor specific,", af_name(af));
+ else {
+ printf(" %s %s,", af_name(af),
+ bgp_attr_nlri_safi(safi));
+ }
+ p += 3;
+
+ if (af == AFNUM_INET)
+ ;
+#ifdef INET6
+ else if (af == AFNUM_INET6)
+ ;
+#endif
+ else
+ break;
+
+ tlen = p[0];
+ if (tlen) {
+ printf(" nexthop");
+ if (af == AFNUM_INET)
+ advance = 4;
+#ifdef INET6
+ else if (af == AFNUM_INET6)
+ advance = 16;
+#endif
+
+ for (i = 0; i < tlen; i += advance) {
+ if (af == AFNUM_INET)
+ printf(" %s", getname(p + 1 + i));
+#ifdef INET6
+ else if (af == AFNUM_INET6)
+ printf(" %s", getname6(p + 1 + i));
+#endif
+ }
+ printf(",");
+ }
+ p += 1 + tlen;
+
+ snpa = p[0];
+ p++;
+ if (snpa) {
+ printf(" %u snpa", snpa);
+ for (/*nothing*/; snpa > 0; snpa--) {
+ printf("(%d bytes)", p[0]);
+ p += p[0] + 1;
+ }
+ printf(",");
+ }
+
+ printf(" NLRI");
+ while (len - (p - dat) > 0) {
+ if (af == AFNUM_INET)
+ advance = decode_prefix4(p, buf, sizeof(buf));
+#ifdef INET6
+ else if (af == AFNUM_INET6)
+ advance = decode_prefix6(p, buf, sizeof(buf));
+#endif
+ printf(" %s", buf);
+
+ p += advance;
+ }
+
+ break;
+
+ case BGPTYPE_MP_UNREACH_NLRI:
+ af = ntohs(*(u_int16_t *)p);
+ safi = p[2];
+ if (safi >= 128)
+ printf(" %s vendor specific,", af_name(af));
+ else {
+ printf(" %s %s,", af_name(af),
+ bgp_attr_nlri_safi(safi));
+ }
+ p += 3;
+
+ printf(" Withdraw");
+ while (len - (p - dat) > 0) {
+ if (af == AFNUM_INET)
+ advance = decode_prefix4(p, buf, sizeof(buf));
+#ifdef INET6
+ else if (af == AFNUM_INET6)
+ advance = decode_prefix6(p, buf, sizeof(buf));
+#endif
+ printf(" %s", buf);
+
+ p += advance;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+bgp_open_print(const u_char *dat, int length)
+{
+ struct bgp_open bgpo;
+ struct bgp_opt bgpopt;
+ int hlen;
+ const u_char *opt;
+ int i;
+
+ memcpy(&bgpo, dat, sizeof(bgpo));
+ hlen = ntohs(bgpo.bgpo_len);
+
+ printf(": Version %d,", bgpo.bgpo_version);
+ printf(" AS #%u,", ntohs(bgpo.bgpo_myas));
+ printf(" Holdtime %u,", ntohs(bgpo.bgpo_holdtime));
+ printf(" ID %s,", getname((char *)&bgpo.bgpo_id));
+ printf(" Option length %u", bgpo.bgpo_optlen);
+
+ /* ugly! */
+ opt = &((struct bgp_open *)dat)->bgpo_optlen;
+ opt++;
+
+ for (i = 0; i < bgpo.bgpo_optlen; i++) {
+ memcpy(&bgpopt, &opt[i], sizeof(bgpopt));
+ if (i + 2 + bgpopt.bgpopt_len > bgpo.bgpo_optlen) {
+ printf(" [|opt %d %d]", bgpopt.bgpopt_len, bgpopt.bgpopt_type);
+ break;
+ }
+
+ printf(" (option %s, len=%d)", bgp_opttype(bgpopt.bgpopt_type),
+ bgpopt.bgpopt_len);
+ i += sizeof(bgpopt) + bgpopt.bgpopt_len;
+ }
+}
+
+static void
+bgp_update_print(const u_char *dat, int length)
+{
+ struct bgp bgp;
+ struct bgp_attr bgpa;
+ int hlen;
+ const u_char *p;
+ int len;
+ int i;
+ int newline;
+
+ memcpy(&bgp, dat, sizeof(bgp));
+ hlen = ntohs(bgp.bgp_len);
+ p = dat + BGP_SIZE; /*XXX*/
+ printf(":");
+
+ /* Unfeasible routes */
+ len = ntohs(*(u_int16_t *)p);
+ if (len) {
+ printf(" (Withdrawn routes: %d bytes)", len);
+ }
+ p += 2 + len;
+
+ len = ntohs(*(u_int16_t *)p);
+ if (len) {
+ /* do something more useful!*/
+ i = 2;
+ printf(" (Path attributes:"); /* ) */
+ newline = 0;
+ while (i < 2 + len) {
+ int alen, aoff;
+
+ memcpy(&bgpa, &p[i], sizeof(bgpa));
+ alen = bgp_attr_len(&bgpa);
+ aoff = bgp_attr_off(&bgpa);
+
+ if (vflag && newline)
+ printf("\n\t\t");
+ else
+ printf(" ");
+ printf("("); /* ) */
+ printf("%s", bgp_attr_type(bgpa.bgpa_type));
+ if (bgpa.bgpa_flags) {
+ printf("[%s%s%s%s]",
+ bgpa.bgpa_flags & 0x80 ? "O" : "",
+ bgpa.bgpa_flags & 0x40 ? "T" : "",
+ bgpa.bgpa_flags & 0x20 ? "P" : "",
+ bgpa.bgpa_flags & 0x00 ? "E" : "");
+ }
+
+ bgp_attr_print(&bgpa, &p[i + aoff], alen);
+ newline = 1;
+
+ /* ( */
+ printf(")");
+
+ i += aoff + alen;
+ }
+
+ /* ( */
+ printf(")");
+ }
+ p += 2 + len;
+
+ if (len && dat + length > p)
+ printf("\n\t\t");
+ if (dat + length > p) {
+ printf("(NLRI:"); /* ) */
+ while (dat + length > p) {
+ char buf[256];
+ i = decode_prefix4(p, buf, sizeof(buf));
+ printf(" %s", buf);
+ if (i < 0)
+ break;
+ p += i;
+ }
+
+ /* ( */
+ printf(")");
+ }
+}
+
+static void
+bgp_notification_print(const u_char *dat, int length)
+{
+ struct bgp_notification bgpn;
+ int hlen;
+
+ memcpy(&bgpn, dat, sizeof(bgpn));
+ hlen = ntohs(bgpn.bgpn_len);
+
+ printf(": error %s,", bgp_notify_major(bgpn.bgpn_major));
+ printf(" subcode %s",
+ bgp_notify_minor(bgpn.bgpn_major, bgpn.bgpn_minor));
+}
+
+static void
+bgp_header_print(const u_char *dat, int length)
+{
+ struct bgp bgp;
+
+ memcpy(&bgp, dat, sizeof(bgp));
+ printf("(%s", bgp_type(bgp.bgp_type)); /* ) */
+
+ switch (bgp.bgp_type) {
+ case BGP_OPEN:
+ bgp_open_print(dat, length);
+ break;
+ case BGP_UPDATE:
+ bgp_update_print(dat, length);
+ break;
+ case BGP_NOTIFICATION:
+ bgp_notification_print(dat, length);
+ break;
+ }
+
+ /* ( */
+ printf(")");
+}
+
+void
+bgp_print(const u_char *dat, int length)
+{
+ const u_char *p;
+ const u_char *ep;
+ const u_char *start;
+ const u_char marker[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+ struct bgp bgp;
+ u_int16_t hlen;
+ int newline;
+
+ ep = dat + length;
+ if (snapend < dat + length)
+ ep = snapend;
+
+ printf(": BGP");
+
+ p = dat;
+ newline = 0;
+ start = p;
+ while (p < snapend) {
+ if (!TTEST2(p[0], 1))
+ break;
+ if (p[0] != 0xff) {
+ p++;
+ continue;
+ }
+
+ if (!TTEST2(p[0], sizeof(marker)))
+ break;
+ if (memcmp(p, marker, sizeof(marker)) != 0) {
+ p++;
+ continue;
+ }
+
+ /* found BGP header */
+ TCHECK2(p[0], BGP_SIZE); /*XXX*/
+ memcpy(&bgp, p, sizeof(bgp));
+
+ if (start != p)
+ printf(" [|BGP]");
+
+ hlen = ntohs(bgp.bgp_len);
+ if (vflag && newline)
+ printf("\n\t");
+ else
+ printf(" ");
+ if (TTEST2(p[0], hlen)) {
+ bgp_header_print(p, hlen);
+ newline = 1;
+ p += hlen;
+ start = p;
+ } else {
+ printf("[|BGP %s]", bgp_type(bgp.bgp_type));
+ break;
+ }
+ }
+
+ return;
+
+trunc:
+ printf(" [|BGP]");
+}