xref: /openbsd-src/usr.sbin/tcpdump/print-bgp.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: print-bgp.c,v 1.4 2002/09/03 12:21:12 ho Exp $	*/
2 
3 /*
4  * Copyright (C) 1999 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 static const char rcsid[] =
34      "@(#) $TCPDUMP: /tcpdump/master/tcpdump/print-bgp.c,v 1.27 2001/10/18 09:52:17 itojun Exp $";
35 #endif
36 
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 
42 #include <netinet/in.h>
43 
44 #include <errno.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <netdb.h>
48 
49 #include "interface.h"
50 #include "addrtoname.h"
51 #include "extract.h"
52 
53 struct bgp {
54 	u_int8_t bgp_marker[16];
55 	u_int16_t bgp_len;
56 	u_int8_t bgp_type;
57 };
58 #define BGP_SIZE		19	/* unaligned */
59 
60 #define BGP_OPEN		1
61 #define BGP_UPDATE		2
62 #define BGP_NOTIFICATION	3
63 #define BGP_KEEPALIVE		4
64 
65 struct bgp_open {
66 	u_int8_t bgpo_marker[16];
67 	u_int16_t bgpo_len;
68 	u_int8_t bgpo_type;
69 	u_int8_t bgpo_version;
70 	u_int16_t bgpo_myas;
71 	u_int16_t bgpo_holdtime;
72 	u_int32_t bgpo_id;
73 	u_int8_t bgpo_optlen;
74 	/* options should follow */
75 };
76 #define BGP_OPEN_SIZE		29	/* unaligned */
77 
78 struct bgp_opt {
79 	u_int8_t bgpopt_type;
80 	u_int8_t bgpopt_len;
81 	/* variable length */
82 };
83 #define BGP_OPT_SIZE		2	/* some compilers may pad to 4 bytes */
84 
85 struct bgp_notification {
86 	u_int8_t bgpn_marker[16];
87 	u_int16_t bgpn_len;
88 	u_int8_t bgpn_type;
89 	u_int8_t bgpn_major;
90 	u_int8_t bgpn_minor;
91 	/* data should follow */
92 };
93 #define BGP_NOTIFICATION_SIZE		21	/* unaligned */
94 
95 struct bgp_attr {
96 	u_int8_t bgpa_flags;
97 	u_int8_t bgpa_type;
98 	union {
99 		u_int8_t len;
100 		u_int16_t elen;
101 	} bgpa_len;
102 #define bgp_attr_len(p) \
103 	(((p)->bgpa_flags & 0x10) ? \
104 		ntohs((p)->bgpa_len.elen) : (p)->bgpa_len.len)
105 #define bgp_attr_off(p) \
106 	(((p)->bgpa_flags & 0x10) ? 4 : 3)
107 };
108 
109 #define BGPTYPE_ORIGIN			1
110 #define BGPTYPE_AS_PATH			2
111 #define BGPTYPE_NEXT_HOP		3
112 #define BGPTYPE_MULTI_EXIT_DISC		4
113 #define BGPTYPE_LOCAL_PREF		5
114 #define BGPTYPE_ATOMIC_AGGREGATE	6
115 #define BGPTYPE_AGGREGATOR		7
116 #define	BGPTYPE_COMMUNITIES		8	/* RFC1997 */
117 #define	BGPTYPE_ORIGINATOR_ID		9	/* RFC1998 */
118 #define	BGPTYPE_CLUSTER_LIST		10	/* RFC1998 */
119 #define	BGPTYPE_DPA			11	/* work in progress */
120 #define	BGPTYPE_ADVERTISERS		12	/* RFC1863 */
121 #define	BGPTYPE_RCID_PATH		13	/* RFC1863 */
122 #define BGPTYPE_MP_REACH_NLRI		14	/* RFC2283 */
123 #define BGPTYPE_MP_UNREACH_NLRI		15	/* RFC2283 */
124 
125 
126 static const char *bgptype[] = {
127 	NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE",
128 };
129 #define bgp_type(x) num_or_str(bgptype, sizeof(bgptype)/sizeof(bgptype[0]), (x))
130 
131 static const char *bgpopt_type[] = {
132 	NULL, "Authentication Information", "Capabilities Advertisement",
133 };
134 #define bgp_opttype(x) \
135 	num_or_str(bgpopt_type, sizeof(bgpopt_type)/sizeof(bgpopt_type[0]), (x))
136 
137 static const char *bgpnotify_major[] = {
138 	NULL, "Message Header Error",
139 	"OPEN Message Error", "UPDATE Message Error",
140 	"Hold Timer Expired", "Finite State Machine Error",
141 	"Cease",
142 };
143 #define bgp_notify_major(x) \
144 	num_or_str(bgpnotify_major, \
145 		sizeof(bgpnotify_major)/sizeof(bgpnotify_major[0]), (x))
146 
147 static const char *bgpnotify_minor_1[] = {
148 	NULL, "Connection Not Synchronized",
149 	"Bad Message Length", "Bad Message Type",
150 };
151 
152 static const char *bgpnotify_minor_2[] = {
153 	NULL, "Unsupported Version Number",
154 	"Bad Peer AS", "Bad BGP Identifier",
155 	"Unsupported Optional Parameter", "Authentication Failure",
156 	"Unacceptable Hold Time",
157 };
158 
159 static const char *bgpnotify_minor_3[] = {
160 	NULL, "Malformed Attribute List",
161 	"Unrecognized Well-known Attribute", "Missing Well-known Attribute",
162 	"Attribute Flags Error", "Attribute Length Error",
163 	"Invalid ORIGIN Attribute", "AS Routing Loop",
164 	"Invalid NEXT_HOP Attribute", "Optional Attribute Error",
165 	"Invalid Network Field", "Malformed AS_PATH",
166 };
167 
168 static const char **bgpnotify_minor[] = {
169 	NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
170 };
171 static const int bgpnotify_minor_siz[] = {
172 	0, sizeof(bgpnotify_minor_1)/sizeof(bgpnotify_minor_1[0]),
173 	sizeof(bgpnotify_minor_2)/sizeof(bgpnotify_minor_2[0]),
174 	sizeof(bgpnotify_minor_3)/sizeof(bgpnotify_minor_3[0]),
175 };
176 
177 static const char *bgpattr_origin[] = {
178 	"IGP", "EGP", "INCOMPLETE",
179 };
180 #define bgp_attr_origin(x) \
181 	num_or_str(bgpattr_origin, \
182 		sizeof(bgpattr_origin)/sizeof(bgpattr_origin[0]), (x))
183 
184 static const char *bgpattr_type[] = {
185 	NULL, "ORIGIN", "AS_PATH", "NEXT_HOP",
186 	"MULTI_EXIT_DISC", "LOCAL_PREF", "ATOMIC_AGGREGATE", "AGGREGATOR",
187 	"COMMUNITIES", "ORIGINATOR_ID", "CLUSTER_LIST", "DPA",
188 	"ADVERTISERS", "RCID_PATH", "MP_REACH_NLRI", "MP_UNREACH_NLRI",
189 };
190 #define bgp_attr_type(x) \
191 	num_or_str(bgpattr_type, \
192 		sizeof(bgpattr_type)/sizeof(bgpattr_type[0]), (x))
193 
194 /* Subsequent address family identifier, RFC2283 section 7 */
195 static const char *bgpattr_nlri_safi[] = {
196 	"Reserved", "Unicast", "Multicast", "Unicast+Multicast",
197 };
198 #define bgp_attr_nlri_safi(x) \
199 	num_or_str(bgpattr_nlri_safi, \
200 		sizeof(bgpattr_nlri_safi)/sizeof(bgpattr_nlri_safi[0]), (x))
201 
202 /* well-known community */
203 #define BGP_COMMUNITY_NO_EXPORT			0xffffff01
204 #define BGP_COMMUNITY_NO_ADVERT			0xffffff02
205 #define BGP_COMMUNITY_NO_EXPORT_SUBCONFED	0xffffff03
206 
207 /* RFC1700 address family numbers */
208 #define AFNUM_INET	1
209 #define AFNUM_INET6	2
210 #define AFNUM_NSAP	3
211 #define AFNUM_HDLC	4
212 #define AFNUM_BBN1822	5
213 #define AFNUM_802	6
214 #define AFNUM_E163	7
215 #define AFNUM_E164	8
216 #define AFNUM_F69	9
217 #define AFNUM_X121	10
218 #define AFNUM_IPX	11
219 #define AFNUM_ATALK	12
220 #define AFNUM_DECNET	13
221 #define AFNUM_BANYAN	14
222 #define AFNUM_E164NSAP	15
223 
224 static const char *afnumber[] = {
225 	"Reserved", "IPv4", "IPv6", "NSAP", "HDLC",
226 	"BBN 1822", "802", "E.163", "E.164", "F.69",
227 	"X.121", "IPX", "Appletalk", "Decnet IV", "Banyan Vines",
228 	"E.164 with NSAP subaddress",
229 };
230 #define af_name(x) \
231 	(((x) == 65535) ? afnumber[0] : \
232 		num_or_str(afnumber, \
233 			sizeof(afnumber)/sizeof(afnumber[0]), (x)))
234 
235 
236 static const char *
237 num_or_str(const char **table, size_t siz, int value)
238 {
239 	static char buf[20];
240 	if (value < 0 || siz <= value || table[value] == NULL) {
241 		snprintf(buf, sizeof(buf), "#%d", value);
242 		return buf;
243 	} else
244 		return table[value];
245 }
246 
247 static const char *
248 bgp_notify_minor(int major, int minor)
249 {
250 	static const char **table;
251 	int siz;
252 	static char buf[20];
253 	const char *p;
254 
255 	if (0 <= major
256 	 && major < sizeof(bgpnotify_minor)/sizeof(bgpnotify_minor[0])
257 	 && bgpnotify_minor[major]) {
258 		table = bgpnotify_minor[major];
259 		siz = bgpnotify_minor_siz[major];
260 		if (0 <= minor && minor < siz && table[minor])
261 			p = table[minor];
262 		else
263 			p = NULL;
264 	} else
265 		p = NULL;
266 	if (p == NULL) {
267 		snprintf(buf, sizeof(buf), "#%d", minor);
268 		return buf;
269 	} else
270 		return p;
271 }
272 
273 static int
274 decode_prefix4(const u_char *pd, char *buf, u_int buflen)
275 {
276 	struct in_addr addr;
277 	u_int plen;
278 
279 	plen = pd[0];
280 	if (plen < 0 || 32 < plen)
281 		return -1;
282 
283 	memset(&addr, 0, sizeof(addr));
284 	memcpy(&addr, &pd[1], (plen + 7) / 8);
285 	if (plen % 8) {
286 		((u_char *)&addr)[(plen + 7) / 8 - 1] &=
287 			((0xff00 >> (plen % 8)) & 0xff);
288 	}
289 	snprintf(buf, buflen, "%s/%d", getname((u_char *)&addr), plen);
290 	return 1 + (plen + 7) / 8;
291 }
292 
293 #ifdef INET6
294 static int
295 decode_prefix6(const u_char *pd, char *buf, u_int buflen)
296 {
297 	struct in6_addr addr;
298 	u_int plen;
299 
300 	plen = pd[0];
301 	if (plen < 0 || 128 < plen)
302 		return -1;
303 
304 	memset(&addr, 0, sizeof(addr));
305 	memcpy(&addr, &pd[1], (plen + 7) / 8);
306 	if (plen % 8) {
307 		addr.s6_addr[(plen + 7) / 8 - 1] &=
308 			((0xff00 >> (plen % 8)) & 0xff);
309 	}
310 	snprintf(buf, buflen, "%s/%d", getname6((u_char *)&addr), plen);
311 	return 1 + (plen + 7) / 8;
312 }
313 #endif
314 
315 static void
316 bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len)
317 {
318 	int i;
319 	u_int16_t af;
320 	u_int8_t safi, snpa;
321 	int advance;
322 	int tlen;
323 	const u_char *p;
324 	char buf[MAXHOSTNAMELEN + 100];
325 
326 	p = dat;
327 
328 	switch (attr->bgpa_type) {
329 	case BGPTYPE_ORIGIN:
330 		if (len != 1)
331 			printf(" invalid len");
332 		else
333 			printf(" %s", bgp_attr_origin(p[0]));
334 		break;
335 	case BGPTYPE_AS_PATH:
336 		if (len % 2) {
337 			printf(" invalid len");
338 			break;
339 		}
340 		while (p < dat + len) {
341 			/*
342 			 * under RFC1965, p[0] means:
343 			 * 1: AS_SET 2: AS_SEQUENCE
344 			 * 3: AS_CONFED_SET 4: AS_CONFED_SEQUENCE
345 			 */
346 			printf(" ");
347 			if (p[0] == 3 || p[0] == 4)
348 				printf("confed");
349 			printf("%s", (p[0] & 1) ? "{" : "");
350 			for (i = 0; i < p[1] * 2; i += 2) {
351 				printf("%s%u", i == 0 ? "" : " ",
352 					EXTRACT_16BITS(&p[2 + i]));
353 			}
354 			printf("%s", (p[0] & 1) ? "}" : "");
355 			p += 2 + p[1] * 2;
356 		}
357 		break;
358 	case BGPTYPE_NEXT_HOP:
359 		if (len != 4)
360 			printf(" invalid len");
361 		else
362 			printf(" %s", getname(p));
363 		break;
364 	case BGPTYPE_MULTI_EXIT_DISC:
365 	case BGPTYPE_LOCAL_PREF:
366 		if (len != 4)
367 			printf(" invalid len");
368 		else
369 			printf(" %u", EXTRACT_32BITS(p));
370 		break;
371 	case BGPTYPE_ATOMIC_AGGREGATE:
372 		if (len != 0)
373 			printf(" invalid len");
374 		break;
375 	case BGPTYPE_AGGREGATOR:
376 		if (len != 6) {
377 			printf(" invalid len");
378 			break;
379 		}
380 		printf(" AS #%u, origin %s", EXTRACT_16BITS(p),
381 			getname(p + 2));
382 		break;
383 	case BGPTYPE_COMMUNITIES:
384 		if (len % 4) {
385 			printf(" invalid len");
386 			break;
387 		}
388 		for (i = 0; i < len; i += 4) {
389 			u_int32_t comm;
390 			comm = EXTRACT_32BITS(&p[i]);
391 			switch (comm) {
392 			case BGP_COMMUNITY_NO_EXPORT:
393 				printf(" NO_EXPORT");
394 				break;
395 			case BGP_COMMUNITY_NO_ADVERT:
396 				printf(" NO_ADVERTISE");
397 				break;
398 			case BGP_COMMUNITY_NO_EXPORT_SUBCONFED:
399 				printf(" NO_EXPORT_SUBCONFED");
400 				break;
401 			default:
402 				printf(" (AS #%d value 0x%04x)",
403 					(comm >> 16) & 0xffff, comm & 0xffff);
404 				break;
405 			}
406 		}
407 		break;
408 	case BGPTYPE_MP_REACH_NLRI:
409 		af = EXTRACT_16BITS(p);
410 		safi = p[2];
411 		if (safi >= 128)
412 			printf(" %s vendor specific,", af_name(af));
413 		else {
414 			printf(" %s %s,", af_name(af),
415 				bgp_attr_nlri_safi(safi));
416 		}
417 		p += 3;
418 
419 		if (af == AFNUM_INET)
420 			;
421 #ifdef INET6
422 		else if (af == AFNUM_INET6)
423 			;
424 #endif
425 		else
426 			break;
427 
428 		tlen = p[0];
429 		if (tlen) {
430 			printf(" nexthop");
431 			i = 0;
432 			while (i < tlen) {
433 				switch (af) {
434 				case AFNUM_INET:
435 					printf(" %s", getname(p + 1 + i));
436 					i += sizeof(struct in_addr);
437 					break;
438 #ifdef INET6
439 				case AFNUM_INET6:
440 					printf(" %s", getname6(p + 1 + i));
441 					i += sizeof(struct in6_addr);
442 					break;
443 #endif
444 				default:
445 					printf(" (unknown af)");
446 					i = tlen;	/*exit loop*/
447 					break;
448 				}
449 			}
450 			printf(",");
451 		}
452 		p += 1 + tlen;
453 
454 		snpa = p[0];
455 		p++;
456 		if (snpa) {
457 			printf(" %u snpa", snpa);
458 			for (/*nothing*/; snpa > 0; snpa--) {
459 				printf("(%d bytes)", p[0]);
460 				p += p[0] + 1;
461 			}
462 			printf(",");
463 		}
464 
465 		printf(" NLRI");
466 		while (len - (p - dat) > 0) {
467 			switch (af) {
468 			case AFNUM_INET:
469 				advance = decode_prefix4(p, buf, sizeof(buf));
470 				printf(" %s", buf);
471 				break;
472 #ifdef INET6
473 			case AFNUM_INET6:
474 				advance = decode_prefix6(p, buf, sizeof(buf));
475 				printf(" %s", buf);
476 				break;
477 #endif
478 			default:
479 				printf(" (unknown af)");
480 				advance = 0;
481 				p = dat + len;
482 				break;
483 			}
484 
485 			p += advance;
486 		}
487 
488 		break;
489 
490 	case BGPTYPE_MP_UNREACH_NLRI:
491 		af = EXTRACT_16BITS(p);
492 		safi = p[2];
493 		if (safi >= 128)
494 			printf(" %s vendor specific,", af_name(af));
495 		else {
496 			printf(" %s %s,", af_name(af),
497 				bgp_attr_nlri_safi(safi));
498 		}
499 		p += 3;
500 
501 		printf(" Withdraw");
502 		while (len - (p - dat) > 0) {
503 			switch (af) {
504 			case AFNUM_INET:
505 				advance = decode_prefix4(p, buf, sizeof(buf));
506 				printf(" %s", buf);
507 				break;
508 #ifdef INET6
509 			case AFNUM_INET6:
510 				advance = decode_prefix6(p, buf, sizeof(buf));
511 				printf(" %s", buf);
512 				break;
513 #endif
514 			default:
515 				printf(" (unknown af)");
516 				advance = 0;
517 				p = dat + len;
518 				break;
519 			}
520 
521 			p += advance;
522 		}
523 		break;
524 	default:
525 		break;
526 	}
527 }
528 
529 static void
530 bgp_open_print(const u_char *dat, int length)
531 {
532 	struct bgp_open bgpo;
533 	struct bgp_opt bgpopt;
534 	int hlen;
535 	const u_char *opt;
536 	int i;
537 
538 	TCHECK2(dat[0], BGP_OPEN_SIZE);
539 	memcpy(&bgpo, dat, BGP_OPEN_SIZE);
540 	hlen = ntohs(bgpo.bgpo_len);
541 
542 	printf(": Version %d,", bgpo.bgpo_version);
543 	printf(" AS #%u,", ntohs(bgpo.bgpo_myas));
544 	printf(" Holdtime %u,", ntohs(bgpo.bgpo_holdtime));
545 	printf(" ID %s,", getname((u_char *)&bgpo.bgpo_id));
546 	printf(" Option length %u", bgpo.bgpo_optlen);
547 
548 	/* ugly! */
549 	opt = &((const struct bgp_open *)dat)->bgpo_optlen;
550 	opt++;
551 
552 	i = 0;
553 	while (i < bgpo.bgpo_optlen) {
554 		TCHECK2(opt[i], BGP_OPT_SIZE);
555 		memcpy(&bgpopt, &opt[i], BGP_OPT_SIZE);
556 		if (i + 2 + bgpopt.bgpopt_len > bgpo.bgpo_optlen) {
557 			printf(" [|opt %d %d]", bgpopt.bgpopt_len, bgpopt.bgpopt_type);
558 			break;
559 		}
560 
561 		printf(" (option %s, len=%d)", bgp_opttype(bgpopt.bgpopt_type),
562 			bgpopt.bgpopt_len);
563 		i += BGP_OPT_SIZE + bgpopt.bgpopt_len;
564 	}
565 	return;
566 trunc:
567 	printf("[|BGP]");
568 }
569 
570 static void
571 bgp_update_print(const u_char *dat, int length)
572 {
573 	struct bgp bgp;
574 	struct bgp_attr bgpa;
575 	int hlen;
576 	const u_char *p;
577 	int len;
578 	int i;
579 	int newline;
580 
581 	TCHECK2(dat[0], BGP_SIZE);
582 	memcpy(&bgp, dat, BGP_SIZE);
583 	hlen = ntohs(bgp.bgp_len);
584 	p = dat + BGP_SIZE;	/*XXX*/
585 	printf(":");
586 
587 	/* Unfeasible routes */
588 	len = EXTRACT_16BITS(p);
589 	if (len) {
590 		/*
591 		 * Without keeping state from the original NLRI message,
592 		 * it's not possible to tell if this a v4 or v6 route,
593 		 * so only try to decode it if we're not v6 enabled.
594 	         */
595 #ifdef INET6
596 		printf(" (Withdrawn routes: %d bytes)", len);
597 #else
598 		char buf[MAXHOSTNAMELEN + 100];
599 
600 		TCHECK2(p[2], len);
601  		i = 2;
602 
603 		printf(" (Withdrawn routes:");
604 
605 		while(i < 2 + len) {
606 			i += decode_prefix4(&p[i], buf, sizeof(buf));
607 			printf(" %s", buf);
608 		}
609 		printf(")\n");
610 #endif
611 	}
612 	p += 2 + len;
613 
614 	TCHECK2(p[0], 2);
615 	len = EXTRACT_16BITS(p);
616 	if (len) {
617 		/* do something more useful!*/
618 		i = 2;
619 		printf(" (Path attributes:");	/* ) */
620 		newline = 0;
621 		while (i < 2 + len) {
622 			int alen, aoff;
623 
624 			TCHECK2(p[i], sizeof(bgpa));
625 			memcpy(&bgpa, &p[i], sizeof(bgpa));
626 			alen = bgp_attr_len(&bgpa);
627 			aoff = bgp_attr_off(&bgpa);
628 
629 			if (vflag && newline)
630 				printf("\n\t\t");
631 			else
632 				printf(" ");
633 			printf("(");		/* ) */
634 			printf("%s", bgp_attr_type(bgpa.bgpa_type));
635 			if (bgpa.bgpa_flags) {
636 				printf("[%s%s%s%s",
637 					bgpa.bgpa_flags & 0x80 ? "O" : "",
638 					bgpa.bgpa_flags & 0x40 ? "T" : "",
639 					bgpa.bgpa_flags & 0x20 ? "P" : "",
640 					bgpa.bgpa_flags & 0x10 ? "E" : "");
641 				if (bgpa.bgpa_flags & 0xf)
642 					printf("+%x", bgpa.bgpa_flags & 0xf);
643 				printf("]");
644 			}
645 
646 			bgp_attr_print(&bgpa, &p[i + aoff], alen);
647 			newline = 1;
648 
649 			/* ( */
650 			printf(")");
651 
652 			i += aoff + alen;
653 		}
654 
655 		/* ( */
656 		printf(")");
657 	}
658 	p += 2 + len;
659 
660 	if (len && dat + length > p)
661 		printf("\n\t\t");
662 	if (dat + length > p) {
663 		printf("(NLRI:");	/* ) */
664 		while (dat + length > p) {
665 			char buf[MAXHOSTNAMELEN + 100];
666 			i = decode_prefix4(p, buf, sizeof(buf));
667 			printf(" %s", buf);
668 			if (i < 0)
669 				break;
670 			p += i;
671 		}
672 
673 		/* ( */
674 		printf(")");
675 	}
676 	return;
677 trunc:
678 	printf("[|BGP]");
679 }
680 
681 static void
682 bgp_notification_print(const u_char *dat, int length)
683 {
684 	struct bgp_notification bgpn;
685 	int hlen;
686 
687 	TCHECK2(dat[0], BGP_NOTIFICATION_SIZE);
688 	memcpy(&bgpn, dat, BGP_NOTIFICATION_SIZE);
689 	hlen = ntohs(bgpn.bgpn_len);
690 
691 	printf(": error %s,", bgp_notify_major(bgpn.bgpn_major));
692 	printf(" subcode %s",
693 		bgp_notify_minor(bgpn.bgpn_major, bgpn.bgpn_minor));
694 	return;
695 trunc:
696 	printf("[|BGP]");
697 }
698 
699 static void
700 bgp_header_print(const u_char *dat, int length)
701 {
702 	struct bgp bgp;
703 
704 	TCHECK2(dat[0], BGP_SIZE);
705 	memcpy(&bgp, dat, BGP_SIZE);
706 	printf("(%s", bgp_type(bgp.bgp_type));		/* ) */
707 
708 	switch (bgp.bgp_type) {
709 	case BGP_OPEN:
710 		bgp_open_print(dat, length);
711 		break;
712 	case BGP_UPDATE:
713 		bgp_update_print(dat, length);
714 		break;
715 	case BGP_NOTIFICATION:
716 		bgp_notification_print(dat, length);
717 		break;
718 	}
719 
720 	/* ( */
721 	printf(")");
722 	return;
723 trunc:
724 	printf("[|BGP]");
725 }
726 
727 void
728 bgp_print(const u_char *dat, int length)
729 {
730 	const u_char *p;
731 	const u_char *ep;
732 	const u_char *start;
733 	const u_char marker[] = {
734 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
735 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
736 	};
737 	struct bgp bgp;
738 	u_int16_t hlen;
739 	int newline;
740 
741 	ep = dat + length;
742 	if (snapend < dat + length)
743 		ep = snapend;
744 
745 	printf(": BGP");
746 
747 	p = dat;
748 	newline = 0;
749 	start = p;
750 	while (p < snapend) {
751 		if (!TTEST2(p[0], 1))
752 			break;
753 		if (p[0] != 0xff) {
754 			p++;
755 			continue;
756 		}
757 
758 		if (!TTEST2(p[0], sizeof(marker)))
759 			break;
760 		if (memcmp(p, marker, sizeof(marker)) != 0) {
761 			p++;
762 			continue;
763 		}
764 
765 		/* found BGP header */
766 		TCHECK2(p[0], BGP_SIZE);	/*XXX*/
767 		memcpy(&bgp, p, BGP_SIZE);
768 
769 		if (start != p)
770 			printf(" [|BGP]");
771 
772 		hlen = ntohs(bgp.bgp_len);
773 		if (vflag && newline)
774 			printf("\n\t");
775 		else
776 			printf(" ");
777 		if (TTEST2(p[0], hlen)) {
778 			bgp_header_print(p, hlen);
779 			newline = 1;
780 			p += hlen;
781 			start = p;
782 		} else {
783 			printf("[|BGP %s]", bgp_type(bgp.bgp_type));
784 			break;
785 		}
786 	}
787 
788 	return;
789 
790 trunc:
791 	printf(" [|BGP]");
792 }
793