156893Sfenner/*
256893Sfenner * Copyright (C) 1999 WIDE Project.
356893Sfenner * All rights reserved.
4127668Sbms *
556893Sfenner * Redistribution and use in source and binary forms, with or without
656893Sfenner * modification, are permitted provided that the following conditions
756893Sfenner * are met:
856893Sfenner * 1. Redistributions of source code must retain the above copyright
956893Sfenner *    notice, this list of conditions and the following disclaimer.
1056893Sfenner * 2. Redistributions in binary form must reproduce the above copyright
1156893Sfenner *    notice, this list of conditions and the following disclaimer in the
1256893Sfenner *    documentation and/or other materials provided with the distribution.
1356893Sfenner * 3. Neither the name of the project nor the names of its contributors
1456893Sfenner *    may be used to endorse or promote products derived from this software
1556893Sfenner *    without specific prior written permission.
16127668Sbms *
1756893Sfenner * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1856893Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1956893Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2056893Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2156893Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2256893Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2356893Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2456893Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2556893Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2656893Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2756893Sfenner * SUCH DAMAGE.
28127668Sbms *
29127668Sbms * Extensively modified by Hannes Gredler (hannes@juniper.net) for more
30127668Sbms * complete BGP support.
3156893Sfenner */
3256893Sfenner
3356893Sfenner#ifdef HAVE_CONFIG_H
3456893Sfenner#include "config.h"
3556893Sfenner#endif
3656893Sfenner
3756893Sfenner#ifndef lint
38127668Sbmsstatic const char rcsid[] _U_ =
39214478Srpaulo     "@(#) $Header: /tcpdump/master/tcpdump/print-bgp.c,v 1.118 2007-12-07 15:54:52 hannes Exp $";
4056893Sfenner#endif
4156893Sfenner
42127668Sbms#include <tcpdump-stdinc.h>
4356893Sfenner
4456893Sfenner#include <stdio.h>
4556893Sfenner#include <string.h>
4656893Sfenner
4756893Sfenner#include "interface.h"
48146773Ssam#include "decode_prefix.h"
4956893Sfenner#include "addrtoname.h"
5075115Sfenner#include "extract.h"
51146773Ssam#include "bgp.h"
52190207Srpaulo#include "af.h"
53146773Ssam#include "l2vpn.h"
5456893Sfenner
5556893Sfennerstruct bgp {
5656893Sfenner	u_int8_t bgp_marker[16];
5756893Sfenner	u_int16_t bgp_len;
5856893Sfenner	u_int8_t bgp_type;
5956893Sfenner};
6056893Sfenner#define BGP_SIZE		19	/* unaligned */
6156893Sfenner
6256893Sfenner#define BGP_OPEN		1
6356893Sfenner#define BGP_UPDATE		2
6456893Sfenner#define BGP_NOTIFICATION	3
6556893Sfenner#define BGP_KEEPALIVE		4
66127668Sbms#define BGP_ROUTE_REFRESH       5
6756893Sfenner
68127668Sbmsstatic struct tok bgp_msg_values[] = {
69127668Sbms    { BGP_OPEN,                 "Open"},
70127668Sbms    { BGP_UPDATE,               "Update"},
71127668Sbms    { BGP_NOTIFICATION,         "Notification"},
72127668Sbms    { BGP_KEEPALIVE,            "Keepalive"},
73127668Sbms    { BGP_ROUTE_REFRESH,        "Route Refresh"},
74127668Sbms    { 0, NULL}
75127668Sbms};
76127668Sbms
7756893Sfennerstruct bgp_open {
7856893Sfenner	u_int8_t bgpo_marker[16];
7956893Sfenner	u_int16_t bgpo_len;
8056893Sfenner	u_int8_t bgpo_type;
8156893Sfenner	u_int8_t bgpo_version;
8256893Sfenner	u_int16_t bgpo_myas;
8356893Sfenner	u_int16_t bgpo_holdtime;
8456893Sfenner	u_int32_t bgpo_id;
8556893Sfenner	u_int8_t bgpo_optlen;
8656893Sfenner	/* options should follow */
8756893Sfenner};
8898524Sfenner#define BGP_OPEN_SIZE		29	/* unaligned */
8956893Sfenner
9056893Sfennerstruct bgp_opt {
9156893Sfenner	u_int8_t bgpopt_type;
9256893Sfenner	u_int8_t bgpopt_len;
9356893Sfenner	/* variable length */
9456893Sfenner};
9598524Sfenner#define BGP_OPT_SIZE		2	/* some compilers may pad to 4 bytes */
96241235Sdelphij#define BGP_CAP_HEADER_SIZE	2	/* some compilers may pad to 4 bytes */
9756893Sfenner
9856893Sfennerstruct bgp_notification {
9956893Sfenner	u_int8_t bgpn_marker[16];
10056893Sfenner	u_int16_t bgpn_len;
10156893Sfenner	u_int8_t bgpn_type;
10256893Sfenner	u_int8_t bgpn_major;
10356893Sfenner	u_int8_t bgpn_minor;
10456893Sfenner};
10598524Sfenner#define BGP_NOTIFICATION_SIZE		21	/* unaligned */
10656893Sfenner
107127668Sbmsstruct bgp_route_refresh {
108127668Sbms    u_int8_t  bgp_marker[16];
109127668Sbms    u_int16_t len;
110127668Sbms    u_int8_t  type;
111127668Sbms    u_int8_t  afi[2]; /* the compiler messes this structure up               */
112127668Sbms    u_int8_t  res;    /* when doing misaligned sequences of int8 and int16   */
113127668Sbms    u_int8_t  safi;   /* afi should be int16 - so we have to access it using */
114127668Sbms};                    /* EXTRACT_16BITS(&bgp_route_refresh->afi) (sigh)      */
115127668Sbms#define BGP_ROUTE_REFRESH_SIZE          23
116127668Sbms
117241235Sdelphij#define bgp_attr_lenlen(flags, p) \
118241235Sdelphij	(((flags) & 0x10) ? 2 : 1)
119241235Sdelphij#define bgp_attr_len(flags, p) \
120241235Sdelphij	(((flags) & 0x10) ? EXTRACT_16BITS(p) : *(p))
12156893Sfenner
12256893Sfenner#define BGPTYPE_ORIGIN			1
12356893Sfenner#define BGPTYPE_AS_PATH			2
12456893Sfenner#define BGPTYPE_NEXT_HOP		3
12556893Sfenner#define BGPTYPE_MULTI_EXIT_DISC		4
12656893Sfenner#define BGPTYPE_LOCAL_PREF		5
12756893Sfenner#define BGPTYPE_ATOMIC_AGGREGATE	6
12856893Sfenner#define BGPTYPE_AGGREGATOR		7
12956893Sfenner#define	BGPTYPE_COMMUNITIES		8	/* RFC1997 */
13056893Sfenner#define	BGPTYPE_ORIGINATOR_ID		9	/* RFC1998 */
13156893Sfenner#define	BGPTYPE_CLUSTER_LIST		10	/* RFC1998 */
132127668Sbms#define	BGPTYPE_DPA			11	/* draft-ietf-idr-bgp-dpa */
13356893Sfenner#define	BGPTYPE_ADVERTISERS		12	/* RFC1863 */
13456893Sfenner#define	BGPTYPE_RCID_PATH		13	/* RFC1863 */
13556893Sfenner#define BGPTYPE_MP_REACH_NLRI		14	/* RFC2283 */
13656893Sfenner#define BGPTYPE_MP_UNREACH_NLRI		15	/* RFC2283 */
137127668Sbms#define BGPTYPE_EXTD_COMMUNITIES        16      /* draft-ietf-idr-bgp-ext-communities */
138190207Srpaulo#define BGPTYPE_AS4_PATH	        17      /* RFC4893 */
139190207Srpaulo#define BGPTYPE_AGGREGATOR4		18      /* RFC4893 */
140190207Srpaulo#define BGPTYPE_PMSI_TUNNEL             22      /* draft-ietf-l3vpn-2547bis-mcast-bgp-02.txt */
141146773Ssam#define BGPTYPE_ATTR_SET               128      /* draft-marques-ppvpn-ibgp */
14256893Sfenner
143146773Ssam#define BGP_MP_NLRI_MINSIZE              3       /* End of RIB Marker detection */
144146773Ssam
145127668Sbmsstatic struct tok bgp_attr_values[] = {
146127668Sbms    { BGPTYPE_ORIGIN,           "Origin"},
147127668Sbms    { BGPTYPE_AS_PATH,          "AS Path"},
148190207Srpaulo    { BGPTYPE_AS4_PATH,         "AS4 Path"},
149127668Sbms    { BGPTYPE_NEXT_HOP,         "Next Hop"},
150127668Sbms    { BGPTYPE_MULTI_EXIT_DISC,  "Multi Exit Discriminator"},
151127668Sbms    { BGPTYPE_LOCAL_PREF,       "Local Preference"},
152127668Sbms    { BGPTYPE_ATOMIC_AGGREGATE, "Atomic Aggregate"},
153127668Sbms    { BGPTYPE_AGGREGATOR,       "Aggregator"},
154190207Srpaulo    { BGPTYPE_AGGREGATOR4,      "Aggregator4"},
155127668Sbms    { BGPTYPE_COMMUNITIES,      "Community"},
156127668Sbms    { BGPTYPE_ORIGINATOR_ID,    "Originator ID"},
157127668Sbms    { BGPTYPE_CLUSTER_LIST,     "Cluster List"},
158127668Sbms    { BGPTYPE_DPA,              "DPA"},
159127668Sbms    { BGPTYPE_ADVERTISERS,      "Advertisers"},
160127668Sbms    { BGPTYPE_RCID_PATH,        "RCID Path / Cluster ID"},
161127668Sbms    { BGPTYPE_MP_REACH_NLRI,    "Multi-Protocol Reach NLRI"},
162127668Sbms    { BGPTYPE_MP_UNREACH_NLRI,  "Multi-Protocol Unreach NLRI"},
163127668Sbms    { BGPTYPE_EXTD_COMMUNITIES, "Extended Community"},
164190207Srpaulo    { BGPTYPE_PMSI_TUNNEL,      "PMSI Tunnel"},
165146773Ssam    { BGPTYPE_ATTR_SET,         "Attribute Set"},
166127668Sbms    { 255,                      "Reserved for development"},
167127668Sbms    { 0, NULL}
168127668Sbms};
16956893Sfenner
170127668Sbms#define BGP_AS_SET             1
171127668Sbms#define BGP_AS_SEQUENCE        2
172127668Sbms#define BGP_CONFED_AS_SEQUENCE 3 /* draft-ietf-idr-rfc3065bis-01 */
173127668Sbms#define BGP_CONFED_AS_SET      4 /* draft-ietf-idr-rfc3065bis-01  */
174127668Sbms
175190207Srpaulo#define BGP_AS_SEG_TYPE_MIN    BGP_AS_SET
176190207Srpaulo#define BGP_AS_SEG_TYPE_MAX    BGP_CONFED_AS_SET
177190207Srpaulo
178127668Sbmsstatic struct tok bgp_as_path_segment_open_values[] = {
179127668Sbms    { BGP_AS_SEQUENCE,         ""},
180127668Sbms    { BGP_AS_SET,              "{ "},
181127668Sbms    { BGP_CONFED_AS_SEQUENCE,  "( "},
182127668Sbms    { BGP_CONFED_AS_SET,       "({ "},
183127668Sbms    { 0, NULL}
18456893Sfenner};
18556893Sfenner
186127668Sbmsstatic struct tok bgp_as_path_segment_close_values[] = {
187127668Sbms    { BGP_AS_SEQUENCE,         ""},
188127668Sbms    { BGP_AS_SET,              "}"},
189127668Sbms    { BGP_CONFED_AS_SEQUENCE,  ")"},
190127668Sbms    { BGP_CONFED_AS_SET,       "})"},
191127668Sbms    { 0, NULL}
19256893Sfenner};
19356893Sfenner
194127668Sbms#define BGP_OPT_AUTH                    1
195127668Sbms#define BGP_OPT_CAP                     2
196127668Sbms
197127668Sbms
198127668Sbmsstatic struct tok bgp_opt_values[] = {
199127668Sbms    { BGP_OPT_AUTH,             "Authentication Information"},
200127668Sbms    { BGP_OPT_CAP,              "Capabilities Advertisement"},
201127668Sbms    { 0, NULL}
20256893Sfenner};
20356893Sfenner
204127668Sbms#define BGP_CAPCODE_MP                  1
205127668Sbms#define BGP_CAPCODE_RR                  2
206146773Ssam#define BGP_CAPCODE_ORF                 3 /* XXX */
207127668Sbms#define BGP_CAPCODE_RESTART            64 /* draft-ietf-idr-restart-05  */
208146773Ssam#define BGP_CAPCODE_AS_NEW             65 /* XXX */
209146773Ssam#define BGP_CAPCODE_DYN_CAP            67 /* XXX */
210127668Sbms#define BGP_CAPCODE_RR_CISCO          128
211127668Sbms
212127668Sbmsstatic struct tok bgp_capcode_values[] = {
213127668Sbms    { BGP_CAPCODE_MP,           "Multiprotocol Extensions"},
214127668Sbms    { BGP_CAPCODE_RR,           "Route Refresh"},
215146773Ssam    { BGP_CAPCODE_ORF,          "Cooperative Route Filtering"},
216127668Sbms    { BGP_CAPCODE_RESTART,      "Graceful Restart"},
217146773Ssam    { BGP_CAPCODE_AS_NEW,       "32-Bit AS Number"},
218146773Ssam    { BGP_CAPCODE_DYN_CAP,      "Dynamic Capability"},
219127668Sbms    { BGP_CAPCODE_RR_CISCO,     "Route Refresh (Cisco)"},
220127668Sbms    { 0, NULL}
22156893Sfenner};
22256893Sfenner
223127668Sbms#define BGP_NOTIFY_MAJOR_MSG            1
224127668Sbms#define BGP_NOTIFY_MAJOR_OPEN           2
225127668Sbms#define BGP_NOTIFY_MAJOR_UPDATE         3
226127668Sbms#define BGP_NOTIFY_MAJOR_HOLDTIME       4
227127668Sbms#define BGP_NOTIFY_MAJOR_FSM            5
228127668Sbms#define BGP_NOTIFY_MAJOR_CEASE          6
229127668Sbms#define BGP_NOTIFY_MAJOR_CAP            7
230127668Sbms
231127668Sbmsstatic struct tok bgp_notify_major_values[] = {
232127668Sbms    { BGP_NOTIFY_MAJOR_MSG,     "Message Header Error"},
233127668Sbms    { BGP_NOTIFY_MAJOR_OPEN,    "OPEN Message Error"},
234127668Sbms    { BGP_NOTIFY_MAJOR_UPDATE,  "UPDATE Message Error"},
235127668Sbms    { BGP_NOTIFY_MAJOR_HOLDTIME,"Hold Timer Expired"},
236127668Sbms    { BGP_NOTIFY_MAJOR_FSM,     "Finite State Machine Error"},
237127668Sbms    { BGP_NOTIFY_MAJOR_CEASE,   "Cease"},
238127668Sbms    { BGP_NOTIFY_MAJOR_CAP,     "Capability Message Error"},
239127668Sbms    { 0, NULL}
24056893Sfenner};
24156893Sfenner
242127668Sbms/* draft-ietf-idr-cease-subcode-02 */
243127668Sbms#define BGP_NOTIFY_MINOR_CEASE_MAXPRFX  1
244127668Sbmsstatic struct tok bgp_notify_minor_cease_values[] = {
245127668Sbms    { BGP_NOTIFY_MINOR_CEASE_MAXPRFX, "Maximum Number of Prefixes Reached"},
246127668Sbms    { 2,                        "Administratively Shutdown"},
247127668Sbms    { 3,                        "Peer Unconfigured"},
248127668Sbms    { 4,                        "Administratively Reset"},
249127668Sbms    { 5,                        "Connection Rejected"},
250127668Sbms    { 6,                        "Other Configuration Change"},
251127668Sbms    { 7,                        "Connection Collision Resolution"},
252127668Sbms    { 0, NULL}
25356893Sfenner};
25456893Sfenner
255127668Sbmsstatic struct tok bgp_notify_minor_msg_values[] = {
256127668Sbms    { 1,                        "Connection Not Synchronized"},
257127668Sbms    { 2,                        "Bad Message Length"},
258127668Sbms    { 3,                        "Bad Message Type"},
259127668Sbms    { 0, NULL}
26056893Sfenner};
261127668Sbms
262127668Sbmsstatic struct tok bgp_notify_minor_open_values[] = {
263127668Sbms    { 1,                        "Unsupported Version Number"},
264127668Sbms    { 2,                        "Bad Peer AS"},
265127668Sbms    { 3,                        "Bad BGP Identifier"},
266127668Sbms    { 4,                        "Unsupported Optional Parameter"},
267127668Sbms    { 5,                        "Authentication Failure"},
268127668Sbms    { 6,                        "Unacceptable Hold Time"},
269190207Srpaulo    { 7,                        "Capability Message Error"},
270127668Sbms    { 0, NULL}
27156893Sfenner};
27256893Sfenner
273127668Sbmsstatic struct tok bgp_notify_minor_update_values[] = {
274127668Sbms    { 1,                        "Malformed Attribute List"},
275127668Sbms    { 2,                        "Unrecognized Well-known Attribute"},
276127668Sbms    { 3,                        "Missing Well-known Attribute"},
277127668Sbms    { 4,                        "Attribute Flags Error"},
278127668Sbms    { 5,                        "Attribute Length Error"},
279127668Sbms    { 6,                        "Invalid ORIGIN Attribute"},
280127668Sbms    { 7,                        "AS Routing Loop"},
281127668Sbms    { 8,                        "Invalid NEXT_HOP Attribute"},
282127668Sbms    { 9,                        "Optional Attribute Error"},
283127668Sbms    { 10,                       "Invalid Network Field"},
284127668Sbms    { 11,                       "Malformed AS_PATH"},
285127668Sbms    { 0, NULL}
28656893Sfenner};
28756893Sfenner
288127668Sbmsstatic struct tok bgp_notify_minor_cap_values[] = {
289127668Sbms    { 1,                        "Invalid Action Value" },
290127668Sbms    { 2,                        "Invalid Capability Length" },
291127668Sbms    { 3,                        "Malformed Capability Value" },
292127668Sbms    { 4,                        "Unsupported Capability Code" },
293127668Sbms    { 0, NULL }
29456893Sfenner};
29556893Sfenner
296127668Sbmsstatic struct tok bgp_origin_values[] = {
297127668Sbms    { 0,                        "IGP"},
298127668Sbms    { 1,                        "EGP"},
299127668Sbms    { 2,                        "Incomplete"},
300127668Sbms    { 0, NULL}
301127668Sbms};
302127668Sbms
303190207Srpaulo#define BGP_PMSI_TUNNEL_RSVP_P2MP 1
304190207Srpaulo#define BGP_PMSI_TUNNEL_LDP_P2MP  2
305190207Srpaulo#define BGP_PMSI_TUNNEL_PIM_SSM   3
306190207Srpaulo#define BGP_PMSI_TUNNEL_PIM_SM    4
307190207Srpaulo#define BGP_PMSI_TUNNEL_PIM_BIDIR 5
308190207Srpaulo#define BGP_PMSI_TUNNEL_INGRESS   6
309190207Srpaulo#define BGP_PMSI_TUNNEL_LDP_MP2MP 7
310190207Srpaulo
311190207Srpaulostatic struct tok bgp_pmsi_tunnel_values[] = {
312190207Srpaulo    { BGP_PMSI_TUNNEL_RSVP_P2MP, "RSVP-TE P2MP LSP"},
313190207Srpaulo    { BGP_PMSI_TUNNEL_LDP_P2MP, "LDP P2MP LSP"},
314190207Srpaulo    { BGP_PMSI_TUNNEL_PIM_SSM, "PIM-SSM Tree"},
315190207Srpaulo    { BGP_PMSI_TUNNEL_PIM_SM, "PIM-SM Tree"},
316190207Srpaulo    { BGP_PMSI_TUNNEL_PIM_BIDIR, "PIM-Bidir Tree"},
317190207Srpaulo    { BGP_PMSI_TUNNEL_INGRESS, "Ingress Replication"},
318190207Srpaulo    { BGP_PMSI_TUNNEL_LDP_MP2MP, "LDP MP2MP LSP"},
319190207Srpaulo    { 0, NULL}
320190207Srpaulo};
321190207Srpaulo
322190207Srpaulostatic struct tok bgp_pmsi_flag_values[] = {
323190207Srpaulo    { 0x01, "Leaf Information required"},
324190207Srpaulo    { 0, NULL}
325190207Srpaulo};
326190207Srpaulo
327190207Srpaulo
32856893Sfenner/* Subsequent address family identifier, RFC2283 section 7 */
329127668Sbms#define SAFNUM_RES                      0
330127668Sbms#define SAFNUM_UNICAST                  1
331127668Sbms#define SAFNUM_MULTICAST                2
332127668Sbms#define SAFNUM_UNIMULTICAST             3
333127668Sbms/* labeled BGP RFC3107 */
334127668Sbms#define SAFNUM_LABUNICAST               4
335190207Srpaulo/* draft-ietf-l3vpn-2547bis-mcast-bgp-02.txt */
336190207Srpaulo#define SAFNUM_MULTICAST_VPN            5
337146773Ssam#define SAFNUM_TUNNEL                   64 /* XXX */
338146773Ssam#define SAFNUM_VPLS                     65 /* XXX */
339214478Srpaulo/* draft-nalawade-idr-mdt-safi-03 */
340214478Srpaulo#define SAFNUM_MDT                      66
341127668Sbms/* Section 4.3.4 of draft-rosen-rfc2547bis-03.txt  */
342127668Sbms#define SAFNUM_VPNUNICAST               128
343127668Sbms#define SAFNUM_VPNMULTICAST             129
344127668Sbms#define SAFNUM_VPNUNIMULTICAST          130
345127668Sbms/* draft-marques-ppvpn-rt-constrain-01.txt */
346127668Sbms#define SAFNUM_RT_ROUTING_INFO          132
347127668Sbms
348127668Sbms#define BGP_VPN_RD_LEN                  8
349127668Sbms
350127668Sbmsstatic struct tok bgp_safi_values[] = {
351127668Sbms    { SAFNUM_RES,               "Reserved"},
352127668Sbms    { SAFNUM_UNICAST,           "Unicast"},
353127668Sbms    { SAFNUM_MULTICAST,         "Multicast"},
354127668Sbms    { SAFNUM_UNIMULTICAST,      "Unicast+Multicast"},
355127668Sbms    { SAFNUM_LABUNICAST,        "labeled Unicast"},
356146773Ssam    { SAFNUM_TUNNEL,            "Tunnel"},
357146773Ssam    { SAFNUM_VPLS,              "VPLS"},
358146773Ssam    { SAFNUM_MDT,               "MDT"},
359127668Sbms    { SAFNUM_VPNUNICAST,        "labeled VPN Unicast"},
360127668Sbms    { SAFNUM_VPNMULTICAST,      "labeled VPN Multicast"},
361127668Sbms    { SAFNUM_VPNUNIMULTICAST,   "labeled VPN Unicast+Multicast"},
362190207Srpaulo    { SAFNUM_RT_ROUTING_INFO,   "Route Target Routing Information"},
363190207Srpaulo    { SAFNUM_MULTICAST_VPN,     "Multicast VPN"},
364127668Sbms    { 0, NULL }
36556893Sfenner};
36656893Sfenner
36756893Sfenner/* well-known community */
36856893Sfenner#define BGP_COMMUNITY_NO_EXPORT			0xffffff01
36956893Sfenner#define BGP_COMMUNITY_NO_ADVERT			0xffffff02
37056893Sfenner#define BGP_COMMUNITY_NO_EXPORT_SUBCONFED	0xffffff03
37156893Sfenner
372127668Sbms/* Extended community type - draft-ietf-idr-bgp-ext-communities-05 */
373127668Sbms#define BGP_EXT_COM_RT_0        0x0002  /* Route Target,Format AS(2bytes):AN(4bytes) */
374127668Sbms#define BGP_EXT_COM_RT_1        0x0102  /* Route Target,Format IP address:AN(2bytes) */
375127668Sbms#define BGP_EXT_COM_RT_2        0x0202  /* Route Target,Format AN(4bytes):local(2bytes) */
376127668Sbms#define BGP_EXT_COM_RO_0        0x0003  /* Route Origin,Format AS(2bytes):AN(4bytes) */
377127668Sbms#define BGP_EXT_COM_RO_1        0x0103  /* Route Origin,Format IP address:AN(2bytes) */
378127668Sbms#define BGP_EXT_COM_RO_2        0x0203  /* Route Origin,Format AN(4bytes):local(2bytes) */
379127668Sbms#define BGP_EXT_COM_LINKBAND    0x4004  /* Link Bandwidth,Format AS(2B):Bandwidth(4B) */
380127668Sbms                                        /* rfc2547 bgp-mpls-vpns */
381127668Sbms#define BGP_EXT_COM_VPN_ORIGIN  0x0005  /* OSPF Domain ID / VPN of Origin  - draft-rosen-vpns-ospf-bgp-mpls */
382127668Sbms#define BGP_EXT_COM_VPN_ORIGIN2 0x0105  /* duplicate - keep for backwards compatability */
383127668Sbms#define BGP_EXT_COM_VPN_ORIGIN3 0x0205  /* duplicate - keep for backwards compatability */
384127668Sbms#define BGP_EXT_COM_VPN_ORIGIN4 0x8005  /* duplicate - keep for backwards compatability */
385127668Sbms
386127668Sbms#define BGP_EXT_COM_OSPF_RTYPE  0x0306  /* OSPF Route Type,Format Area(4B):RouteType(1B):Options(1B) */
387127668Sbms#define BGP_EXT_COM_OSPF_RTYPE2 0x8000  /* duplicate - keep for backwards compatability */
388127668Sbms
389127668Sbms#define BGP_EXT_COM_OSPF_RID    0x0107  /* OSPF Router ID,Format RouterID(4B):Unused(2B) */
390127668Sbms#define BGP_EXT_COM_OSPF_RID2   0x8001  /* duplicate - keep for backwards compatability */
391127668Sbms
392127668Sbms#define BGP_EXT_COM_L2INFO      0x800a  /* draft-kompella-ppvpn-l2vpn */
393127668Sbms
394235530Sdelphij#define BGP_EXT_COM_SOURCE_AS   0x0009  /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */
395235530Sdelphij#define BGP_EXT_COM_VRF_RT_IMP  0x010b  /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */
396235530Sdelphij#define BGP_EXT_COM_L2VPN_RT_0  0x000a  /* L2VPN Identifier,Format AS(2bytes):AN(4bytes) */
397235530Sdelphij#define BGP_EXT_COM_L2VPN_RT_1  0xF10a  /* L2VPN Identifier,Format IP address:AN(2bytes) */
398190207Srpaulo
399235530Sdelphij
400172683Smlaier/* http://www.cisco.com/en/US/tech/tk436/tk428/technologies_tech_note09186a00801eb09a.shtml  */
401172683Smlaier#define BGP_EXT_COM_EIGRP_GEN   0x8800
402172683Smlaier#define BGP_EXT_COM_EIGRP_METRIC_AS_DELAY  0x8801
403172683Smlaier#define BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW 0x8802
404172683Smlaier#define BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU  0x8803
405172683Smlaier#define BGP_EXT_COM_EIGRP_EXT_REMAS_REMID  0x8804
406172683Smlaier#define BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC 0x8805
407172683Smlaier
408127668Sbmsstatic struct tok bgp_extd_comm_flag_values[] = {
409127668Sbms    { 0x8000,                  "vendor-specific"},
410127668Sbms    { 0x4000,                  "non-transitive"},
411127668Sbms    { 0, NULL},
412127668Sbms};
413127668Sbms
414127668Sbmsstatic struct tok bgp_extd_comm_subtype_values[] = {
415127668Sbms    { BGP_EXT_COM_RT_0,        "target"},
416127668Sbms    { BGP_EXT_COM_RT_1,        "target"},
417127668Sbms    { BGP_EXT_COM_RT_2,        "target"},
418127668Sbms    { BGP_EXT_COM_RO_0,        "origin"},
419127668Sbms    { BGP_EXT_COM_RO_1,        "origin"},
420127668Sbms    { BGP_EXT_COM_RO_2,        "origin"},
421127668Sbms    { BGP_EXT_COM_LINKBAND,    "link-BW"},
422127668Sbms    { BGP_EXT_COM_VPN_ORIGIN,  "ospf-domain"},
423127668Sbms    { BGP_EXT_COM_VPN_ORIGIN2, "ospf-domain"},
424127668Sbms    { BGP_EXT_COM_VPN_ORIGIN3, "ospf-domain"},
425127668Sbms    { BGP_EXT_COM_VPN_ORIGIN4, "ospf-domain"},
426127668Sbms    { BGP_EXT_COM_OSPF_RTYPE,  "ospf-route-type"},
427127668Sbms    { BGP_EXT_COM_OSPF_RTYPE2, "ospf-route-type"},
428127668Sbms    { BGP_EXT_COM_OSPF_RID,    "ospf-router-id"},
429127668Sbms    { BGP_EXT_COM_OSPF_RID2,   "ospf-router-id"},
430127668Sbms    { BGP_EXT_COM_L2INFO,      "layer2-info"},
431172683Smlaier    { BGP_EXT_COM_EIGRP_GEN , "eigrp-general-route (flag, tag)" },
432172683Smlaier    { BGP_EXT_COM_EIGRP_METRIC_AS_DELAY , "eigrp-route-metric (AS, delay)" },
433172683Smlaier    { BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW , "eigrp-route-metric (reliability, nexthop, bandwidth)" },
434172683Smlaier    { BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU , "eigrp-route-metric (load, MTU)" },
435172683Smlaier    { BGP_EXT_COM_EIGRP_EXT_REMAS_REMID , "eigrp-external-route (remote-AS, remote-ID)" },
436172683Smlaier    { BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC , "eigrp-external-route (remote-proto, remote-metric)" },
437190207Srpaulo    { BGP_EXT_COM_SOURCE_AS, "source-AS" },
438190207Srpaulo    { BGP_EXT_COM_VRF_RT_IMP, "vrf-route-import"},
439235530Sdelphij    { BGP_EXT_COM_L2VPN_RT_0, "l2vpn-id"},
440235530Sdelphij    { BGP_EXT_COM_L2VPN_RT_1, "l2vpn-id"},
441127668Sbms    { 0, NULL},
442127668Sbms};
443127668Sbms
444127668Sbms/* OSPF codes for  BGP_EXT_COM_OSPF_RTYPE draft-rosen-vpns-ospf-bgp-mpls  */
445127668Sbms#define BGP_OSPF_RTYPE_RTR      1 /* OSPF Router LSA */
446127668Sbms#define BGP_OSPF_RTYPE_NET      2 /* OSPF Network LSA */
447127668Sbms#define BGP_OSPF_RTYPE_SUM      3 /* OSPF Summary LSA */
448127668Sbms#define BGP_OSPF_RTYPE_EXT      5 /* OSPF External LSA, note that ASBR doesn't apply to MPLS-VPN */
449127668Sbms#define BGP_OSPF_RTYPE_NSSA     7 /* OSPF NSSA External*/
450127668Sbms#define BGP_OSPF_RTYPE_SHAM     129 /* OSPF-MPLS-VPN Sham link */
451127668Sbms#define BGP_OSPF_RTYPE_METRIC_TYPE 0x1 /* LSB of RTYPE Options Field */
452127668Sbms
453127668Sbmsstatic struct tok bgp_extd_comm_ospf_rtype_values[] = {
454127668Sbms  { BGP_OSPF_RTYPE_RTR, "Router" },
455127668Sbms  { BGP_OSPF_RTYPE_NET, "Network" },
456127668Sbms  { BGP_OSPF_RTYPE_SUM, "Summary" },
457127668Sbms  { BGP_OSPF_RTYPE_EXT, "External" },
458127668Sbms  { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
459127668Sbms  { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },
460127668Sbms  { 0, NULL },
461127668Sbms};
462127668Sbms
463214478Srpaulo#define TOKBUFSIZE 128
464214478Srpaulostatic char astostr[20];
465214478Srpaulo
466214478Srpaulo/*
467214478Srpaulo * as_printf
468214478Srpaulo *
469214478Srpaulo * Convert an AS number into a string and return string pointer.
470214478Srpaulo *
471214478Srpaulo * Bepending on bflag is set or not, AS number is converted into ASDOT notation
472214478Srpaulo * or plain number notation.
473214478Srpaulo *
474214478Srpaulo */
475214478Srpaulostatic char *
476214478Srpauloas_printf (char *str, int size, u_int asnum)
477214478Srpaulo{
478214478Srpaulo	if (!bflag || asnum <= 0xFFFF) {
479214478Srpaulo		snprintf(str, size, "%u", asnum);
480214478Srpaulo	} else {
481214478Srpaulo		snprintf(str, size, "%u.%u", asnum >> 16, asnum & 0xFFFF);
482214478Srpaulo	}
483214478Srpaulo	return str;
484214478Srpaulo}
485214478Srpaulo
486241235Sdelphij#define ITEMCHECK(minlen) if (itemlen < minlen) goto badtlv;
487241235Sdelphij
488146773Ssamint
489241235Sdelphijdecode_prefix4(const u_char *pptr, u_int itemlen, char *buf, u_int buflen)
49056893Sfenner{
491127668Sbms	struct in_addr addr;
492241235Sdelphij	u_int plen, plenbytes;
493127668Sbms
494127668Sbms	TCHECK(pptr[0]);
495241235Sdelphij	ITEMCHECK(1);
496127668Sbms	plen = pptr[0];
497127668Sbms	if (32 < plen)
498127668Sbms		return -1;
499241235Sdelphij	itemlen -= 1;
500127668Sbms
501127668Sbms	memset(&addr, 0, sizeof(addr));
502241235Sdelphij	plenbytes = (plen + 7) / 8;
503241235Sdelphij	TCHECK2(pptr[1], plenbytes);
504241235Sdelphij	ITEMCHECK(plenbytes);
505241235Sdelphij	memcpy(&addr, &pptr[1], plenbytes);
506127668Sbms	if (plen % 8) {
507241235Sdelphij		((u_char *)&addr)[plenbytes - 1] &=
508127668Sbms			((0xff00 >> (plen % 8)) & 0xff);
509127668Sbms	}
510127668Sbms	snprintf(buf, buflen, "%s/%d", getname((u_char *)&addr), plen);
511241235Sdelphij	return 1 + plenbytes;
512127668Sbms
513127668Sbmstrunc:
514127668Sbms	return -2;
515241235Sdelphij
516241235Sdelphijbadtlv:
517241235Sdelphij	return -3;
51856893Sfenner}
51956893Sfenner
520127668Sbmsstatic int
521241235Sdelphijdecode_labeled_prefix4(const u_char *pptr, u_int itemlen, char *buf, u_int buflen)
52256893Sfenner{
523127668Sbms	struct in_addr addr;
524241235Sdelphij	u_int plen, plenbytes;
52556893Sfenner
526241235Sdelphij	/* prefix length and label = 4 bytes */
527241235Sdelphij	TCHECK2(pptr[0], 4);
528241235Sdelphij	ITEMCHECK(4);
529127668Sbms	plen = pptr[0];   /* get prefix length */
530127668Sbms
531127668Sbms        /* this is one of the weirdnesses of rfc3107
532127668Sbms           the label length (actually the label + COS bits)
533127668Sbms           is added to the prefix length;
534127668Sbms           we also do only read out just one label -
535127668Sbms           there is no real application for advertisement of
536127668Sbms           stacked labels in a a single BGP message
537127668Sbms        */
538127668Sbms
539172683Smlaier	if (24 > plen)
540172683Smlaier		return -1;
541172683Smlaier
542127668Sbms        plen-=24; /* adjust prefixlen - labellength */
543127668Sbms
544127668Sbms	if (32 < plen)
545127668Sbms		return -1;
546241235Sdelphij	itemlen -= 4;
547127668Sbms
548127668Sbms	memset(&addr, 0, sizeof(addr));
549241235Sdelphij	plenbytes = (plen + 7) / 8;
550241235Sdelphij	TCHECK2(pptr[4], plenbytes);
551241235Sdelphij	ITEMCHECK(plenbytes);
552241235Sdelphij	memcpy(&addr, &pptr[4], plenbytes);
553127668Sbms	if (plen % 8) {
554241235Sdelphij		((u_char *)&addr)[plenbytes - 1] &=
555127668Sbms			((0xff00 >> (plen % 8)) & 0xff);
556127668Sbms	}
557127668Sbms        /* the label may get offsetted by 4 bits so lets shift it right */
558127668Sbms	snprintf(buf, buflen, "%s/%d, label:%u %s",
559127668Sbms                 getname((u_char *)&addr),
560127668Sbms                 plen,
561127668Sbms                 EXTRACT_24BITS(pptr+1)>>4,
562127668Sbms                 ((pptr[3]&1)==0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
563127668Sbms
564241235Sdelphij	return 4 + plenbytes;
565127668Sbms
566127668Sbmstrunc:
567127668Sbms	return -2;
568241235Sdelphij
569241235Sdelphijbadtlv:
570241235Sdelphij	return -3;
57156893Sfenner}
57256893Sfenner
573190207Srpaulo/*
574190207Srpaulo * bgp_vpn_ip_print
575190207Srpaulo *
576190207Srpaulo * print an ipv4 or ipv6 address into a buffer dependend on address length.
577190207Srpaulo */
578190207Srpaulostatic char *
579190207Srpaulobgp_vpn_ip_print (const u_char *pptr, u_int addr_length) {
580190207Srpaulo
581190207Srpaulo    /* worst case string is s fully formatted v6 address */
582190207Srpaulo    static char addr[sizeof("1234:5678:89ab:cdef:1234:5678:89ab:cdef")];
583190207Srpaulo    char *pos = addr;
584190207Srpaulo
585190207Srpaulo    switch(addr_length) {
586190207Srpaulo    case (sizeof(struct in_addr) << 3): /* 32 */
587190207Srpaulo        TCHECK2(pptr[0], sizeof(struct in_addr));
588190207Srpaulo        snprintf(pos, sizeof(addr), "%s", ipaddr_string(pptr));
589190207Srpaulo        break;
590190207Srpaulo#ifdef INET6
591190207Srpaulo    case (sizeof(struct in6_addr) << 3): /* 128 */
592190207Srpaulo        TCHECK2(pptr[0], sizeof(struct in6_addr));
593190207Srpaulo        snprintf(pos, sizeof(addr), "%s", ip6addr_string(pptr));
594190207Srpaulo        break;
595190207Srpaulo#endif
596190207Srpaulo    default:
597190207Srpaulo        snprintf(pos, sizeof(addr), "bogus address length %u", addr_length);
598190207Srpaulo        break;
599190207Srpaulo    }
600190207Srpaulo    pos += strlen(pos);
601190207Srpaulo
602190207Srpaulotrunc:
603190207Srpaulo    *(pos) = '\0';
604190207Srpaulo    return (addr);
605190207Srpaulo}
606190207Srpaulo
607190207Srpaulo/*
608190207Srpaulo * bgp_vpn_sg_print
609190207Srpaulo *
610190207Srpaulo * print an multicast s,g entry into a buffer.
611190207Srpaulo * the s,g entry is encoded like this.
612190207Srpaulo *
613190207Srpaulo * +-----------------------------------+
614190207Srpaulo * | Multicast Source Length (1 octet) |
615190207Srpaulo * +-----------------------------------+
616190207Srpaulo * |   Multicast Source (Variable)     |
617190207Srpaulo * +-----------------------------------+
618190207Srpaulo * |  Multicast Group Length (1 octet) |
619190207Srpaulo * +-----------------------------------+
620190207Srpaulo * |  Multicast Group   (Variable)     |
621190207Srpaulo * +-----------------------------------+
622190207Srpaulo *
623190207Srpaulo * return the number of bytes read from the wire.
624190207Srpaulo */
625190207Srpaulostatic int
626190207Srpaulobgp_vpn_sg_print (const u_char *pptr, char *buf, u_int buflen) {
627190207Srpaulo
628190207Srpaulo    u_int8_t addr_length;
629190207Srpaulo    u_int total_length, offset;
630190207Srpaulo
631190207Srpaulo    total_length = 0;
632190207Srpaulo
633190207Srpaulo    /* Source address length, encoded in bits */
634190207Srpaulo    TCHECK2(pptr[0], 1);
635190207Srpaulo    addr_length =  *pptr++;
636190207Srpaulo
637190207Srpaulo    /* Source address */
638190207Srpaulo    TCHECK2(pptr[0], (addr_length >> 3));
639190207Srpaulo    total_length += (addr_length >> 3) + 1;
640190207Srpaulo    offset = strlen(buf);
641190207Srpaulo    if (addr_length) {
642190207Srpaulo        snprintf(buf + offset, buflen - offset, ", Source %s",
643190207Srpaulo                 bgp_vpn_ip_print(pptr, addr_length));
644190207Srpaulo        pptr += (addr_length >> 3);
645190207Srpaulo    }
646190207Srpaulo
647190207Srpaulo    /* Group address length, encoded in bits */
648190207Srpaulo    TCHECK2(pptr[0], 1);
649190207Srpaulo    addr_length =  *pptr++;
650190207Srpaulo
651190207Srpaulo    /* Group address */
652190207Srpaulo    TCHECK2(pptr[0], (addr_length >> 3));
653190207Srpaulo    total_length += (addr_length >> 3) + 1;
654190207Srpaulo    offset = strlen(buf);
655190207Srpaulo    if (addr_length) {
656190207Srpaulo        snprintf(buf + offset, buflen - offset, ", Group %s",
657190207Srpaulo                 bgp_vpn_ip_print(pptr, addr_length));
658190207Srpaulo        pptr += (addr_length >> 3);
659190207Srpaulo    }
660190207Srpaulo
661190207Srpaulotrunc:
662190207Srpaulo    return (total_length);
663190207Srpaulo}
664190207Srpaulo
665190207Srpaulo
666127668Sbms/* RDs and RTs share the same semantics
667127668Sbms * we use bgp_vpn_rd_print for
668127668Sbms * printing route targets inside a NLRI */
669146773Ssamchar *
670127668Sbmsbgp_vpn_rd_print (const u_char *pptr) {
671127668Sbms
672146773Ssam   /* allocate space for the largest possible string */
673146773Ssam    static char rd[sizeof("xxxxxxxxxx:xxxxx (xxx.xxx.xxx.xxx:xxxxx)")];
674127668Sbms    char *pos = rd;
675127668Sbms
676127668Sbms    /* ok lets load the RD format */
677127668Sbms    switch (EXTRACT_16BITS(pptr)) {
678127668Sbms
679190207Srpaulo        /* 2-byte-AS:number fmt*/
680127668Sbms    case 0:
681190207Srpaulo        snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (= %u.%u.%u.%u)",
682190207Srpaulo                 EXTRACT_16BITS(pptr+2),
683190207Srpaulo                 EXTRACT_32BITS(pptr+4),
684190207Srpaulo                 *(pptr+4), *(pptr+5), *(pptr+6), *(pptr+7));
685127668Sbms        break;
686127668Sbms        /* IP-address:AS fmt*/
687127668Sbms
688127668Sbms    case 1:
689127668Sbms        snprintf(pos, sizeof(rd) - (pos - rd), "%u.%u.%u.%u:%u",
690127668Sbms            *(pptr+2), *(pptr+3), *(pptr+4), *(pptr+5), EXTRACT_16BITS(pptr+6));
691127668Sbms        break;
692127668Sbms
693127668Sbms        /* 4-byte-AS:number fmt*/
694127668Sbms    case 2:
695214478Srpaulo	snprintf(pos, sizeof(rd) - (pos - rd), "%s:%u (%u.%u.%u.%u:%u)",
696214478Srpaulo	    as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(pptr+2)),
697214478Srpaulo	    EXTRACT_16BITS(pptr+6), *(pptr+2), *(pptr+3), *(pptr+4),
698214478Srpaulo	    *(pptr+5), EXTRACT_16BITS(pptr+6));
699127668Sbms        break;
700127668Sbms    default:
701127668Sbms        snprintf(pos, sizeof(rd) - (pos - rd), "unknown RD format");
702127668Sbms        break;
703127668Sbms    }
704127668Sbms    pos += strlen(pos);
705127668Sbms    *(pos) = '\0';
706127668Sbms    return (rd);
707127668Sbms}
708127668Sbms
70956893Sfennerstatic int
710127668Sbmsdecode_rt_routing_info(const u_char *pptr, char *buf, u_int buflen)
71156893Sfenner{
712127668Sbms	u_int8_t route_target[8];
713127668Sbms	u_int plen;
714127668Sbms
715127668Sbms	TCHECK(pptr[0]);
716127668Sbms	plen = pptr[0];   /* get prefix length */
717127668Sbms
718172683Smlaier	if (0 == plen)
719172683Smlaier		return 1; /* default route target */
720172683Smlaier
721172683Smlaier	if (32 > plen)
722172683Smlaier		return -1;
723172683Smlaier
724127668Sbms        plen-=32; /* adjust prefix length */
725127668Sbms
726172683Smlaier	if (64 < plen)
727127668Sbms		return -1;
728127668Sbms
729127668Sbms	memset(&route_target, 0, sizeof(route_target));
730127668Sbms	TCHECK2(pptr[1], (plen + 7) / 8);
731127668Sbms	memcpy(&route_target, &pptr[1], (plen + 7) / 8);
732127668Sbms	if (plen % 8) {
733127668Sbms		((u_char *)&route_target)[(plen + 7) / 8 - 1] &=
734127668Sbms			((0xff00 >> (plen % 8)) & 0xff);
735127668Sbms	}
736214478Srpaulo	snprintf(buf, buflen, "origin AS: %s, route target %s",
737214478Srpaulo	    as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(pptr+1)),
738214478Srpaulo	    bgp_vpn_rd_print((u_char *)&route_target));
739127668Sbms
740127668Sbms	return 5 + (plen + 7) / 8;
741127668Sbms
742127668Sbmstrunc:
743127668Sbms	return -2;
744127668Sbms}
745127668Sbms
746127668Sbmsstatic int
747127668Sbmsdecode_labeled_vpn_prefix4(const u_char *pptr, char *buf, u_int buflen)
748127668Sbms{
74956893Sfenner	struct in_addr addr;
75098524Sfenner	u_int plen;
75156893Sfenner
752127668Sbms	TCHECK(pptr[0]);
753127668Sbms	plen = pptr[0];   /* get prefix length */
754127668Sbms
755172683Smlaier	if ((24+64) > plen)
756172683Smlaier		return -1;
757172683Smlaier
758127668Sbms        plen-=(24+64); /* adjust prefixlen - labellength - RD len*/
759127668Sbms
760127668Sbms	if (32 < plen)
76156893Sfenner		return -1;
76256893Sfenner
76356893Sfenner	memset(&addr, 0, sizeof(addr));
764127668Sbms	TCHECK2(pptr[12], (plen + 7) / 8);
765127668Sbms	memcpy(&addr, &pptr[12], (plen + 7) / 8);
76656893Sfenner	if (plen % 8) {
76756893Sfenner		((u_char *)&addr)[(plen + 7) / 8 - 1] &=
76856893Sfenner			((0xff00 >> (plen % 8)) & 0xff);
76956893Sfenner	}
770127668Sbms        /* the label may get offsetted by 4 bits so lets shift it right */
771127668Sbms	snprintf(buf, buflen, "RD: %s, %s/%d, label:%u %s",
772127668Sbms                 bgp_vpn_rd_print(pptr+4),
773127668Sbms                 getname((u_char *)&addr),
774127668Sbms                 plen,
775127668Sbms                 EXTRACT_24BITS(pptr+1)>>4,
776127668Sbms                 ((pptr[3]&1)==0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
777127668Sbms
778127668Sbms	return 12 + (plen + 7) / 8;
779127668Sbms
780127668Sbmstrunc:
781127668Sbms	return -2;
78256893Sfenner}
78356893Sfenner
784214478Srpaulo/*
785214478Srpaulo * +-------------------------------+
786214478Srpaulo * |                               |
787214478Srpaulo * |  RD:IPv4-address (12 octets)  |
788214478Srpaulo * |                               |
789214478Srpaulo * +-------------------------------+
790214478Srpaulo * |  MDT Group-address (4 octets) |
791214478Srpaulo * +-------------------------------+
792214478Srpaulo */
793214478Srpaulo
794214478Srpaulo#define MDT_VPN_NLRI_LEN 16
795214478Srpaulo
796214478Srpaulostatic int
797214478Srpaulodecode_mdt_vpn_nlri(const u_char *pptr, char *buf, u_int buflen)
798214478Srpaulo{
799214478Srpaulo
800214478Srpaulo    const u_char *rd;
801214478Srpaulo    const u_char *vpn_ip;
802214478Srpaulo
803214478Srpaulo    TCHECK(pptr[0]);
804214478Srpaulo
805214478Srpaulo    /* if the NLRI is not predefined length, quit.*/
806214478Srpaulo    if (*pptr != MDT_VPN_NLRI_LEN * NBBY)
807214478Srpaulo	return -1;
808214478Srpaulo    pptr++;
809214478Srpaulo
810214478Srpaulo    /* RD */
811214478Srpaulo    TCHECK2(pptr[0], 8);
812214478Srpaulo    rd = pptr;
813214478Srpaulo    pptr+=8;
814214478Srpaulo
815214478Srpaulo    /* IPv4 address */
816214478Srpaulo    TCHECK2(pptr[0], sizeof(struct in_addr));
817214478Srpaulo    vpn_ip = pptr;
818214478Srpaulo    pptr+=sizeof(struct in_addr);
819214478Srpaulo
820214478Srpaulo    /* MDT Group Address */
821214478Srpaulo    TCHECK2(pptr[0], sizeof(struct in_addr));
822214478Srpaulo
823214478Srpaulo    snprintf(buf, buflen, "RD: %s, VPN IP Address: %s, MC Group Address: %s",
824214478Srpaulo	     bgp_vpn_rd_print(rd), ipaddr_string(vpn_ip), ipaddr_string(pptr));
825214478Srpaulo
826214478Srpaulo    return MDT_VPN_NLRI_LEN + 1;
827214478Srpaulo
828214478Srpaulo trunc:
829214478Srpaulo
830214478Srpauloreturn -2;
831214478Srpaulo}
832214478Srpaulo
833190207Srpaulo#define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI   1
834190207Srpaulo#define BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI   2
835190207Srpaulo#define BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI            3
836190207Srpaulo#define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF 4
837190207Srpaulo#define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE     5
838190207Srpaulo#define BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN  6
839190207Srpaulo#define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN  7
840190207Srpaulo
841190207Srpaulostatic struct tok bgp_multicast_vpn_route_type_values[] = {
842190207Srpaulo    { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI, "Intra-AS I-PMSI"},
843190207Srpaulo    { BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI, "Inter-AS I-PMSI"},
844190207Srpaulo    { BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI, "S-PMSI"},
845190207Srpaulo    { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF, "Intra-AS Segment-Leaf"},
846190207Srpaulo    { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE, "Source-Active"},
847190207Srpaulo    { BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN, "Shared Tree Join"},
848190207Srpaulo    { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN, "Source Tree Join"},
849190207Srpaulo};
850190207Srpaulo
851190207Srpaulostatic int
852190207Srpaulodecode_multicast_vpn(const u_char *pptr, char *buf, u_int buflen)
853190207Srpaulo{
854190207Srpaulo        u_int8_t route_type, route_length, addr_length, sg_length;
855190207Srpaulo        u_int offset;
856190207Srpaulo
857190207Srpaulo	TCHECK2(pptr[0], 2);
858190207Srpaulo        route_type = *pptr++;
859190207Srpaulo        route_length = *pptr++;
860190207Srpaulo
861190207Srpaulo        snprintf(buf, buflen, "Route-Type: %s (%u), length: %u",
862190207Srpaulo                 tok2str(bgp_multicast_vpn_route_type_values,
863190207Srpaulo                         "Unknown", route_type),
864190207Srpaulo                 route_type, route_length);
865190207Srpaulo
866190207Srpaulo        switch(route_type) {
867190207Srpaulo        case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI:
868190207Srpaulo            TCHECK2(pptr[0], BGP_VPN_RD_LEN);
869190207Srpaulo            offset = strlen(buf);
870190207Srpaulo            snprintf(buf + offset, buflen - offset, ", RD: %s, Originator %s",
871190207Srpaulo                     bgp_vpn_rd_print(pptr),
872190207Srpaulo                     bgp_vpn_ip_print(pptr + BGP_VPN_RD_LEN,
873190207Srpaulo                                      (route_length - BGP_VPN_RD_LEN) << 3));
874190207Srpaulo            break;
875190207Srpaulo        case BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI:
876190207Srpaulo            TCHECK2(pptr[0], BGP_VPN_RD_LEN + 4);
877190207Srpaulo            offset = strlen(buf);
878214478Srpaulo	    snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s",
879214478Srpaulo		bgp_vpn_rd_print(pptr),
880214478Srpaulo		as_printf(astostr, sizeof(astostr),
881214478Srpaulo		EXTRACT_32BITS(pptr + BGP_VPN_RD_LEN)));
882190207Srpaulo            break;
883190207Srpaulo
884190207Srpaulo        case BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI:
885190207Srpaulo            TCHECK2(pptr[0], BGP_VPN_RD_LEN);
886190207Srpaulo            offset = strlen(buf);
887190207Srpaulo            snprintf(buf + offset, buflen - offset, ", RD: %s",
888190207Srpaulo                     bgp_vpn_rd_print(pptr));
889190207Srpaulo            pptr += BGP_VPN_RD_LEN;
890190207Srpaulo
891190207Srpaulo            sg_length = bgp_vpn_sg_print(pptr, buf, buflen);
892190207Srpaulo            addr_length =  route_length - sg_length;
893190207Srpaulo
894190207Srpaulo            TCHECK2(pptr[0], addr_length);
895190207Srpaulo            offset = strlen(buf);
896190207Srpaulo            snprintf(buf + offset, buflen - offset, ", Originator %s",
897190207Srpaulo                     bgp_vpn_ip_print(pptr, addr_length << 3));
898190207Srpaulo            break;
899190207Srpaulo
900190207Srpaulo        case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE:
901190207Srpaulo            TCHECK2(pptr[0], BGP_VPN_RD_LEN);
902190207Srpaulo            offset = strlen(buf);
903190207Srpaulo            snprintf(buf + offset, buflen - offset, ", RD: %s",
904190207Srpaulo                     bgp_vpn_rd_print(pptr));
905190207Srpaulo            pptr += BGP_VPN_RD_LEN;
906190207Srpaulo
907190207Srpaulo            bgp_vpn_sg_print(pptr, buf, buflen);
908190207Srpaulo            break;
909190207Srpaulo
910190207Srpaulo        case BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN: /* fall through */
911190207Srpaulo        case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN:
912190207Srpaulo            TCHECK2(pptr[0], BGP_VPN_RD_LEN);
913190207Srpaulo            offset = strlen(buf);
914214478Srpaulo	    snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s",
915214478Srpaulo		bgp_vpn_rd_print(pptr),
916214478Srpaulo		as_printf(astostr, sizeof(astostr),
917214478Srpaulo		EXTRACT_32BITS(pptr + BGP_VPN_RD_LEN)));
918190207Srpaulo            pptr += BGP_VPN_RD_LEN;
919190207Srpaulo
920190207Srpaulo            bgp_vpn_sg_print(pptr, buf, buflen);
921190207Srpaulo            break;
922190207Srpaulo
923190207Srpaulo            /*
924190207Srpaulo             * no per route-type printing yet.
925190207Srpaulo             */
926190207Srpaulo        case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF:
927190207Srpaulo        default:
928190207Srpaulo            break;
929190207Srpaulo        }
930190207Srpaulo
931190207Srpaulo        return route_length + 2;
932190207Srpaulo
933190207Srpaulotrunc:
934190207Srpaulo	return -2;
935190207Srpaulo}
936190207Srpaulo
937171682Ssimon/*
938171682Ssimon * As I remember, some versions of systems have an snprintf() that
939171682Ssimon * returns -1 if the buffer would have overflowed.  If the return
940171682Ssimon * value is negative, set buflen to 0, to indicate that we've filled
941171682Ssimon * the buffer up.
942171682Ssimon *
943171682Ssimon * If the return value is greater than buflen, that means that
944171682Ssimon * the buffer would have overflowed; again, set buflen to 0 in
945171682Ssimon * that case.
946171682Ssimon */
947171682Ssimon#define UPDATE_BUF_BUFLEN(buf, buflen, strlen) \
948171682Ssimon    if (strlen<0) \
949171682Ssimon       	buflen=0; \
950171682Ssimon    else if ((u_int)strlen>buflen) \
951171682Ssimon        buflen=0; \
952171682Ssimon    else { \
953171682Ssimon        buflen-=strlen; \
954171682Ssimon	buf+=strlen; \
955171682Ssimon    }
956171682Ssimon
957127668Sbmsstatic int
958127668Sbmsdecode_labeled_vpn_l2(const u_char *pptr, char *buf, u_int buflen)
959127668Sbms{
960127668Sbms        int plen,tlen,strlen,tlv_type,tlv_len,ttlv_len;
961127668Sbms
962127668Sbms	TCHECK2(pptr[0], 2);
963127668Sbms        plen=EXTRACT_16BITS(pptr);
964127668Sbms        tlen=plen;
965127668Sbms        pptr+=2;
966235530Sdelphij	/* Old and new L2VPN NLRI share AFI/SAFI
967235530Sdelphij         *   -> Assume a 12 Byte-length NLRI is auto-discovery-only
968235530Sdelphij         *      and > 17 as old format. Complain for the middle case
969235530Sdelphij         */
970235530Sdelphij        if (plen==12) {
971235530Sdelphij	    /* assume AD-only with RD, BGPNH */
972235530Sdelphij	    TCHECK2(pptr[0],12);
973235530Sdelphij	    buf[0]='\0';
974235530Sdelphij	    strlen=snprintf(buf, buflen, "RD: %s, BGPNH: %s",
975235530Sdelphij			    bgp_vpn_rd_print(pptr),
976235530Sdelphij			    /* need something like getname() here */
977235530Sdelphij			    getname(pptr+8)
978235530Sdelphij			    );
979235530Sdelphij	    UPDATE_BUF_BUFLEN(buf, buflen, strlen);
980235530Sdelphij	    pptr+=12;
981235530Sdelphij	    tlen-=12;
982235530Sdelphij	    return plen;
983235530Sdelphij        } else if (plen>17) {
984235530Sdelphij	    /* assume old format */
985235530Sdelphij	    /* RD, ID, LBLKOFF, LBLBASE */
986127668Sbms
987235530Sdelphij	    TCHECK2(pptr[0],15);
988235530Sdelphij	    buf[0]='\0';
989235530Sdelphij	    strlen=snprintf(buf, buflen, "RD: %s, CE-ID: %u, Label-Block Offset: %u, Label Base %u",
990235530Sdelphij			    bgp_vpn_rd_print(pptr),
991235530Sdelphij			    EXTRACT_16BITS(pptr+8),
992235530Sdelphij			    EXTRACT_16BITS(pptr+10),
993235530Sdelphij			    EXTRACT_24BITS(pptr+12)>>4); /* the label is offsetted by 4 bits so lets shift it right */
994235530Sdelphij	    UPDATE_BUF_BUFLEN(buf, buflen, strlen);
995235530Sdelphij	    pptr+=15;
996235530Sdelphij	    tlen-=15;
997127668Sbms
998235530Sdelphij	    /* ok now the variable part - lets read out TLVs*/
999235530Sdelphij	    while (tlen>0) {
1000235530Sdelphij		if (tlen < 3)
1001235530Sdelphij		    return -1;
1002235530Sdelphij		TCHECK2(pptr[0], 3);
1003235530Sdelphij		tlv_type=*pptr++;
1004235530Sdelphij		tlv_len=EXTRACT_16BITS(pptr);
1005235530Sdelphij		ttlv_len=tlv_len;
1006235530Sdelphij		pptr+=2;
1007235530Sdelphij
1008235530Sdelphij		switch(tlv_type) {
1009235530Sdelphij		case 1:
1010235530Sdelphij		    if (buflen!=0) {
1011235530Sdelphij			strlen=snprintf(buf,buflen, "\n\t\tcircuit status vector (%u) length: %u: 0x",
1012235530Sdelphij					tlv_type,
1013235530Sdelphij					tlv_len);
1014235530Sdelphij			UPDATE_BUF_BUFLEN(buf, buflen, strlen);
1015235530Sdelphij		    }
1016235530Sdelphij		    ttlv_len=ttlv_len/8+1; /* how many bytes do we need to read ? */
1017235530Sdelphij		    while (ttlv_len>0) {
1018235530Sdelphij			TCHECK(pptr[0]);
1019235530Sdelphij			if (buflen!=0) {
1020235530Sdelphij			    strlen=snprintf(buf,buflen, "%02x",*pptr++);
1021235530Sdelphij			    UPDATE_BUF_BUFLEN(buf, buflen, strlen);
1022235530Sdelphij			}
1023235530Sdelphij			ttlv_len--;
1024235530Sdelphij		    }
1025235530Sdelphij		    break;
1026235530Sdelphij		default:
1027235530Sdelphij		    if (buflen!=0) {
1028235530Sdelphij			strlen=snprintf(buf,buflen, "\n\t\tunknown TLV #%u, length: %u",
1029235530Sdelphij					tlv_type,
1030235530Sdelphij					tlv_len);
1031235530Sdelphij			UPDATE_BUF_BUFLEN(buf, buflen, strlen);
1032235530Sdelphij		    }
1033235530Sdelphij		    break;
1034235530Sdelphij		}
1035235530Sdelphij		tlen-=(tlv_len<<3); /* the tlv-length is expressed in bits so lets shift it right */
1036235530Sdelphij	    }
1037235530Sdelphij	    return plen+2;
1038235530Sdelphij
1039235530Sdelphij        } else {
1040235530Sdelphij	    /* complain bitterly ? */
1041235530Sdelphij	    /* fall through */
1042235530Sdelphij            goto trunc;
1043127668Sbms        }
1044127668Sbms
1045127668Sbmstrunc:
1046127668Sbms        return -2;
1047127668Sbms}
1048127668Sbms
104956893Sfenner#ifdef INET6
1050146773Ssamint
1051241235Sdelphijdecode_prefix6(const u_char *pd, u_int itemlen, char *buf, u_int buflen)
105256893Sfenner{
105356893Sfenner	struct in6_addr addr;
1054241235Sdelphij	u_int plen, plenbytes;
105556893Sfenner
1056127668Sbms	TCHECK(pd[0]);
1057241235Sdelphij	ITEMCHECK(1);
105856893Sfenner	plen = pd[0];
1059127668Sbms	if (128 < plen)
106056893Sfenner		return -1;
1061241235Sdelphij	itemlen -= 1;
106256893Sfenner
106356893Sfenner	memset(&addr, 0, sizeof(addr));
1064241235Sdelphij	plenbytes = (plen + 7) / 8;
1065241235Sdelphij	TCHECK2(pd[1], plenbytes);
1066241235Sdelphij	ITEMCHECK(plenbytes);
1067241235Sdelphij	memcpy(&addr, &pd[1], plenbytes);
106856893Sfenner	if (plen % 8) {
1069241235Sdelphij		addr.s6_addr[plenbytes - 1] &=
107056893Sfenner			((0xff00 >> (plen % 8)) & 0xff);
107156893Sfenner	}
107298524Sfenner	snprintf(buf, buflen, "%s/%d", getname6((u_char *)&addr), plen);
1073241235Sdelphij	return 1 + plenbytes;
1074127668Sbms
1075127668Sbmstrunc:
1076127668Sbms	return -2;
1077241235Sdelphij
1078241235Sdelphijbadtlv:
1079241235Sdelphij	return -3;
108056893Sfenner}
1081127668Sbms
1082127668Sbmsstatic int
1083241235Sdelphijdecode_labeled_prefix6(const u_char *pptr, u_int itemlen, char *buf, u_int buflen)
1084127668Sbms{
1085127668Sbms	struct in6_addr addr;
1086241235Sdelphij	u_int plen, plenbytes;
1087127668Sbms
1088241235Sdelphij	/* prefix length and label = 4 bytes */
1089241235Sdelphij	TCHECK2(pptr[0], 4);
1090241235Sdelphij	ITEMCHECK(4);
1091127668Sbms	plen = pptr[0]; /* get prefix length */
1092172683Smlaier
1093172683Smlaier	if (24 > plen)
1094172683Smlaier		return -1;
1095172683Smlaier
1096127668Sbms        plen-=24; /* adjust prefixlen - labellength */
1097127668Sbms
1098127668Sbms	if (128 < plen)
1099127668Sbms		return -1;
1100241235Sdelphij	itemlen -= 4;
1101127668Sbms
1102127668Sbms	memset(&addr, 0, sizeof(addr));
1103241235Sdelphij	plenbytes = (plen + 7) / 8;
1104241235Sdelphij	TCHECK2(pptr[4], plenbytes);
1105241235Sdelphij	memcpy(&addr, &pptr[4], plenbytes);
1106127668Sbms	if (plen % 8) {
1107241235Sdelphij		addr.s6_addr[plenbytes - 1] &=
1108127668Sbms			((0xff00 >> (plen % 8)) & 0xff);
1109127668Sbms	}
1110127668Sbms        /* the label may get offsetted by 4 bits so lets shift it right */
1111127668Sbms	snprintf(buf, buflen, "%s/%d, label:%u %s",
1112127668Sbms                 getname6((u_char *)&addr),
1113127668Sbms                 plen,
1114127668Sbms                 EXTRACT_24BITS(pptr+1)>>4,
1115127668Sbms                 ((pptr[3]&1)==0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
1116127668Sbms
1117241235Sdelphij	return 4 + plenbytes;
1118127668Sbms
1119127668Sbmstrunc:
1120127668Sbms	return -2;
1121241235Sdelphij
1122241235Sdelphijbadtlv:
1123241235Sdelphij	return -3;
1124127668Sbms}
1125127668Sbms
1126127668Sbmsstatic int
1127127668Sbmsdecode_labeled_vpn_prefix6(const u_char *pptr, char *buf, u_int buflen)
1128127668Sbms{
1129127668Sbms	struct in6_addr addr;
1130127668Sbms	u_int plen;
1131127668Sbms
1132127668Sbms	TCHECK(pptr[0]);
1133127668Sbms	plen = pptr[0];   /* get prefix length */
1134127668Sbms
1135172683Smlaier	if ((24+64) > plen)
1136172683Smlaier		return -1;
1137172683Smlaier
1138127668Sbms        plen-=(24+64); /* adjust prefixlen - labellength - RD len*/
1139127668Sbms
1140127668Sbms	if (128 < plen)
1141127668Sbms		return -1;
1142127668Sbms
1143127668Sbms	memset(&addr, 0, sizeof(addr));
1144127668Sbms	TCHECK2(pptr[12], (plen + 7) / 8);
1145127668Sbms	memcpy(&addr, &pptr[12], (plen + 7) / 8);
1146127668Sbms	if (plen % 8) {
1147127668Sbms		addr.s6_addr[(plen + 7) / 8 - 1] &=
1148127668Sbms			((0xff00 >> (plen % 8)) & 0xff);
1149127668Sbms	}
1150127668Sbms        /* the label may get offsetted by 4 bits so lets shift it right */
1151127668Sbms	snprintf(buf, buflen, "RD: %s, %s/%d, label:%u %s",
1152127668Sbms                 bgp_vpn_rd_print(pptr+4),
1153127668Sbms                 getname6((u_char *)&addr),
1154127668Sbms                 plen,
1155127668Sbms                 EXTRACT_24BITS(pptr+1)>>4,
1156127668Sbms                 ((pptr[3]&1)==0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
1157127668Sbms
1158127668Sbms	return 12 + (plen + 7) / 8;
1159127668Sbms
1160127668Sbmstrunc:
1161127668Sbms	return -2;
1162127668Sbms}
116356893Sfenner#endif
116456893Sfenner
1165127668Sbmsstatic int
1166147899Ssamdecode_clnp_prefix(const u_char *pptr, char *buf, u_int buflen)
1167146773Ssam{
1168146773Ssam        u_int8_t addr[19];
1169146773Ssam	u_int plen;
1170146773Ssam
1171146773Ssam	TCHECK(pptr[0]);
1172146773Ssam	plen = pptr[0]; /* get prefix length */
1173146773Ssam
1174146773Ssam	if (152 < plen)
1175146773Ssam		return -1;
1176146773Ssam
1177146773Ssam	memset(&addr, 0, sizeof(addr));
1178146773Ssam	TCHECK2(pptr[4], (plen + 7) / 8);
1179146773Ssam	memcpy(&addr, &pptr[4], (plen + 7) / 8);
1180146773Ssam	if (plen % 8) {
1181146773Ssam		addr[(plen + 7) / 8 - 1] &=
1182146773Ssam			((0xff00 >> (plen % 8)) & 0xff);
1183146773Ssam	}
1184147899Ssam	snprintf(buf, buflen, "%s/%d",
1185147899Ssam                 isonsap_string(addr,(plen + 7) / 8),
1186147899Ssam                 plen);
1187146773Ssam
1188147899Ssam	return 1 + (plen + 7) / 8;
1189146773Ssam
1190146773Ssamtrunc:
1191146773Ssam	return -2;
1192146773Ssam}
1193146773Ssam
1194146773Ssamstatic int
1195146773Ssamdecode_labeled_vpn_clnp_prefix(const u_char *pptr, char *buf, u_int buflen)
1196146773Ssam{
1197146773Ssam        u_int8_t addr[19];
1198146773Ssam	u_int plen;
1199146773Ssam
1200146773Ssam	TCHECK(pptr[0]);
1201146773Ssam	plen = pptr[0];   /* get prefix length */
1202146773Ssam
1203172683Smlaier	if ((24+64) > plen)
1204172683Smlaier		return -1;
1205172683Smlaier
1206146773Ssam        plen-=(24+64); /* adjust prefixlen - labellength - RD len*/
1207146773Ssam
1208146773Ssam	if (152 < plen)
1209146773Ssam		return -1;
1210146773Ssam
1211146773Ssam	memset(&addr, 0, sizeof(addr));
1212146773Ssam	TCHECK2(pptr[12], (plen + 7) / 8);
1213146773Ssam	memcpy(&addr, &pptr[12], (plen + 7) / 8);
1214146773Ssam	if (plen % 8) {
1215146773Ssam		addr[(plen + 7) / 8 - 1] &=
1216146773Ssam			((0xff00 >> (plen % 8)) & 0xff);
1217146773Ssam	}
1218146773Ssam        /* the label may get offsetted by 4 bits so lets shift it right */
1219146773Ssam	snprintf(buf, buflen, "RD: %s, %s/%d, label:%u %s",
1220146773Ssam                 bgp_vpn_rd_print(pptr+4),
1221147899Ssam                 isonsap_string(addr,(plen + 7) / 8),
1222146773Ssam                 plen,
1223146773Ssam                 EXTRACT_24BITS(pptr+1)>>4,
1224146773Ssam                 ((pptr[3]&1)==0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
1225146773Ssam
1226146773Ssam	return 12 + (plen + 7) / 8;
1227146773Ssam
1228146773Ssamtrunc:
1229146773Ssam	return -2;
1230146773Ssam}
1231146773Ssam
1232190207Srpaulo/*
1233190207Srpaulo * bgp_attr_get_as_size
1234190207Srpaulo *
1235190207Srpaulo * Try to find the size of the ASs encoded in an as-path. It is not obvious, as
1236190207Srpaulo * both Old speakers that do not support 4 byte AS, and the new speakers that do
1237190207Srpaulo * support, exchange AS-Path with the same path-attribute type value 0x02.
1238190207Srpaulo */
1239146773Ssamstatic int
1240190207Srpaulobgp_attr_get_as_size (u_int8_t bgpa_type, const u_char *pptr, int len)
1241190207Srpaulo{
1242190207Srpaulo    const u_char *tptr = pptr;
1243190207Srpaulo
1244190207Srpaulo    /*
1245190207Srpaulo     * If the path attribute is the optional AS4 path type, then we already
1246190207Srpaulo     * know, that ASs must be encoded in 4 byte format.
1247190207Srpaulo     */
1248190207Srpaulo    if (bgpa_type == BGPTYPE_AS4_PATH) {
1249190207Srpaulo        return 4;
1250190207Srpaulo    }
1251190207Srpaulo
1252190207Srpaulo    /*
1253190207Srpaulo     * Let us assume that ASs are of 2 bytes in size, and check if the AS-Path
1254190207Srpaulo     * TLV is good. If not, ask the caller to try with AS encoded as 4 bytes
1255190207Srpaulo     * each.
1256190207Srpaulo     */
1257190207Srpaulo    while (tptr < pptr + len) {
1258190207Srpaulo        TCHECK(tptr[0]);
1259190207Srpaulo
1260190207Srpaulo        /*
1261190207Srpaulo         * If we do not find a valid segment type, our guess might be wrong.
1262190207Srpaulo         */
1263190207Srpaulo        if (tptr[0] < BGP_AS_SEG_TYPE_MIN || tptr[0] > BGP_AS_SEG_TYPE_MAX) {
1264190207Srpaulo            goto trunc;
1265190207Srpaulo        }
1266190207Srpaulo        TCHECK(tptr[1]);
1267190207Srpaulo        tptr += 2 + tptr[1] * 2;
1268190207Srpaulo    }
1269190207Srpaulo
1270190207Srpaulo    /*
1271190207Srpaulo     * If we correctly reached end of the AS path attribute data content,
1272190207Srpaulo     * then most likely ASs were indeed encoded as 2 bytes.
1273190207Srpaulo     */
1274190207Srpaulo    if (tptr == pptr + len) {
1275190207Srpaulo        return 2;
1276190207Srpaulo    }
1277190207Srpaulo
1278190207Srpaulotrunc:
1279190207Srpaulo
1280190207Srpaulo    /*
1281190207Srpaulo     * We can come here, either we did not have enough data, or if we
1282190207Srpaulo     * try to decode 4 byte ASs in 2 byte format. Either way, return 4,
1283190207Srpaulo     * so that calller can try to decode each AS as of 4 bytes. If indeed
1284190207Srpaulo     * there was not enough data, it will crib and end the parse anyways.
1285190207Srpaulo     */
1286190207Srpaulo   return 4;
1287190207Srpaulo}
1288190207Srpaulo
1289190207Srpaulostatic int
1290241235Sdelphijbgp_attr_print(u_int atype, const u_char *pptr, u_int len)
129156893Sfenner{
129256893Sfenner	int i;
129356893Sfenner	u_int16_t af;
1294147899Ssam	u_int8_t safi, snpa, nhlen;
1295127668Sbms        union { /* copy buffer for bandwidth values */
1296127668Sbms            float f;
1297127668Sbms            u_int32_t i;
1298127668Sbms        } bw;
129956893Sfenner	int advance;
1300241235Sdelphij	u_int tlen;
1301127668Sbms	const u_char *tptr;
130275115Sfenner	char buf[MAXHOSTNAMELEN + 100];
1303146773Ssam	char tokbuf[TOKBUFSIZE];
1304190207Srpaulo        int  as_size;
130556893Sfenner
1306127668Sbms        tptr = pptr;
1307127668Sbms        tlen=len;
130856893Sfenner
1309241235Sdelphij	switch (atype) {
131056893Sfenner	case BGPTYPE_ORIGIN:
131156893Sfenner		if (len != 1)
1312127668Sbms			printf("invalid len");
1313127668Sbms		else {
1314127668Sbms			TCHECK(*tptr);
1315146773Ssam			printf("%s", tok2strbuf(bgp_origin_values,
1316146773Ssam						"Unknown Origin Typecode",
1317146773Ssam						tptr[0],
1318146773Ssam						tokbuf, sizeof(tokbuf)));
1319127668Sbms		}
132056893Sfenner		break;
1321146773Ssam
1322190207Srpaulo
1323190207Srpaulo        /*
1324190207Srpaulo         * Process AS4 byte path and AS2 byte path attributes here.
1325190207Srpaulo         */
1326190207Srpaulo	case BGPTYPE_AS4_PATH:
132756893Sfenner	case BGPTYPE_AS_PATH:
132856893Sfenner		if (len % 2) {
1329127668Sbms			printf("invalid len");
133056893Sfenner			break;
133156893Sfenner		}
1332127668Sbms                if (!len) {
1333127668Sbms			printf("empty");
1334127668Sbms			break;
1335127668Sbms                }
1336127668Sbms
1337190207Srpaulo                /*
1338190207Srpaulo                 * BGP updates exchanged between New speakers that support 4
1339190207Srpaulo                 * byte AS, ASs are always encoded in 4 bytes. There is no
1340190207Srpaulo                 * definitive way to find this, just by the packet's
1341190207Srpaulo                 * contents. So, check for packet's TLV's sanity assuming
1342190207Srpaulo                 * 2 bytes first, and it does not pass, assume that ASs are
1343190207Srpaulo                 * encoded in 4 bytes format and move on.
1344190207Srpaulo                 */
1345241235Sdelphij                as_size = bgp_attr_get_as_size(atype, pptr, len);
1346190207Srpaulo
1347127668Sbms		while (tptr < pptr + len) {
1348127668Sbms			TCHECK(tptr[0]);
1349146773Ssam                        printf("%s", tok2strbuf(bgp_as_path_segment_open_values,
1350146773Ssam						"?", tptr[0],
1351146773Ssam						tokbuf, sizeof(tokbuf)));
1352190207Srpaulo                        for (i = 0; i < tptr[1] * as_size; i += as_size) {
1353190207Srpaulo                            TCHECK2(tptr[2 + i], as_size);
1354214478Srpaulo			    printf("%s ",
1355214478Srpaulo				as_printf(astostr, sizeof(astostr),
1356214478Srpaulo				as_size == 2 ?
1357214478Srpaulo				EXTRACT_16BITS(&tptr[2 + i]) :
1358214478Srpaulo				EXTRACT_32BITS(&tptr[2 + i])));
1359127668Sbms                        }
1360127668Sbms			TCHECK(tptr[0]);
1361146773Ssam                        printf("%s", tok2strbuf(bgp_as_path_segment_close_values,
1362146773Ssam						"?", tptr[0],
1363146773Ssam						tokbuf, sizeof(tokbuf)));
1364127668Sbms                        TCHECK(tptr[1]);
1365190207Srpaulo                        tptr += 2 + tptr[1] * as_size;
136656893Sfenner		}
136756893Sfenner		break;
136856893Sfenner	case BGPTYPE_NEXT_HOP:
136956893Sfenner		if (len != 4)
1370127668Sbms			printf("invalid len");
1371127668Sbms		else {
1372127668Sbms			TCHECK2(tptr[0], 4);
1373127668Sbms			printf("%s", getname(tptr));
1374127668Sbms		}
137556893Sfenner		break;
137656893Sfenner	case BGPTYPE_MULTI_EXIT_DISC:
137756893Sfenner	case BGPTYPE_LOCAL_PREF:
137856893Sfenner		if (len != 4)
1379127668Sbms			printf("invalid len");
1380127668Sbms		else {
1381127668Sbms			TCHECK2(tptr[0], 4);
1382127668Sbms			printf("%u", EXTRACT_32BITS(tptr));
1383127668Sbms		}
138456893Sfenner		break;
138556893Sfenner	case BGPTYPE_ATOMIC_AGGREGATE:
138656893Sfenner		if (len != 0)
1387127668Sbms			printf("invalid len");
138856893Sfenner		break;
1389214478Srpaulo        case BGPTYPE_AGGREGATOR:
1390214478Srpaulo
1391214478Srpaulo                /*
1392214478Srpaulo                 * Depending on the AS encoded is of 2 bytes or of 4 bytes,
1393214478Srpaulo                 * the length of this PA can be either 6 bytes or 8 bytes.
1394214478Srpaulo                 */
1395214478Srpaulo                if (len != 6 && len != 8) {
1396214478Srpaulo                    printf("invalid len");
1397214478Srpaulo                    break;
1398214478Srpaulo                }
1399214478Srpaulo                TCHECK2(tptr[0], len);
1400214478Srpaulo                if (len == 6) {
1401214478Srpaulo		    printf(" AS #%s, origin %s",
1402214478Srpaulo			as_printf(astostr, sizeof(astostr), EXTRACT_16BITS(tptr)),
1403127668Sbms			getname(tptr + 2));
1404214478Srpaulo                } else {
1405214478Srpaulo		    printf(" AS #%s, origin %s",
1406214478Srpaulo			as_printf(astostr, sizeof(astostr),
1407214478Srpaulo			EXTRACT_32BITS(tptr)), getname(tptr + 4));
1408214478Srpaulo                }
1409214478Srpaulo                break;
1410190207Srpaulo	case BGPTYPE_AGGREGATOR4:
1411190207Srpaulo		if (len != 8) {
1412190207Srpaulo			printf("invalid len");
1413190207Srpaulo			break;
1414190207Srpaulo		}
1415190207Srpaulo		TCHECK2(tptr[0], 8);
1416214478Srpaulo		printf(" AS #%s, origin %s",
1417214478Srpaulo	   	    as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(tptr)),
1418214478Srpaulo		    getname(tptr + 4));
1419190207Srpaulo		break;
142056893Sfenner	case BGPTYPE_COMMUNITIES:
142156893Sfenner		if (len % 4) {
1422127668Sbms			printf("invalid len");
142356893Sfenner			break;
142456893Sfenner		}
1425127668Sbms		while (tlen>0) {
142656893Sfenner			u_int32_t comm;
1427127668Sbms			TCHECK2(tptr[0], 4);
1428127668Sbms			comm = EXTRACT_32BITS(tptr);
142956893Sfenner			switch (comm) {
143056893Sfenner			case BGP_COMMUNITY_NO_EXPORT:
143156893Sfenner				printf(" NO_EXPORT");
143256893Sfenner				break;
143356893Sfenner			case BGP_COMMUNITY_NO_ADVERT:
143456893Sfenner				printf(" NO_ADVERTISE");
143556893Sfenner				break;
143656893Sfenner			case BGP_COMMUNITY_NO_EXPORT_SUBCONFED:
143756893Sfenner				printf(" NO_EXPORT_SUBCONFED");
143856893Sfenner				break;
143956893Sfenner			default:
1440127668Sbms				printf("%u:%u%s",
1441127668Sbms                                       (comm >> 16) & 0xffff,
1442127668Sbms                                       comm & 0xffff,
1443127668Sbms                                       (tlen>4) ? ", " : "");
144456893Sfenner				break;
144556893Sfenner			}
1446127668Sbms                        tlen -=4;
1447127668Sbms                        tptr +=4;
144856893Sfenner		}
144956893Sfenner		break;
1450127668Sbms        case BGPTYPE_ORIGINATOR_ID:
1451127668Sbms		if (len != 4) {
1452127668Sbms			printf("invalid len");
1453127668Sbms			break;
1454127668Sbms		}
1455127668Sbms		TCHECK2(tptr[0], 4);
1456127668Sbms                printf("%s",getname(tptr));
1457127668Sbms                break;
1458127668Sbms        case BGPTYPE_CLUSTER_LIST:
1459127668Sbms		if (len % 4) {
1460127668Sbms			printf("invalid len");
1461127668Sbms			break;
1462127668Sbms		}
1463127668Sbms                while (tlen>0) {
1464127668Sbms			TCHECK2(tptr[0], 4);
1465127668Sbms                        printf("%s%s",
1466127668Sbms                               getname(tptr),
1467127668Sbms                                (tlen>4) ? ", " : "");
1468127668Sbms                        tlen -=4;
1469127668Sbms                        tptr +=4;
1470127668Sbms                }
1471127668Sbms                break;
147256893Sfenner	case BGPTYPE_MP_REACH_NLRI:
1473127668Sbms		TCHECK2(tptr[0], 3);
1474127668Sbms		af = EXTRACT_16BITS(tptr);
1475127668Sbms		safi = tptr[2];
1476127668Sbms
1477127668Sbms                printf("\n\t    AFI: %s (%u), %sSAFI: %s (%u)",
1478172683Smlaier                       tok2strbuf(af_values, "Unknown AFI", af,
1479146773Ssam				  tokbuf, sizeof(tokbuf)),
1480127668Sbms                       af,
1481127668Sbms                       (safi>128) ? "vendor specific " : "", /* 128 is meanwhile wellknown */
1482146773Ssam                       tok2strbuf(bgp_safi_values, "Unknown SAFI", safi,
1483146773Ssam				  tokbuf, sizeof(tokbuf)),
1484127668Sbms                       safi);
148556893Sfenner
1486146773Ssam                switch(af<<8 | safi) {
1487146773Ssam                case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1488146773Ssam                case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1489146773Ssam                case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1490146773Ssam                case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1491146773Ssam                case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
1492146773Ssam                case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1493146773Ssam                case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1494146773Ssam                case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1495190207Srpaulo                case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
1496214478Srpaulo		case (AFNUM_INET<<8 | SAFNUM_MDT):
149756893Sfenner#ifdef INET6
1498146773Ssam                case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1499146773Ssam                case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1500146773Ssam                case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1501146773Ssam                case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1502146773Ssam                case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1503146773Ssam                case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1504146773Ssam                case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
150556893Sfenner#endif
1506146773Ssam                case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1507146773Ssam                case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1508146773Ssam                case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1509146773Ssam                case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1510146773Ssam                case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1511146773Ssam                case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1512146773Ssam                case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1513146773Ssam                case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1514146773Ssam                case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1515172683Smlaier                case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1516146773Ssam                    break;
1517146773Ssam                default:
1518147899Ssam                    TCHECK2(tptr[0], tlen);
1519146773Ssam                    printf("\n\t    no AFI %u / SAFI %u decoder",af,safi);
1520127668Sbms                    if (vflag <= 1)
1521127668Sbms                        print_unknown_data(tptr,"\n\t    ",tlen);
1522146773Ssam                    goto done;
1523127668Sbms                    break;
1524127668Sbms                }
152556893Sfenner
1526127668Sbms                tptr +=3;
1527127668Sbms
1528127668Sbms		TCHECK(tptr[0]);
1529147899Ssam		nhlen = tptr[0];
1530147899Ssam                tlen = nhlen;
1531127668Sbms                tptr++;
1532127668Sbms
153356893Sfenner		if (tlen) {
1534251158Sdelphij                    int nnh = 0;
1535146773Ssam                    printf("\n\t    nexthop: ");
1536146773Ssam                    while (tlen > 0) {
1537251158Sdelphij                        if ( nnh++ > 0 ) {
1538251158Sdelphij                            printf( ", " );
1539251158Sdelphij                        }
1540146773Ssam                        switch(af<<8 | safi) {
1541146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1542146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1543146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1544146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1545146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
1546190207Srpaulo                        case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
1547214478Srpaulo                        case (AFNUM_INET<<8 | SAFNUM_MDT):
1548214478Srpaulo			    if (tlen < (int)sizeof(struct in_addr)) {
1549146773Ssam                                printf("invalid len");
1550146773Ssam                                tlen = 0;
1551146773Ssam                            } else {
1552146773Ssam                                TCHECK2(tptr[0], sizeof(struct in_addr));
1553146773Ssam                                printf("%s",getname(tptr));
1554146773Ssam                                tlen -= sizeof(struct in_addr);
1555146773Ssam                                tptr += sizeof(struct in_addr);
1556146773Ssam                            }
1557146773Ssam                            break;
1558146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1559146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1560146773Ssam                        case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1561146773Ssam                            if (tlen < (int)(sizeof(struct in_addr)+BGP_VPN_RD_LEN)) {
1562146773Ssam                                printf("invalid len");
1563146773Ssam                                tlen = 0;
1564146773Ssam                            } else {
1565146773Ssam                                TCHECK2(tptr[0], sizeof(struct in_addr)+BGP_VPN_RD_LEN);
1566146773Ssam                                printf("RD: %s, %s",
1567146773Ssam                                       bgp_vpn_rd_print(tptr),
1568146773Ssam                                       getname(tptr+BGP_VPN_RD_LEN));
1569146773Ssam                                tlen -= (sizeof(struct in_addr)+BGP_VPN_RD_LEN);
1570146773Ssam                                tptr += (sizeof(struct in_addr)+BGP_VPN_RD_LEN);
1571146773Ssam                            }
1572146773Ssam                            break;
157356893Sfenner#ifdef INET6
1574146773Ssam                        case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1575146773Ssam                        case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1576146773Ssam                        case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1577146773Ssam                        case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1578146773Ssam                            if (tlen < (int)sizeof(struct in6_addr)) {
1579146773Ssam                                printf("invalid len");
1580146773Ssam                                tlen = 0;
1581146773Ssam                            } else {
1582146773Ssam                                TCHECK2(tptr[0], sizeof(struct in6_addr));
1583146773Ssam                                printf("%s", getname6(tptr));
1584146773Ssam                                tlen -= sizeof(struct in6_addr);
1585146773Ssam                                tptr += sizeof(struct in6_addr);
1586146773Ssam                            }
1587146773Ssam                            break;
1588146773Ssam                        case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1589146773Ssam                        case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1590146773Ssam                        case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
1591146773Ssam                            if (tlen < (int)(sizeof(struct in6_addr)+BGP_VPN_RD_LEN)) {
1592146773Ssam                                printf("invalid len");
1593146773Ssam                                tlen = 0;
1594146773Ssam                            } else {
1595146773Ssam                                TCHECK2(tptr[0], sizeof(struct in6_addr)+BGP_VPN_RD_LEN);
1596146773Ssam                                printf("RD: %s, %s",
1597146773Ssam                                       bgp_vpn_rd_print(tptr),
1598146773Ssam                                       getname6(tptr+BGP_VPN_RD_LEN));
1599146773Ssam                                tlen -= (sizeof(struct in6_addr)+BGP_VPN_RD_LEN);
1600146773Ssam                                tptr += (sizeof(struct in6_addr)+BGP_VPN_RD_LEN);
1601146773Ssam                            }
1602146773Ssam                            break;
160356893Sfenner#endif
1604172683Smlaier                        case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1605146773Ssam                        case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1606146773Ssam                        case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1607146773Ssam                        case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1608146773Ssam                            if (tlen < (int)sizeof(struct in_addr)) {
1609146773Ssam                                printf("invalid len");
1610146773Ssam                                tlen = 0;
1611146773Ssam                            } else {
1612146773Ssam                                TCHECK2(tptr[0], sizeof(struct in_addr));
1613146773Ssam                                printf("%s", getname(tptr));
1614146773Ssam                                tlen -= (sizeof(struct in_addr));
1615146773Ssam                                tptr += (sizeof(struct in_addr));
1616146773Ssam                            }
1617146773Ssam                            break;
1618146773Ssam                        case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1619146773Ssam                        case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1620146773Ssam                        case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1621146773Ssam                            TCHECK2(tptr[0], tlen);
1622146773Ssam                            printf("%s",isonsap_string(tptr,tlen));
1623146773Ssam                            tptr += tlen;
1624146773Ssam                            tlen = 0;
1625146773Ssam                            break;
1626127668Sbms
1627146773Ssam                        case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1628146773Ssam                        case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1629146773Ssam                        case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1630146773Ssam                            if (tlen < BGP_VPN_RD_LEN+1) {
1631146773Ssam                                printf("invalid len");
1632146773Ssam                                tlen = 0;
1633146773Ssam                            } else {
1634146773Ssam                                TCHECK2(tptr[0], tlen);
1635146773Ssam                                printf("RD: %s, %s",
1636146773Ssam                                       bgp_vpn_rd_print(tptr),
1637146773Ssam                                       isonsap_string(tptr+BGP_VPN_RD_LEN,tlen-BGP_VPN_RD_LEN));
1638146773Ssam                                /* rfc986 mapped IPv4 address ? */
1639146773Ssam                                if (EXTRACT_32BITS(tptr+BGP_VPN_RD_LEN) ==  0x47000601)
1640146773Ssam                                    printf(" = %s", getname(tptr+BGP_VPN_RD_LEN+4));
1641146773Ssam#ifdef INET6
1642146773Ssam                                /* rfc1888 mapped IPv6 address ? */
1643146773Ssam                                else if (EXTRACT_24BITS(tptr+BGP_VPN_RD_LEN) ==  0x350000)
1644146773Ssam                                    printf(" = %s", getname6(tptr+BGP_VPN_RD_LEN+3));
1645146773Ssam#endif
1646146773Ssam                                tptr += tlen;
1647146773Ssam                                tlen = 0;
1648146773Ssam                            }
1649146773Ssam                            break;
1650146773Ssam                        default:
1651146773Ssam                            TCHECK2(tptr[0], tlen);
1652146773Ssam                            printf("no AFI %u/SAFI %u decoder",af,safi);
1653146773Ssam                            if (vflag <= 1)
1654146773Ssam                                print_unknown_data(tptr,"\n\t    ",tlen);
1655146773Ssam                            tptr += tlen;
1656146773Ssam                            tlen = 0;
1657146773Ssam                            goto done;
1658146773Ssam                            break;
1659146773Ssam                        }
1660146773Ssam                    }
166156893Sfenner		}
1662147899Ssam                printf(", nh-length: %u", nhlen);
1663127668Sbms		tptr += tlen;
166456893Sfenner
1665127668Sbms		TCHECK(tptr[0]);
1666127668Sbms		snpa = tptr[0];
1667127668Sbms		tptr++;
1668127668Sbms
166956893Sfenner		if (snpa) {
1670127668Sbms			printf("\n\t    %u SNPA", snpa);
167156893Sfenner			for (/*nothing*/; snpa > 0; snpa--) {
1672127668Sbms				TCHECK(tptr[0]);
1673127668Sbms				printf("\n\t      %d bytes", tptr[0]);
1674127668Sbms				tptr += tptr[0] + 1;
167556893Sfenner			}
1676127668Sbms		} else {
1677127668Sbms			printf(", no SNPA");
1678127668Sbms                }
167956893Sfenner
1680127668Sbms		while (len - (tptr - pptr) > 0) {
1681146773Ssam                    switch (af<<8 | safi) {
1682146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1683146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1684146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1685241235Sdelphij                        advance = decode_prefix4(tptr, len, buf, sizeof(buf));
1686146773Ssam                        if (advance == -1)
1687146773Ssam                            printf("\n\t    (illegal prefix length)");
1688146773Ssam                        else if (advance == -2)
1689146773Ssam                            goto trunc;
1690241235Sdelphij                        else if (advance == -3)
1691241235Sdelphij                            break; /* bytes left, but not enough */
1692146773Ssam                        else
1693146773Ssam                            printf("\n\t      %s", buf);
1694146773Ssam                        break;
1695146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1696241235Sdelphij                        advance = decode_labeled_prefix4(tptr, len, buf, sizeof(buf));
1697146773Ssam                        if (advance == -1)
1698146773Ssam                            printf("\n\t    (illegal prefix length)");
1699146773Ssam                        else if (advance == -2)
1700146773Ssam                            goto trunc;
1701241235Sdelphij                        else if (advance == -3)
1702241235Sdelphij                            break; /* bytes left, but not enough */
1703146773Ssam                        else
1704146773Ssam                            printf("\n\t      %s", buf);
1705146773Ssam                        break;
1706146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1707146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1708146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1709146773Ssam                        advance = decode_labeled_vpn_prefix4(tptr, buf, sizeof(buf));
1710146773Ssam                        if (advance == -1)
1711146773Ssam                            printf("\n\t    (illegal prefix length)");
1712146773Ssam                        else if (advance == -2)
1713146773Ssam                            goto trunc;
1714146773Ssam                        else
1715146773Ssam                            printf("\n\t      %s", buf);
1716146773Ssam                        break;
1717146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
1718146773Ssam                        advance = decode_rt_routing_info(tptr, buf, sizeof(buf));
1719146773Ssam                        if (advance == -1)
1720146773Ssam                            printf("\n\t    (illegal prefix length)");
1721146773Ssam                        else if (advance == -2)
1722146773Ssam                            goto trunc;
1723146773Ssam                        else
1724146773Ssam                            printf("\n\t      %s", buf);
1725146773Ssam                        break;
1726190207Srpaulo                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */
1727190207Srpaulo                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN):
1728190207Srpaulo                        advance = decode_multicast_vpn(tptr, buf, sizeof(buf));
1729190207Srpaulo                        if (advance == -1)
1730190207Srpaulo                            printf("\n\t    (illegal prefix length)");
1731190207Srpaulo                        else if (advance == -2)
1732190207Srpaulo                            goto trunc;
1733190207Srpaulo                        else
1734190207Srpaulo                            printf("\n\t      %s", buf);
1735190207Srpaulo                        break;
1736214478Srpaulo
1737214478Srpaulo		    case (AFNUM_INET<<8 | SAFNUM_MDT):
1738214478Srpaulo		      advance = decode_mdt_vpn_nlri(tptr, buf, sizeof(buf));
1739214478Srpaulo		      if (advance == -1)
1740214478Srpaulo                            printf("\n\t    (illegal prefix length)");
1741214478Srpaulo                        else if (advance == -2)
1742214478Srpaulo                            goto trunc;
1743214478Srpaulo                        else
1744214478Srpaulo                            printf("\n\t      %s", buf);
1745214478Srpaulo		       break;
174656893Sfenner#ifdef INET6
1747146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1748146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1749146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1750241235Sdelphij                        advance = decode_prefix6(tptr, len, buf, sizeof(buf));
1751146773Ssam                        if (advance == -1)
1752146773Ssam                            printf("\n\t    (illegal prefix length)");
1753146773Ssam                        else if (advance == -2)
1754146773Ssam                            goto trunc;
1755241235Sdelphij                        else if (advance == -3)
1756241235Sdelphij                            break; /* bytes left, but not enough */
1757146773Ssam                        else
1758146773Ssam                            printf("\n\t      %s", buf);
1759146773Ssam                        break;
1760146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1761241235Sdelphij                        advance = decode_labeled_prefix6(tptr, len, buf, sizeof(buf));
1762146773Ssam                        if (advance == -1)
1763146773Ssam                            printf("\n\t    (illegal prefix length)");
1764146773Ssam                        else if (advance == -2)
1765146773Ssam                            goto trunc;
1766241235Sdelphij                        else if (advance == -3)
1767241235Sdelphij                            break; /* bytes left, but not enough */
1768146773Ssam                        else
1769146773Ssam                            printf("\n\t      %s", buf);
1770146773Ssam                        break;
1771146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1772146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1773146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
1774146773Ssam                        advance = decode_labeled_vpn_prefix6(tptr, buf, sizeof(buf));
1775146773Ssam                        if (advance == -1)
1776146773Ssam                            printf("\n\t    (illegal prefix length)");
1777146773Ssam                        else if (advance == -2)
1778146773Ssam                            goto trunc;
1779146773Ssam                        else
1780146773Ssam                            printf("\n\t      %s", buf);
1781146773Ssam                        break;
178256893Sfenner#endif
1783172683Smlaier                    case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1784146773Ssam                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1785146773Ssam                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1786146773Ssam                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1787146773Ssam                        advance = decode_labeled_vpn_l2(tptr, buf, sizeof(buf));
1788146773Ssam                        if (advance == -1)
1789146773Ssam                            printf("\n\t    (illegal length)");
1790146773Ssam                        else if (advance == -2)
1791146773Ssam                            goto trunc;
1792146773Ssam                        else
1793146773Ssam                            printf("\n\t      %s", buf);
1794146773Ssam                        break;
1795146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1796146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1797146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1798147899Ssam                        advance = decode_clnp_prefix(tptr, buf, sizeof(buf));
1799146773Ssam                        if (advance == -1)
1800146773Ssam                            printf("\n\t    (illegal prefix length)");
1801146773Ssam                        else if (advance == -2)
1802146773Ssam                            goto trunc;
1803146773Ssam                        else
1804146773Ssam                            printf("\n\t      %s", buf);
1805146773Ssam                        break;
1806146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1807146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1808146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1809146773Ssam                        advance = decode_labeled_vpn_clnp_prefix(tptr, buf, sizeof(buf));
1810146773Ssam                        if (advance == -1)
1811146773Ssam                            printf("\n\t    (illegal prefix length)");
1812146773Ssam                        else if (advance == -2)
1813146773Ssam                            goto trunc;
1814146773Ssam                        else
1815146773Ssam                            printf("\n\t      %s", buf);
1816146773Ssam                        break;
1817146773Ssam                    default:
1818146773Ssam                        TCHECK2(*tptr,tlen);
1819146773Ssam                        printf("\n\t    no AFI %u / SAFI %u decoder",af,safi);
1820146773Ssam                        if (vflag <= 1)
1821146773Ssam                            print_unknown_data(tptr,"\n\t    ",tlen);
1822146773Ssam                        advance = 0;
1823146773Ssam                        tptr = pptr + len;
1824146773Ssam                        break;
1825146773Ssam                    }
1826147899Ssam                    if (advance < 0)
1827147899Ssam                        break;
1828146773Ssam                    tptr += advance;
182956893Sfenner		}
1830146773Ssam        done:
183156893Sfenner		break;
183256893Sfenner
183356893Sfenner	case BGPTYPE_MP_UNREACH_NLRI:
1834146773Ssam		TCHECK2(tptr[0], BGP_MP_NLRI_MINSIZE);
1835127668Sbms		af = EXTRACT_16BITS(tptr);
1836127668Sbms		safi = tptr[2];
183756893Sfenner
1838127668Sbms                printf("\n\t    AFI: %s (%u), %sSAFI: %s (%u)",
1839172683Smlaier                       tok2strbuf(af_values, "Unknown AFI", af,
1840146773Ssam				  tokbuf, sizeof(tokbuf)),
1841127668Sbms                       af,
1842127668Sbms                       (safi>128) ? "vendor specific " : "", /* 128 is meanwhile wellknown */
1843146773Ssam                       tok2strbuf(bgp_safi_values, "Unknown SAFI", safi,
1844146773Ssam				  tokbuf, sizeof(tokbuf)),
1845127668Sbms                       safi);
1846127668Sbms
1847146773Ssam                if (len == BGP_MP_NLRI_MINSIZE)
1848146773Ssam                    printf("\n\t      End-of-Rib Marker (empty NLRI)");
1849146773Ssam
1850127668Sbms		tptr += 3;
1851127668Sbms
1852127668Sbms		while (len - (tptr - pptr) > 0) {
1853146773Ssam                    switch (af<<8 | safi) {
1854146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1855146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1856146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1857241235Sdelphij                        advance = decode_prefix4(tptr, len, buf, sizeof(buf));
1858146773Ssam                        if (advance == -1)
1859146773Ssam                            printf("\n\t    (illegal prefix length)");
1860146773Ssam                        else if (advance == -2)
1861146773Ssam                            goto trunc;
1862241235Sdelphij                        else if (advance == -3)
1863241235Sdelphij                            break; /* bytes left, but not enough */
1864146773Ssam                        else
1865146773Ssam                            printf("\n\t      %s", buf);
1866146773Ssam                        break;
1867146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1868241235Sdelphij                        advance = decode_labeled_prefix4(tptr, len, buf, sizeof(buf));
1869146773Ssam                        if (advance == -1)
1870146773Ssam                            printf("\n\t    (illegal prefix length)");
1871146773Ssam                        else if (advance == -2)
1872146773Ssam                            goto trunc;
1873241235Sdelphij                        else if (advance == -3)
1874241235Sdelphij                            break; /* bytes left, but not enough */
1875146773Ssam                        else
1876146773Ssam                            printf("\n\t      %s", buf);
1877146773Ssam                        break;
1878146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1879146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1880146773Ssam                    case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1881146773Ssam                        advance = decode_labeled_vpn_prefix4(tptr, buf, sizeof(buf));
1882146773Ssam                        if (advance == -1)
1883146773Ssam                            printf("\n\t    (illegal prefix length)");
1884146773Ssam                        else if (advance == -2)
1885146773Ssam                            goto trunc;
1886146773Ssam                        else
1887146773Ssam                            printf("\n\t      %s", buf);
1888146773Ssam                        break;
188956893Sfenner#ifdef INET6
1890146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1891146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1892146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1893241235Sdelphij                        advance = decode_prefix6(tptr, len, buf, sizeof(buf));
1894146773Ssam                        if (advance == -1)
1895146773Ssam                            printf("\n\t    (illegal prefix length)");
1896146773Ssam                        else if (advance == -2)
1897146773Ssam                            goto trunc;
1898241235Sdelphij                        else if (advance == -3)
1899241235Sdelphij                            break; /* bytes left, but not enough */
1900146773Ssam                        else
1901146773Ssam                            printf("\n\t      %s", buf);
1902146773Ssam                        break;
1903146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1904241235Sdelphij                        advance = decode_labeled_prefix6(tptr, len, buf, sizeof(buf));
1905146773Ssam                        if (advance == -1)
1906146773Ssam                            printf("\n\t    (illegal prefix length)");
1907146773Ssam                        else if (advance == -2)
1908146773Ssam                            goto trunc;
1909241235Sdelphij                        else if (advance == -3)
1910241235Sdelphij                            break; /* bytes left, but not enough */
1911146773Ssam                        else
1912146773Ssam                            printf("\n\t      %s", buf);
1913146773Ssam                        break;
1914146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1915146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1916146773Ssam                    case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
1917146773Ssam                        advance = decode_labeled_vpn_prefix6(tptr, buf, sizeof(buf));
1918146773Ssam                        if (advance == -1)
1919146773Ssam                            printf("\n\t    (illegal prefix length)");
1920146773Ssam                        else if (advance == -2)
1921146773Ssam                            goto trunc;
1922146773Ssam                        else
1923146773Ssam                            printf("\n\t      %s", buf);
1924146773Ssam                        break;
192556893Sfenner#endif
1926172683Smlaier                    case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1927146773Ssam                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1928146773Ssam                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1929146773Ssam                    case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1930146773Ssam                        advance = decode_labeled_vpn_l2(tptr, buf, sizeof(buf));
1931146773Ssam                        if (advance == -1)
1932146773Ssam                            printf("\n\t    (illegal length)");
1933146773Ssam                        else if (advance == -2)
1934146773Ssam                            goto trunc;
1935146773Ssam                        else
1936146773Ssam                            printf("\n\t      %s", buf);
1937146773Ssam                        break;
1938146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1939146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1940146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1941147899Ssam                        advance = decode_clnp_prefix(tptr, buf, sizeof(buf));
1942146773Ssam                        if (advance == -1)
1943146773Ssam                            printf("\n\t    (illegal prefix length)");
1944146773Ssam                        else if (advance == -2)
1945146773Ssam                            goto trunc;
1946146773Ssam                        else
1947146773Ssam                            printf("\n\t      %s", buf);
1948146773Ssam                        break;
1949146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1950146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1951146773Ssam                    case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1952146773Ssam                        advance = decode_labeled_vpn_clnp_prefix(tptr, buf, sizeof(buf));
1953146773Ssam                        if (advance == -1)
1954146773Ssam                            printf("\n\t    (illegal prefix length)");
1955146773Ssam                        else if (advance == -2)
1956146773Ssam                            goto trunc;
1957146773Ssam                        else
1958146773Ssam                            printf("\n\t      %s", buf);
1959146773Ssam                        break;
1960214478Srpaulo		    case (AFNUM_INET<<8 | SAFNUM_MDT):
1961214478Srpaulo		      advance = decode_mdt_vpn_nlri(tptr, buf, sizeof(buf));
1962214478Srpaulo		      if (advance == -1)
1963214478Srpaulo                            printf("\n\t    (illegal prefix length)");
1964214478Srpaulo                        else if (advance == -2)
1965214478Srpaulo                            goto trunc;
1966214478Srpaulo                        else
1967214478Srpaulo                            printf("\n\t      %s", buf);
1968214478Srpaulo		       break;
1969190207Srpaulo                    case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */
1970190207Srpaulo                    case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN):
1971190207Srpaulo                        advance = decode_multicast_vpn(tptr, buf, sizeof(buf));
1972190207Srpaulo                        if (advance == -1)
1973190207Srpaulo                            printf("\n\t    (illegal prefix length)");
1974190207Srpaulo                        else if (advance == -2)
1975190207Srpaulo                            goto trunc;
1976190207Srpaulo                        else
1977190207Srpaulo                            printf("\n\t      %s", buf);
1978190207Srpaulo                        break;
1979146773Ssam                    default:
1980146773Ssam                        TCHECK2(*(tptr-3),tlen);
1981146773Ssam                        printf("no AFI %u / SAFI %u decoder",af,safi);
1982146773Ssam                        if (vflag <= 1)
1983146773Ssam                            print_unknown_data(tptr-3,"\n\t    ",tlen);
1984146773Ssam                        advance = 0;
1985146773Ssam                        tptr = pptr + len;
1986146773Ssam                        break;
1987146773Ssam                    }
1988147899Ssam                    if (advance < 0)
1989147899Ssam                        break;
1990146773Ssam                    tptr += advance;
199156893Sfenner		}
199256893Sfenner		break;
1993127668Sbms        case BGPTYPE_EXTD_COMMUNITIES:
1994127668Sbms		if (len % 8) {
1995127668Sbms			printf("invalid len");
1996127668Sbms			break;
1997127668Sbms		}
1998127668Sbms                while (tlen>0) {
1999127668Sbms                    u_int16_t extd_comm;
2000127668Sbms
2001127668Sbms                    TCHECK2(tptr[0], 2);
2002127668Sbms                    extd_comm=EXTRACT_16BITS(tptr);
2003127668Sbms
2004127668Sbms		    printf("\n\t    %s (0x%04x), Flags [%s]",
2005146773Ssam			   tok2strbuf(bgp_extd_comm_subtype_values,
2006146773Ssam				      "unknown extd community typecode",
2007146773Ssam				      extd_comm, tokbuf, sizeof(tokbuf)),
2008127668Sbms			   extd_comm,
2009127668Sbms			   bittok2str(bgp_extd_comm_flag_values, "none", extd_comm));
2010127668Sbms
2011127668Sbms                    TCHECK2(*(tptr+2), 6);
2012127668Sbms                    switch(extd_comm) {
2013127668Sbms                    case BGP_EXT_COM_RT_0:
2014127668Sbms                    case BGP_EXT_COM_RO_0:
2015235530Sdelphij                    case BGP_EXT_COM_L2VPN_RT_0:
2016190207Srpaulo                        printf(": %u:%u (= %s)",
2017127668Sbms                               EXTRACT_16BITS(tptr+2),
2018190207Srpaulo                               EXTRACT_32BITS(tptr+4),
2019127668Sbms                               getname(tptr+4));
2020127668Sbms                        break;
2021127668Sbms                    case BGP_EXT_COM_RT_1:
2022127668Sbms                    case BGP_EXT_COM_RO_1:
2023235530Sdelphij                    case BGP_EXT_COM_L2VPN_RT_1:
2024190207Srpaulo                    case BGP_EXT_COM_VRF_RT_IMP:
2025127668Sbms                        printf(": %s:%u",
2026127668Sbms                               getname(tptr+2),
2027127668Sbms                               EXTRACT_16BITS(tptr+6));
2028127668Sbms                        break;
2029127668Sbms                    case BGP_EXT_COM_RT_2:
2030127668Sbms                    case BGP_EXT_COM_RO_2:
2031214478Srpaulo			printf(": %s:%u",
2032214478Srpaulo			    as_printf(astostr, sizeof(astostr),
2033214478Srpaulo			    EXTRACT_32BITS(tptr+2)), EXTRACT_16BITS(tptr+6));
2034214478Srpaulo			break;
2035127668Sbms                    case BGP_EXT_COM_LINKBAND:
2036127668Sbms		        bw.i = EXTRACT_32BITS(tptr+2);
2037127668Sbms                        printf(": bandwidth: %.3f Mbps",
2038127668Sbms                               bw.f*8/1000000);
2039127668Sbms                        break;
2040127668Sbms                    case BGP_EXT_COM_VPN_ORIGIN:
2041127668Sbms                    case BGP_EXT_COM_VPN_ORIGIN2:
2042127668Sbms                    case BGP_EXT_COM_VPN_ORIGIN3:
2043127668Sbms                    case BGP_EXT_COM_VPN_ORIGIN4:
2044127668Sbms                    case BGP_EXT_COM_OSPF_RID:
2045127668Sbms                    case BGP_EXT_COM_OSPF_RID2:
2046127668Sbms                        printf("%s", getname(tptr+2));
2047127668Sbms                        break;
2048127668Sbms                    case BGP_EXT_COM_OSPF_RTYPE:
2049127668Sbms                    case BGP_EXT_COM_OSPF_RTYPE2:
2050127668Sbms                        printf(": area:%s, router-type:%s, metric-type:%s%s",
2051127668Sbms                               getname(tptr+2),
2052146773Ssam                               tok2strbuf(bgp_extd_comm_ospf_rtype_values,
2053146773Ssam					  "unknown (0x%02x)",
2054146773Ssam					  *(tptr+6),
2055146773Ssam					  tokbuf, sizeof(tokbuf)),
2056127668Sbms                               (*(tptr+7) &  BGP_OSPF_RTYPE_METRIC_TYPE) ? "E2" : "",
2057172683Smlaier                               ((*(tptr+6) == BGP_OSPF_RTYPE_EXT) || (*(tptr+6) == BGP_OSPF_RTYPE_NSSA)) ? "E1" : "");
2058127668Sbms                        break;
2059127668Sbms                    case BGP_EXT_COM_L2INFO:
2060127668Sbms                        printf(": %s Control Flags [0x%02x]:MTU %u",
2061146773Ssam                               tok2strbuf(l2vpn_encaps_values,
2062146773Ssam					  "unknown encaps",
2063146773Ssam					  *(tptr+2),
2064146773Ssam					  tokbuf, sizeof(tokbuf)),
2065127668Sbms                                       *(tptr+3),
2066127668Sbms                               EXTRACT_16BITS(tptr+4));
2067127668Sbms                        break;
2068190207Srpaulo                    case BGP_EXT_COM_SOURCE_AS:
2069190207Srpaulo                        printf(": AS %u", EXTRACT_16BITS(tptr+2));
2070190207Srpaulo                        break;
2071127668Sbms                    default:
2072147899Ssam                        TCHECK2(*tptr,8);
2073127668Sbms                        print_unknown_data(tptr,"\n\t      ",8);
2074127668Sbms                        break;
2075127668Sbms                    }
2076127668Sbms                    tlen -=8;
2077127668Sbms                    tptr +=8;
2078127668Sbms                }
2079127668Sbms                break;
2080127668Sbms
2081190207Srpaulo        case BGPTYPE_PMSI_TUNNEL:
2082190207Srpaulo        {
2083190207Srpaulo                u_int8_t tunnel_type, flags;
2084190207Srpaulo
2085190207Srpaulo                tunnel_type = *(tptr+1);
2086190207Srpaulo                flags = *tptr;
2087190207Srpaulo                tlen = len;
2088190207Srpaulo
2089190207Srpaulo                TCHECK2(tptr[0], 5);
2090190207Srpaulo                printf("\n\t    Tunnel-type %s (%u), Flags [%s], MPLS Label %u",
2091190207Srpaulo                       tok2str(bgp_pmsi_tunnel_values, "Unknown", tunnel_type),
2092190207Srpaulo                       tunnel_type,
2093190207Srpaulo                       bittok2str(bgp_pmsi_flag_values, "none", flags),
2094190207Srpaulo                       EXTRACT_24BITS(tptr+2)>>4);
2095190207Srpaulo
2096190207Srpaulo                tptr +=5;
2097190207Srpaulo                tlen -= 5;
2098190207Srpaulo
2099190207Srpaulo                switch (tunnel_type) {
2100190207Srpaulo                case BGP_PMSI_TUNNEL_PIM_SM: /* fall through */
2101190207Srpaulo                case BGP_PMSI_TUNNEL_PIM_BIDIR:
2102190207Srpaulo                    TCHECK2(tptr[0], 8);
2103190207Srpaulo                    printf("\n\t      Sender %s, P-Group %s",
2104190207Srpaulo                           ipaddr_string(tptr),
2105190207Srpaulo                           ipaddr_string(tptr+4));
2106190207Srpaulo                    break;
2107190207Srpaulo
2108190207Srpaulo                case BGP_PMSI_TUNNEL_PIM_SSM:
2109190207Srpaulo                    TCHECK2(tptr[0], 8);
2110190207Srpaulo                    printf("\n\t      Root-Node %s, P-Group %s",
2111190207Srpaulo                           ipaddr_string(tptr),
2112190207Srpaulo                           ipaddr_string(tptr+4));
2113190207Srpaulo                    break;
2114190207Srpaulo                case BGP_PMSI_TUNNEL_INGRESS:
2115190207Srpaulo                    TCHECK2(tptr[0], 4);
2116190207Srpaulo                    printf("\n\t      Tunnel-Endpoint %s",
2117190207Srpaulo                           ipaddr_string(tptr));
2118190207Srpaulo                    break;
2119190207Srpaulo                case BGP_PMSI_TUNNEL_LDP_P2MP: /* fall through */
2120190207Srpaulo                case BGP_PMSI_TUNNEL_LDP_MP2MP:
2121190207Srpaulo                    TCHECK2(tptr[0], 8);
2122190207Srpaulo                    printf("\n\t      Root-Node %s, LSP-ID 0x%08x",
2123190207Srpaulo                           ipaddr_string(tptr),
2124190207Srpaulo                           EXTRACT_32BITS(tptr+4));
2125190207Srpaulo                    break;
2126190207Srpaulo                case BGP_PMSI_TUNNEL_RSVP_P2MP:
2127190207Srpaulo                    TCHECK2(tptr[0], 8);
2128190207Srpaulo                    printf("\n\t      Extended-Tunnel-ID %s, P2MP-ID 0x%08x",
2129190207Srpaulo                           ipaddr_string(tptr),
2130190207Srpaulo                           EXTRACT_32BITS(tptr+4));
2131190207Srpaulo                    break;
2132190207Srpaulo                default:
2133190207Srpaulo                    if (vflag <= 1) {
2134190207Srpaulo                        print_unknown_data(tptr,"\n\t      ",tlen);
2135190207Srpaulo                    }
2136190207Srpaulo                }
2137190207Srpaulo                break;
2138190207Srpaulo        }
2139146773Ssam        case BGPTYPE_ATTR_SET:
2140146773Ssam                TCHECK2(tptr[0], 4);
2141241235Sdelphij                if (len < 4)
2142241235Sdelphij                	goto trunc;
2143214478Srpaulo		printf("\n\t    Origin AS: %s",
2144214478Srpaulo		    as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(tptr)));
2145214478Srpaulo		tptr+=4;
2146146773Ssam                len -=4;
2147146773Ssam
2148241235Sdelphij                while (len) {
2149241235Sdelphij                    u_int aflags, atype, alenlen, alen;
2150146773Ssam
2151241235Sdelphij                    TCHECK2(tptr[0], 2);
2152241235Sdelphij                    if (len < 2)
2153241235Sdelphij                        goto trunc;
2154241235Sdelphij                    aflags = *tptr;
2155241235Sdelphij                    atype = *(tptr + 1);
2156241235Sdelphij                    tptr += 2;
2157241235Sdelphij                    len -= 2;
2158241235Sdelphij                    alenlen = bgp_attr_lenlen(aflags, tptr);
2159241235Sdelphij                    TCHECK2(tptr[0], alenlen);
2160241235Sdelphij                    if (len < alenlen)
2161241235Sdelphij                        goto trunc;
2162241235Sdelphij                    alen = bgp_attr_len(aflags, tptr);
2163241235Sdelphij                    tptr += alenlen;
2164241235Sdelphij                    len -= alenlen;
2165146773Ssam
2166146773Ssam                    printf("\n\t      %s (%u), length: %u",
2167146773Ssam                           tok2strbuf(bgp_attr_values,
2168241235Sdelphij                                      "Unknown Attribute", atype,
2169241235Sdelphij                                      tokbuf, sizeof(tokbuf)),
2170241235Sdelphij                           atype,
2171146773Ssam                           alen);
2172146773Ssam
2173241235Sdelphij                    if (aflags) {
2174146773Ssam                        printf(", Flags [%s%s%s%s",
2175241235Sdelphij                               aflags & 0x80 ? "O" : "",
2176241235Sdelphij                               aflags & 0x40 ? "T" : "",
2177241235Sdelphij                               aflags & 0x20 ? "P" : "",
2178241235Sdelphij                               aflags & 0x10 ? "E" : "");
2179241235Sdelphij                        if (aflags & 0xf)
2180241235Sdelphij                            printf("+%x", aflags & 0xf);
2181146773Ssam                        printf("]: ");
2182146773Ssam                    }
2183146773Ssam                    /* FIXME check for recursion */
2184241235Sdelphij                    if (!bgp_attr_print(atype, tptr, alen))
2185146773Ssam                        return 0;
2186146773Ssam                    tptr += alen;
2187146773Ssam                    len -= alen;
2188146773Ssam		}
2189146773Ssam                break;
2190146773Ssam
2191146773Ssam
219256893Sfenner	default:
2193127668Sbms	    TCHECK2(*pptr,len);
2194241235Sdelphij            printf("\n\t    no Attribute %u decoder",atype); /* we have no decoder for the attribute */
2195127668Sbms            if (vflag <= 1)
2196127668Sbms                print_unknown_data(pptr,"\n\t    ",len);
2197127668Sbms            break;
219856893Sfenner	}
2199147899Ssam        if (vflag > 1 && len) { /* omit zero length attributes*/
2200147899Ssam            TCHECK2(*pptr,len);
2201127668Sbms            print_unknown_data(pptr,"\n\t    ",len);
2202147899Ssam        }
2203127668Sbms        return 1;
2204127668Sbms
2205127668Sbmstrunc:
2206127668Sbms        return 0;
220756893Sfenner}
220856893Sfenner
220956893Sfennerstatic void
2210241235Sdelphijbgp_capabilities_print(const u_char *opt, int caps_len)
2211241235Sdelphij{
2212241235Sdelphij	char tokbuf[TOKBUFSIZE];
2213241235Sdelphij	char tokbuf2[TOKBUFSIZE];
2214241235Sdelphij	int cap_type, cap_len, tcap_len, cap_offset;
2215241235Sdelphij        int i = 0;
2216241235Sdelphij
2217241235Sdelphij        while (i < caps_len) {
2218241235Sdelphij                TCHECK2(opt[i], BGP_CAP_HEADER_SIZE);
2219241235Sdelphij                cap_type=opt[i];
2220241235Sdelphij                cap_len=opt[i+1];
2221241235Sdelphij                tcap_len=cap_len;
2222241235Sdelphij                printf("\n\t      %s (%u), length: %u",
2223241235Sdelphij                       tok2strbuf(bgp_capcode_values, "Unknown",
2224241235Sdelphij                                  cap_type, tokbuf, sizeof(tokbuf)),
2225241235Sdelphij                       cap_type,
2226241235Sdelphij                       cap_len);
2227241235Sdelphij                TCHECK2(opt[i+2], cap_len);
2228241235Sdelphij                switch (cap_type) {
2229241235Sdelphij                case BGP_CAPCODE_MP:
2230241235Sdelphij                    printf("\n\t\tAFI %s (%u), SAFI %s (%u)",
2231241235Sdelphij                           tok2strbuf(af_values, "Unknown",
2232241235Sdelphij                                      EXTRACT_16BITS(opt+i+2),
2233241235Sdelphij                                      tokbuf, sizeof(tokbuf)),
2234241235Sdelphij                           EXTRACT_16BITS(opt+i+2),
2235241235Sdelphij                           tok2strbuf(bgp_safi_values, "Unknown",
2236241235Sdelphij                                      opt[i+5],
2237241235Sdelphij                                      tokbuf, sizeof(tokbuf)),
2238241235Sdelphij                           opt[i+5]);
2239241235Sdelphij                    break;
2240241235Sdelphij                case BGP_CAPCODE_RESTART:
2241241235Sdelphij                    printf("\n\t\tRestart Flags: [%s], Restart Time %us",
2242241235Sdelphij                           ((opt[i+2])&0x80) ? "R" : "none",
2243241235Sdelphij                           EXTRACT_16BITS(opt+i+2)&0xfff);
2244241235Sdelphij                    tcap_len-=2;
2245241235Sdelphij                    cap_offset=4;
2246241235Sdelphij                    while(tcap_len>=4) {
2247241235Sdelphij                        printf("\n\t\t  AFI %s (%u), SAFI %s (%u), Forwarding state preserved: %s",
2248241235Sdelphij                               tok2strbuf(af_values,"Unknown",
2249241235Sdelphij                                          EXTRACT_16BITS(opt+i+cap_offset),
2250241235Sdelphij                                          tokbuf, sizeof(tokbuf)),
2251241235Sdelphij                               EXTRACT_16BITS(opt+i+cap_offset),
2252241235Sdelphij                               tok2strbuf(bgp_safi_values,"Unknown",
2253241235Sdelphij                                          opt[i+cap_offset+2],
2254241235Sdelphij                                          tokbuf2, sizeof(tokbuf2)),
2255241235Sdelphij                               opt[i+cap_offset+2],
2256241235Sdelphij                               ((opt[i+cap_offset+3])&0x80) ? "yes" : "no" );
2257241235Sdelphij                        tcap_len-=4;
2258241235Sdelphij                        cap_offset+=4;
2259241235Sdelphij                    }
2260241235Sdelphij                    break;
2261241235Sdelphij                case BGP_CAPCODE_RR:
2262241235Sdelphij                case BGP_CAPCODE_RR_CISCO:
2263241235Sdelphij                    break;
2264241235Sdelphij                case BGP_CAPCODE_AS_NEW:
2265241235Sdelphij
2266241235Sdelphij                    /*
2267241235Sdelphij                     * Extract the 4 byte AS number encoded.
2268241235Sdelphij                     */
2269241235Sdelphij                    if (cap_len == 4) {
2270241235Sdelphij                        printf("\n\t\t 4 Byte AS %s",
2271241235Sdelphij                            as_printf(astostr, sizeof(astostr),
2272241235Sdelphij                            EXTRACT_32BITS(opt + i + 2)));
2273241235Sdelphij                    }
2274241235Sdelphij                    break;
2275241235Sdelphij                default:
2276241235Sdelphij                    printf("\n\t\tno decoder for Capability %u",
2277241235Sdelphij                           cap_type);
2278241235Sdelphij                    if (vflag <= 1)
2279241235Sdelphij                        print_unknown_data(&opt[i+2],"\n\t\t",cap_len);
2280241235Sdelphij                    break;
2281241235Sdelphij                }
2282241235Sdelphij                if (vflag > 1 && cap_len > 0) {
2283241235Sdelphij                    print_unknown_data(&opt[i+2],"\n\t\t",cap_len);
2284241235Sdelphij                }
2285241235Sdelphij                i += BGP_CAP_HEADER_SIZE + cap_len;
2286241235Sdelphij        }
2287241235Sdelphij        return;
2288241235Sdelphij
2289241235Sdelphijtrunc:
2290241235Sdelphij	printf("[|BGP]");
2291241235Sdelphij}
2292241235Sdelphij
2293241235Sdelphijstatic void
229456893Sfennerbgp_open_print(const u_char *dat, int length)
229556893Sfenner{
229656893Sfenner	struct bgp_open bgpo;
229756893Sfenner	struct bgp_opt bgpopt;
229856893Sfenner	const u_char *opt;
2299241235Sdelphij	int i;
2300146773Ssam	char tokbuf[TOKBUFSIZE];
230156893Sfenner
230298524Sfenner	TCHECK2(dat[0], BGP_OPEN_SIZE);
230398524Sfenner	memcpy(&bgpo, dat, BGP_OPEN_SIZE);
230456893Sfenner
2305127668Sbms	printf("\n\t  Version %d, ", bgpo.bgpo_version);
2306214478Srpaulo	printf("my AS %s, ",
2307214478Srpaulo	    as_printf(astostr, sizeof(astostr), ntohs(bgpo.bgpo_myas)));
2308127668Sbms	printf("Holdtime %us, ", ntohs(bgpo.bgpo_holdtime));
2309127668Sbms	printf("ID %s", getname((u_char *)&bgpo.bgpo_id));
2310127668Sbms	printf("\n\t  Optional parameters, length: %u", bgpo.bgpo_optlen);
231156893Sfenner
2312127668Sbms        /* some little sanity checking */
2313127668Sbms        if (length < bgpo.bgpo_optlen+BGP_OPEN_SIZE)
2314127668Sbms            return;
2315127668Sbms
231656893Sfenner	/* ugly! */
231798524Sfenner	opt = &((const struct bgp_open *)dat)->bgpo_optlen;
231856893Sfenner	opt++;
231956893Sfenner
232098524Sfenner	i = 0;
232198524Sfenner	while (i < bgpo.bgpo_optlen) {
232298524Sfenner		TCHECK2(opt[i], BGP_OPT_SIZE);
232398524Sfenner		memcpy(&bgpopt, &opt[i], BGP_OPT_SIZE);
232456893Sfenner		if (i + 2 + bgpopt.bgpopt_len > bgpo.bgpo_optlen) {
2325241235Sdelphij			printf("\n\t     Option %d, length: %u", bgpopt.bgpopt_type, bgpopt.bgpopt_len);
232656893Sfenner			break;
232756893Sfenner		}
232856893Sfenner
2329127668Sbms		printf("\n\t    Option %s (%u), length: %u",
2330241235Sdelphij		       tok2strbuf(bgp_opt_values,"Unknown",
2331146773Ssam				  bgpopt.bgpopt_type,
2332146773Ssam				  tokbuf, sizeof(tokbuf)),
2333241235Sdelphij		       bgpopt.bgpopt_type,
2334241235Sdelphij		       bgpopt.bgpopt_len);
2335127668Sbms
2336241235Sdelphij		/* now let's decode the options we know*/
2337241235Sdelphij		switch(bgpopt.bgpopt_type) {
2338214478Srpaulo
2339241235Sdelphij		case BGP_OPT_CAP:
2340241235Sdelphij			bgp_capabilities_print(&opt[i+BGP_OPT_SIZE],
2341241235Sdelphij			    bgpopt.bgpopt_len);
2342241235Sdelphij			break;
2343127668Sbms
2344241235Sdelphij		case BGP_OPT_AUTH:
2345241235Sdelphij		default:
2346241235Sdelphij		       printf("\n\t      no decoder for option %u",
2347241235Sdelphij			   bgpopt.bgpopt_type);
2348241235Sdelphij		       break;
2349241235Sdelphij		}
235098524Sfenner		i += BGP_OPT_SIZE + bgpopt.bgpopt_len;
235156893Sfenner	}
235275115Sfenner	return;
235375115Sfennertrunc:
235475115Sfenner	printf("[|BGP]");
235556893Sfenner}
235656893Sfenner
235756893Sfennerstatic void
235856893Sfennerbgp_update_print(const u_char *dat, int length)
235956893Sfenner{
236056893Sfenner	struct bgp bgp;
236156893Sfenner	const u_char *p;
2362241235Sdelphij	int withdrawn_routes_len;
236356893Sfenner	int len;
236456893Sfenner	int i;
2365146773Ssam	char tokbuf[TOKBUFSIZE];
2366241235Sdelphij#ifndef INET6
2367241235Sdelphij	char buf[MAXHOSTNAMELEN + 100];
2368241235Sdelphij	int wpfx;
2369241235Sdelphij#endif
237056893Sfenner
237198524Sfenner	TCHECK2(dat[0], BGP_SIZE);
2372241235Sdelphij	if (length < BGP_SIZE)
2373241235Sdelphij		goto trunc;
237498524Sfenner	memcpy(&bgp, dat, BGP_SIZE);
237556893Sfenner	p = dat + BGP_SIZE;	/*XXX*/
2376241235Sdelphij	length -= BGP_SIZE;
237756893Sfenner
237856893Sfenner	/* Unfeasible routes */
2379241235Sdelphij	TCHECK2(p[0], 2);
2380241235Sdelphij	if (length < 2)
2381241235Sdelphij		goto trunc;
2382241235Sdelphij	withdrawn_routes_len = EXTRACT_16BITS(p);
2383241235Sdelphij	p += 2;
2384241235Sdelphij	length -= 2;
2385241235Sdelphij	if (withdrawn_routes_len) {
238698524Sfenner		/*
238798524Sfenner		 * Without keeping state from the original NLRI message,
238898524Sfenner		 * it's not possible to tell if this a v4 or v6 route,
238998524Sfenner		 * so only try to decode it if we're not v6 enabled.
239075115Sfenner	         */
2391241235Sdelphij		TCHECK2(p[0], withdrawn_routes_len);
2392241235Sdelphij		if (length < withdrawn_routes_len)
2393241235Sdelphij			goto trunc;
239475115Sfenner#ifdef INET6
2395241235Sdelphij		printf("\n\t  Withdrawn routes: %d bytes", withdrawn_routes_len);
2396241235Sdelphij		p += withdrawn_routes_len;
2397241235Sdelphij		length -= withdrawn_routes_len;
2398127668Sbms#else
2399241235Sdelphij		if (withdrawn_routes_len < 2)
2400241235Sdelphij			goto trunc;
2401241235Sdelphij		length -= 2;
2402241235Sdelphij		withdrawn_routes_len -= 2;
240375115Sfenner
240475115Sfenner
2405127668Sbms		printf("\n\t  Withdrawn routes:");
2406127668Sbms
2407241235Sdelphij		while(withdrawn_routes_len > 0) {
2408241235Sdelphij			wpfx = decode_prefix4(p, withdrawn_routes_len, buf, sizeof(buf));
2409127668Sbms			if (wpfx == -1) {
2410127668Sbms				printf("\n\t    (illegal prefix length)");
2411111726Sfenner				break;
2412127668Sbms			} else if (wpfx == -2)
2413127668Sbms				goto trunc;
2414241235Sdelphij			else if (wpfx == -3)
2415241235Sdelphij				goto trunc; /* bytes left, but not enough */
2416127668Sbms			else {
2417127668Sbms				printf("\n\t    %s", buf);
2418241235Sdelphij				p += wpfx;
2419241235Sdelphij				length -= wpfx;
2420241235Sdelphij				withdrawn_routes_len -= wpfx;
2421127668Sbms			}
242275115Sfenner		}
242375115Sfenner#endif
242456893Sfenner	}
242556893Sfenner
242675115Sfenner	TCHECK2(p[0], 2);
2427241235Sdelphij	if (length < 2)
2428241235Sdelphij		goto trunc;
242975115Sfenner	len = EXTRACT_16BITS(p);
2430241235Sdelphij	p += 2;
2431241235Sdelphij	length -= 2;
2432146773Ssam
2433241235Sdelphij        if (withdrawn_routes_len == 0 && len == 0 && length == 0) {
2434241235Sdelphij            /* No withdrawn routes, no path attributes, no NLRI */
2435146773Ssam            printf("\n\t  End-of-Rib Marker (empty NLRI)");
2436146773Ssam            return;
2437146773Ssam        }
2438146773Ssam
243956893Sfenner	if (len) {
244056893Sfenner		/* do something more useful!*/
2441241235Sdelphij		while (len) {
2442241235Sdelphij			int aflags, atype, alenlen, alen;
244356893Sfenner
2444241235Sdelphij			TCHECK2(p[0], 2);
2445241235Sdelphij			if (len < 2)
2446241235Sdelphij			    goto trunc;
2447241235Sdelphij			if (length < 2)
2448241235Sdelphij			    goto trunc;
2449241235Sdelphij			aflags = *p;
2450241235Sdelphij			atype = *(p + 1);
2451241235Sdelphij			p += 2;
2452241235Sdelphij			len -= 2;
2453241235Sdelphij			length -= 2;
2454241235Sdelphij			alenlen = bgp_attr_lenlen(aflags, p);
2455241235Sdelphij			TCHECK2(p[0], alenlen);
2456241235Sdelphij			if (len < alenlen)
2457241235Sdelphij			    goto trunc;
2458241235Sdelphij			if (length < alenlen)
2459241235Sdelphij			    goto trunc;
2460241235Sdelphij			alen = bgp_attr_len(aflags, p);
2461241235Sdelphij			p += alenlen;
2462241235Sdelphij			len -= alenlen;
2463241235Sdelphij			length -= alenlen;
246456893Sfenner
2465241235Sdelphij			printf("\n\t  %s (%u), length: %u",
2466146773Ssam                              tok2strbuf(bgp_attr_values, "Unknown Attribute",
2467241235Sdelphij					 atype,
2468146773Ssam					 tokbuf, sizeof(tokbuf)),
2469241235Sdelphij                              atype,
2470127668Sbms                              alen);
2471127668Sbms
2472241235Sdelphij			if (aflags) {
2473127668Sbms				printf(", Flags [%s%s%s%s",
2474241235Sdelphij					aflags & 0x80 ? "O" : "",
2475241235Sdelphij					aflags & 0x40 ? "T" : "",
2476241235Sdelphij					aflags & 0x20 ? "P" : "",
2477241235Sdelphij					aflags & 0x10 ? "E" : "");
2478241235Sdelphij				if (aflags & 0xf)
2479241235Sdelphij					printf("+%x", aflags & 0xf);
2480127668Sbms				printf("]: ");
248156893Sfenner			}
2482241235Sdelphij			if (len < alen)
2483127668Sbms				goto trunc;
2484241235Sdelphij			if (length < alen)
2485241235Sdelphij				goto trunc;
2486241235Sdelphij			if (!bgp_attr_print(atype, p, alen))
2487241235Sdelphij				goto trunc;
2488241235Sdelphij			p += alen;
2489241235Sdelphij			len -= alen;
2490241235Sdelphij			length -= alen;
249156893Sfenner		}
2492146773Ssam	}
249356893Sfenner
2494241235Sdelphij	if (length) {
2495241235Sdelphij		/*
2496241235Sdelphij		 * XXX - what if they're using the "Advertisement of
2497241235Sdelphij		 * Multiple Paths in BGP" feature:
2498241235Sdelphij		 *
2499241235Sdelphij		 * https://datatracker.ietf.org/doc/draft-ietf-idr-add-paths/
2500241235Sdelphij		 *
2501241235Sdelphij		 * http://tools.ietf.org/html/draft-ietf-idr-add-paths-06
2502241235Sdelphij		 */
2503147899Ssam		printf("\n\t  Updated routes:");
2504241235Sdelphij		while (length) {
250575115Sfenner			char buf[MAXHOSTNAMELEN + 100];
2506241235Sdelphij			i = decode_prefix4(p, length, buf, sizeof(buf));
2507147173Ssam			if (i == -1) {
2508127668Sbms				printf("\n\t    (illegal prefix length)");
2509147173Ssam				break;
2510147173Ssam			} else if (i == -2)
2511127668Sbms				goto trunc;
2512241235Sdelphij			else if (i == -3)
2513241235Sdelphij				goto trunc; /* bytes left, but not enough */
2514127668Sbms			else {
2515127668Sbms				printf("\n\t    %s", buf);
2516127668Sbms				p += i;
2517241235Sdelphij				length -= i;
2518127668Sbms			}
251956893Sfenner		}
252056893Sfenner	}
252175115Sfenner	return;
252275115Sfennertrunc:
252375115Sfenner	printf("[|BGP]");
252456893Sfenner}
252556893Sfenner
252656893Sfennerstatic void
252756893Sfennerbgp_notification_print(const u_char *dat, int length)
252856893Sfenner{
252956893Sfenner	struct bgp_notification bgpn;
2530127668Sbms	const u_char *tptr;
2531146773Ssam	char tokbuf[TOKBUFSIZE];
2532146773Ssam	char tokbuf2[TOKBUFSIZE];
253356893Sfenner
253498524Sfenner	TCHECK2(dat[0], BGP_NOTIFICATION_SIZE);
253598524Sfenner	memcpy(&bgpn, dat, BGP_NOTIFICATION_SIZE);
253656893Sfenner
2537127668Sbms        /* some little sanity checking */
2538127668Sbms        if (length<BGP_NOTIFICATION_SIZE)
2539127668Sbms            return;
2540127668Sbms
2541127668Sbms	printf(", %s (%u)",
2542146773Ssam	       tok2strbuf(bgp_notify_major_values, "Unknown Error",
2543146773Ssam			  bgpn.bgpn_major, tokbuf, sizeof(tokbuf)),
2544127668Sbms	       bgpn.bgpn_major);
2545127668Sbms
2546127668Sbms        switch (bgpn.bgpn_major) {
2547127668Sbms
2548127668Sbms        case BGP_NOTIFY_MAJOR_MSG:
2549127668Sbms            printf(", subcode %s (%u)",
2550146773Ssam		   tok2strbuf(bgp_notify_minor_msg_values, "Unknown",
2551146773Ssam			      bgpn.bgpn_minor, tokbuf, sizeof(tokbuf)),
2552127668Sbms		   bgpn.bgpn_minor);
2553127668Sbms            break;
2554127668Sbms        case BGP_NOTIFY_MAJOR_OPEN:
2555127668Sbms            printf(", subcode %s (%u)",
2556146773Ssam		   tok2strbuf(bgp_notify_minor_open_values, "Unknown",
2557146773Ssam			      bgpn.bgpn_minor, tokbuf, sizeof(tokbuf)),
2558127668Sbms		   bgpn.bgpn_minor);
2559127668Sbms            break;
2560127668Sbms        case BGP_NOTIFY_MAJOR_UPDATE:
2561127668Sbms            printf(", subcode %s (%u)",
2562146773Ssam		   tok2strbuf(bgp_notify_minor_update_values, "Unknown",
2563146773Ssam			      bgpn.bgpn_minor, tokbuf, sizeof(tokbuf)),
2564127668Sbms		   bgpn.bgpn_minor);
2565127668Sbms            break;
2566127668Sbms        case BGP_NOTIFY_MAJOR_CAP:
2567127668Sbms            printf(" subcode %s (%u)",
2568146773Ssam		   tok2strbuf(bgp_notify_minor_cap_values, "Unknown",
2569146773Ssam			      bgpn.bgpn_minor, tokbuf, sizeof(tokbuf)),
2570127668Sbms		   bgpn.bgpn_minor);
2571127668Sbms        case BGP_NOTIFY_MAJOR_CEASE:
2572127668Sbms            printf(", subcode %s (%u)",
2573146773Ssam		   tok2strbuf(bgp_notify_minor_cease_values, "Unknown",
2574146773Ssam			      bgpn.bgpn_minor, tokbuf, sizeof(tokbuf)),
2575127668Sbms		   bgpn.bgpn_minor);
2576127668Sbms
2577127668Sbms	    /* draft-ietf-idr-cease-subcode-02 mentions optionally 7 bytes
2578127668Sbms             * for the maxprefix subtype, which may contain AFI, SAFI and MAXPREFIXES
2579127668Sbms             */
2580127668Sbms	    if(bgpn.bgpn_minor == BGP_NOTIFY_MINOR_CEASE_MAXPRFX && length >= BGP_NOTIFICATION_SIZE + 7) {
2581127668Sbms		tptr = dat + BGP_NOTIFICATION_SIZE;
2582127668Sbms		TCHECK2(*tptr, 7);
2583127668Sbms		printf(", AFI %s (%u), SAFI %s (%u), Max Prefixes: %u",
2584172683Smlaier		       tok2strbuf(af_values, "Unknown",
2585146773Ssam				  EXTRACT_16BITS(tptr), tokbuf, sizeof(tokbuf)),
2586127668Sbms		       EXTRACT_16BITS(tptr),
2587146773Ssam		       tok2strbuf(bgp_safi_values, "Unknown", *(tptr+2),
2588146773Ssam				  tokbuf2, sizeof(tokbuf)),
2589127668Sbms		       *(tptr+2),
2590127668Sbms		       EXTRACT_32BITS(tptr+3));
2591127668Sbms	    }
2592127668Sbms            break;
2593127668Sbms        default:
2594127668Sbms            break;
2595127668Sbms        }
2596127668Sbms
259775115Sfenner	return;
259875115Sfennertrunc:
259975115Sfenner	printf("[|BGP]");
260056893Sfenner}
260156893Sfenner
260256893Sfennerstatic void
2603127668Sbmsbgp_route_refresh_print(const u_char *pptr, int len) {
2604127668Sbms
2605127668Sbms        const struct bgp_route_refresh *bgp_route_refresh_header;
2606146773Ssam	char tokbuf[TOKBUFSIZE];
2607146773Ssam	char tokbuf2[TOKBUFSIZE];
2608146773Ssam
2609147899Ssam	TCHECK2(pptr[0], BGP_ROUTE_REFRESH_SIZE);
2610147899Ssam
2611147899Ssam        /* some little sanity checking */
2612147899Ssam        if (len<BGP_ROUTE_REFRESH_SIZE)
2613147899Ssam            return;
2614147899Ssam
2615127668Sbms        bgp_route_refresh_header = (const struct bgp_route_refresh *)pptr;
2616127668Sbms
2617127668Sbms        printf("\n\t  AFI %s (%u), SAFI %s (%u)",
2618172683Smlaier               tok2strbuf(af_values,"Unknown",
2619146773Ssam			  /* this stinks but the compiler pads the structure
2620146773Ssam			   * weird */
2621146773Ssam			  EXTRACT_16BITS(&bgp_route_refresh_header->afi),
2622146773Ssam			  tokbuf, sizeof(tokbuf)),
2623127668Sbms               EXTRACT_16BITS(&bgp_route_refresh_header->afi),
2624146773Ssam               tok2strbuf(bgp_safi_values,"Unknown",
2625146773Ssam			  bgp_route_refresh_header->safi,
2626146773Ssam			  tokbuf2, sizeof(tokbuf2)),
2627127668Sbms               bgp_route_refresh_header->safi);
2628127668Sbms
2629147899Ssam        if (vflag > 1) {
2630147899Ssam            TCHECK2(*pptr, len);
2631127668Sbms            print_unknown_data(pptr,"\n\t  ", len);
2632147899Ssam        }
2633127668Sbms
2634127668Sbms        return;
2635147899Ssamtrunc:
2636147899Ssam	printf("[|BGP]");
2637127668Sbms}
2638127668Sbms
2639127668Sbmsstatic int
264056893Sfennerbgp_header_print(const u_char *dat, int length)
264156893Sfenner{
264256893Sfenner	struct bgp bgp;
2643146773Ssam	char tokbuf[TOKBUFSIZE];
264456893Sfenner
264598524Sfenner	TCHECK2(dat[0], BGP_SIZE);
264698524Sfenner	memcpy(&bgp, dat, BGP_SIZE);
2647127668Sbms	printf("\n\t%s Message (%u), length: %u",
2648146773Ssam               tok2strbuf(bgp_msg_values, "Unknown", bgp.bgp_type,
2649146773Ssam			  tokbuf, sizeof(tokbuf)),
2650127668Sbms               bgp.bgp_type,
2651127668Sbms               length);
265256893Sfenner
265356893Sfenner	switch (bgp.bgp_type) {
265456893Sfenner	case BGP_OPEN:
265556893Sfenner		bgp_open_print(dat, length);
265656893Sfenner		break;
265756893Sfenner	case BGP_UPDATE:
265856893Sfenner		bgp_update_print(dat, length);
265956893Sfenner		break;
266056893Sfenner	case BGP_NOTIFICATION:
266156893Sfenner		bgp_notification_print(dat, length);
266256893Sfenner		break;
2663127668Sbms        case BGP_KEEPALIVE:
2664127668Sbms                break;
2665127668Sbms        case BGP_ROUTE_REFRESH:
2666127668Sbms                bgp_route_refresh_print(dat, length);
2667127668Sbms                break;
2668127668Sbms        default:
2669147899Ssam                /* we have no decoder for the BGP message */
2670147899Ssam                TCHECK2(*dat, length);
2671147899Ssam                printf("\n\t  no Message %u decoder",bgp.bgp_type);
2672147899Ssam                print_unknown_data(dat,"\n\t  ",length);
2673127668Sbms                break;
267456893Sfenner	}
2675127668Sbms	return 1;
267675115Sfennertrunc:
267775115Sfenner	printf("[|BGP]");
2678127668Sbms	return 0;
267956893Sfenner}
268056893Sfenner
268156893Sfennervoid
268256893Sfennerbgp_print(const u_char *dat, int length)
268356893Sfenner{
268456893Sfenner	const u_char *p;
268556893Sfenner	const u_char *ep;
268656893Sfenner	const u_char *start;
268756893Sfenner	const u_char marker[] = {
2688127668Sbms		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2689127668Sbms		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
269056893Sfenner	};
269156893Sfenner	struct bgp bgp;
269256893Sfenner	u_int16_t hlen;
2693146773Ssam	char tokbuf[TOKBUFSIZE];
269456893Sfenner
269556893Sfenner	ep = dat + length;
269656893Sfenner	if (snapend < dat + length)
269756893Sfenner		ep = snapend;
269856893Sfenner
2699127668Sbms	printf(": BGP, length: %u",length);
270056893Sfenner
2701127668Sbms        if (vflag < 1) /* lets be less chatty */
2702127668Sbms                return;
2703127668Sbms
270456893Sfenner	p = dat;
270556893Sfenner	start = p;
2706147899Ssam	while (p < ep) {
270756893Sfenner		if (!TTEST2(p[0], 1))
270856893Sfenner			break;
270956893Sfenner		if (p[0] != 0xff) {
271056893Sfenner			p++;
271156893Sfenner			continue;
271256893Sfenner		}
271356893Sfenner
271456893Sfenner		if (!TTEST2(p[0], sizeof(marker)))
271556893Sfenner			break;
271656893Sfenner		if (memcmp(p, marker, sizeof(marker)) != 0) {
271756893Sfenner			p++;
271856893Sfenner			continue;
271956893Sfenner		}
272056893Sfenner
272156893Sfenner		/* found BGP header */
272298524Sfenner		TCHECK2(p[0], BGP_SIZE);	/*XXX*/
272398524Sfenner		memcpy(&bgp, p, BGP_SIZE);
272456893Sfenner
272556893Sfenner		if (start != p)
272656893Sfenner			printf(" [|BGP]");
272756893Sfenner
272856893Sfenner		hlen = ntohs(bgp.bgp_len);
2729127668Sbms		if (hlen < BGP_SIZE) {
2730127668Sbms			printf("\n[|BGP Bogus header length %u < %u]", hlen,
2731127668Sbms			    BGP_SIZE);
2732127668Sbms			break;
2733127668Sbms		}
2734127668Sbms
273556893Sfenner		if (TTEST2(p[0], hlen)) {
2736127668Sbms			if (!bgp_header_print(p, hlen))
2737127668Sbms				return;
273856893Sfenner			p += hlen;
273956893Sfenner			start = p;
274056893Sfenner		} else {
2741146773Ssam			printf("\n[|BGP %s]",
2742146773Ssam			       tok2strbuf(bgp_msg_values,
2743146773Ssam					  "Unknown Message Type",
2744146773Ssam					  bgp.bgp_type,
2745146773Ssam					  tokbuf, sizeof(tokbuf)));
274656893Sfenner			break;
274756893Sfenner		}
274856893Sfenner	}
274956893Sfenner
275056893Sfenner	return;
275156893Sfenner
275256893Sfennertrunc:
275356893Sfenner	printf(" [|BGP]");
275456893Sfenner}
2755190207Srpaulo
2756190207Srpaulo/*
2757190207Srpaulo * Local Variables:
2758190207Srpaulo * c-style: whitesmith
2759190207Srpaulo * c-basic-offset: 4
2760190207Srpaulo * End:
2761190207Srpaulo */
2762