156160Sru/*
2146515Sru * Copyright (C) 1999 WIDE Project.
321495Sjmacd * All rights reserved.
4146515Sru *
521495Sjmacd * Redistribution and use in source and binary forms, with or without
621495Sjmacd * modification, are permitted provided that the following conditions
721495Sjmacd * are met:
821495Sjmacd * 1. Redistributions of source code must retain the above copyright
921495Sjmacd *    notice, this list of conditions and the following disclaimer.
1021495Sjmacd * 2. Redistributions in binary form must reproduce the above copyright
1121495Sjmacd *    notice, this list of conditions and the following disclaimer in the
1221495Sjmacd *    documentation and/or other materials provided with the distribution.
1321495Sjmacd * 3. Neither the name of the project nor the names of its contributors
1421495Sjmacd *    may be used to endorse or promote products derived from this software
1521495Sjmacd *    without specific prior written permission.
1621495Sjmacd *
1721495Sjmacd * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1821495Sjmacd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1921495Sjmacd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20146515Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2121495Sjmacd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2242660Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2321495Sjmacd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2421495Sjmacd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2521495Sjmacd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2621495Sjmacd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2721495Sjmacd * SUCH DAMAGE.
2821495Sjmacd *
2921495Sjmacd * Extensively modified by Hannes Gredler (hannes@gredler.at) for more
3056160Sru * complete BGP support.
3121495Sjmacd */
3221495Sjmacd
3321495Sjmacd#include <sys/cdefs.h>
3421495Sjmacd#ifndef lint
3521495Sjmacd__RCSID("$NetBSD: print-bgp.c,v 1.12 2023/08/17 20:19:40 christos Exp $");
3621495Sjmacd#endif
3721495Sjmacd
3821495Sjmacd/* \summary: Border Gateway Protocol (BGP) printer */
3921495Sjmacd
40146515Sru/* specification: RFC 4271 */
41146515Sru
42146515Sru#ifdef HAVE_CONFIG_H
43146515Sru#include <config.h>
4421495Sjmacd#endif
45146515Sru
46146515Sru#include "netdissect-stdinc.h"
47146515Sru
48146515Sru#include <stdio.h>
4921495Sjmacd#include <string.h>
5021495Sjmacd
51146515Sru#include "netdissect.h"
52146515Sru#include "addrtoname.h"
5321495Sjmacd#include "extract.h"
5421495Sjmacd#include "af.h"
5521495Sjmacd#include "l2vpn.h"
5621495Sjmacd
5721495Sjmacdstruct bgp {
5821495Sjmacd    nd_byte     bgp_marker[16];
5921495Sjmacd    nd_uint16_t bgp_len;
60146515Sru    nd_uint8_t  bgp_type;
6121495Sjmacd};
6221495Sjmacd#define BGP_SIZE        19    /* unaligned */
6321495Sjmacd
6421495Sjmacd#define BGP_OPEN                1
6521495Sjmacd#define BGP_UPDATE              2
6621495Sjmacd#define BGP_NOTIFICATION        3
6721495Sjmacd#define BGP_KEEPALIVE           4
6821495Sjmacd#define BGP_ROUTE_REFRESH       5
6921495Sjmacd
7021495Sjmacdstatic const struct tok bgp_msg_values[] = {
7121495Sjmacd    { BGP_OPEN,                 "Open"},
7221495Sjmacd    { BGP_UPDATE,               "Update"},
7321495Sjmacd    { BGP_NOTIFICATION,         "Notification"},
7421495Sjmacd    { BGP_KEEPALIVE,            "Keepalive"},
7521495Sjmacd    { BGP_ROUTE_REFRESH,        "Route Refresh"},
7621495Sjmacd    { 0, NULL}
7721495Sjmacd};
7821495Sjmacd
7921495Sjmacdstruct bgp_open {
8021495Sjmacd    nd_byte     bgpo_marker[16];
8121495Sjmacd    nd_uint16_t bgpo_len;
8221495Sjmacd    nd_uint8_t  bgpo_type;
8342660Smarkm    nd_uint8_t  bgpo_version;
8421495Sjmacd    nd_uint16_t bgpo_myas;
8521495Sjmacd    nd_uint16_t bgpo_holdtime;
8621495Sjmacd    nd_uint32_t bgpo_id;
8721495Sjmacd    nd_uint8_t  bgpo_optlen;
8821495Sjmacd    /* options should follow */
8921495Sjmacd};
9021495Sjmacd#define BGP_OPEN_SIZE        29    /* unaligned */
9121495Sjmacd
9242660Smarkmstruct bgp_opt {
9321495Sjmacd    nd_uint8_t bgpopt_type;
9421495Sjmacd    nd_uint8_t bgpopt_len;
9521495Sjmacd    /* variable length */
9621495Sjmacd};
9721495Sjmacd#define BGP_OPT_SIZE           2    /* some compilers may pad to 4 bytes */
9821495Sjmacd#define BGP_CAP_HEADER_SIZE    2    /* some compilers may pad to 4 bytes */
9921495Sjmacd
10021495Sjmacdstruct bgp_notification {
10121495Sjmacd    nd_byte     bgpn_marker[16];
10221495Sjmacd    nd_uint16_t bgpn_len;
10321495Sjmacd    nd_uint8_t  bgpn_type;
104146515Sru    nd_uint8_t  bgpn_major;
105146515Sru    nd_uint8_t  bgpn_minor;
106146515Sru};
107146515Sru#define BGP_NOTIFICATION_SIZE        21    /* unaligned */
108146515Sru
109146515Srustruct bgp_route_refresh {
110146515Sru    nd_byte     bgp_marker[16];
111146515Sru    nd_uint16_t len;
112146515Sru    nd_uint8_t  type;   /* No padding after this; afi is, in fact, not aligned */
113146515Sru    nd_uint16_t afi;
114146515Sru    nd_uint8_t  res;
115146515Sru    nd_uint8_t  safi;
116146515Sru};
117146515Sru#define BGP_ROUTE_REFRESH_SIZE          23
118146515Sru
119146515Sru#define bgp_attr_lenlen(flags, p) \
120146515Sru    (((flags) & 0x10) ? 2U : 1U)
121146515Sru#define bgp_attr_len(flags, p) \
122146515Sru    (((flags) & 0x10) ? GET_BE_U_2(p) : GET_U_1(p))
123146515Sru
124146515Sru#define BGPTYPE_ORIGIN                   1
125146515Sru#define BGPTYPE_AS_PATH                  2
126146515Sru#define BGPTYPE_NEXT_HOP                 3
127146515Sru#define BGPTYPE_MULTI_EXIT_DISC          4
128146515Sru#define BGPTYPE_LOCAL_PREF               5
129146515Sru#define BGPTYPE_ATOMIC_AGGREGATE         6
130146515Sru#define BGPTYPE_AGGREGATOR               7
131146515Sru#define BGPTYPE_COMMUNITIES              8    /* RFC1997 */
132146515Sru#define BGPTYPE_ORIGINATOR_ID            9    /* RFC4456 */
133146515Sru#define BGPTYPE_CLUSTER_LIST            10    /* RFC4456 */
134146515Sru#define BGPTYPE_DPA                     11    /* deprecated, draft-ietf-idr-bgp-dpa */
13521495Sjmacd#define BGPTYPE_ADVERTISERS             12    /* deprecated RFC1863 */
13621495Sjmacd#define BGPTYPE_RCID_PATH               13    /* deprecated RFC1863 */
13721495Sjmacd#define BGPTYPE_MP_REACH_NLRI           14    /* RFC4760 */
13821495Sjmacd#define BGPTYPE_MP_UNREACH_NLRI         15    /* RFC4760 */
13921495Sjmacd#define BGPTYPE_EXTD_COMMUNITIES        16    /* RFC4360 */
14021495Sjmacd#define BGPTYPE_AS4_PATH                17    /* RFC6793 */
14121495Sjmacd#define BGPTYPE_AGGREGATOR4             18    /* RFC6793 */
142146515Sru#define BGPTYPE_PMSI_TUNNEL             22    /* RFC6514 */
14321495Sjmacd#define BGPTYPE_TUNNEL_ENCAP            23    /* RFC5512 */
14421495Sjmacd#define BGPTYPE_TRAFFIC_ENG             24    /* RFC5543 */
14521495Sjmacd#define BGPTYPE_IPV6_EXTD_COMMUNITIES   25    /* RFC5701 */
14621495Sjmacd#define BGPTYPE_AIGP                    26    /* RFC7311 */
14721495Sjmacd#define BGPTYPE_PE_DISTINGUISHER_LABEL  27    /* RFC6514 */
14821495Sjmacd#define BGPTYPE_ENTROPY_LABEL           28    /* RFC6790 */
14921495Sjmacd#define BGPTYPE_LARGE_COMMUNITY         32    /* draft-ietf-idr-large-community-05 */
15021495Sjmacd#define BGPTYPE_ATTR_SET               128    /* RFC6368 */
15121495Sjmacd
15221495Sjmacd#define BGP_MP_NLRI_MINSIZE              3    /* End of RIB Marker detection */
15321495Sjmacd
15421495Sjmacdstatic const struct tok bgp_attr_values[] = {
15521495Sjmacd    { BGPTYPE_ORIGIN,           "Origin"},
15621495Sjmacd    { BGPTYPE_AS_PATH,          "AS Path"},
15721495Sjmacd    { BGPTYPE_AS4_PATH,         "AS4 Path"},
15821495Sjmacd    { BGPTYPE_NEXT_HOP,         "Next Hop"},
15921495Sjmacd    { BGPTYPE_MULTI_EXIT_DISC,  "Multi Exit Discriminator"},
16021495Sjmacd    { BGPTYPE_LOCAL_PREF,       "Local Preference"},
16121495Sjmacd    { BGPTYPE_ATOMIC_AGGREGATE, "Atomic Aggregate"},
16221495Sjmacd    { BGPTYPE_AGGREGATOR,       "Aggregator"},
16321495Sjmacd    { BGPTYPE_AGGREGATOR4,      "Aggregator4"},
16442660Smarkm    { BGPTYPE_COMMUNITIES,      "Community"},
16542660Smarkm    { BGPTYPE_ORIGINATOR_ID,    "Originator ID"},
16642660Smarkm    { BGPTYPE_CLUSTER_LIST,     "Cluster List"},
16721495Sjmacd    { BGPTYPE_DPA,              "DPA"},
16821495Sjmacd    { BGPTYPE_ADVERTISERS,      "Advertisers"},
16921495Sjmacd    { BGPTYPE_RCID_PATH,        "RCID Path / Cluster ID"},
17021495Sjmacd    { BGPTYPE_MP_REACH_NLRI,    "Multi-Protocol Reach NLRI"},
17121495Sjmacd    { BGPTYPE_MP_UNREACH_NLRI,  "Multi-Protocol Unreach NLRI"},
172146515Sru    { BGPTYPE_EXTD_COMMUNITIES, "Extended Community"},
17321495Sjmacd    { BGPTYPE_PMSI_TUNNEL,      "PMSI Tunnel"},
17421495Sjmacd    { BGPTYPE_TUNNEL_ENCAP,     "Tunnel Encapsulation"},
175146515Sru    { BGPTYPE_TRAFFIC_ENG,      "Traffic Engineering"},
17621495Sjmacd    { BGPTYPE_IPV6_EXTD_COMMUNITIES, "IPv6 Extended Community"},
17721495Sjmacd    { BGPTYPE_AIGP,             "Accumulated IGP Metric"},
178146515Sru    { BGPTYPE_PE_DISTINGUISHER_LABEL, "PE Distinguisher Label"},
179146515Sru    { BGPTYPE_ENTROPY_LABEL,    "Entropy Label"},
180146515Sru    { BGPTYPE_LARGE_COMMUNITY,  "Large Community"},
181146515Sru    { BGPTYPE_ATTR_SET,         "Attribute Set"},
18221495Sjmacd    { 255,                      "Reserved for development"},
18321495Sjmacd    { 0, NULL}
184146515Sru};
18521495Sjmacd
18621495Sjmacd#define BGP_AS_SET             1
18721495Sjmacd#define BGP_AS_SEQUENCE        2
18821495Sjmacd#define BGP_CONFED_AS_SEQUENCE 3 /* draft-ietf-idr-rfc3065bis-01 */
18921495Sjmacd#define BGP_CONFED_AS_SET      4 /* draft-ietf-idr-rfc3065bis-01  */
19021495Sjmacd
191146515Sru#define BGP_AS_SEG_TYPE_MIN    BGP_AS_SET
192146515Sru#define BGP_AS_SEG_TYPE_MAX    BGP_CONFED_AS_SET
193146515Sru
194146515Srustatic const struct tok bgp_as_path_segment_open_values[] = {
19521495Sjmacd    { BGP_AS_SEQUENCE,         ""},
19621495Sjmacd    { BGP_AS_SET,              "{ "},
19721495Sjmacd    { BGP_CONFED_AS_SEQUENCE,  "( "},
19821495Sjmacd    { BGP_CONFED_AS_SET,       "({ "},
19921495Sjmacd    { 0, NULL}
20021495Sjmacd};
20121495Sjmacd
202146515Srustatic const struct tok bgp_as_path_segment_close_values[] = {
20321495Sjmacd    { BGP_AS_SEQUENCE,         ""},
204146515Sru    { BGP_AS_SET,              "}"},
20521495Sjmacd    { BGP_CONFED_AS_SEQUENCE,  ")"},
20621495Sjmacd    { BGP_CONFED_AS_SET,       "})"},
20721495Sjmacd    { 0, NULL}
20821495Sjmacd};
20921495Sjmacd
21021495Sjmacd#define BGP_OPT_AUTH                    1
211146515Sru#define BGP_OPT_CAP                     2
212146515Sru
213146515Srustatic const struct tok bgp_opt_values[] = {
214146515Sru    { BGP_OPT_AUTH,             "Authentication Information"},
21521495Sjmacd    { BGP_OPT_CAP,              "Capabilities Advertisement"},
216146515Sru    { 0, NULL}
21721495Sjmacd};
21821495Sjmacd
21921495Sjmacd#define BGP_CAPCODE_MP                  1 /* RFC2858 */
22021495Sjmacd#define BGP_CAPCODE_RR                  2 /* RFC2918 */
22121495Sjmacd#define BGP_CAPCODE_ORF                 3 /* RFC5291 */
22221495Sjmacd#define BGP_CAPCODE_MR                  4 /* RFC3107 */
223146515Sru#define BGP_CAPCODE_EXT_NH              5 /* RFC5549 */
22421495Sjmacd#define BGP_CAPCODE_ML                  8 /* RFC8277 */
22521495Sjmacd#define BGP_CAPCODE_RESTART            64 /* RFC4724  */
22621495Sjmacd#define BGP_CAPCODE_AS_NEW             65 /* RFC6793 */
22721495Sjmacd#define BGP_CAPCODE_DYN_CAP            67 /* draft-ietf-idr-dynamic-cap */
22821495Sjmacd#define BGP_CAPCODE_MULTISESS          68 /* draft-ietf-idr-bgp-multisession */
22921495Sjmacd#define BGP_CAPCODE_ADD_PATH           69 /* RFC7911 */
23021495Sjmacd#define BGP_CAPCODE_ENH_RR             70 /* draft-keyur-bgp-enhanced-route-refresh */
23121495Sjmacd#define BGP_CAPCODE_LLGR               71 /* draft-uttaro-idr-bgp-persistence-05 */
232146515Sru#define BGP_CAPCODE_RR_CISCO          128
23321495Sjmacd
23421495Sjmacdstatic const struct tok bgp_capcode_values[] = {
23521495Sjmacd    { BGP_CAPCODE_MP,           "Multiprotocol Extensions"},
23621495Sjmacd    { BGP_CAPCODE_RR,           "Route Refresh"},
23721495Sjmacd    { BGP_CAPCODE_ORF,          "Cooperative Route Filtering"},
23821495Sjmacd    { BGP_CAPCODE_MR,           "Multiple Routes to a Destination"},
23921495Sjmacd    { BGP_CAPCODE_EXT_NH,       "Extended Next Hop Encoding"},
240146515Sru    { BGP_CAPCODE_ML,           "Multiple Labels"},
24121495Sjmacd    { BGP_CAPCODE_RESTART,      "Graceful Restart"},
242146515Sru    { BGP_CAPCODE_AS_NEW,       "32-Bit AS Number"},
24321495Sjmacd    { BGP_CAPCODE_DYN_CAP,      "Dynamic Capability"},
24421495Sjmacd    { BGP_CAPCODE_MULTISESS,    "Multisession BGP"},
24521495Sjmacd    { BGP_CAPCODE_ADD_PATH,     "Multiple Paths"},
24621495Sjmacd    { BGP_CAPCODE_ENH_RR,       "Enhanced Route Refresh"},
24721495Sjmacd    { BGP_CAPCODE_LLGR,         "Long-lived Graceful Restart"},
248146515Sru    { BGP_CAPCODE_RR_CISCO,     "Route Refresh (Cisco)"},
249146515Sru    { 0, NULL}
250146515Sru};
251146515Sru
25221495Sjmacd#define BGP_NOTIFY_MAJOR_MSG            1
25321495Sjmacd#define BGP_NOTIFY_MAJOR_OPEN           2
25421495Sjmacd#define BGP_NOTIFY_MAJOR_UPDATE         3
255146515Sru#define BGP_NOTIFY_MAJOR_HOLDTIME       4
25621495Sjmacd#define BGP_NOTIFY_MAJOR_FSM            5
25721495Sjmacd#define BGP_NOTIFY_MAJOR_CEASE          6
25821495Sjmacd#define BGP_NOTIFY_MAJOR_CAP            7
25921495Sjmacd
26021495Sjmacdstatic const struct tok bgp_notify_major_values[] = {
261146515Sru    { BGP_NOTIFY_MAJOR_MSG,     "Message Header Error"},
262146515Sru    { BGP_NOTIFY_MAJOR_OPEN,    "OPEN Message Error"},
263146515Sru    { BGP_NOTIFY_MAJOR_UPDATE,  "UPDATE Message Error"},
264146515Sru    { BGP_NOTIFY_MAJOR_HOLDTIME,"Hold Timer Expired"},
26521495Sjmacd    { BGP_NOTIFY_MAJOR_FSM,     "Finite State Machine Error"},
26621495Sjmacd    { BGP_NOTIFY_MAJOR_CEASE,   "Cease"},
26721495Sjmacd    { BGP_NOTIFY_MAJOR_CAP,     "Capability Message Error"},
26842660Smarkm    { 0, NULL}
26921495Sjmacd};
27042660Smarkm
27142660Smarkm/* RFC 4486 */
27242660Smarkm#define BGP_NOTIFY_MINOR_CEASE_MAXPRFX  1
27342660Smarkm#define BGP_NOTIFY_MINOR_CEASE_SHUT     2
27442660Smarkm#define BGP_NOTIFY_MINOR_CEASE_RESET    4
27542660Smarkmstatic const struct tok bgp_notify_minor_cease_values[] = {
27621495Sjmacd    { BGP_NOTIFY_MINOR_CEASE_MAXPRFX, "Maximum Number of Prefixes Reached"},
27742660Smarkm    { BGP_NOTIFY_MINOR_CEASE_SHUT,    "Administrative Shutdown"},
27842660Smarkm    { 3,                        "Peer Unconfigured"},
27942660Smarkm    { BGP_NOTIFY_MINOR_CEASE_RESET,   "Administrative Reset"},
28042660Smarkm    { 5,                        "Connection Rejected"},
28142660Smarkm    { 6,                        "Other Configuration Change"},
28242660Smarkm    { 7,                        "Connection Collision Resolution"},
28342660Smarkm    { 0, NULL}
28442660Smarkm};
28521495Sjmacd
28621495Sjmacdstatic const struct tok bgp_notify_minor_msg_values[] = {
28721495Sjmacd    { 1,                        "Connection Not Synchronized"},
28821495Sjmacd    { 2,                        "Bad Message Length"},
28921495Sjmacd    { 3,                        "Bad Message Type"},
29021495Sjmacd    { 0, NULL}
29121495Sjmacd};
29221495Sjmacd
29321495Sjmacdstatic const struct tok bgp_notify_minor_open_values[] = {
29421495Sjmacd    { 1,                        "Unsupported Version Number"},
29521495Sjmacd    { 2,                        "Bad Peer AS"},
29621495Sjmacd    { 3,                        "Bad BGP Identifier"},
29721495Sjmacd    { 4,                        "Unsupported Optional Parameter"},
29821495Sjmacd    { 5,                        "Authentication Failure"},
29942660Smarkm    { 6,                        "Unacceptable Hold Time"},
30021495Sjmacd    { 7,                        "Capability Message Error"},
30142660Smarkm    { 0, NULL}
30242660Smarkm};
30342660Smarkm
30421495Sjmacdstatic const struct tok bgp_notify_minor_update_values[] = {
30542660Smarkm    { 1,                        "Malformed Attribute List"},
30642660Smarkm    { 2,                        "Unrecognized Well-known Attribute"},
30742660Smarkm    { 3,                        "Missing Well-known Attribute"},
30821495Sjmacd    { 4,                        "Attribute Flags Error"},
30942660Smarkm    { 5,                        "Attribute Length Error"},
31021495Sjmacd    { 6,                        "Invalid ORIGIN Attribute"},
31142660Smarkm    { 7,                        "AS Routing Loop"},
31242660Smarkm    { 8,                        "Invalid NEXT_HOP Attribute"},
31342660Smarkm    { 9,                        "Optional Attribute Error"},
31442660Smarkm    { 10,                       "Invalid Network Field"},
31521495Sjmacd    { 11,                       "Malformed AS_PATH"},
31642660Smarkm    { 0, NULL}
31742660Smarkm};
31821495Sjmacd
31942660Smarkmstatic const struct tok bgp_notify_minor_fsm_values[] = {
32042660Smarkm    { 0,                        "Unspecified Error"},
321146515Sru    { 1,                        "In OpenSent State"},
322146515Sru    { 2,                        "In OpenConfirm State"},
32342660Smarkm    { 3,                        "In Established State"},
32421495Sjmacd    { 0, NULL }
32521495Sjmacd};
32642660Smarkm
32721495Sjmacdstatic const struct tok bgp_notify_minor_cap_values[] = {
32821495Sjmacd    { 1,                        "Invalid Action Value" },
32921495Sjmacd    { 2,                        "Invalid Capability Length" },
33021495Sjmacd    { 3,                        "Malformed Capability Value" },
33156160Sru    { 4,                        "Unsupported Capability Code" },
33256160Sru    { 0, NULL }
33321495Sjmacd};
334146515Sru
33521495Sjmacdstatic const struct tok bgp_origin_values[] = {
33621495Sjmacd    { 0,                        "IGP"},
33721495Sjmacd    { 1,                        "EGP"},
33821495Sjmacd    { 2,                        "Incomplete"},
33921495Sjmacd    { 0, NULL}
34021495Sjmacd};
34121495Sjmacd
34242660Smarkm#define BGP_PMSI_TUNNEL_RSVP_P2MP 1
34321495Sjmacd#define BGP_PMSI_TUNNEL_LDP_P2MP  2
34421495Sjmacd#define BGP_PMSI_TUNNEL_PIM_SSM   3
34521495Sjmacd#define BGP_PMSI_TUNNEL_PIM_SM    4
34621495Sjmacd#define BGP_PMSI_TUNNEL_PIM_BIDIR 5
34721495Sjmacd#define BGP_PMSI_TUNNEL_INGRESS   6
34821495Sjmacd#define BGP_PMSI_TUNNEL_LDP_MP2MP 7
34921495Sjmacd
35021495Sjmacdstatic const struct tok bgp_pmsi_tunnel_values[] = {
351146515Sru    { BGP_PMSI_TUNNEL_RSVP_P2MP, "RSVP-TE P2MP LSP"},
35221495Sjmacd    { BGP_PMSI_TUNNEL_LDP_P2MP, "LDP P2MP LSP"},
35321495Sjmacd    { BGP_PMSI_TUNNEL_PIM_SSM, "PIM-SSM Tree"},
35421495Sjmacd    { BGP_PMSI_TUNNEL_PIM_SM, "PIM-SM Tree"},
35521495Sjmacd    { BGP_PMSI_TUNNEL_PIM_BIDIR, "PIM-Bidir Tree"},
35621495Sjmacd    { BGP_PMSI_TUNNEL_INGRESS, "Ingress Replication"},
35721495Sjmacd    { BGP_PMSI_TUNNEL_LDP_MP2MP, "LDP MP2MP LSP"},
35821495Sjmacd    { 0, NULL}
35921495Sjmacd};
36021495Sjmacd
36121495Sjmacdstatic const struct tok bgp_pmsi_flag_values[] = {
36221495Sjmacd    { 0x01, "Leaf Information required"},
36321495Sjmacd    { 0, NULL}
36421495Sjmacd};
36521495Sjmacd
36621495Sjmacd#define BGP_AIGP_TLV 1
36721495Sjmacd
36821495Sjmacdstatic const struct tok bgp_aigp_values[] = {
36921495Sjmacd    { BGP_AIGP_TLV, "AIGP"},
37021495Sjmacd    { 0, NULL}
37121495Sjmacd};
37221495Sjmacd
37321495Sjmacd/* Subsequent address family identifier, RFC2283 section 7 */
37421495Sjmacd#define SAFNUM_RES                      0
37521495Sjmacd#define SAFNUM_UNICAST                  1
37621495Sjmacd#define SAFNUM_MULTICAST                2
37721495Sjmacd#define SAFNUM_UNIMULTICAST             3       /* deprecated now */
37821495Sjmacd/* labeled BGP RFC3107 */
37921495Sjmacd#define SAFNUM_LABUNICAST               4
38021495Sjmacd/* RFC6514 */
38121495Sjmacd#define SAFNUM_MULTICAST_VPN            5
38221495Sjmacd/* draft-nalawade-kapoor-tunnel-safi */
38321495Sjmacd#define SAFNUM_TUNNEL                   64
38421495Sjmacd/* RFC4761 */
385116525Sru#define SAFNUM_VPLS                     65
386116525Sru/* RFC6037 */
387116525Sru#define SAFNUM_MDT                      66
388116525Sru/* RFC7432 */
389116525Sru#define SAFNUM_EVPN                     70
390116525Sru/* RFC4364 */
391146515Sru#define SAFNUM_VPNUNICAST               128
392116525Sru/* RFC6513 */
393116525Sru#define SAFNUM_VPNMULTICAST             129
394116525Sru#define SAFNUM_VPNUNIMULTICAST          130     /* deprecated now */
395116525Sru/* RFC4684 */
396116525Sru#define SAFNUM_RT_ROUTING_INFO          132
397116525Sru
398116525Sru#define BGP_VPN_RD_LEN                  8
399116525Sru
400116525Srustatic const struct tok bgp_safi_values[] = {
401116525Sru    { SAFNUM_RES,               "Reserved"},
402116525Sru    { SAFNUM_UNICAST,           "Unicast"},
403116525Sru    { SAFNUM_MULTICAST,         "Multicast"},
404116525Sru    { SAFNUM_UNIMULTICAST,      "Unicast+Multicast"},
40521495Sjmacd    { SAFNUM_LABUNICAST,        "labeled Unicast"},
40621495Sjmacd    { SAFNUM_TUNNEL,            "Tunnel"},
407146515Sru    { SAFNUM_VPLS,              "VPLS"},
40821495Sjmacd    { SAFNUM_MDT,               "MDT"},
40921495Sjmacd    { SAFNUM_EVPN,              "EVPN"},
41021495Sjmacd    { SAFNUM_VPNUNICAST,        "labeled VPN Unicast"},
41121495Sjmacd    { SAFNUM_VPNMULTICAST,      "labeled VPN Multicast"},
41221495Sjmacd    { SAFNUM_VPNUNIMULTICAST,   "labeled VPN Unicast+Multicast"},
41321495Sjmacd    { SAFNUM_RT_ROUTING_INFO,   "Route Target Routing Information"},
41421495Sjmacd    { SAFNUM_MULTICAST_VPN,     "Multicast VPN"},
41542660Smarkm    { 0, NULL }
41642660Smarkm};
41742660Smarkm
41842660Smarkm/* well-known community */
41921495Sjmacd#define BGP_COMMUNITY_NO_EXPORT              0xffffff01
42042660Smarkm#define BGP_COMMUNITY_NO_ADVERT              0xffffff02
42142660Smarkm#define BGP_COMMUNITY_NO_EXPORT_SUBCONFED    0xffffff03
42221495Sjmacd
42321495Sjmacd/* Extended community type - RFC 4360 */
42421495Sjmacd#define BGP_EXT_COM_RT_0        0x0002  /* Route Target,Format AS(2bytes):AN(4bytes) */
42521495Sjmacd#define BGP_EXT_COM_RT_1        0x0102  /* Route Target,Format IP address:AN(2bytes) */
42621495Sjmacd#define BGP_EXT_COM_RT_2        0x0202  /* Route Target,Format AN(4bytes):local(2bytes) */
42721495Sjmacd#define BGP_EXT_COM_RO_0        0x0003  /* Route Origin,Format AS(2bytes):AN(4bytes) */
42821495Sjmacd#define BGP_EXT_COM_RO_1        0x0103  /* Route Origin,Format IP address:AN(2bytes) */
42921495Sjmacd#define BGP_EXT_COM_RO_2        0x0203  /* Route Origin,Format AN(4bytes):local(2bytes) */
43021495Sjmacd#define BGP_EXT_COM_LINKBAND    0x4004  /* Link Bandwidth,Format AS(2B):Bandwidth(4B) */
431146515Sru                                        /* rfc2547 bgp-mpls-vpns */
43221495Sjmacd#define BGP_EXT_COM_VPN_ORIGIN  0x0005  /* OSPF Domain ID / VPN of Origin  - draft-rosen-vpns-ospf-bgp-mpls */
43321495Sjmacd#define BGP_EXT_COM_VPN_ORIGIN2 0x0105  /* duplicate - keep for backwards compatibility */
434146515Sru#define BGP_EXT_COM_VPN_ORIGIN3 0x0205  /* duplicate - keep for backwards compatibility */
43521495Sjmacd#define BGP_EXT_COM_VPN_ORIGIN4 0x8005  /* duplicate - keep for backwards compatibility */
43621495Sjmacd
43721495Sjmacd#define BGP_EXT_COM_OSPF_RTYPE  0x0306  /* OSPF Route Type,Format Area(4B):RouteType(1B):Options(1B) */
43821495Sjmacd#define BGP_EXT_COM_OSPF_RTYPE2 0x8000  /* duplicate - keep for backwards compatibility */
43921495Sjmacd#define BGP_EXT_COM_ENCAP       0x030c  /* rfc5512 */
44021495Sjmacd
44121495Sjmacd#define BGP_EXT_COM_OSPF_RID    0x0107  /* OSPF Router ID,Format RouterID(4B):Unused(2B) */
44221495Sjmacd#define BGP_EXT_COM_OSPF_RID2   0x8001  /* duplicate - keep for backwards compatibility */
44321495Sjmacd
44421495Sjmacd#define BGP_EXT_COM_L2INFO      0x800a  /* draft-kompella-ppvpn-l2vpn */
44521495Sjmacd
44621495Sjmacd#define BGP_EXT_COM_SOURCE_AS   0x0009  /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */
44721495Sjmacd#define BGP_EXT_COM_VRF_RT_IMP  0x010b  /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */
44821495Sjmacd#define BGP_EXT_COM_L2VPN_RT_0  0x000a  /* L2VPN Identifier,Format AS(2bytes):AN(4bytes) */
44921495Sjmacd#define BGP_EXT_COM_L2VPN_RT_1  0xF10a  /* L2VPN Identifier,Format IP address:AN(2bytes) */
45042660Smarkm
45142660Smarkm/* https://www.cisco.com/en/US/tech/tk436/tk428/technologies_tech_note09186a00801eb09a.shtml  */
45242660Smarkm#define BGP_EXT_COM_EIGRP_GEN                    0x8800
45342660Smarkm#define BGP_EXT_COM_EIGRP_METRIC_AS_DELAY        0x8801
45442660Smarkm#define BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW       0x8802
45521495Sjmacd#define BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU        0x8803
45642660Smarkm#define BGP_EXT_COM_EIGRP_EXT_REMAS_REMID        0x8804
45742660Smarkm#define BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC 0x8805
45842660Smarkm
45942660Smarkmstatic const struct tok bgp_extd_comm_flag_values[] = {
46021495Sjmacd    { 0x8000,                  "vendor-specific"},
46142660Smarkm    { 0x4000,                  "non-transitive"},
46242660Smarkm    { 0, NULL},
46342660Smarkm};
46442660Smarkm
46521495Sjmacdstatic const struct tok bgp_extd_comm_subtype_values[] = {
46642660Smarkm    { BGP_EXT_COM_RT_0,        "target"},
46742660Smarkm    { BGP_EXT_COM_RT_1,        "target"},
46821495Sjmacd    { BGP_EXT_COM_RT_2,        "target"},
46921495Sjmacd    { BGP_EXT_COM_RO_0,        "origin"},
47021495Sjmacd    { BGP_EXT_COM_RO_1,        "origin"},
47121495Sjmacd    { BGP_EXT_COM_RO_2,        "origin"},
47221495Sjmacd    { BGP_EXT_COM_LINKBAND,    "link-BW"},
47321495Sjmacd    { BGP_EXT_COM_VPN_ORIGIN,  "ospf-domain"},
47421495Sjmacd    { BGP_EXT_COM_VPN_ORIGIN2, "ospf-domain"},
47521495Sjmacd    { BGP_EXT_COM_VPN_ORIGIN3, "ospf-domain"},
47621495Sjmacd    { BGP_EXT_COM_VPN_ORIGIN4, "ospf-domain"},
47721495Sjmacd    { BGP_EXT_COM_OSPF_RTYPE,  "ospf-route-type"},
47821495Sjmacd    { BGP_EXT_COM_OSPF_RTYPE2, "ospf-route-type"},
47921495Sjmacd    { BGP_EXT_COM_ENCAP,       "encapsulation"},
48021495Sjmacd    { BGP_EXT_COM_OSPF_RID,    "ospf-router-id"},
48121495Sjmacd    { BGP_EXT_COM_OSPF_RID2,   "ospf-router-id"},
48221495Sjmacd    { BGP_EXT_COM_L2INFO,      "layer2-info"},
48321495Sjmacd    { BGP_EXT_COM_EIGRP_GEN,   "eigrp-general-route (flag, tag)" },
48421495Sjmacd    { BGP_EXT_COM_EIGRP_METRIC_AS_DELAY, "eigrp-route-metric (AS, delay)" },
485146515Sru    { BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW, "eigrp-route-metric (reliability, nexthop, bandwidth)" },
48621495Sjmacd    { BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU, "eigrp-route-metric (load, MTU)" },
48721495Sjmacd    { BGP_EXT_COM_EIGRP_EXT_REMAS_REMID, "eigrp-external-route (remote-AS, remote-ID)" },
48856160Sru    { BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC, "eigrp-external-route (remote-proto, remote-metric)" },
489100513Sru    { BGP_EXT_COM_SOURCE_AS, "source-AS" },
490100513Sru    { BGP_EXT_COM_VRF_RT_IMP, "vrf-route-import"},
491100513Sru    { BGP_EXT_COM_L2VPN_RT_0, "l2vpn-id"},
49256160Sru    { BGP_EXT_COM_L2VPN_RT_1, "l2vpn-id"},
493100513Sru    { 0, NULL},
49421495Sjmacd};
49521495Sjmacd
49642660Smarkm/* RFC RFC5512 BGP Tunnel Encapsulation Attribute Tunnel Types */
49742660Smarkm#define BGP_ENCAP_TUNNEL_L2TPV3_IP  1
49842660Smarkm#define BGP_ENCAP_TUNNEL_GRE        2
49942660Smarkm#define BGP_ENCAP_TUNNEL_TRANSMIT   3
50042660Smarkm#define BGP_ENCAP_TUNNEL_IPSEC      4
50121495Sjmacd#define BGP_ENCAP_TUNNEL_IP_IPSEC   5
50242660Smarkm#define BGP_ENCAP_TUNNEL_MPLS_IP    6
50342660Smarkm#define BGP_ENCAP_TUNNEL_IP_IP      7
50442660Smarkm#define BGP_ENCAP_TUNNEL_VXLAN      8
50521495Sjmacd#define BGP_ENCAP_TUNNEL_NVGRE      9
50642660Smarkm#define BGP_ENCAP_TUNNEL_MPLS       10
50742660Smarkm#define BGP_ENCAP_TUNNEL_MPLS_GRE   11
50842660Smarkm#define BGP_ENCAP_TUNNEL_VXLAN_GPE  12
50942660Smarkm#define BGP_ENCAP_TUNNEL_MPLS_UDP   13
51042660Smarkm#define BGP_ENCAP_TUNNEL_IPV6       14
51121495Sjmacd#define BGP_ENCAP_TUNNEL_SR_TE      15
51242660Smarkm#define BGP_ENCAP_TUNNEL_BARE       16
51342660Smarkm#define BGP_ENCAP_TUNNEL_SR         17
51442660Smarkm
51542660Smarkmstatic const struct tok bgp_extd_comm_encap_tunnel_values[] = {
51621495Sjmacd    { BGP_ENCAP_TUNNEL_L2TPV3_IP,    "L2TPv3 over IP"},
51756160Sru    { BGP_ENCAP_TUNNEL_GRE,          "GRE"},
51821495Sjmacd    { BGP_ENCAP_TUNNEL_TRANSMIT,     "Transmit Tunnel"},
51921495Sjmacd    { BGP_ENCAP_TUNNEL_IPSEC,        "IPsec"},
52021495Sjmacd    { BGP_ENCAP_TUNNEL_IP_IPSEC,     "IP in IP with IPsec"},
52121495Sjmacd    { BGP_ENCAP_TUNNEL_MPLS_IP,      "MPLS in IP with IPsec"},
52221495Sjmacd    { BGP_ENCAP_TUNNEL_IP_IP,        "IP in IP"},
52356160Sru    { BGP_ENCAP_TUNNEL_VXLAN,        "VXLAN"},
52456160Sru    { BGP_ENCAP_TUNNEL_NVGRE,        "NVGRE"},
52556160Sru    { BGP_ENCAP_TUNNEL_MPLS,         "MPLS"},
52656160Sru    { BGP_ENCAP_TUNNEL_MPLS_GRE,     "MPLS in GRE"},
52756160Sru    { BGP_ENCAP_TUNNEL_VXLAN_GPE,    "VXLAN GPE"},
52821495Sjmacd    { BGP_ENCAP_TUNNEL_MPLS_UDP,     "MPLS in UDP"},
52921495Sjmacd    { BGP_ENCAP_TUNNEL_IPV6,         "IPv6"},
53021495Sjmacd    { BGP_ENCAP_TUNNEL_SR_TE,        "SR TE"},
53156160Sru    { BGP_ENCAP_TUNNEL_BARE,         "Bare"},
53221495Sjmacd    { BGP_ENCAP_TUNNEL_SR,           "SR"},
53356160Sru    { 0, NULL},
53421495Sjmacd};
53521495Sjmacd
53621495Sjmacd/* OSPF codes for  BGP_EXT_COM_OSPF_RTYPE draft-rosen-vpns-ospf-bgp-mpls  */
53721495Sjmacd#define BGP_OSPF_RTYPE_RTR      1 /* OSPF Router LSA */
53842660Smarkm#define BGP_OSPF_RTYPE_NET      2 /* OSPF Network LSA */
53942660Smarkm#define BGP_OSPF_RTYPE_SUM      3 /* OSPF Summary LSA */
54042660Smarkm#define BGP_OSPF_RTYPE_EXT      5 /* OSPF External LSA, note that ASBR doesn't apply to MPLS-VPN */
54121495Sjmacd#define BGP_OSPF_RTYPE_NSSA     7 /* OSPF NSSA External*/
54221495Sjmacd#define BGP_OSPF_RTYPE_SHAM     129 /* OSPF-MPLS-VPN Sham link */
54321495Sjmacd#define BGP_OSPF_RTYPE_METRIC_TYPE 0x1 /* LSB of RTYPE Options Field */
54421495Sjmacd
54521495Sjmacdstatic const struct tok bgp_extd_comm_ospf_rtype_values[] = {
54621495Sjmacd  { BGP_OSPF_RTYPE_RTR, "Router" },
54721495Sjmacd  { BGP_OSPF_RTYPE_NET, "Network" },
54821495Sjmacd  { BGP_OSPF_RTYPE_SUM, "Summary" },
549146515Sru  { BGP_OSPF_RTYPE_EXT, "External" },
550146515Sru  { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
551146515Sru  { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },
55221495Sjmacd  { 0, NULL },
55321495Sjmacd};
55421495Sjmacd
55521495Sjmacd/* ADD-PATH Send/Receive field values */
556146515Srustatic const struct tok bgp_add_path_recvsend[] = {
55721495Sjmacd    { 1, "Receive" },
55821495Sjmacd    { 2, "Send" },
55921495Sjmacd    { 3, "Both" },
56021495Sjmacd    { 0, NULL },
56121495Sjmacd};
56221495Sjmacd
563146515Sru#define AS_STR_SIZE sizeof("xxxxx.xxxxx")
56421495Sjmacd
56521495Sjmacd/*
56642660Smarkm * as_printf
56721495Sjmacd *
56821495Sjmacd * Convert an AS number into a string and return string pointer.
56921495Sjmacd *
57021495Sjmacd * Depending on bflag is set or not, AS number is converted into ASDOT notation
57121495Sjmacd * or plain number notation.
572146515Sru *
57321495Sjmacd */
57421495Sjmacdstatic char *
57521495Sjmacdas_printf(netdissect_options *ndo,
57621495Sjmacd          char *str, size_t size, u_int asnum)
57721495Sjmacd{
57821495Sjmacd    if (!ndo->ndo_bflag || asnum <= 0xFFFF) {
579146515Sru        snprintf(str, size, "%u", asnum);
58021495Sjmacd    } else {
58121495Sjmacd        snprintf(str, size, "%u.%u", asnum >> 16, asnum & 0xFFFF);
58242660Smarkm    }
58321495Sjmacd    return str;
58421495Sjmacd}
58521495Sjmacd
58621495Sjmacd#define ITEMCHECK(minlen) if (itemlen < minlen) goto badtlv;
58721495Sjmacd
58821495Sjmacdint
589146515Srudecode_prefix4(netdissect_options *ndo,
59021495Sjmacd               const u_char *pptr, u_int itemlen, char *buf, size_t buflen)
59121495Sjmacd{
59221495Sjmacd    nd_ipv4 addr;
59321495Sjmacd    u_int plen, plenbytes;
59442660Smarkm
59521495Sjmacd    ITEMCHECK(1);
59621495Sjmacd    plen = GET_U_1(pptr);
59721495Sjmacd    if (32 < plen)
59821495Sjmacd        return -1;
59921495Sjmacd    itemlen -= 1;
60021495Sjmacd
601146515Sru    memset(&addr, 0, sizeof(addr));
60242660Smarkm    plenbytes = (plen + 7) / 8;
60342660Smarkm    ITEMCHECK(plenbytes);
60421495Sjmacd    GET_CPY_BYTES(&addr, pptr + 1, plenbytes);
60521495Sjmacd    if (plen % 8) {
60621495Sjmacd        ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
60721495Sjmacd    }
60821495Sjmacd    snprintf(buf, buflen, "%s/%u", ipaddr_string(ndo, (const u_char *)&addr), plen);
60921495Sjmacd    return 1 + plenbytes;
61021495Sjmacd
611146515Srubadtlv:
61221495Sjmacd    return -2;
61321495Sjmacd}
61421495Sjmacd
61521495Sjmacdstatic int
61642660Smarkmdecode_labeled_prefix4(netdissect_options *ndo,
61721495Sjmacd                       const u_char *pptr, u_int itemlen, char *buf,
61821495Sjmacd                       size_t buflen)
61921495Sjmacd{
62021495Sjmacd    nd_ipv4 addr;
62121495Sjmacd    u_int plen, plenbytes;
62221495Sjmacd
62321495Sjmacd    /* prefix length and label = 4 bytes */
62442660Smarkm    ND_TCHECK_4(pptr);
62521495Sjmacd    ITEMCHECK(4);
62621495Sjmacd    plen = GET_U_1(pptr);   /* get prefix length */
62721495Sjmacd
62821495Sjmacd    /* this is one of the weirdnesses of rfc3107
62921495Sjmacd       the label length (actually the label + COS bits)
63021495Sjmacd       is added to the prefix length;
63121495Sjmacd       we also do only read out just one label -
63221495Sjmacd       there is no real application for advertisement of
633146515Sru       stacked labels in a single BGP message
63421495Sjmacd    */
63556160Sru
63621495Sjmacd    if (24 > plen)
63756160Sru        return -1;
63856160Sru
63921495Sjmacd    plen-=24; /* adjust prefixlen - labellength */
64056160Sru
64156160Sru    if (32 < plen)
64221495Sjmacd        return -1;
64321495Sjmacd    itemlen -= 4;
64421495Sjmacd
64521495Sjmacd    memset(&addr, 0, sizeof(addr));
64621495Sjmacd    plenbytes = (plen + 7) / 8;
64721495Sjmacd    ITEMCHECK(plenbytes);
648146515Sru    GET_CPY_BYTES(&addr, pptr + 4, plenbytes);
64921495Sjmacd    if (plen % 8) {
65021495Sjmacd        ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
65121495Sjmacd    }
65221495Sjmacd    /* the label may get offsetted by 4 bits so lets shift it right */
65321495Sjmacd    snprintf(buf, buflen, "%s/%u, label:%u %s",
65421495Sjmacd             ipaddr_string(ndo, (const u_char *)&addr),
65521495Sjmacd             plen,
65621495Sjmacd             GET_BE_U_3(pptr + 1)>>4,
65721495Sjmacd             ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
65821495Sjmacd
65921495Sjmacd    return 4 + plenbytes;
66021495Sjmacd
66121495Sjmacdtrunc:
66221495Sjmacd    return -2;
66321495Sjmacd
664146515Srubadtlv:
66521495Sjmacd    return -3;
66621495Sjmacd}
66721495Sjmacd
66821495Sjmacd/*
66921495Sjmacd * bgp_vpn_ip_print
67021495Sjmacd *
67121495Sjmacd * print an ipv4 or ipv6 address into a buffer dependent on address length.
67221495Sjmacd */
67321495Sjmacdstatic char *
67421495Sjmacdbgp_vpn_ip_print(netdissect_options *ndo,
67521495Sjmacd                 const u_char *pptr, u_int addr_length)
67621495Sjmacd{
67721495Sjmacd
678146515Sru    /* worst case string is s fully formatted v6 address */
67921495Sjmacd    static char addr[sizeof("1234:5678:89ab:cdef:1234:5678:89ab:cdef")];
68021495Sjmacd    char *pos = addr;
68121495Sjmacd
68221495Sjmacd    switch(addr_length) {
68321495Sjmacd    case (sizeof(nd_ipv4) << 3): /* 32 */
68442660Smarkm        snprintf(pos, sizeof(addr), "%s", GET_IPADDR_STRING(pptr));
68521495Sjmacd        break;
68621495Sjmacd    case (sizeof(nd_ipv6) << 3): /* 128 */
68721495Sjmacd        snprintf(pos, sizeof(addr), "%s", GET_IP6ADDR_STRING(pptr));
68821495Sjmacd        break;
68956160Sru    default:
69056160Sru        snprintf(pos, sizeof(addr), "bogus address length %u", addr_length);
69156160Sru        break;
692146515Sru    }
69356160Sru    pos += strlen(pos);
69456160Sru
69556160Sru    *(pos) = '\0';
69656160Sru    return (addr);
69756160Sru}
69856160Sru
69956160Sru/*
70056160Sru * bgp_vpn_sg_print
70156160Sru *
702 * print an multicast s,g entry into a buffer.
703 * the s,g entry is encoded like this.
704 *
705 * +-----------------------------------+
706 * | Multicast Source Length (1 octet) |
707 * +-----------------------------------+
708 * |   Multicast Source (Variable)     |
709 * +-----------------------------------+
710 * |  Multicast Group Length (1 octet) |
711 * +-----------------------------------+
712 * |  Multicast Group   (Variable)     |
713 * +-----------------------------------+
714 *
715 * return the number of bytes read from the wire.
716 */
717static u_int
718bgp_vpn_sg_print(netdissect_options *ndo,
719                 const u_char *pptr, char *buf, size_t buflen)
720{
721    uint8_t addr_length;
722    u_int total_length, offset;
723
724    total_length = 0;
725
726    /* Source address length, encoded in bits */
727    addr_length = GET_U_1(pptr);
728    pptr++;
729
730    /* Source address */
731    ND_TCHECK_LEN(pptr, (addr_length >> 3));
732    total_length += (addr_length >> 3) + 1;
733    offset = (u_int)strlen(buf);
734    if (addr_length) {
735        snprintf(buf + offset, buflen - offset, ", Source %s",
736             bgp_vpn_ip_print(ndo, pptr, addr_length));
737        pptr += (addr_length >> 3);
738    }
739
740    /* Group address length, encoded in bits */
741    addr_length = GET_U_1(pptr);
742    pptr++;
743
744    /* Group address */
745    ND_TCHECK_LEN(pptr, (addr_length >> 3));
746    total_length += (addr_length >> 3) + 1;
747    offset = (u_int)strlen(buf);
748    if (addr_length) {
749        snprintf(buf + offset, buflen - offset, ", Group %s",
750             bgp_vpn_ip_print(ndo, pptr, addr_length));
751        pptr += (addr_length >> 3);
752    }
753
754trunc:
755    return (total_length);
756}
757
758/* Print an RFC 4364 Route Distinguisher */
759const char *
760bgp_vpn_rd_print(netdissect_options *ndo,
761                 const u_char *pptr)
762{
763    /* allocate space for the largest possible string */
764    static char rd[sizeof("xxxxx.xxxxx:xxxxx (xxx.xxx.xxx.xxx:xxxxx)")];
765    char *pos = rd;
766    /* allocate space for the largest possible string */
767    char astostr[AS_STR_SIZE];
768
769    /* ok lets load the RD format */
770    switch (GET_BE_U_2(pptr)) {
771
772    case 0:
773        /* 2-byte-AS:number fmt */
774        snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (= %u.%u.%u.%u)",
775                    GET_BE_U_2(pptr + 2),
776                    GET_BE_U_4(pptr + 4),
777                    GET_U_1(pptr + 4), GET_U_1(pptr + 5),
778                    GET_U_1(pptr + 6), GET_U_1(pptr + 7));
779        break;
780
781    case 1:
782        /* IP-address:AS fmt */
783        snprintf(pos, sizeof(rd) - (pos - rd), "%u.%u.%u.%u:%u",
784                    GET_U_1(pptr + 2), GET_U_1(pptr + 3),
785                    GET_U_1(pptr + 4), GET_U_1(pptr + 5),
786                    GET_BE_U_2(pptr + 6));
787        break;
788
789    case 2:
790        /* 4-byte-AS:number fmt */
791        snprintf(pos, sizeof(rd) - (pos - rd), "%s:%u (%u.%u.%u.%u:%u)",
792                    as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 2)),
793                    GET_BE_U_2(pptr + 6), GET_U_1(pptr + 2),
794                    GET_U_1(pptr + 3), GET_U_1(pptr + 4),
795                    GET_U_1(pptr + 5), GET_BE_U_2(pptr + 6));
796        break;
797    default:
798        snprintf(pos, sizeof(rd) - (pos - rd), "unknown RD format");
799        break;
800    }
801    pos += strlen(pos);
802    *(pos) = '\0';
803    return (rd);
804}
805
806/*
807 * Print an RFC 4360 Extended Community.
808 */
809static void
810bgp_extended_community_print(netdissect_options *ndo,
811                             const u_char *pptr)
812{
813    union { /* copy buffer for bandwidth values */
814        float f;
815        uint32_t i;
816    } bw;
817    /* allocate space for the largest possible string */
818    char astostr[AS_STR_SIZE];
819
820    switch (GET_BE_U_2(pptr)) {
821
822    case BGP_EXT_COM_RT_0:
823    case BGP_EXT_COM_RO_0:
824    case BGP_EXT_COM_L2VPN_RT_0:
825        ND_PRINT("%u:%u (= %s)",
826                 GET_BE_U_2(pptr + 2),
827                 GET_BE_U_4(pptr + 4),
828                 GET_IPADDR_STRING(pptr+4));
829        break;
830
831    case BGP_EXT_COM_RT_1:
832    case BGP_EXT_COM_RO_1:
833    case BGP_EXT_COM_L2VPN_RT_1:
834    case BGP_EXT_COM_VRF_RT_IMP:
835        ND_PRINT("%s:%u",
836                 GET_IPADDR_STRING(pptr+2),
837                 GET_BE_U_2(pptr + 6));
838        break;
839
840    case BGP_EXT_COM_RT_2:
841        case BGP_EXT_COM_RO_2:
842            ND_PRINT("%s:%u",
843                     as_printf(ndo, astostr, sizeof(astostr),
844                     GET_BE_U_4(pptr + 2)), GET_BE_U_2(pptr + 6));
845            break;
846
847    case BGP_EXT_COM_LINKBAND:
848            bw.i = GET_BE_U_4(pptr + 4);
849            ND_PRINT("bandwidth: %.3f Mbps",
850                     bw.f*8/1000000);
851            break;
852
853    case BGP_EXT_COM_VPN_ORIGIN:
854    case BGP_EXT_COM_VPN_ORIGIN2:
855    case BGP_EXT_COM_VPN_ORIGIN3:
856    case BGP_EXT_COM_VPN_ORIGIN4:
857    case BGP_EXT_COM_OSPF_RID:
858    case BGP_EXT_COM_OSPF_RID2:
859        ND_PRINT("%s", GET_IPADDR_STRING(pptr+2));
860        break;
861
862    case BGP_EXT_COM_OSPF_RTYPE:
863    case BGP_EXT_COM_OSPF_RTYPE2:
864        ND_PRINT("area:%s, router-type:%s, metric-type:%s%s",
865                 GET_IPADDR_STRING(pptr+2),
866                 tok2str(bgp_extd_comm_ospf_rtype_values,
867                         "unknown (0x%02x)",
868                         GET_U_1((pptr + 6))),
869                 (GET_U_1(pptr + 7) &  BGP_OSPF_RTYPE_METRIC_TYPE) ? "E2" : "",
870                 ((GET_U_1(pptr + 6) == BGP_OSPF_RTYPE_EXT) || (GET_U_1(pptr + 6) == BGP_OSPF_RTYPE_NSSA)) ? "E1" : "");
871        break;
872
873    case BGP_EXT_COM_L2INFO:
874        ND_PRINT("%s Control Flags [0x%02x]:MTU %u",
875                 tok2str(l2vpn_encaps_values,
876                         "unknown encaps",
877                         GET_U_1((pptr + 2))),
878                 GET_U_1((pptr + 3)),
879                 GET_BE_U_2(pptr + 4));
880        break;
881
882    case BGP_EXT_COM_SOURCE_AS:
883        ND_PRINT("AS %u", GET_BE_U_2(pptr + 2));
884        break;
885
886    case BGP_EXT_COM_ENCAP:
887        ND_PRINT("Tunnel type: %s", tok2str(bgp_extd_comm_encap_tunnel_values,
888                                           "unknown encaps",
889                                           GET_BE_U_2(pptr + 6)));
890        break;
891
892    default:
893        ND_PRINT("%02x%02x%02x%02x%02x%02x",
894                 GET_U_1(pptr + 2),
895                 GET_U_1(pptr + 3),
896                 GET_U_1(pptr + 4),
897                 GET_U_1(pptr + 5),
898                 GET_U_1(pptr + 6),
899                 GET_U_1(pptr + 7));
900        break;
901    }
902}
903
904/*
905 * RFC4684 (Section 4)/RFC2858 (Section 4).
906 * RTC membership prefix is structured as follows
907 * [prefix-len] [origin-as] [route-target]
908 * The route-target is encoded as RT ext-comms.
909 * Prefix-len may be 0, 32..96
910 *
911 * Note that pptr is not packet data - it is
912 * a buffer owned by our caller - therefore GET_*
913 * macros can not be used.
914 */
915static char *
916bgp_rt_prefix_print(netdissect_options *ndo,
917                    const u_char *pptr,
918                    u_int plen)
919{
920    /* allocate space for the largest possible string */
921    char rtc_prefix_in_hex[sizeof("0000 0000 0000 0000")] = "";
922    u_int rtc_prefix_in_hex_len = 0;
923    static char output[61]; /* max response string */
924    /* allocate space for the largest possible string */
925    char astostr[AS_STR_SIZE];
926    uint16_t ec_type = 0;
927    u_int octet_count;
928    u_int i;
929
930    if (plen == 0) {
931        snprintf(output, sizeof(output), "route-target: 0:0/0");
932        return (output);
933    }
934
935    /* hex representation of the prefix */
936    octet_count = (plen+7)/8;
937    for (i=0; i<octet_count; i++) {
938        rtc_prefix_in_hex_len += snprintf(rtc_prefix_in_hex+rtc_prefix_in_hex_len,
939                                sizeof(rtc_prefix_in_hex)-rtc_prefix_in_hex_len,
940                                "%02x%s", *(pptr+i),
941                                ((i%2 == 1) && (i<octet_count-1)) ? " " : "");
942            }
943
944    if (plen < 16) {
945	/*
946	 * The prefix is too short to include the full ext-comm type,
947	 * so we have no way to parse it further.
948	 */
949        snprintf(output, sizeof(output), "route-target: partial-type: (%s/%d)",
950                 rtc_prefix_in_hex, plen);
951        return (output);
952    }
953
954    /*
955     * get the ext-comm type
956     * Note: pptr references a static 8 octet buffer with unused bits set to 0,
957     * hence EXTRACT_*() macros are safe.
958     */
959    ec_type = EXTRACT_BE_U_2(pptr);
960    switch (ec_type) {
961    case BGP_EXT_COM_RT_0:
962        /* 2-byte-AS:number fmt */
963        snprintf(output, sizeof(output), "route-target: %u:%u/%d (%s)",
964                 EXTRACT_BE_U_2(pptr+2),
965                 EXTRACT_BE_U_4(pptr+4),
966                 plen, rtc_prefix_in_hex);
967        break;
968
969    case BGP_EXT_COM_RT_1:
970        /* IP-address:AS fmt */
971        snprintf(output, sizeof(output), "route-target: %u.%u.%u.%u:%u/%d (%s)",
972                 *(pptr+2), *(pptr+3), *(pptr+4), *(pptr+5),
973                 EXTRACT_BE_U_2(pptr+6), plen, rtc_prefix_in_hex);
974        break;
975
976    case BGP_EXT_COM_RT_2:
977        /* 4-byte-AS:number fmt */
978        snprintf(output, sizeof(output), "route-target: %s:%u/%d (%s)",
979                 as_printf(ndo, astostr, sizeof(astostr), EXTRACT_BE_U_4(pptr+2)),
980                 EXTRACT_BE_U_2(pptr+6), plen, rtc_prefix_in_hex);
981        break;
982
983    default:
984        snprintf(output, sizeof(output), "route target: unknown-type(%04x) (%s/%d)",
985                 ec_type,
986                 rtc_prefix_in_hex, plen);
987        break;
988    }
989    return (output);
990}
991
992/* RFC 4684 */
993static int
994decode_rt_routing_info(netdissect_options *ndo,
995                       const u_char *pptr)
996{
997    uint8_t route_target[8];
998    u_int plen;
999    /* allocate space for the largest possible string */
1000    char astostr[AS_STR_SIZE];
1001    u_int num_octets;
1002
1003    /* NLRI "prefix length" from RFC 2858 Section 4. */
1004    plen = GET_U_1(pptr);   /* get prefix length */
1005
1006    /* NLRI "prefix" (ibid), valid lengths are { 0, 32, 33, ..., 96 } bits.
1007     * RFC 4684 Section 4 defines the layout of "origin AS" and "route
1008     * target" fields inside the "prefix" depending on its length.
1009     */
1010    if (0 == plen) {
1011        /* Without "origin AS", without "route target". */
1012        ND_PRINT("\n\t      default route target");
1013        return 1;
1014    }
1015
1016    if (32 > plen) {
1017        ND_PRINT("\n\t      (illegal prefix length)");
1018        return -1;
1019    }
1020
1021    /* With at least "origin AS", possibly with "route target". */
1022    as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 1));
1023
1024    plen -= 32; /* adjust prefix length */
1025
1026    if (64 < plen) {
1027        ND_PRINT("\n\t      (illegal prefix length)");
1028        return -1;
1029    }
1030
1031    /* From now on (plen + 7) / 8 evaluates to { 0, 1, 2, ..., 8 }
1032     * and gives the number of octets in the variable-length "route
1033     * target" field inside this NLRI "prefix". Look for it.
1034     */
1035    memset(&route_target, 0, sizeof(route_target));
1036    num_octets = (plen + 7) / 8;
1037    GET_CPY_BYTES(&route_target, pptr + 5, num_octets);
1038    /* If mask-len is not on octet boundary, ensure all extra bits are 0 */
1039    if (plen % 8) {
1040        ((u_char *)&route_target)[num_octets - 1] &=
1041            ((0xff00 >> (plen % 8)) & 0xff);
1042    }
1043    ND_PRINT("\n\t      origin AS: %s, %s",
1044             astostr,
1045             bgp_rt_prefix_print(ndo, (u_char *)&route_target, plen));
1046
1047    return 5 + num_octets;
1048}
1049
1050static int
1051decode_labeled_vpn_prefix4(netdissect_options *ndo,
1052                           const u_char *pptr, char *buf, size_t buflen)
1053{
1054    nd_ipv4 addr;
1055    u_int plen;
1056
1057    plen = GET_U_1(pptr);   /* get prefix length */
1058
1059    if ((24+64) > plen)
1060        return -1;
1061
1062    plen -= (24+64); /* adjust prefixlen - labellength - RD len*/
1063
1064    if (32 < plen)
1065        return -1;
1066
1067    memset(&addr, 0, sizeof(addr));
1068    GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
1069    if (plen % 8) {
1070        ((u_char *)&addr)[(plen + 7) / 8 - 1] &=
1071            ((0xff00 >> (plen % 8)) & 0xff);
1072    }
1073    /* the label may get offsetted by 4 bits so lets shift it right */
1074    snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s",
1075                bgp_vpn_rd_print(ndo, pptr+4),
1076                ipaddr_string(ndo, (const u_char *)&addr),
1077                plen,
1078                GET_BE_U_3(pptr + 1)>>4,
1079                ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
1080
1081    return 12 + (plen + 7) / 8;
1082}
1083
1084/*
1085 * +-------------------------------+
1086 * |                               |
1087 * |  RD:IPv4-address (12 octets)  |
1088 * |                               |
1089 * +-------------------------------+
1090 * |  MDT Group-address (4 octets) |
1091 * +-------------------------------+
1092 */
1093
1094#define MDT_VPN_NLRI_LEN 16
1095
1096static int
1097decode_mdt_vpn_nlri(netdissect_options *ndo,
1098                    const u_char *pptr, char *buf, size_t buflen)
1099{
1100    const u_char *rd;
1101    const u_char *vpn_ip;
1102
1103    /* if the NLRI is not predefined length, quit.*/
1104    if (GET_U_1(pptr) != MDT_VPN_NLRI_LEN * 8)
1105        return -1;
1106    pptr++;
1107
1108    /* RD */
1109    ND_TCHECK_8(pptr);
1110    rd = pptr;
1111    pptr += 8;
1112
1113    /* IPv4 address */
1114    vpn_ip = pptr;
1115    pptr += sizeof(nd_ipv4);
1116
1117    /* MDT Group Address */
1118    snprintf(buf, buflen, "RD: %s, VPN IP Address: %s, MC Group Address: %s",
1119                bgp_vpn_rd_print(ndo, rd), GET_IPADDR_STRING(vpn_ip), GET_IPADDR_STRING(pptr));
1120
1121    return MDT_VPN_NLRI_LEN + 1;
1122
1123 trunc:
1124    return -2;
1125}
1126
1127#define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI   1
1128#define BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI   2
1129#define BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI            3
1130#define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF 4
1131#define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE     5
1132#define BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN  6
1133#define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN  7
1134
1135static const struct tok bgp_multicast_vpn_route_type_values[] = {
1136    { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI, "Intra-AS I-PMSI"},
1137    { BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI, "Inter-AS I-PMSI"},
1138    { BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI, "S-PMSI"},
1139    { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF, "Intra-AS Segment-Leaf"},
1140    { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE, "Source-Active"},
1141    { BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN, "Shared Tree Join"},
1142    { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN, "Source Tree Join"},
1143    { 0, NULL}
1144};
1145
1146UNALIGNED_OK
1147static int
1148decode_multicast_vpn(netdissect_options *ndo,
1149                     const u_char *pptr, char *buf, size_t buflen)
1150{
1151    /* allocate space for the largest possible string */
1152    char astostr[AS_STR_SIZE];
1153    uint8_t route_type, route_length;
1154    u_int addr_length, sg_length;
1155    u_int offset;
1156
1157    route_type = GET_U_1(pptr);
1158    pptr++;
1159    route_length = GET_U_1(pptr);
1160    pptr++;
1161
1162    snprintf(buf, buflen, "Route-Type: %s (%u), length: %u",
1163         tok2str(bgp_multicast_vpn_route_type_values,
1164                 "Unknown", route_type),
1165         route_type, route_length);
1166
1167    switch(route_type) {
1168    case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI:
1169        ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN);
1170        offset = (u_int)strlen(buf);
1171        snprintf(buf + offset, buflen - offset, ", RD: %s, Originator %s",
1172                    bgp_vpn_rd_print(ndo, pptr),
1173                    bgp_vpn_ip_print(ndo, pptr + BGP_VPN_RD_LEN,
1174                                     (route_length - BGP_VPN_RD_LEN) << 3));
1175        break;
1176    case BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI:
1177        ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4);
1178        offset = (u_int)strlen(buf);
1179        snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s",
1180        bgp_vpn_rd_print(ndo, pptr),
1181        as_printf(ndo, astostr, sizeof(astostr),
1182        GET_BE_U_4(pptr + BGP_VPN_RD_LEN)));
1183        break;
1184
1185    case BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI:
1186        ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN);
1187        offset = (u_int)strlen(buf);
1188        snprintf(buf + offset, buflen - offset, ", RD: %s",
1189                    bgp_vpn_rd_print(ndo, pptr));
1190        pptr += BGP_VPN_RD_LEN;
1191
1192        sg_length = bgp_vpn_sg_print(ndo, pptr, buf, buflen);
1193        addr_length =  route_length - sg_length;
1194
1195        ND_TCHECK_LEN(pptr, addr_length);
1196        offset = (u_int)strlen(buf);
1197        snprintf(buf + offset, buflen - offset, ", Originator %s",
1198                    bgp_vpn_ip_print(ndo, pptr, addr_length << 3));
1199        break;
1200
1201    case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE:
1202        ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN);
1203        offset = (u_int)strlen(buf);
1204        snprintf(buf + offset, buflen - offset, ", RD: %s",
1205                    bgp_vpn_rd_print(ndo, pptr));
1206        pptr += BGP_VPN_RD_LEN;
1207
1208        bgp_vpn_sg_print(ndo, pptr, buf, buflen);
1209        break;
1210
1211    case BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN: /* fall through */
1212    case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN:
1213        ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4);
1214        offset = (u_int)strlen(buf);
1215        snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s",
1216                    bgp_vpn_rd_print(ndo, pptr),
1217                    as_printf(ndo, astostr, sizeof(astostr),
1218                    GET_BE_U_4(pptr + BGP_VPN_RD_LEN)));
1219        pptr += BGP_VPN_RD_LEN + 4;
1220
1221        bgp_vpn_sg_print(ndo, pptr, buf, buflen);
1222        break;
1223
1224        /*
1225         * no per route-type printing yet.
1226         */
1227    case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF:
1228    default:
1229        break;
1230    }
1231
1232    return route_length + 2;
1233
1234trunc:
1235    return -2;
1236}
1237
1238/*
1239 * As I remember, some versions of systems have an snprintf() that
1240 * returns -1 if the buffer would have overflowed.  If the return
1241 * value is negative, set buflen to 0, to indicate that we've filled
1242 * the buffer up.
1243 *
1244 * If the return value is greater than buflen, that means that
1245 * the buffer would have overflowed; again, set buflen to 0 in
1246 * that case.
1247 */
1248#define UPDATE_BUF_BUFLEN(buf, buflen, stringlen) \
1249    if (stringlen<0) \
1250        buflen=0; \
1251    else if ((u_int)stringlen>buflen) \
1252        buflen=0; \
1253    else { \
1254        buflen-=stringlen; \
1255        buf+=stringlen; \
1256    }
1257
1258static int
1259decode_labeled_vpn_l2(netdissect_options *ndo,
1260                      const u_char *pptr, char *buf, size_t buflen)
1261{
1262    u_int plen, tlen, tlv_type, tlv_len, ttlv_len;
1263    int stringlen;
1264
1265    plen = GET_BE_U_2(pptr);
1266    tlen = plen;
1267    pptr += 2;
1268    /* Old and new L2VPN NLRI share AFI/SAFI
1269     *   -> Assume a 12 Byte-length NLRI is auto-discovery-only
1270     *      and > 17 as old format. Complain for the middle case
1271     */
1272    if (plen == 12) {
1273        /* assume AD-only with RD, BGPNH */
1274        ND_TCHECK_LEN(pptr, 12);
1275        buf[0] = '\0';
1276        stringlen = snprintf(buf, buflen, "RD: %s, BGPNH: %s",
1277                                bgp_vpn_rd_print(ndo, pptr),
1278                                GET_IPADDR_STRING(pptr+8));
1279        UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1280        pptr += 12;
1281        tlen -= 12;
1282        return plen + 2;
1283    } else if (plen > 17) {
1284        /* assume old format */
1285        /* RD, ID, LBLKOFF, LBLBASE */
1286
1287        ND_TCHECK_LEN(pptr, 15);
1288        buf[0] = '\0';
1289        stringlen = snprintf(buf, buflen, "RD: %s, CE-ID: %u, Label-Block Offset: %u, Label Base %u",
1290                                bgp_vpn_rd_print(ndo, pptr),
1291                                GET_BE_U_2(pptr + 8),
1292                                GET_BE_U_2(pptr + 10),
1293                                GET_BE_U_3(pptr + 12)>>4); /* the label is offsetted by 4 bits so lets shift it right */
1294        UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1295        pptr += 15;
1296        tlen -= 15;
1297
1298        /* ok now the variable part - lets read out TLVs*/
1299        while (tlen != 0) {
1300            if (tlen < 3) {
1301                if (buflen != 0) {
1302                    stringlen=snprintf(buf,buflen, "\n\t\tran past the end");
1303                    UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1304                }
1305                return plen + 2;
1306            }
1307            tlv_type = GET_U_1(pptr);
1308            pptr++;
1309            tlv_len = GET_BE_U_2(pptr);  /* length, in *bits* */
1310            ttlv_len = (tlv_len + 7)/8;      /* length, in *bytes* */
1311            pptr += 2;
1312
1313            switch(tlv_type) {
1314            case 1:
1315                if (buflen != 0) {
1316                    stringlen=snprintf(buf,buflen, "\n\t\tcircuit status vector (%u) length: %u: 0x",
1317                                          tlv_type,
1318                                          tlv_len);
1319                    UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1320                }
1321                while (ttlv_len != 0) {
1322                    if (tlen < 1) {
1323                        if (buflen != 0) {
1324                            stringlen=snprintf(buf,buflen, " (ran past the end)");
1325                            UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1326                        }
1327                        return plen + 2;
1328                    }
1329                    ND_TCHECK_1(pptr);
1330                    if (buflen != 0) {
1331                        stringlen=snprintf(buf,buflen, "%02x",
1332                                              GET_U_1(pptr));
1333                        pptr++;
1334                        UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1335                    }
1336                    ttlv_len--;
1337                    tlen--;
1338                }
1339                break;
1340            default:
1341                if (buflen != 0) {
1342                    stringlen=snprintf(buf,buflen, "\n\t\tunknown TLV #%u, length: %u",
1343                                          tlv_type,
1344                                          tlv_len);
1345                    UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1346                }
1347                if (tlen < ttlv_len) {
1348                    if (buflen != 0) {
1349                        stringlen=snprintf(buf,buflen, " (ran past the end)");
1350                        UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1351                    }
1352                    return plen + 2;
1353                }
1354                tlen -= ttlv_len;
1355                break;
1356            }
1357        }
1358        return plen + 2;
1359    } else {
1360        /* complain bitterly ? */
1361        /* fall through */
1362        goto trunc;
1363    }
1364
1365trunc:
1366    return -2;
1367}
1368
1369int
1370decode_prefix6(netdissect_options *ndo,
1371               const u_char *pd, u_int itemlen, char *buf, size_t buflen)
1372{
1373    nd_ipv6 addr;
1374    u_int plen, plenbytes;
1375
1376    ITEMCHECK(1);
1377    plen = GET_U_1(pd);
1378    if (128 < plen)
1379        return -1;
1380    itemlen -= 1;
1381
1382    memset(&addr, 0, sizeof(addr));
1383    plenbytes = (plen + 7) / 8;
1384    ITEMCHECK(plenbytes);
1385    GET_CPY_BYTES(&addr, pd + 1, plenbytes);
1386    if (plen % 8) {
1387        addr[plenbytes - 1] &=
1388            ((0xff00 >> (plen % 8)) & 0xff);
1389    }
1390    snprintf(buf, buflen, "%s/%u", ip6addr_string(ndo, (const u_char *)&addr), plen);
1391    return 1 + plenbytes;
1392
1393badtlv:
1394    return -2;
1395}
1396
1397static int
1398decode_labeled_prefix6(netdissect_options *ndo,
1399               const u_char *pptr, u_int itemlen, char *buf, size_t buflen)
1400{
1401    nd_ipv6 addr;
1402    u_int plen, plenbytes;
1403
1404    /* prefix length and label = 4 bytes */
1405    ND_TCHECK_4(pptr);
1406    ITEMCHECK(4);
1407    plen = GET_U_1(pptr); /* get prefix length */
1408
1409    if (24 > plen)
1410        return -1;
1411
1412    plen -= 24; /* adjust prefixlen - labellength */
1413
1414    if (128 < plen)
1415        return -1;
1416    itemlen -= 4;
1417
1418    memset(&addr, 0, sizeof(addr));
1419    plenbytes = (plen + 7) / 8;
1420    GET_CPY_BYTES(&addr, pptr + 4, plenbytes);
1421    if (plen % 8) {
1422        addr[plenbytes - 1] &=
1423            ((0xff00 >> (plen % 8)) & 0xff);
1424    }
1425    /* the label may get offsetted by 4 bits so lets shift it right */
1426    snprintf(buf, buflen, "%s/%u, label:%u %s",
1427                ip6addr_string(ndo, (const u_char *)&addr),
1428                plen,
1429                GET_BE_U_3(pptr + 1)>>4,
1430                ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
1431
1432    return 4 + plenbytes;
1433
1434trunc:
1435    return -2;
1436
1437badtlv:
1438    return -3;
1439}
1440
1441static int
1442decode_labeled_vpn_prefix6(netdissect_options *ndo,
1443                           const u_char *pptr, char *buf, size_t buflen)
1444{
1445    nd_ipv6 addr;
1446    u_int plen;
1447
1448    plen = GET_U_1(pptr);   /* get prefix length */
1449
1450    if ((24+64) > plen)
1451        return -1;
1452
1453    plen -= (24+64); /* adjust prefixlen - labellength - RD len*/
1454
1455    if (128 < plen)
1456        return -1;
1457
1458    memset(&addr, 0, sizeof(addr));
1459    GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
1460    if (plen % 8) {
1461        addr[(plen + 7) / 8 - 1] &=
1462            ((0xff00 >> (plen % 8)) & 0xff);
1463    }
1464    /* the label may get offsetted by 4 bits so lets shift it right */
1465    snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s",
1466                bgp_vpn_rd_print(ndo, pptr+4),
1467                ip6addr_string(ndo, (const u_char *)&addr),
1468                plen,
1469                GET_BE_U_3(pptr + 1)>>4,
1470                ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
1471
1472    return 12 + (plen + 7) / 8;
1473}
1474
1475static int
1476decode_clnp_prefix(netdissect_options *ndo,
1477                   const u_char *pptr, char *buf, size_t buflen)
1478{
1479    uint8_t addr[19];
1480    u_int plen;
1481
1482    plen = GET_U_1(pptr); /* get prefix length */
1483
1484    if (152 < plen)
1485        return -1;
1486
1487    memset(&addr, 0, sizeof(addr));
1488    GET_CPY_BYTES(&addr, pptr + 4, (plen + 7) / 8);
1489    if (plen % 8) {
1490        addr[(plen + 7) / 8 - 1] &=
1491            ((0xff00 >> (plen % 8)) & 0xff);
1492    }
1493    /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */
1494    snprintf(buf, buflen, "%s/%u",
1495                isonsap_string(ndo, addr,(plen + 7) / 8),
1496                plen);
1497
1498    return 1 + (plen + 7) / 8;
1499}
1500
1501static int
1502decode_labeled_vpn_clnp_prefix(netdissect_options *ndo,
1503                               const u_char *pptr, char *buf, size_t buflen)
1504{
1505    uint8_t addr[19];
1506    u_int plen;
1507
1508    plen = GET_U_1(pptr);   /* get prefix length */
1509
1510    if ((24+64) > plen)
1511        return -1;
1512
1513    plen -= (24+64); /* adjust prefixlen - labellength - RD len*/
1514
1515    if (152 < plen)
1516        return -1;
1517
1518    memset(&addr, 0, sizeof(addr));
1519    GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
1520    if (plen % 8) {
1521        addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
1522    }
1523    /* the label may get offsetted by 4 bits so lets shift it right */
1524    /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */
1525    snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s",
1526                bgp_vpn_rd_print(ndo, pptr+4),
1527                isonsap_string(ndo, addr,(plen + 7) / 8),
1528                plen,
1529                GET_BE_U_3(pptr + 1)>>4,
1530                ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
1531
1532    return 12 + (plen + 7) / 8;
1533}
1534
1535/*
1536 * bgp_attr_get_as_size
1537 *
1538 * Try to find the size of the ASs encoded in an as-path. It is not obvious, as
1539 * both Old speakers that do not support 4 byte AS, and the new speakers that do
1540 * support, exchange AS-Path with the same path-attribute type value 0x02.
1541 */
1542static u_int
1543bgp_attr_get_as_size(netdissect_options *ndo,
1544                     uint8_t bgpa_type, const u_char *pptr, u_int len)
1545{
1546    const u_char *tptr = pptr;
1547
1548    /*
1549     * If the path attribute is the optional AS4 path type, then we already
1550     * know, that ASs must be encoded in 4 byte format.
1551     */
1552    if (bgpa_type == BGPTYPE_AS4_PATH) {
1553        return 4;
1554    }
1555
1556    /*
1557     * Let us assume that ASs are of 2 bytes in size, and check if the AS-Path
1558     * TLV is good. If not, ask the caller to try with AS encoded as 4 bytes
1559     * each.
1560     */
1561    while (tptr < pptr + len) {
1562        /*
1563         * If we do not find a valid segment type, our guess might be wrong.
1564         */
1565        if (GET_U_1(tptr) < BGP_AS_SEG_TYPE_MIN || GET_U_1(tptr) > BGP_AS_SEG_TYPE_MAX) {
1566            goto trunc;
1567        }
1568        tptr += 2 + GET_U_1(tptr + 1) * 2;
1569    }
1570
1571    /*
1572     * If we correctly reached end of the AS path attribute data content,
1573     * then most likely ASs were indeed encoded as 2 bytes.
1574     */
1575    if (tptr == pptr + len) {
1576        return 2;
1577    }
1578
1579trunc:
1580
1581    /*
1582     * We can come here, either we did not have enough data, or if we
1583     * try to decode 4 byte ASs in 2 byte format. Either way, return 4,
1584     * so that calller can try to decode each AS as of 4 bytes. If indeed
1585     * there was not enough data, it will crib and end the parse anyways.
1586     */
1587    return 4;
1588}
1589
1590/*
1591 * The only way to know that a BGP UPDATE message is using add path is
1592 * by checking if the capability is in the OPEN message which we may have missed.
1593 * So this function checks if it is possible that the update could contain add path
1594 * and if so it checks that standard BGP doesn't make sense.
1595 */
1596static int
1597check_add_path(netdissect_options *ndo, const u_char *pptr, u_int length,
1598               u_int max_prefix_length)
1599{
1600    u_int offset, prefix_length;
1601
1602    if (length < 5) {
1603        return 0;
1604    }
1605
1606    /*
1607     * Scan through the NLRI information under the assumpetion that
1608     * it doesn't have path IDs.
1609     */
1610    for (offset = 0; offset < length;) {
1611        offset += 4;
1612        if (!ND_TTEST_1(pptr + offset)) {
1613            /* We ran out of captured data; quit scanning. */
1614            break;
1615        }
1616        prefix_length = GET_U_1(pptr + offset);
1617        /*
1618         * Add 4 to cover the path id
1619         * and check the prefix length isn't greater than 32/128.
1620         */
1621        if (prefix_length > max_prefix_length) {
1622            return 0;
1623        }
1624        /* Add 1 for the prefix_length byte and prefix_length to cover the address */
1625        offset += 1 + ((prefix_length + 7) / 8);
1626    }
1627    /* check we haven't gone past the end of the section */
1628    if (offset > length) {
1629        return 0;
1630    }
1631
1632    /* check it's not standard BGP */
1633    for (offset = 0; offset < length; ) {
1634        if (!ND_TTEST_1(pptr + offset)) {
1635            /* We ran out of captured data; quit scanning. */
1636            break;
1637        }
1638        prefix_length = GET_U_1(pptr + offset);
1639        /*
1640         * If the prefix_length is zero (0.0.0.0/0)
1641         * and since it's not the only address (length >= 5)
1642         * then it is add-path
1643         */
1644        if (prefix_length < 1 || prefix_length > max_prefix_length) {
1645            return 1;
1646        }
1647        offset += 1 + ((prefix_length + 7) / 8);
1648    }
1649    if (offset > length) {
1650        return 1;
1651    }
1652
1653    /* assume not add-path by default */
1654    return 0;
1655}
1656
1657static int
1658bgp_mp_af_print(netdissect_options *ndo,
1659	        const u_char *tptr, u_int tlen,
1660		uint16_t *afp, uint8_t *safip)
1661{
1662	uint16_t af;
1663	uint8_t safi;
1664
1665        af = GET_BE_U_2(tptr);
1666	*afp = af;
1667        safi = GET_U_1(tptr + 2);
1668	*safip = safi;
1669
1670        ND_PRINT("\n\t    AFI: %s (%u), %sSAFI: %s (%u)",
1671                  tok2str(af_values, "Unknown AFI", af),
1672                  af,
1673                  (safi>128) ? "vendor specific " : "", /* 128 is meanwhile wellknown */
1674                  tok2str(bgp_safi_values, "Unknown SAFI", safi),
1675                  safi);
1676
1677        switch(af<<8 | safi) {
1678        case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1679        case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1680        case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1681        case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1682        case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
1683        case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1684        case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1685        case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1686        case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
1687        case (AFNUM_INET<<8 | SAFNUM_MDT):
1688        case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1689        case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1690        case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1691        case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1692        case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1693        case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1694        case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
1695        case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1696        case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1697        case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1698        case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1699        case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1700        case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1701        case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1702        case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1703        case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1704        case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1705            break;
1706        default:
1707            ND_TCHECK_LEN(tptr, tlen);
1708            ND_PRINT("\n\t    no AFI %u / SAFI %u decoder", af, safi);
1709            if (ndo->ndo_vflag <= 1)
1710                print_unknown_data(ndo, tptr, "\n\t    ", tlen);
1711            return -1;
1712        }
1713	return 0;
1714trunc:
1715	return -2;
1716}
1717
1718static int
1719bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi,
1720	       const u_char *tptr, u_int len,
1721	       char *buf, size_t buflen,
1722	       int add_path4, int add_path6)
1723{
1724	int advance;
1725	u_int path_id = 0;
1726
1727	switch (af<<8 | safi) {
1728            case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1729            case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1730            case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1731                if (add_path4) {
1732                    path_id = GET_BE_U_4(tptr);
1733                    tptr += 4;
1734                }
1735                advance = decode_prefix4(ndo, tptr, len, buf, buflen);
1736                if (advance == -1)
1737                    ND_PRINT("\n\t    (illegal prefix length)");
1738                else if (advance == -2)
1739                    break; /* bytes left, but not enough */
1740                else
1741                    ND_PRINT("\n\t      %s", buf);
1742                if (add_path4) {
1743                    ND_PRINT("   Path Id: %u", path_id);
1744		    advance += 4;
1745                }
1746                break;
1747            case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1748                advance = decode_labeled_prefix4(ndo, tptr, len, buf, buflen);
1749                if (advance == -1)
1750                    ND_PRINT("\n\t    (illegal prefix length)");
1751                else if (advance == -2)
1752                    goto trunc;
1753                else if (advance == -3)
1754                    break; /* bytes left, but not enough */
1755                else
1756                    ND_PRINT("\n\t      %s", buf);
1757                break;
1758            case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1759            case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1760            case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1761                advance = decode_labeled_vpn_prefix4(ndo, tptr, buf, buflen);
1762                if (advance == -1)
1763                    ND_PRINT("\n\t    (illegal prefix length)");
1764                else
1765                    ND_PRINT("\n\t      %s", buf);
1766                break;
1767            case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
1768                advance = decode_rt_routing_info(ndo, tptr);
1769                break;
1770            case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */
1771            case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN):
1772                advance = decode_multicast_vpn(ndo, tptr, buf, buflen);
1773                if (advance == -1)
1774                    ND_PRINT("\n\t    (illegal prefix length)");
1775                else if (advance == -2)
1776                    goto trunc;
1777                else
1778                    ND_PRINT("\n\t      %s", buf);
1779                break;
1780
1781            case (AFNUM_INET<<8 | SAFNUM_MDT):
1782                advance = decode_mdt_vpn_nlri(ndo, tptr, buf, buflen);
1783                if (advance == -1)
1784                    ND_PRINT("\n\t    (illegal prefix length)");
1785                else if (advance == -2)
1786                    goto trunc;
1787                else
1788                    ND_PRINT("\n\t      %s", buf);
1789                break;
1790            case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1791            case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1792            case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1793                if (add_path6) {
1794                    path_id = GET_BE_U_4(tptr);
1795                    tptr += 4;
1796                }
1797                advance = decode_prefix6(ndo, tptr, len, buf, buflen);
1798                if (advance == -1)
1799                    ND_PRINT("\n\t    (illegal prefix length)");
1800                else if (advance == -2)
1801                    break; /* bytes left, but not enough */
1802                else
1803                    ND_PRINT("\n\t      %s", buf);
1804                if (add_path6) {
1805                    ND_PRINT("   Path Id: %u", path_id);
1806		    advance += 4;
1807                }
1808                break;
1809            case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1810                advance = decode_labeled_prefix6(ndo, tptr, len, buf, buflen);
1811                if (advance == -1)
1812                    ND_PRINT("\n\t    (illegal prefix length)");
1813                else if (advance == -2)
1814                    goto trunc;
1815                else if (advance == -3)
1816                    break; /* bytes left, but not enough */
1817                else
1818                    ND_PRINT("\n\t      %s", buf);
1819                break;
1820            case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1821            case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1822            case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
1823                advance = decode_labeled_vpn_prefix6(ndo, tptr, buf, buflen);
1824                if (advance == -1)
1825                    ND_PRINT("\n\t    (illegal prefix length)");
1826                else
1827                    ND_PRINT("\n\t      %s", buf);
1828                break;
1829            case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1830            case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1831            case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1832            case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1833                advance = decode_labeled_vpn_l2(ndo, tptr, buf, buflen);
1834                if (advance == -1)
1835                    ND_PRINT("\n\t    (illegal length)");
1836                else if (advance == -2)
1837                    goto trunc;
1838                else
1839                    ND_PRINT("\n\t      %s", buf);
1840                break;
1841            case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1842            case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1843            case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1844                advance = decode_clnp_prefix(ndo, tptr, buf, buflen);
1845                if (advance == -1)
1846                    ND_PRINT("\n\t    (illegal prefix length)");
1847                else
1848                    ND_PRINT("\n\t      %s", buf);
1849                break;
1850            case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1851            case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1852            case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1853                advance = decode_labeled_vpn_clnp_prefix(ndo, tptr, buf, buflen);
1854                if (advance == -1)
1855                    ND_PRINT("\n\t    (illegal prefix length)");
1856                else
1857                    ND_PRINT("\n\t      %s", buf);
1858                break;
1859            default:
1860		/*
1861		 * This should not happen, we should have been protected
1862		 * by bgp_mp_af_print()'s return value.
1863		 */
1864                ND_PRINT("\n\t    ERROR: no AFI %u / SAFI %u decoder", af, safi);
1865                advance = -4;
1866                break;
1867	}
1868	return advance;
1869trunc:	/* we rely on the caller to recognize -2 return value */
1870	return -2;
1871}
1872
1873static int
1874bgp_attr_print(netdissect_options *ndo,
1875               uint8_t atype, const u_char *pptr, u_int len,
1876               const unsigned attr_set_level)
1877{
1878    /* allocate space for the largest possible string */
1879    char astostr[AS_STR_SIZE];
1880    u_int i;
1881    uint16_t af;
1882    uint8_t safi, snpa, nhlen;
1883    int advance;
1884    u_int tlen;
1885    const u_char *tptr;
1886    char buf[MAXHOSTNAMELEN + 100];
1887    u_int as_size;
1888    int add_path4, add_path6;
1889    int ret;
1890
1891    tptr = pptr;
1892    tlen = len;
1893
1894    switch (atype) {
1895    case BGPTYPE_ORIGIN:
1896        if (len != 1)
1897            ND_PRINT("invalid len");
1898        else {
1899            ND_PRINT("%s", tok2str(bgp_origin_values,
1900                      "Unknown Origin Typecode",
1901                      GET_U_1(tptr)));
1902        }
1903        break;
1904
1905    /*
1906     * Process AS4 byte path and AS2 byte path attributes here.
1907     */
1908    case BGPTYPE_AS4_PATH:
1909    case BGPTYPE_AS_PATH:
1910        if (len % 2) {
1911            ND_PRINT("invalid len");
1912            break;
1913        }
1914        if (!len) {
1915            ND_PRINT("empty");
1916            break;
1917        }
1918
1919        /*
1920         * BGP updates exchanged between New speakers that support 4
1921         * byte AS, ASs are always encoded in 4 bytes. There is no
1922         * definitive way to find this, just by the packet's
1923         * contents. So, check for packet's TLV's sanity assuming
1924         * 2 bytes first, and it does not pass, assume that ASs are
1925         * encoded in 4 bytes format and move on.
1926         */
1927        as_size = bgp_attr_get_as_size(ndo, atype, pptr, len);
1928
1929        while (tptr < pptr + len) {
1930            ND_PRINT("%s", tok2str(bgp_as_path_segment_open_values,
1931                      "?", GET_U_1(tptr)));
1932            for (i = 0; i < GET_U_1(tptr + 1) * as_size; i += as_size) {
1933                ND_TCHECK_LEN(tptr + 2 + i, as_size);
1934                ND_PRINT("%s ",
1935                          as_printf(ndo, astostr, sizeof(astostr),
1936                          as_size == 2 ?
1937                              GET_BE_U_2(tptr + i + 2) :
1938                              GET_BE_U_4(tptr + i + 2)));
1939            }
1940            ND_PRINT("%s", tok2str(bgp_as_path_segment_close_values,
1941                      "?", GET_U_1(tptr)));
1942            tptr += 2 + GET_U_1(tptr + 1) * as_size;
1943        }
1944        break;
1945    case BGPTYPE_NEXT_HOP:
1946        if (len != 4)
1947            ND_PRINT("invalid len");
1948        else {
1949            ND_PRINT("%s", GET_IPADDR_STRING(tptr));
1950        }
1951        break;
1952    case BGPTYPE_MULTI_EXIT_DISC:
1953    case BGPTYPE_LOCAL_PREF:
1954        if (len != 4)
1955            ND_PRINT("invalid len");
1956        else {
1957            ND_PRINT("%u", GET_BE_U_4(tptr));
1958        }
1959        break;
1960    case BGPTYPE_ATOMIC_AGGREGATE:
1961        if (len != 0)
1962            ND_PRINT("invalid len");
1963        break;
1964    case BGPTYPE_AGGREGATOR:
1965
1966        /*
1967         * Depending on the AS encoded is of 2 bytes or of 4 bytes,
1968         * the length of this PA can be either 6 bytes or 8 bytes.
1969         */
1970        if (len != 6 && len != 8) {
1971            ND_PRINT("invalid len");
1972            break;
1973        }
1974        ND_TCHECK_LEN(tptr, len);
1975        if (len == 6) {
1976            ND_PRINT(" AS #%s, origin %s",
1977                      as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(tptr)),
1978                      GET_IPADDR_STRING(tptr + 2));
1979        } else {
1980            ND_PRINT(" AS #%s, origin %s",
1981                      as_printf(ndo, astostr, sizeof(astostr),
1982                      GET_BE_U_4(tptr)), GET_IPADDR_STRING(tptr + 4));
1983        }
1984        break;
1985    case BGPTYPE_AGGREGATOR4:
1986        if (len != 8) {
1987            ND_PRINT("invalid len");
1988            break;
1989        }
1990        ND_PRINT(" AS #%s, origin %s",
1991                  as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(tptr)),
1992                  GET_IPADDR_STRING(tptr + 4));
1993        break;
1994    case BGPTYPE_COMMUNITIES:
1995        if (len % 4) {
1996            ND_PRINT("invalid len");
1997            break;
1998        }
1999        while (tlen != 0) {
2000            uint32_t comm;
2001            ND_TCHECK_4(tptr);
2002            if (tlen < 4)
2003                goto trunc;
2004            comm = GET_BE_U_4(tptr);
2005            switch (comm) {
2006            case BGP_COMMUNITY_NO_EXPORT:
2007                ND_PRINT(" NO_EXPORT");
2008                break;
2009            case BGP_COMMUNITY_NO_ADVERT:
2010                ND_PRINT(" NO_ADVERTISE");
2011                break;
2012            case BGP_COMMUNITY_NO_EXPORT_SUBCONFED:
2013                ND_PRINT(" NO_EXPORT_SUBCONFED");
2014                break;
2015            default:
2016                ND_PRINT("%u:%u%s",
2017                         (comm >> 16) & 0xffff,
2018                         comm & 0xffff,
2019                         (tlen>4) ? ", " : "");
2020                break;
2021            }
2022            tlen -=4;
2023            tptr +=4;
2024        }
2025        break;
2026    case BGPTYPE_ORIGINATOR_ID:
2027        if (len != 4) {
2028            ND_PRINT("invalid len");
2029            break;
2030        }
2031        ND_PRINT("%s",GET_IPADDR_STRING(tptr));
2032        break;
2033    case BGPTYPE_CLUSTER_LIST:
2034        if (len % 4) {
2035            ND_PRINT("invalid len");
2036            break;
2037        }
2038        while (tlen != 0) {
2039            if (tlen < 4)
2040                goto trunc;
2041            ND_PRINT("%s%s",
2042                      GET_IPADDR_STRING(tptr),
2043                      (tlen>4) ? ", " : "");
2044            tlen -=4;
2045            tptr +=4;
2046        }
2047        break;
2048    case BGPTYPE_MP_REACH_NLRI:
2049        ND_TCHECK_3(tptr);
2050        if (tlen < 3)
2051            goto trunc;
2052	ret = bgp_mp_af_print(ndo, tptr, tlen, &af, &safi);
2053	if (ret == -2)
2054	    goto trunc;
2055	if (ret < 0)
2056	    break;
2057
2058        tptr += 3;
2059        tlen -= 3;
2060
2061        ND_TCHECK_1(tptr);
2062        if (tlen < 1)
2063            goto trunc;
2064        nhlen = GET_U_1(tptr);
2065        tptr++;
2066        tlen--;
2067
2068        if (nhlen) {
2069            u_int nnh = 0;
2070            uint8_t tnhlen = nhlen;
2071            if (tlen < tnhlen)
2072                goto trunc;
2073            ND_PRINT("\n\t    nexthop: ");
2074            while (tnhlen != 0) {
2075                if (nnh++ > 0) {
2076                    ND_PRINT(", " );
2077                }
2078                switch(af<<8 | safi) {
2079                case (AFNUM_INET<<8 | SAFNUM_UNICAST):
2080                case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
2081                case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
2082                case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
2083                case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
2084                case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
2085                case (AFNUM_INET<<8 | SAFNUM_MDT):
2086                    if (tnhlen < sizeof(nd_ipv4)) {
2087                        ND_PRINT("invalid len");
2088                        tptr += tnhlen;
2089                        tlen -= tnhlen;
2090                        tnhlen = 0;
2091                    } else {
2092                        ND_PRINT("%s",GET_IPADDR_STRING(tptr));
2093                        tptr += sizeof(nd_ipv4);
2094                        tnhlen -= sizeof(nd_ipv4);
2095                        tlen -= sizeof(nd_ipv4);
2096                    }
2097                    break;
2098                case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
2099                case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
2100                case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
2101                    if (tnhlen < sizeof(nd_ipv4)+BGP_VPN_RD_LEN) {
2102                        ND_PRINT("invalid len");
2103                        tptr += tnhlen;
2104                        tlen -= tnhlen;
2105                        tnhlen = 0;
2106                    } else {
2107                        ND_PRINT("RD: %s, %s",
2108                                  bgp_vpn_rd_print(ndo, tptr),
2109                                  GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN));
2110                        tptr += (sizeof(nd_ipv4)+BGP_VPN_RD_LEN);
2111                        tlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN);
2112                        tnhlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN);
2113                    }
2114                    break;
2115                case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
2116                case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
2117                case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
2118                case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
2119                    if (tnhlen < sizeof(nd_ipv6)) {
2120                        ND_PRINT("invalid len");
2121                        tptr += tnhlen;
2122                        tlen -= tnhlen;
2123                        tnhlen = 0;
2124                    } else {
2125                        ND_PRINT("%s", GET_IP6ADDR_STRING(tptr));
2126                        tptr += sizeof(nd_ipv6);
2127                        tlen -= sizeof(nd_ipv6);
2128                        tnhlen -= sizeof(nd_ipv6);
2129                    }
2130                    break;
2131                case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
2132                case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
2133                case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
2134                    if (tnhlen < sizeof(nd_ipv6)+BGP_VPN_RD_LEN) {
2135                        ND_PRINT("invalid len");
2136                        tptr += tnhlen;
2137                        tlen -= tnhlen;
2138                        tnhlen = 0;
2139                    } else {
2140                        ND_PRINT("RD: %s, %s",
2141                                  bgp_vpn_rd_print(ndo, tptr),
2142                                  GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN));
2143                        tptr += (sizeof(nd_ipv6)+BGP_VPN_RD_LEN);
2144                        tlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN);
2145                        tnhlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN);
2146                    }
2147                    break;
2148                case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
2149                case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
2150                case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
2151                case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
2152                    if (tnhlen < sizeof(nd_ipv4)) {
2153                        ND_PRINT("invalid len");
2154                        tptr += tnhlen;
2155                        tlen -= tnhlen;
2156                        tnhlen = 0;
2157                    } else {
2158                        ND_PRINT("%s", GET_IPADDR_STRING(tptr));
2159                        tptr += (sizeof(nd_ipv4));
2160                        tlen -= (sizeof(nd_ipv4));
2161                        tnhlen -= (sizeof(nd_ipv4));
2162                    }
2163                    break;
2164                case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
2165                case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
2166                case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
2167                    ND_PRINT("%s", GET_ISONSAP_STRING(tptr, tnhlen));
2168                    tptr += tnhlen;
2169                    tlen -= tnhlen;
2170                    tnhlen = 0;
2171                    break;
2172
2173                case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
2174                case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
2175                case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
2176                    if (tnhlen < BGP_VPN_RD_LEN+1) {
2177                        ND_PRINT("invalid len");
2178                        tptr += tnhlen;
2179                        tlen -= tnhlen;
2180                        tnhlen = 0;
2181                    } else {
2182                        ND_TCHECK_LEN(tptr, tnhlen);
2183                        ND_PRINT("RD: %s, %s",
2184                                  bgp_vpn_rd_print(ndo, tptr),
2185                                  GET_ISONSAP_STRING(tptr+BGP_VPN_RD_LEN,tnhlen-BGP_VPN_RD_LEN));
2186                        /* rfc986 mapped IPv4 address ? */
2187                        if (GET_BE_U_4(tptr + BGP_VPN_RD_LEN) ==  0x47000601)
2188                            ND_PRINT(" = %s", GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN+4));
2189                        /* rfc1888 mapped IPv6 address ? */
2190                        else if (GET_BE_U_3(tptr + BGP_VPN_RD_LEN) ==  0x350000)
2191                            ND_PRINT(" = %s", GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN+3));
2192                        tptr += tnhlen;
2193                        tlen -= tnhlen;
2194                        tnhlen = 0;
2195                    }
2196                    break;
2197                default:
2198		    /*
2199		     * bgp_mp_af_print() should have saved us from
2200		     * an unsupported AFI/SAFI.
2201		     */
2202                    ND_PRINT("ERROR: no AFI %u/SAFI %u nexthop decoder", af, safi);
2203                    tptr += tnhlen;
2204                    tlen -= tnhlen;
2205                    tnhlen = 0;
2206                    goto done;
2207                    break;
2208                }
2209            }
2210        }
2211        ND_PRINT(", nh-length: %u", nhlen);
2212
2213        /* As per RFC 2858; this is reserved in RFC 4760 */
2214        if (tlen < 1)
2215            goto trunc;
2216        snpa = GET_U_1(tptr);
2217        tptr++;
2218        tlen--;
2219
2220        if (snpa) {
2221            ND_PRINT("\n\t    %u SNPA", snpa);
2222            for (/*nothing*/; snpa != 0; snpa--) {
2223                uint8_t snpalen;
2224		if (tlen < 1)
2225		    goto trunc;
2226                snpalen = GET_U_1(tptr);
2227                ND_PRINT("\n\t      %u bytes", snpalen);
2228                tptr++;
2229                tlen--;
2230                if (tlen < snpalen)
2231                    goto trunc;
2232                ND_TCHECK_LEN(tptr, snpalen);
2233                tptr += snpalen;
2234                tlen -= snpalen;
2235            }
2236        } else {
2237            ND_PRINT(", no SNPA");
2238        }
2239
2240        add_path4 = check_add_path(ndo, tptr, (len-ND_BYTES_BETWEEN(tptr, pptr)), 32);
2241        add_path6 = check_add_path(ndo, tptr, (len-ND_BYTES_BETWEEN(tptr, pptr)), 128);
2242
2243        while (tptr < pptr + len) {
2244            advance = bgp_nlri_print(ndo, af, safi, tptr, len, buf, sizeof(buf),
2245                    add_path4, add_path6);
2246            if (advance == -2)
2247                goto trunc;
2248            if (advance < 0)
2249                break;
2250            tptr += advance;
2251        }
2252        break;
2253
2254    case BGPTYPE_MP_UNREACH_NLRI:
2255        ND_TCHECK_LEN(tptr, BGP_MP_NLRI_MINSIZE);
2256	ret = bgp_mp_af_print(ndo, tptr, tlen, &af, &safi);
2257	if (ret == -2)
2258	    goto trunc;
2259	if (ret < 0)
2260	    break;
2261
2262        if (len == BGP_MP_NLRI_MINSIZE)
2263            ND_PRINT("\n\t      End-of-Rib Marker (empty NLRI)");
2264
2265        tptr += 3;
2266
2267        add_path4 = check_add_path(ndo, tptr, (len-ND_BYTES_BETWEEN(tptr, pptr)), 32);
2268        add_path6 = check_add_path(ndo, tptr, (len-ND_BYTES_BETWEEN(tptr, pptr)), 128);
2269
2270        while (tptr < pptr + len) {
2271            advance = bgp_nlri_print(ndo, af, safi, tptr, len, buf, sizeof(buf),
2272                    add_path4, add_path6);
2273            if (advance == -2)
2274                goto trunc;
2275            if (advance < 0)
2276                break;
2277            tptr += advance;
2278        }
2279        break;
2280    case BGPTYPE_EXTD_COMMUNITIES:
2281        if (len % 8) {
2282            ND_PRINT("invalid len");
2283            break;
2284        }
2285        while (tlen != 0) {
2286            uint16_t extd_comm;
2287
2288            ND_TCHECK_2(tptr);
2289            if (tlen < 2)
2290                goto trunc;
2291            extd_comm=GET_BE_U_2(tptr);
2292
2293            ND_PRINT("\n\t    %s (0x%04x), Flags [%s]",
2294                      tok2str(bgp_extd_comm_subtype_values,
2295                              "unknown extd community typecode",
2296                              extd_comm),
2297                      extd_comm,
2298                      bittok2str(bgp_extd_comm_flag_values, "none", extd_comm));
2299
2300            ND_TCHECK_8(tptr);
2301            if (tlen < 8)
2302                goto trunc;
2303            ND_PRINT(": ");
2304            bgp_extended_community_print(ndo, tptr);
2305            tlen -= 8;
2306            tptr += 8;
2307        }
2308        break;
2309
2310    case BGPTYPE_PMSI_TUNNEL:
2311    {
2312        uint8_t tunnel_type, flags;
2313
2314        ND_TCHECK_5(tptr);
2315        if (tlen < 5)
2316            goto trunc;
2317        flags = GET_U_1(tptr);
2318        tunnel_type = GET_U_1(tptr + 1);
2319
2320        ND_PRINT("\n\t    Tunnel-type %s (%u), Flags [%s], MPLS Label %u",
2321                  tok2str(bgp_pmsi_tunnel_values, "Unknown", tunnel_type),
2322                  tunnel_type,
2323                  bittok2str(bgp_pmsi_flag_values, "none", flags),
2324                  GET_BE_U_3(tptr + 2)>>4);
2325
2326        tptr +=5;
2327        tlen -= 5;
2328
2329        switch (tunnel_type) {
2330        case BGP_PMSI_TUNNEL_PIM_SM: /* fall through */
2331        case BGP_PMSI_TUNNEL_PIM_BIDIR:
2332            ND_PRINT("\n\t      Sender %s, P-Group %s",
2333                      GET_IPADDR_STRING(tptr),
2334                      GET_IPADDR_STRING(tptr+4));
2335            break;
2336
2337        case BGP_PMSI_TUNNEL_PIM_SSM:
2338            ND_PRINT("\n\t      Root-Node %s, P-Group %s",
2339                      GET_IPADDR_STRING(tptr),
2340                      GET_IPADDR_STRING(tptr+4));
2341            break;
2342        case BGP_PMSI_TUNNEL_INGRESS:
2343            ND_PRINT("\n\t      Tunnel-Endpoint %s",
2344                      GET_IPADDR_STRING(tptr));
2345            break;
2346        case BGP_PMSI_TUNNEL_LDP_P2MP: /* fall through */
2347        case BGP_PMSI_TUNNEL_LDP_MP2MP:
2348            ND_PRINT("\n\t      Root-Node %s, LSP-ID 0x%08x",
2349                      GET_IPADDR_STRING(tptr),
2350                      GET_BE_U_4(tptr + 4));
2351            break;
2352        case BGP_PMSI_TUNNEL_RSVP_P2MP:
2353            ND_PRINT("\n\t      Extended-Tunnel-ID %s, P2MP-ID 0x%08x",
2354                      GET_IPADDR_STRING(tptr),
2355                      GET_BE_U_4(tptr + 4));
2356            break;
2357        default:
2358            if (ndo->ndo_vflag <= 1) {
2359                print_unknown_data(ndo, tptr, "\n\t      ", tlen);
2360            }
2361        }
2362        break;
2363    }
2364    case BGPTYPE_AIGP:
2365    {
2366        uint8_t type;
2367        uint16_t length;
2368
2369        while (tlen >= 3) {
2370            type = GET_U_1(tptr);
2371            length = GET_BE_U_2(tptr + 1);
2372            tptr += 3;
2373            tlen -= 3;
2374
2375            ND_PRINT("\n\t    %s TLV (%u), length %u",
2376                      tok2str(bgp_aigp_values, "Unknown", type),
2377                      type, length);
2378
2379            if (length < 3)
2380                goto trunc;
2381            length -= 3;
2382
2383            /*
2384             * Check if we can read the TLV data.
2385             */
2386            if (tlen < length)
2387                goto trunc;
2388
2389            switch (type) {
2390
2391            case BGP_AIGP_TLV:
2392                if (length < 8)
2393                    goto trunc;
2394                ND_PRINT(", metric %" PRIu64,
2395                          GET_BE_U_8(tptr));
2396                break;
2397
2398            default:
2399                if (ndo->ndo_vflag <= 1) {
2400                    print_unknown_data(ndo, tptr,"\n\t      ", length);
2401                }
2402            }
2403
2404            tptr += length;
2405            tlen -= length;
2406        }
2407        break;
2408    }
2409    case BGPTYPE_ATTR_SET:
2410        ND_TCHECK_4(tptr);
2411        if (len < 4)
2412            goto trunc;
2413        ND_PRINT("\n\t    Origin AS: %s",
2414                  as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(tptr)));
2415        tptr += 4;
2416        len -= 4;
2417
2418        while (len) {
2419            u_int aflags, alenlen, alen;
2420
2421            ND_TCHECK_2(tptr);
2422            if (len < 2) {
2423                ND_PRINT(" [path attr too short]");
2424                tptr += len;
2425                break;
2426            }
2427            aflags = GET_U_1(tptr);
2428            atype = GET_U_1(tptr + 1);
2429            tptr += 2;
2430            len -= 2;
2431            alenlen = bgp_attr_lenlen(aflags, tptr);
2432            ND_TCHECK_LEN(tptr, alenlen);
2433            if (len < alenlen) {
2434                ND_PRINT(" [path attr too short]");
2435                tptr += len;
2436                break;
2437            }
2438            alen = bgp_attr_len(aflags, tptr);
2439            tptr += alenlen;
2440            len -= alenlen;
2441
2442            ND_PRINT("\n\t      %s (%u), length: %u",
2443                      tok2str(bgp_attr_values,
2444                              "Unknown Attribute", atype),
2445                      atype,
2446                      alen);
2447
2448            if (aflags) {
2449                ND_PRINT(", Flags [%s%s%s%s",
2450                          aflags & 0x80 ? "O" : "",
2451                          aflags & 0x40 ? "T" : "",
2452                          aflags & 0x20 ? "P" : "",
2453                          aflags & 0x10 ? "E" : "");
2454                if (aflags & 0xf)
2455                    ND_PRINT("+%x", aflags & 0xf);
2456                ND_PRINT("]");
2457            }
2458            ND_PRINT(": ");
2459            if (len < alen) {
2460                ND_PRINT(" [path attr too short]");
2461                tptr += len;
2462                break;
2463            }
2464            /*
2465             * The protocol encoding per se allows ATTR_SET to be nested
2466             * as many times as the message can accommodate. This printer
2467             * used to be able to recurse into ATTR_SET contents until the
2468             * stack exhaustion, but now there is a limit on that (if live
2469             * protocol exchange goes that many levels deep, something is
2470             * probably wrong anyway). Feel free to refine this value if
2471             * you can find the spec with respective normative text.
2472             */
2473            if (attr_set_level == 10)
2474                ND_PRINT("(too many nested levels, not recursing)");
2475            else if (!bgp_attr_print(ndo, atype, tptr, alen, attr_set_level + 1))
2476                return 0;
2477            tptr += alen;
2478            len -= alen;
2479        }
2480        break;
2481
2482    case BGPTYPE_LARGE_COMMUNITY:
2483        if (len == 0 || len % 12) {
2484            ND_PRINT("invalid len");
2485            break;
2486        }
2487        ND_PRINT("\n\t    ");
2488        while (len != 0) {
2489            ND_PRINT("%u:%u:%u%s",
2490                      GET_BE_U_4(tptr),
2491                      GET_BE_U_4(tptr + 4),
2492                      GET_BE_U_4(tptr + 8),
2493                      (len > 12) ? ", " : "");
2494            tptr += 12;
2495            /*
2496             * len will always be a multiple of 12, as per the above,
2497             * so this will never underflow.
2498             */
2499            len -= 12;
2500        }
2501        break;
2502    default:
2503        ND_TCHECK_LEN(pptr, len);
2504        ND_PRINT("\n\t    no Attribute %u decoder", atype); /* we have no decoder for the attribute */
2505        if (ndo->ndo_vflag <= 1)
2506            print_unknown_data(ndo, pptr, "\n\t    ", len);
2507        break;
2508    }
2509done:
2510    if (ndo->ndo_vflag > 1 && len) { /* omit zero length attributes*/
2511        ND_TCHECK_LEN(pptr, len);
2512        print_unknown_data(ndo, pptr, "\n\t    ", len);
2513    }
2514    return 1;
2515
2516trunc:
2517    return 0;
2518}
2519
2520static void
2521bgp_capabilities_print(netdissect_options *ndo,
2522                       const u_char *opt, u_int caps_len)
2523{
2524    /* allocate space for the largest possible string */
2525    char astostr[AS_STR_SIZE];
2526    u_int cap_type, cap_len, tcap_len, cap_offset;
2527    u_int i = 0;
2528
2529    while (i < caps_len) {
2530        ND_TCHECK_LEN(opt + i, BGP_CAP_HEADER_SIZE);
2531        cap_type=GET_U_1(opt + i);
2532        cap_len=GET_U_1(opt + i + 1);
2533        ND_PRINT("\n\t      %s (%u), length: %u",
2534                  tok2str(bgp_capcode_values, "Unknown", cap_type),
2535                  cap_type,
2536                  cap_len);
2537        ND_TCHECK_LEN(opt + 2 + i, cap_len);
2538        switch (cap_type) {
2539        case BGP_CAPCODE_MP:
2540            /* AFI (16 bits), Reserved (8 bits), SAFI (8 bits) */
2541            if (cap_len < 4) {
2542                ND_PRINT(" (too short, < 4)");
2543                return;
2544            }
2545            ND_PRINT("\n\t\tAFI %s (%u), SAFI %s (%u)",
2546               tok2str(af_values, "Unknown", GET_BE_U_2(opt + i + 2)),
2547               GET_BE_U_2(opt + i + 2),
2548               tok2str(bgp_safi_values, "Unknown", GET_U_1(opt + i + 5)),
2549               GET_U_1(opt + i + 5));
2550            break;
2551        case BGP_CAPCODE_ML:
2552            cap_offset = 2;
2553            tcap_len = cap_len;
2554            while (tcap_len >= 4) {
2555                ND_PRINT( "\n\t\tAFI %s (%u), SAFI %s (%u), Count: %u",
2556                       tok2str(af_values, "Unknown",
2557                                  GET_BE_U_2(opt + i + cap_offset)),
2558                       GET_BE_U_2(opt + i + cap_offset),
2559                       tok2str(bgp_safi_values, "Unknown",
2560                                  GET_U_1(opt + i + cap_offset + 2)),
2561                       GET_U_1(opt + i + cap_offset + 2),
2562                       GET_U_1(opt + i + cap_offset + 3));
2563                tcap_len -= 4;
2564                cap_offset += 4;
2565            }
2566            break;
2567        case BGP_CAPCODE_RESTART:
2568            /* Restart Flags (4 bits), Restart Time in seconds (12 bits) */
2569            if (cap_len < 2) {
2570                ND_PRINT(" (too short, < 2)");
2571                return;
2572            }
2573            tcap_len=cap_len;
2574            ND_PRINT("\n\t\tRestart Flags: [%s], Restart Time %us",
2575                      ((GET_U_1(opt + i + 2))&0x80) ? "R" : "none",
2576                      GET_BE_U_2(opt + i + 2)&0xfff);
2577            tcap_len-=2;
2578            cap_offset=4;
2579            while(tcap_len>=4) {
2580                ND_PRINT("\n\t\t  AFI %s (%u), SAFI %s (%u), Forwarding state preserved: %s",
2581                          tok2str(af_values,"Unknown",
2582                                  GET_BE_U_2(opt + i + cap_offset)),
2583                          GET_BE_U_2(opt + i + cap_offset),
2584                          tok2str(bgp_safi_values,"Unknown",
2585                                  GET_U_1(opt + i + cap_offset + 2)),
2586                          GET_U_1(opt + (i + cap_offset + 2)),
2587                          ((GET_U_1(opt + (i + cap_offset + 3)))&0x80) ? "yes" : "no" );
2588                tcap_len -= 4;
2589                cap_offset += 4;
2590            }
2591            break;
2592        case BGP_CAPCODE_RR:
2593        case BGP_CAPCODE_LLGR:
2594        case BGP_CAPCODE_RR_CISCO:
2595            break;
2596        case BGP_CAPCODE_AS_NEW:
2597            /*
2598             * Extract the 4 byte AS number encoded.
2599             */
2600            if (cap_len < 4) {
2601                ND_PRINT(" (too short, < 4)");
2602                return;
2603            }
2604            ND_PRINT("\n\t\t 4 Byte AS %s",
2605                      as_printf(ndo, astostr, sizeof(astostr),
2606                      GET_BE_U_4(opt + i + 2)));
2607            break;
2608        case BGP_CAPCODE_ADD_PATH:
2609            if (cap_len == 0) {
2610                ND_PRINT(" (bogus)"); /* length */
2611                break;
2612            }
2613            tcap_len=cap_len;
2614            cap_offset=2;
2615            while (tcap_len != 0) {
2616                if (tcap_len < 4) {
2617                    nd_print_invalid(ndo);
2618                    break;
2619                }
2620                ND_PRINT("\n\t\tAFI %s (%u), SAFI %s (%u), Send/Receive: %s",
2621                          tok2str(af_values,"Unknown",GET_BE_U_2(opt + i + cap_offset)),
2622                          GET_BE_U_2(opt + i + cap_offset),
2623                          tok2str(bgp_safi_values,"Unknown",GET_U_1(opt + i + cap_offset + 2)),
2624                          GET_U_1(opt + (i + cap_offset + 2)),
2625                          tok2str(bgp_add_path_recvsend,"Bogus (0x%02x)",GET_U_1(opt + i + cap_offset + 3))
2626                );
2627                tcap_len -= 4;
2628                cap_offset += 4;
2629            }
2630            break;
2631        default:
2632            ND_PRINT("\n\t\tno decoder for Capability %u",
2633                      cap_type);
2634            if (ndo->ndo_vflag <= 1)
2635                print_unknown_data(ndo, opt + i + 2, "\n\t\t",
2636                                   cap_len);
2637            break;
2638        }
2639        if (ndo->ndo_vflag > 1 && cap_len != 0) {
2640            print_unknown_data(ndo, opt + i + 2, "\n\t\t", cap_len);
2641        }
2642        i += BGP_CAP_HEADER_SIZE + cap_len;
2643    }
2644    return;
2645
2646trunc:
2647    nd_print_trunc(ndo);
2648}
2649
2650static void
2651bgp_open_print(netdissect_options *ndo,
2652               const u_char *dat, u_int length)
2653{
2654    /* allocate space for the largest possible string */
2655    char astostr[AS_STR_SIZE];
2656    const struct bgp_open *bgp_open_header;
2657    u_int optslen;
2658    const struct bgp_opt *bgpopt;
2659    const u_char *opt;
2660    u_int i;
2661
2662    ND_TCHECK_LEN(dat, BGP_OPEN_SIZE);
2663    if (length < BGP_OPEN_SIZE)
2664        goto trunc;
2665
2666    bgp_open_header = (const struct bgp_open *)dat;
2667
2668    ND_PRINT("\n\t  Version %u, ",
2669        GET_U_1(bgp_open_header->bgpo_version));
2670    ND_PRINT("my AS %s, ",
2671        as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(bgp_open_header->bgpo_myas)));
2672    ND_PRINT("Holdtime %us, ",
2673        GET_BE_U_2(bgp_open_header->bgpo_holdtime));
2674    ND_PRINT("ID %s", GET_IPADDR_STRING(bgp_open_header->bgpo_id));
2675    optslen = GET_U_1(bgp_open_header->bgpo_optlen);
2676    ND_PRINT("\n\t  Optional parameters, length: %u", optslen);
2677
2678    opt = dat + BGP_OPEN_SIZE;
2679    length -= BGP_OPEN_SIZE;
2680
2681    i = 0;
2682    while (i < optslen) {
2683        uint8_t opt_type, opt_len;
2684
2685        ND_TCHECK_LEN(opt + i, BGP_OPT_SIZE);
2686        if (length < BGP_OPT_SIZE + i)
2687            goto trunc;
2688        bgpopt = (const struct bgp_opt *)(opt + i);
2689        opt_type = GET_U_1(bgpopt->bgpopt_type);
2690        opt_len = GET_U_1(bgpopt->bgpopt_len);
2691        if (BGP_OPT_SIZE + i + opt_len > optslen) {
2692            ND_PRINT("\n\t     Option %u, length: %u, goes past the end of the options",
2693                      opt_type, opt_len);
2694            break;
2695        }
2696
2697        ND_PRINT("\n\t    Option %s (%u), length: %u",
2698                  tok2str(bgp_opt_values,"Unknown",opt_type),
2699                  opt_type,
2700                  opt_len);
2701
2702        /* now let's decode the options we know*/
2703        switch(opt_type) {
2704
2705        case BGP_OPT_CAP:
2706            bgp_capabilities_print(ndo, opt + BGP_OPT_SIZE + i,
2707                                   opt_len);
2708            break;
2709
2710        case BGP_OPT_AUTH:
2711        default:
2712               ND_PRINT("\n\t      no decoder for option %u",
2713               opt_type);
2714               break;
2715        }
2716        i += BGP_OPT_SIZE + opt_len;
2717    }
2718    return;
2719trunc:
2720    nd_print_trunc(ndo);
2721}
2722
2723static void
2724bgp_update_print(netdissect_options *ndo,
2725                 const u_char *dat, u_int length)
2726{
2727    const u_char *p;
2728    u_int withdrawn_routes_len;
2729    char buf[MAXHOSTNAMELEN + 100];
2730    int wpfx;
2731    u_int len;
2732    int i;
2733    int add_path;
2734    u_int path_id = 0;
2735
2736    ND_TCHECK_LEN(dat, BGP_SIZE);
2737    if (length < BGP_SIZE)
2738        goto trunc;
2739    p = dat + BGP_SIZE;
2740    length -= BGP_SIZE;
2741
2742    /* Unfeasible routes */
2743    ND_TCHECK_2(p);
2744    if (length < 2)
2745        goto trunc;
2746    withdrawn_routes_len = GET_BE_U_2(p);
2747    p += 2;
2748    length -= 2;
2749    if (withdrawn_routes_len > 1) {
2750        /*
2751         * Without keeping state from the original NLRI message,
2752         * it's not possible to tell if this a v4 or v6 route,
2753         * so only try to decode it if we're not v6 enabled.
2754         */
2755        ND_TCHECK_LEN(p, withdrawn_routes_len);
2756        if (length < withdrawn_routes_len)
2757            goto trunc;
2758        ND_PRINT("\n\t  Withdrawn routes:");
2759        add_path = check_add_path(ndo, p, withdrawn_routes_len, 32);
2760        while (withdrawn_routes_len != 0) {
2761            if (add_path) {
2762                if (withdrawn_routes_len < 4) {
2763                    p += withdrawn_routes_len;
2764                    length -= withdrawn_routes_len;
2765                    break;
2766                }
2767                path_id = GET_BE_U_4(p);
2768                p += 4;
2769                length -= 4;
2770                withdrawn_routes_len -= 4;
2771            }
2772            wpfx = decode_prefix4(ndo, p, withdrawn_routes_len, buf, sizeof(buf));
2773            if (wpfx == -1) {
2774                ND_PRINT("\n\t    (illegal prefix length)");
2775                break;
2776            } else if (wpfx == -2)
2777                goto trunc; /* bytes left, but not enough */
2778            else {
2779                ND_PRINT("\n\t    %s", buf);
2780                if (add_path) {
2781                    ND_PRINT("   Path Id: %u", path_id);
2782                }
2783                p += wpfx;
2784                length -= wpfx;
2785                withdrawn_routes_len -= wpfx;
2786            }
2787        }
2788    } else {
2789        ND_TCHECK_LEN(p, withdrawn_routes_len);
2790        if (length < withdrawn_routes_len)
2791            goto trunc;
2792        p += withdrawn_routes_len;
2793        length -= withdrawn_routes_len;
2794    }
2795
2796    ND_TCHECK_2(p);
2797    if (length < 2)
2798        goto trunc;
2799    len = GET_BE_U_2(p);
2800    p += 2;
2801    length -= 2;
2802
2803    if (withdrawn_routes_len == 0 && len == 0 && length == 0) {
2804        /* No withdrawn routes, no path attributes, no NLRI */
2805        ND_PRINT("\n\t  End-of-Rib Marker (empty NLRI)");
2806        return;
2807    }
2808
2809    if (len) {
2810        /* Make sure the path attributes don't go past the end of the packet */
2811        if (length < len)
2812            goto trunc;
2813        /* do something more useful!*/
2814        while (len) {
2815            uint8_t aflags, atype, alenlen;
2816            uint16_t alen;
2817
2818            ND_TCHECK_2(p);
2819            if (length < 2)
2820                goto trunc;
2821            if (len < 2) {
2822                ND_PRINT("\n\t  [path attrs too short]");
2823                p += len;
2824                length -= len;
2825                break;
2826            }
2827            aflags = GET_U_1(p);
2828            atype = GET_U_1(p + 1);
2829            p += 2;
2830            len -= 2;
2831            length -= 2;
2832            alenlen = bgp_attr_lenlen(aflags, p);
2833            ND_TCHECK_LEN(p, alenlen);
2834            if (length < alenlen)
2835                goto trunc;
2836            if (len < alenlen) {
2837                ND_PRINT("\n\t  [path attrs too short]");
2838                p += len;
2839                length -= len;
2840                break;
2841            }
2842            alen = bgp_attr_len(aflags, p);
2843            p += alenlen;
2844            len -= alenlen;
2845            length -= alenlen;
2846
2847            ND_PRINT("\n\t  %s (%u), length: %u",
2848                      tok2str(bgp_attr_values, "Unknown Attribute", atype),
2849                      atype,
2850                      alen);
2851
2852            if (aflags) {
2853                ND_PRINT(", Flags [%s%s%s%s",
2854                          aflags & 0x80 ? "O" : "",
2855                          aflags & 0x40 ? "T" : "",
2856                          aflags & 0x20 ? "P" : "",
2857                          aflags & 0x10 ? "E" : "");
2858                if (aflags & 0xf)
2859                    ND_PRINT("+%x", aflags & 0xf);
2860                ND_PRINT("]: ");
2861            }
2862            if (len < alen) {
2863                ND_PRINT(" [path attrs too short]");
2864                p += len;
2865                length -= len;
2866                break;
2867            }
2868            if (length < alen)
2869                goto trunc;
2870            if (!bgp_attr_print(ndo, atype, p, alen, 0))
2871                goto trunc;
2872            p += alen;
2873            len -= alen;
2874            length -= alen;
2875        }
2876    }
2877
2878    if (length) {
2879        add_path = check_add_path(ndo, p, length, 32);
2880        ND_PRINT("\n\t  Updated routes:");
2881        while (length != 0) {
2882            if (add_path) {
2883                ND_TCHECK_4(p);
2884                if (length < 4)
2885                    goto trunc;
2886                path_id = GET_BE_U_4(p);
2887                p += 4;
2888                length -= 4;
2889            }
2890            i = decode_prefix4(ndo, p, length, buf, sizeof(buf));
2891            if (i == -1) {
2892                ND_PRINT("\n\t    (illegal prefix length)");
2893                break;
2894            } else if (i == -2)
2895                goto trunc; /* bytes left, but not enough */
2896            else {
2897                ND_PRINT("\n\t    %s", buf);
2898                if (add_path) {
2899                    ND_PRINT("   Path Id: %u", path_id);
2900                }
2901                p += i;
2902                length -= i;
2903            }
2904        }
2905    }
2906    return;
2907trunc:
2908    nd_print_trunc(ndo);
2909}
2910
2911static void
2912bgp_notification_print(netdissect_options *ndo,
2913                       const u_char *dat, u_int length)
2914{
2915    const struct bgp_notification *bgp_notification_header;
2916    const u_char *tptr;
2917    uint8_t bgpn_major, bgpn_minor;
2918
2919    ND_TCHECK_LEN(dat, BGP_NOTIFICATION_SIZE);
2920    if (length<BGP_NOTIFICATION_SIZE)
2921        return;
2922
2923    bgp_notification_header = (const struct bgp_notification *)dat;
2924    bgpn_major = GET_U_1(bgp_notification_header->bgpn_major);
2925    bgpn_minor = GET_U_1(bgp_notification_header->bgpn_minor);
2926
2927    ND_PRINT(", %s (%u)",
2928              tok2str(bgp_notify_major_values, "Unknown Error",
2929                      bgpn_major),
2930              bgpn_major);
2931
2932    switch (bgpn_major) {
2933
2934    case BGP_NOTIFY_MAJOR_MSG:
2935        ND_PRINT(", subcode %s (%u)",
2936                  tok2str(bgp_notify_minor_msg_values, "Unknown",
2937                          bgpn_minor),
2938                  bgpn_minor);
2939        break;
2940    case BGP_NOTIFY_MAJOR_OPEN:
2941        ND_PRINT(", subcode %s (%u)",
2942                  tok2str(bgp_notify_minor_open_values, "Unknown",
2943                          bgpn_minor),
2944                  bgpn_minor);
2945        break;
2946    case BGP_NOTIFY_MAJOR_UPDATE:
2947        ND_PRINT(", subcode %s (%u)",
2948                  tok2str(bgp_notify_minor_update_values, "Unknown",
2949                          bgpn_minor),
2950                  bgpn_minor);
2951        break;
2952    case BGP_NOTIFY_MAJOR_FSM:
2953        ND_PRINT(" subcode %s (%u)",
2954                  tok2str(bgp_notify_minor_fsm_values, "Unknown",
2955                          bgpn_minor),
2956                  bgpn_minor);
2957        break;
2958    case BGP_NOTIFY_MAJOR_CAP:
2959        ND_PRINT(" subcode %s (%u)",
2960                  tok2str(bgp_notify_minor_cap_values, "Unknown",
2961                          bgpn_minor),
2962                  bgpn_minor);
2963        break;
2964    case BGP_NOTIFY_MAJOR_CEASE:
2965        ND_PRINT(", subcode %s (%u)",
2966                  tok2str(bgp_notify_minor_cease_values, "Unknown",
2967                          bgpn_minor),
2968                  bgpn_minor);
2969
2970        /* RFC 4486 mentions optionally 7 bytes
2971         * for the maxprefix subtype, which may contain AFI, SAFI and MAXPREFIXES
2972         */
2973        if(bgpn_minor == BGP_NOTIFY_MINOR_CEASE_MAXPRFX && length >= BGP_NOTIFICATION_SIZE + 7) {
2974            tptr = dat + BGP_NOTIFICATION_SIZE;
2975            ND_PRINT(", AFI %s (%u), SAFI %s (%u), Max Prefixes: %u",
2976                      tok2str(af_values, "Unknown", GET_BE_U_2(tptr)),
2977                      GET_BE_U_2(tptr),
2978                      tok2str(bgp_safi_values, "Unknown", GET_U_1((tptr + 2))),
2979                      GET_U_1((tptr + 2)),
2980                      GET_BE_U_4(tptr + 3));
2981        }
2982        /*
2983         * RFC 9003 describes a method to send a communication
2984         * intended for human consumption regarding the Administrative Shutdown
2985         */
2986        if ((bgpn_minor == BGP_NOTIFY_MINOR_CEASE_SHUT ||
2987             bgpn_minor == BGP_NOTIFY_MINOR_CEASE_RESET) &&
2988             length >= BGP_NOTIFICATION_SIZE + 1) {
2989            tptr = dat + BGP_NOTIFICATION_SIZE;
2990            uint8_t shutdown_comm_length = GET_U_1(tptr);
2991            uint8_t remainder_offset = 0;
2992            /* garbage, hexdump it all */
2993            if (shutdown_comm_length > length - (BGP_NOTIFICATION_SIZE + 1)) {
2994                ND_PRINT(", invalid Shutdown Communication length");
2995            }
2996            else if (shutdown_comm_length == 0) {
2997                ND_PRINT(", empty Shutdown Communication");
2998                remainder_offset += 1;
2999            }
3000            /* a proper shutdown communication */
3001            else {
3002                ND_PRINT(", Shutdown Communication (length: %u): \"", shutdown_comm_length);
3003                (void)nd_printn(ndo, tptr+1, shutdown_comm_length, NULL);
3004                ND_PRINT("\"");
3005                remainder_offset += shutdown_comm_length + 1;
3006            }
3007            /* if there is trailing data, hexdump it */
3008            if(length - (remainder_offset + BGP_NOTIFICATION_SIZE) > 0) {
3009                ND_PRINT(", Data: (length: %u)", length - (remainder_offset + BGP_NOTIFICATION_SIZE));
3010                hex_print(ndo, "\n\t\t", tptr + remainder_offset, length - (remainder_offset + BGP_NOTIFICATION_SIZE));
3011            }
3012        }
3013        break;
3014    default:
3015        break;
3016    }
3017
3018    return;
3019trunc:
3020    nd_print_trunc(ndo);
3021}
3022
3023static void
3024bgp_route_refresh_print(netdissect_options *ndo,
3025                        const u_char *pptr, u_int len)
3026{
3027    const struct bgp_route_refresh *bgp_route_refresh_header;
3028
3029    ND_TCHECK_LEN(pptr, BGP_ROUTE_REFRESH_SIZE);
3030
3031    /* some little sanity checking */
3032    if (len<BGP_ROUTE_REFRESH_SIZE)
3033        return;
3034
3035    bgp_route_refresh_header = (const struct bgp_route_refresh *)pptr;
3036
3037    ND_PRINT("\n\t  AFI %s (%u), SAFI %s (%u)",
3038              tok2str(af_values,"Unknown",
3039                      GET_BE_U_2(bgp_route_refresh_header->afi)),
3040              GET_BE_U_2(bgp_route_refresh_header->afi),
3041              tok2str(bgp_safi_values,"Unknown",
3042                      GET_U_1(bgp_route_refresh_header->safi)),
3043              GET_U_1(bgp_route_refresh_header->safi));
3044
3045    if (ndo->ndo_vflag > 1) {
3046        ND_TCHECK_LEN(pptr, len);
3047        print_unknown_data(ndo, pptr, "\n\t  ", len);
3048    }
3049
3050    return;
3051trunc:
3052    nd_print_trunc(ndo);
3053}
3054
3055static int
3056bgp_pdu_print(netdissect_options *ndo,
3057              const u_char *dat, u_int length)
3058{
3059    const struct bgp *bgp_header;
3060    uint8_t bgp_type;
3061
3062    ND_TCHECK_LEN(dat, BGP_SIZE);
3063    bgp_header = (const struct bgp *)dat;
3064    bgp_type = GET_U_1(bgp_header->bgp_type);
3065
3066    ND_PRINT("\n\t%s Message (%u), length: %u",
3067              tok2str(bgp_msg_values, "Unknown", bgp_type),
3068              bgp_type,
3069              length);
3070
3071    switch (bgp_type) {
3072    case BGP_OPEN:
3073        bgp_open_print(ndo, dat, length);
3074        break;
3075    case BGP_UPDATE:
3076        bgp_update_print(ndo, dat, length);
3077        break;
3078    case BGP_NOTIFICATION:
3079        bgp_notification_print(ndo, dat, length);
3080        break;
3081    case BGP_KEEPALIVE:
3082        break;
3083    case BGP_ROUTE_REFRESH:
3084        bgp_route_refresh_print(ndo, dat, length);
3085        break;
3086    default:
3087        /* we have no decoder for the BGP message */
3088        ND_TCHECK_LEN(dat, length);
3089        ND_PRINT("\n\t  no Message %u decoder", bgp_type);
3090        print_unknown_data(ndo, dat, "\n\t  ", length);
3091        break;
3092    }
3093    return 1;
3094trunc:
3095    nd_print_trunc(ndo);
3096    return 0;
3097}
3098
3099void
3100bgp_print(netdissect_options *ndo,
3101          const u_char *dat, u_int length _U_)
3102{
3103    const u_char *p;
3104    const u_char *ep = ndo->ndo_snapend;
3105    const u_char *start;
3106    const u_char marker[] = {
3107        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3108        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3109    };
3110    const struct bgp *bgp_header;
3111    uint16_t hlen;
3112
3113    ndo->ndo_protocol = "bgp";
3114    ND_PRINT(": BGP");
3115
3116    if (ndo->ndo_vflag < 1) /* lets be less chatty */
3117        return;
3118
3119    p = dat;
3120    start = p;
3121    while (p < ep) {
3122        if (!ND_TTEST_1(p))
3123            break;
3124        if (GET_U_1(p) != 0xff) {
3125            p++;
3126            continue;
3127        }
3128
3129        if (!ND_TTEST_LEN(p, sizeof(marker)))
3130            break;
3131        if (memcmp(p, marker, sizeof(marker)) != 0) {
3132            p++;
3133            continue;
3134        }
3135
3136        /* found BGP header */
3137        ND_TCHECK_LEN(p, BGP_SIZE);
3138        bgp_header = (const struct bgp *)p;
3139
3140        if (start != p)
3141            nd_print_trunc(ndo);
3142
3143        hlen = GET_BE_U_2(bgp_header->bgp_len);
3144        if (hlen < BGP_SIZE) {
3145            ND_PRINT("\nmessage length %u < %u", hlen, BGP_SIZE);
3146            nd_print_invalid(ndo);
3147            break;
3148        }
3149
3150        if (ND_TTEST_LEN(p, hlen)) {
3151            if (!bgp_pdu_print(ndo, p, hlen))
3152                return;
3153            p += hlen;
3154            start = p;
3155        } else {
3156            ND_PRINT("\n[|BGP %s]",
3157                      tok2str(bgp_msg_values,
3158                              "Unknown Message Type",
3159                              GET_U_1(bgp_header->bgp_type)));
3160            break;
3161        }
3162    }
3163
3164    return;
3165
3166trunc:
3167    nd_print_trunc(ndo);
3168}
3169