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