xref: /netbsd-src/external/bsd/tcpdump/dist/print-bgp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (C) 1999 WIDE Project.
30f74e101Schristos  * All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that the following conditions
70f74e101Schristos  * are met:
80f74e101Schristos  * 1. Redistributions of source code must retain the above copyright
90f74e101Schristos  *    notice, this list of conditions and the following disclaimer.
100f74e101Schristos  * 2. Redistributions in binary form must reproduce the above copyright
110f74e101Schristos  *    notice, this list of conditions and the following disclaimer in the
120f74e101Schristos  *    documentation and/or other materials provided with the distribution.
130f74e101Schristos  * 3. Neither the name of the project nor the names of its contributors
140f74e101Schristos  *    may be used to endorse or promote products derived from this software
150f74e101Schristos  *    without specific prior written permission.
160f74e101Schristos  *
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
180f74e101Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190f74e101Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200f74e101Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
210f74e101Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220f74e101Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230f74e101Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240f74e101Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250f74e101Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260f74e101Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270f74e101Schristos  * SUCH DAMAGE.
280f74e101Schristos  *
2972c96ff3Schristos  * Extensively modified by Hannes Gredler (hannes@gredler.at) for more
300f74e101Schristos  * complete BGP support.
310f74e101Schristos  */
320f74e101Schristos 
3311b3aaa1Schristos #include <sys/cdefs.h>
340f74e101Schristos #ifndef lint
35*26ba0b50Schristos __RCSID("$NetBSD: print-bgp.c,v 1.13 2024/09/02 16:15:30 christos Exp $");
3611b3aaa1Schristos #endif
37b3a00663Schristos 
38dc860a36Sspz /* \summary: Border Gateway Protocol (BGP) printer */
39dc860a36Sspz 
40c74ad251Schristos /* specification: RFC 4271 */
41c74ad251Schristos 
42c74ad251Schristos #include <config.h>
430f74e101Schristos 
44c74ad251Schristos #include "netdissect-stdinc.h"
450f74e101Schristos 
460f74e101Schristos #include <stdio.h>
470f74e101Schristos #include <string.h>
480f74e101Schristos 
49fdccd7e4Schristos #include "netdissect.h"
500f74e101Schristos #include "addrtoname.h"
510f74e101Schristos #include "extract.h"
520f74e101Schristos #include "af.h"
530f74e101Schristos #include "l2vpn.h"
540f74e101Schristos 
550f74e101Schristos struct bgp {
56c74ad251Schristos     nd_byte     bgp_marker[16];
57c74ad251Schristos     nd_uint16_t bgp_len;
58c74ad251Schristos     nd_uint8_t  bgp_type;
590f74e101Schristos };
600f74e101Schristos #define BGP_SIZE        19    /* unaligned */
610f74e101Schristos 
620f74e101Schristos #define BGP_OPEN                1
630f74e101Schristos #define BGP_UPDATE              2
640f74e101Schristos #define BGP_NOTIFICATION        3
650f74e101Schristos #define BGP_KEEPALIVE           4
660f74e101Schristos #define BGP_ROUTE_REFRESH       5
670f74e101Schristos 
68870189d2Schristos static const struct tok bgp_msg_values[] = {
690f74e101Schristos     { BGP_OPEN,                 "Open"},
700f74e101Schristos     { BGP_UPDATE,               "Update"},
710f74e101Schristos     { BGP_NOTIFICATION,         "Notification"},
720f74e101Schristos     { BGP_KEEPALIVE,            "Keepalive"},
730f74e101Schristos     { BGP_ROUTE_REFRESH,        "Route Refresh"},
740f74e101Schristos     { 0, NULL}
750f74e101Schristos };
760f74e101Schristos 
770f74e101Schristos struct bgp_open {
78c74ad251Schristos     nd_byte     bgpo_marker[16];
79c74ad251Schristos     nd_uint16_t bgpo_len;
80c74ad251Schristos     nd_uint8_t  bgpo_type;
81c74ad251Schristos     nd_uint8_t  bgpo_version;
82c74ad251Schristos     nd_uint16_t bgpo_myas;
83c74ad251Schristos     nd_uint16_t bgpo_holdtime;
84c74ad251Schristos     nd_uint32_t bgpo_id;
85c74ad251Schristos     nd_uint8_t  bgpo_optlen;
860f74e101Schristos     /* options should follow */
870f74e101Schristos };
880f74e101Schristos #define BGP_OPEN_SIZE        29    /* unaligned */
890f74e101Schristos 
900f74e101Schristos struct bgp_opt {
91c74ad251Schristos     nd_uint8_t bgpopt_type;
92c74ad251Schristos     nd_uint8_t bgpopt_len;
930f74e101Schristos     /* variable length */
940f74e101Schristos };
950f74e101Schristos #define BGP_OPT_SIZE           2    /* some compilers may pad to 4 bytes */
960e9868baSchristos #define BGP_CAP_HEADER_SIZE    2    /* some compilers may pad to 4 bytes */
970f74e101Schristos 
980f74e101Schristos struct bgp_notification {
99c74ad251Schristos     nd_byte     bgpn_marker[16];
100c74ad251Schristos     nd_uint16_t bgpn_len;
101c74ad251Schristos     nd_uint8_t  bgpn_type;
102c74ad251Schristos     nd_uint8_t  bgpn_major;
103c74ad251Schristos     nd_uint8_t  bgpn_minor;
1040f74e101Schristos };
1050f74e101Schristos #define BGP_NOTIFICATION_SIZE        21    /* unaligned */
1060f74e101Schristos 
1070f74e101Schristos struct bgp_route_refresh {
108c74ad251Schristos     nd_byte     bgp_marker[16];
109c74ad251Schristos     nd_uint16_t len;
110c74ad251Schristos     nd_uint8_t  type;   /* No padding after this; afi is, in fact, not aligned */
111c74ad251Schristos     nd_uint16_t afi;
112c74ad251Schristos     nd_uint8_t  res;
113c74ad251Schristos     nd_uint8_t  safi;
114c74ad251Schristos };
1150f74e101Schristos #define BGP_ROUTE_REFRESH_SIZE          23
1160f74e101Schristos 
1170e9868baSchristos #define bgp_attr_lenlen(flags, p) \
118c74ad251Schristos     (((flags) & 0x10) ? 2U : 1U)
1190e9868baSchristos #define bgp_attr_len(flags, p) \
120c74ad251Schristos     (((flags) & 0x10) ? GET_BE_U_2(p) : GET_U_1(p))
1210f74e101Schristos 
1220f74e101Schristos #define BGPTYPE_ORIGIN                   1
1230f74e101Schristos #define BGPTYPE_AS_PATH                  2
1240f74e101Schristos #define BGPTYPE_NEXT_HOP                 3
1250f74e101Schristos #define BGPTYPE_MULTI_EXIT_DISC          4
1260f74e101Schristos #define BGPTYPE_LOCAL_PREF               5
1270f74e101Schristos #define BGPTYPE_ATOMIC_AGGREGATE         6
1280f74e101Schristos #define BGPTYPE_AGGREGATOR               7
1290f74e101Schristos #define BGPTYPE_COMMUNITIES              8    /* RFC1997 */
130dc860a36Sspz #define BGPTYPE_ORIGINATOR_ID            9    /* RFC4456 */
131dc860a36Sspz #define BGPTYPE_CLUSTER_LIST            10    /* RFC4456 */
132dc860a36Sspz #define BGPTYPE_DPA                     11    /* deprecated, draft-ietf-idr-bgp-dpa */
133dc860a36Sspz #define BGPTYPE_ADVERTISERS             12    /* deprecated RFC1863 */
134dc860a36Sspz #define BGPTYPE_RCID_PATH               13    /* deprecated RFC1863 */
135dc860a36Sspz #define BGPTYPE_MP_REACH_NLRI           14    /* RFC4760 */
136dc860a36Sspz #define BGPTYPE_MP_UNREACH_NLRI         15    /* RFC4760 */
137dc860a36Sspz #define BGPTYPE_EXTD_COMMUNITIES        16    /* RFC4360 */
138dc860a36Sspz #define BGPTYPE_AS4_PATH                17    /* RFC6793 */
139dc860a36Sspz #define BGPTYPE_AGGREGATOR4             18    /* RFC6793 */
140dc860a36Sspz #define BGPTYPE_PMSI_TUNNEL             22    /* RFC6514 */
141dc860a36Sspz #define BGPTYPE_TUNNEL_ENCAP            23    /* RFC5512 */
142dc860a36Sspz #define BGPTYPE_TRAFFIC_ENG             24    /* RFC5543 */
143dc860a36Sspz #define BGPTYPE_IPV6_EXTD_COMMUNITIES   25    /* RFC5701 */
144fdccd7e4Schristos #define BGPTYPE_AIGP                    26    /* RFC7311 */
145dc860a36Sspz #define BGPTYPE_PE_DISTINGUISHER_LABEL  27    /* RFC6514 */
146dc860a36Sspz #define BGPTYPE_ENTROPY_LABEL           28    /* RFC6790 */
147dc860a36Sspz #define BGPTYPE_LARGE_COMMUNITY         32    /* draft-ietf-idr-large-community-05 */
148dc860a36Sspz #define BGPTYPE_ATTR_SET               128    /* RFC6368 */
1490f74e101Schristos 
1500f74e101Schristos #define BGP_MP_NLRI_MINSIZE              3    /* End of RIB Marker detection */
1510f74e101Schristos 
152870189d2Schristos static const struct tok bgp_attr_values[] = {
1530f74e101Schristos     { BGPTYPE_ORIGIN,           "Origin"},
1540f74e101Schristos     { BGPTYPE_AS_PATH,          "AS Path"},
1550f74e101Schristos     { BGPTYPE_AS4_PATH,         "AS4 Path"},
1560f74e101Schristos     { BGPTYPE_NEXT_HOP,         "Next Hop"},
1570f74e101Schristos     { BGPTYPE_MULTI_EXIT_DISC,  "Multi Exit Discriminator"},
1580f74e101Schristos     { BGPTYPE_LOCAL_PREF,       "Local Preference"},
1590f74e101Schristos     { BGPTYPE_ATOMIC_AGGREGATE, "Atomic Aggregate"},
1600f74e101Schristos     { BGPTYPE_AGGREGATOR,       "Aggregator"},
1610f74e101Schristos     { BGPTYPE_AGGREGATOR4,      "Aggregator4"},
1620f74e101Schristos     { BGPTYPE_COMMUNITIES,      "Community"},
1630f74e101Schristos     { BGPTYPE_ORIGINATOR_ID,    "Originator ID"},
1640f74e101Schristos     { BGPTYPE_CLUSTER_LIST,     "Cluster List"},
1650f74e101Schristos     { BGPTYPE_DPA,              "DPA"},
1660f74e101Schristos     { BGPTYPE_ADVERTISERS,      "Advertisers"},
1670f74e101Schristos     { BGPTYPE_RCID_PATH,        "RCID Path / Cluster ID"},
1680f74e101Schristos     { BGPTYPE_MP_REACH_NLRI,    "Multi-Protocol Reach NLRI"},
1690f74e101Schristos     { BGPTYPE_MP_UNREACH_NLRI,  "Multi-Protocol Unreach NLRI"},
1700f74e101Schristos     { BGPTYPE_EXTD_COMMUNITIES, "Extended Community"},
1710f74e101Schristos     { BGPTYPE_PMSI_TUNNEL,      "PMSI Tunnel"},
172dc860a36Sspz     { BGPTYPE_TUNNEL_ENCAP,     "Tunnel Encapsulation"},
173dc860a36Sspz     { BGPTYPE_TRAFFIC_ENG,      "Traffic Engineering"},
174dc860a36Sspz     { BGPTYPE_IPV6_EXTD_COMMUNITIES, "IPv6 Extended Community"},
175fdccd7e4Schristos     { BGPTYPE_AIGP,             "Accumulated IGP Metric"},
176dc860a36Sspz     { BGPTYPE_PE_DISTINGUISHER_LABEL, "PE Distinguisher Label"},
177dc860a36Sspz     { BGPTYPE_ENTROPY_LABEL,    "Entropy Label"},
178dc860a36Sspz     { BGPTYPE_LARGE_COMMUNITY,  "Large Community"},
1790f74e101Schristos     { BGPTYPE_ATTR_SET,         "Attribute Set"},
1800f74e101Schristos     { 255,                      "Reserved for development"},
1810f74e101Schristos     { 0, NULL}
1820f74e101Schristos };
1830f74e101Schristos 
1840f74e101Schristos #define BGP_AS_SET             1
1850f74e101Schristos #define BGP_AS_SEQUENCE        2
1860f74e101Schristos #define BGP_CONFED_AS_SEQUENCE 3 /* draft-ietf-idr-rfc3065bis-01 */
1870f74e101Schristos #define BGP_CONFED_AS_SET      4 /* draft-ietf-idr-rfc3065bis-01  */
1880f74e101Schristos 
1890f74e101Schristos #define BGP_AS_SEG_TYPE_MIN    BGP_AS_SET
1900f74e101Schristos #define BGP_AS_SEG_TYPE_MAX    BGP_CONFED_AS_SET
1910f74e101Schristos 
192870189d2Schristos static const struct tok bgp_as_path_segment_open_values[] = {
1930f74e101Schristos     { BGP_AS_SEQUENCE,         ""},
1940f74e101Schristos     { BGP_AS_SET,              "{ "},
1950f74e101Schristos     { BGP_CONFED_AS_SEQUENCE,  "( "},
1960f74e101Schristos     { BGP_CONFED_AS_SET,       "({ "},
1970f74e101Schristos     { 0, NULL}
1980f74e101Schristos };
1990f74e101Schristos 
200870189d2Schristos static const struct tok bgp_as_path_segment_close_values[] = {
2010f74e101Schristos     { BGP_AS_SEQUENCE,         ""},
2020f74e101Schristos     { BGP_AS_SET,              "}"},
2030f74e101Schristos     { BGP_CONFED_AS_SEQUENCE,  ")"},
2040f74e101Schristos     { BGP_CONFED_AS_SET,       "})"},
2050f74e101Schristos     { 0, NULL}
2060f74e101Schristos };
2070f74e101Schristos 
2080f74e101Schristos #define BGP_OPT_AUTH                    1
2090f74e101Schristos #define BGP_OPT_CAP                     2
2100f74e101Schristos 
211870189d2Schristos static const struct tok bgp_opt_values[] = {
2120f74e101Schristos     { BGP_OPT_AUTH,             "Authentication Information"},
2130f74e101Schristos     { BGP_OPT_CAP,              "Capabilities Advertisement"},
2140f74e101Schristos     { 0, NULL}
2150f74e101Schristos };
2160f74e101Schristos 
217dc860a36Sspz #define BGP_CAPCODE_MP                  1 /* RFC2858 */
218dc860a36Sspz #define BGP_CAPCODE_RR                  2 /* RFC2918 */
219dc860a36Sspz #define BGP_CAPCODE_ORF                 3 /* RFC5291 */
220dc860a36Sspz #define BGP_CAPCODE_MR                  4 /* RFC3107 */
221dc860a36Sspz #define BGP_CAPCODE_EXT_NH              5 /* RFC5549 */
222c74ad251Schristos #define BGP_CAPCODE_ML                  8 /* RFC8277 */
223dc860a36Sspz #define BGP_CAPCODE_RESTART            64 /* RFC4724  */
224dc860a36Sspz #define BGP_CAPCODE_AS_NEW             65 /* RFC6793 */
225dc860a36Sspz #define BGP_CAPCODE_DYN_CAP            67 /* draft-ietf-idr-dynamic-cap */
226dc860a36Sspz #define BGP_CAPCODE_MULTISESS          68 /* draft-ietf-idr-bgp-multisession */
227dc860a36Sspz #define BGP_CAPCODE_ADD_PATH           69 /* RFC7911 */
228dc860a36Sspz #define BGP_CAPCODE_ENH_RR             70 /* draft-keyur-bgp-enhanced-route-refresh */
229c74ad251Schristos #define BGP_CAPCODE_LLGR               71 /* draft-uttaro-idr-bgp-persistence-05 */
2300f74e101Schristos #define BGP_CAPCODE_RR_CISCO          128
2310f74e101Schristos 
232870189d2Schristos static const struct tok bgp_capcode_values[] = {
2330f74e101Schristos     { BGP_CAPCODE_MP,           "Multiprotocol Extensions"},
2340f74e101Schristos     { BGP_CAPCODE_RR,           "Route Refresh"},
2350f74e101Schristos     { BGP_CAPCODE_ORF,          "Cooperative Route Filtering"},
236dc860a36Sspz     { BGP_CAPCODE_MR,           "Multiple Routes to a Destination"},
237dc860a36Sspz     { BGP_CAPCODE_EXT_NH,       "Extended Next Hop Encoding"},
238c74ad251Schristos     { BGP_CAPCODE_ML,           "Multiple Labels"},
2390f74e101Schristos     { BGP_CAPCODE_RESTART,      "Graceful Restart"},
2400f74e101Schristos     { BGP_CAPCODE_AS_NEW,       "32-Bit AS Number"},
2410f74e101Schristos     { BGP_CAPCODE_DYN_CAP,      "Dynamic Capability"},
242dc860a36Sspz     { BGP_CAPCODE_MULTISESS,    "Multisession BGP"},
243fdccd7e4Schristos     { BGP_CAPCODE_ADD_PATH,     "Multiple Paths"},
244dc860a36Sspz     { BGP_CAPCODE_ENH_RR,       "Enhanced Route Refresh"},
245c74ad251Schristos     { BGP_CAPCODE_LLGR,         "Long-lived Graceful Restart"},
2460f74e101Schristos     { BGP_CAPCODE_RR_CISCO,     "Route Refresh (Cisco)"},
2470f74e101Schristos     { 0, NULL}
2480f74e101Schristos };
2490f74e101Schristos 
2500f74e101Schristos #define BGP_NOTIFY_MAJOR_MSG            1
2510f74e101Schristos #define BGP_NOTIFY_MAJOR_OPEN           2
2520f74e101Schristos #define BGP_NOTIFY_MAJOR_UPDATE         3
2530f74e101Schristos #define BGP_NOTIFY_MAJOR_HOLDTIME       4
2540f74e101Schristos #define BGP_NOTIFY_MAJOR_FSM            5
2550f74e101Schristos #define BGP_NOTIFY_MAJOR_CEASE          6
2560f74e101Schristos #define BGP_NOTIFY_MAJOR_CAP            7
2570f74e101Schristos 
258870189d2Schristos static const struct tok bgp_notify_major_values[] = {
2590f74e101Schristos     { BGP_NOTIFY_MAJOR_MSG,     "Message Header Error"},
2600f74e101Schristos     { BGP_NOTIFY_MAJOR_OPEN,    "OPEN Message Error"},
2610f74e101Schristos     { BGP_NOTIFY_MAJOR_UPDATE,  "UPDATE Message Error"},
2620f74e101Schristos     { BGP_NOTIFY_MAJOR_HOLDTIME,"Hold Timer Expired"},
2630f74e101Schristos     { BGP_NOTIFY_MAJOR_FSM,     "Finite State Machine Error"},
2640f74e101Schristos     { BGP_NOTIFY_MAJOR_CEASE,   "Cease"},
2650f74e101Schristos     { BGP_NOTIFY_MAJOR_CAP,     "Capability Message Error"},
2660f74e101Schristos     { 0, NULL}
2670f74e101Schristos };
2680f74e101Schristos 
269c74ad251Schristos /* RFC 4486 */
2700f74e101Schristos #define BGP_NOTIFY_MINOR_CEASE_MAXPRFX  1
271c74ad251Schristos #define BGP_NOTIFY_MINOR_CEASE_SHUT     2
272c74ad251Schristos #define BGP_NOTIFY_MINOR_CEASE_RESET    4
273870189d2Schristos static const struct tok bgp_notify_minor_cease_values[] = {
2740f74e101Schristos     { BGP_NOTIFY_MINOR_CEASE_MAXPRFX, "Maximum Number of Prefixes Reached"},
275c74ad251Schristos     { BGP_NOTIFY_MINOR_CEASE_SHUT,    "Administrative Shutdown"},
2760f74e101Schristos     { 3,                        "Peer Unconfigured"},
277c74ad251Schristos     { BGP_NOTIFY_MINOR_CEASE_RESET,   "Administrative Reset"},
2780f74e101Schristos     { 5,                        "Connection Rejected"},
2790f74e101Schristos     { 6,                        "Other Configuration Change"},
2800f74e101Schristos     { 7,                        "Connection Collision Resolution"},
2810f74e101Schristos     { 0, NULL}
2820f74e101Schristos };
2830f74e101Schristos 
284870189d2Schristos static const struct tok bgp_notify_minor_msg_values[] = {
2850f74e101Schristos     { 1,                        "Connection Not Synchronized"},
2860f74e101Schristos     { 2,                        "Bad Message Length"},
2870f74e101Schristos     { 3,                        "Bad Message Type"},
2880f74e101Schristos     { 0, NULL}
2890f74e101Schristos };
2900f74e101Schristos 
291870189d2Schristos static const struct tok bgp_notify_minor_open_values[] = {
2920f74e101Schristos     { 1,                        "Unsupported Version Number"},
2930f74e101Schristos     { 2,                        "Bad Peer AS"},
2940f74e101Schristos     { 3,                        "Bad BGP Identifier"},
2950f74e101Schristos     { 4,                        "Unsupported Optional Parameter"},
2960f74e101Schristos     { 5,                        "Authentication Failure"},
2970f74e101Schristos     { 6,                        "Unacceptable Hold Time"},
2980f74e101Schristos     { 7,                        "Capability Message Error"},
2990f74e101Schristos     { 0, NULL}
3000f74e101Schristos };
3010f74e101Schristos 
302870189d2Schristos static const struct tok bgp_notify_minor_update_values[] = {
3030f74e101Schristos     { 1,                        "Malformed Attribute List"},
3040f74e101Schristos     { 2,                        "Unrecognized Well-known Attribute"},
3050f74e101Schristos     { 3,                        "Missing Well-known Attribute"},
3060f74e101Schristos     { 4,                        "Attribute Flags Error"},
3070f74e101Schristos     { 5,                        "Attribute Length Error"},
3080f74e101Schristos     { 6,                        "Invalid ORIGIN Attribute"},
3090f74e101Schristos     { 7,                        "AS Routing Loop"},
3100f74e101Schristos     { 8,                        "Invalid NEXT_HOP Attribute"},
3110f74e101Schristos     { 9,                        "Optional Attribute Error"},
3120f74e101Schristos     { 10,                       "Invalid Network Field"},
3130f74e101Schristos     { 11,                       "Malformed AS_PATH"},
3140f74e101Schristos     { 0, NULL}
3150f74e101Schristos };
3160f74e101Schristos 
317dc860a36Sspz static const struct tok bgp_notify_minor_fsm_values[] = {
318c74ad251Schristos     { 0,                        "Unspecified Error"},
319dc860a36Sspz     { 1,                        "In OpenSent State"},
320dc860a36Sspz     { 2,                        "In OpenConfirm State"},
321dc860a36Sspz     { 3,                        "In Established State"},
322dc860a36Sspz     { 0, NULL }
323dc860a36Sspz };
324dc860a36Sspz 
325870189d2Schristos static const struct tok bgp_notify_minor_cap_values[] = {
3260f74e101Schristos     { 1,                        "Invalid Action Value" },
3270f74e101Schristos     { 2,                        "Invalid Capability Length" },
3280f74e101Schristos     { 3,                        "Malformed Capability Value" },
3290f74e101Schristos     { 4,                        "Unsupported Capability Code" },
3300f74e101Schristos     { 0, NULL }
3310f74e101Schristos };
3320f74e101Schristos 
333870189d2Schristos static const struct tok bgp_origin_values[] = {
3340f74e101Schristos     { 0,                        "IGP"},
3350f74e101Schristos     { 1,                        "EGP"},
3360f74e101Schristos     { 2,                        "Incomplete"},
3370f74e101Schristos     { 0, NULL}
3380f74e101Schristos };
3390f74e101Schristos 
3400f74e101Schristos #define BGP_PMSI_TUNNEL_RSVP_P2MP 1
3410f74e101Schristos #define BGP_PMSI_TUNNEL_LDP_P2MP  2
3420f74e101Schristos #define BGP_PMSI_TUNNEL_PIM_SSM   3
3430f74e101Schristos #define BGP_PMSI_TUNNEL_PIM_SM    4
3440f74e101Schristos #define BGP_PMSI_TUNNEL_PIM_BIDIR 5
3450f74e101Schristos #define BGP_PMSI_TUNNEL_INGRESS   6
3460f74e101Schristos #define BGP_PMSI_TUNNEL_LDP_MP2MP 7
3470f74e101Schristos 
348870189d2Schristos static const struct tok bgp_pmsi_tunnel_values[] = {
3490f74e101Schristos     { BGP_PMSI_TUNNEL_RSVP_P2MP, "RSVP-TE P2MP LSP"},
3500f74e101Schristos     { BGP_PMSI_TUNNEL_LDP_P2MP, "LDP P2MP LSP"},
3510f74e101Schristos     { BGP_PMSI_TUNNEL_PIM_SSM, "PIM-SSM Tree"},
3520f74e101Schristos     { BGP_PMSI_TUNNEL_PIM_SM, "PIM-SM Tree"},
3530f74e101Schristos     { BGP_PMSI_TUNNEL_PIM_BIDIR, "PIM-Bidir Tree"},
3540f74e101Schristos     { BGP_PMSI_TUNNEL_INGRESS, "Ingress Replication"},
3550f74e101Schristos     { BGP_PMSI_TUNNEL_LDP_MP2MP, "LDP MP2MP LSP"},
3560f74e101Schristos     { 0, NULL}
3570f74e101Schristos };
3580f74e101Schristos 
359870189d2Schristos static const struct tok bgp_pmsi_flag_values[] = {
3600f74e101Schristos     { 0x01, "Leaf Information required"},
3610f74e101Schristos     { 0, NULL}
3620f74e101Schristos };
3630f74e101Schristos 
364fdccd7e4Schristos #define BGP_AIGP_TLV 1
365fdccd7e4Schristos 
366fdccd7e4Schristos static const struct tok bgp_aigp_values[] = {
367fdccd7e4Schristos     { BGP_AIGP_TLV, "AIGP"},
368fdccd7e4Schristos     { 0, NULL}
369fdccd7e4Schristos };
370fdccd7e4Schristos 
3710f74e101Schristos /* Subsequent address family identifier, RFC2283 section 7 */
3720f74e101Schristos #define SAFNUM_RES                      0
3730f74e101Schristos #define SAFNUM_UNICAST                  1
3740f74e101Schristos #define SAFNUM_MULTICAST                2
375dc860a36Sspz #define SAFNUM_UNIMULTICAST             3       /* deprecated now */
3760f74e101Schristos /* labeled BGP RFC3107 */
3770f74e101Schristos #define SAFNUM_LABUNICAST               4
378dc860a36Sspz /* RFC6514 */
3790f74e101Schristos #define SAFNUM_MULTICAST_VPN            5
380dc860a36Sspz /* draft-nalawade-kapoor-tunnel-safi */
381dc860a36Sspz #define SAFNUM_TUNNEL                   64
382dc860a36Sspz /* RFC4761 */
383dc860a36Sspz #define SAFNUM_VPLS                     65
384dc860a36Sspz /* RFC6037 */
3850f74e101Schristos #define SAFNUM_MDT                      66
386c74ad251Schristos /* RFC7432 */
387c74ad251Schristos #define SAFNUM_EVPN                     70
388dc860a36Sspz /* RFC4364 */
3890f74e101Schristos #define SAFNUM_VPNUNICAST               128
390dc860a36Sspz /* RFC6513 */
3910f74e101Schristos #define SAFNUM_VPNMULTICAST             129
392dc860a36Sspz #define SAFNUM_VPNUNIMULTICAST          130     /* deprecated now */
393dc860a36Sspz /* RFC4684 */
3940f74e101Schristos #define SAFNUM_RT_ROUTING_INFO          132
3950f74e101Schristos 
3960f74e101Schristos #define BGP_VPN_RD_LEN                  8
3970f74e101Schristos 
398870189d2Schristos static const struct tok bgp_safi_values[] = {
3990f74e101Schristos     { SAFNUM_RES,               "Reserved"},
4000f74e101Schristos     { SAFNUM_UNICAST,           "Unicast"},
4010f74e101Schristos     { SAFNUM_MULTICAST,         "Multicast"},
4020f74e101Schristos     { SAFNUM_UNIMULTICAST,      "Unicast+Multicast"},
4030f74e101Schristos     { SAFNUM_LABUNICAST,        "labeled Unicast"},
4040f74e101Schristos     { SAFNUM_TUNNEL,            "Tunnel"},
4050f74e101Schristos     { SAFNUM_VPLS,              "VPLS"},
4060f74e101Schristos     { SAFNUM_MDT,               "MDT"},
407c74ad251Schristos     { SAFNUM_EVPN,              "EVPN"},
4080f74e101Schristos     { SAFNUM_VPNUNICAST,        "labeled VPN Unicast"},
4090f74e101Schristos     { SAFNUM_VPNMULTICAST,      "labeled VPN Multicast"},
4100f74e101Schristos     { SAFNUM_VPNUNIMULTICAST,   "labeled VPN Unicast+Multicast"},
4110f74e101Schristos     { SAFNUM_RT_ROUTING_INFO,   "Route Target Routing Information"},
4120f74e101Schristos     { SAFNUM_MULTICAST_VPN,     "Multicast VPN"},
4130f74e101Schristos     { 0, NULL }
4140f74e101Schristos };
4150f74e101Schristos 
4160f74e101Schristos /* well-known community */
4170f74e101Schristos #define BGP_COMMUNITY_NO_EXPORT              0xffffff01
4180f74e101Schristos #define BGP_COMMUNITY_NO_ADVERT              0xffffff02
4190f74e101Schristos #define BGP_COMMUNITY_NO_EXPORT_SUBCONFED    0xffffff03
4200f74e101Schristos 
421c74ad251Schristos /* Extended community type - RFC 4360 */
4220f74e101Schristos #define BGP_EXT_COM_RT_0        0x0002  /* Route Target,Format AS(2bytes):AN(4bytes) */
4230f74e101Schristos #define BGP_EXT_COM_RT_1        0x0102  /* Route Target,Format IP address:AN(2bytes) */
4240f74e101Schristos #define BGP_EXT_COM_RT_2        0x0202  /* Route Target,Format AN(4bytes):local(2bytes) */
4250f74e101Schristos #define BGP_EXT_COM_RO_0        0x0003  /* Route Origin,Format AS(2bytes):AN(4bytes) */
4260f74e101Schristos #define BGP_EXT_COM_RO_1        0x0103  /* Route Origin,Format IP address:AN(2bytes) */
4270f74e101Schristos #define BGP_EXT_COM_RO_2        0x0203  /* Route Origin,Format AN(4bytes):local(2bytes) */
4280f74e101Schristos #define BGP_EXT_COM_LINKBAND    0x4004  /* Link Bandwidth,Format AS(2B):Bandwidth(4B) */
4290f74e101Schristos                                         /* rfc2547 bgp-mpls-vpns */
4300f74e101Schristos #define BGP_EXT_COM_VPN_ORIGIN  0x0005  /* OSPF Domain ID / VPN of Origin  - draft-rosen-vpns-ospf-bgp-mpls */
431c74ad251Schristos #define BGP_EXT_COM_VPN_ORIGIN2 0x0105  /* duplicate - keep for backwards compatibility */
432c74ad251Schristos #define BGP_EXT_COM_VPN_ORIGIN3 0x0205  /* duplicate - keep for backwards compatibility */
433c74ad251Schristos #define BGP_EXT_COM_VPN_ORIGIN4 0x8005  /* duplicate - keep for backwards compatibility */
4340f74e101Schristos 
4350f74e101Schristos #define BGP_EXT_COM_OSPF_RTYPE  0x0306  /* OSPF Route Type,Format Area(4B):RouteType(1B):Options(1B) */
436c74ad251Schristos #define BGP_EXT_COM_OSPF_RTYPE2 0x8000  /* duplicate - keep for backwards compatibility */
437c74ad251Schristos #define BGP_EXT_COM_ENCAP       0x030c  /* rfc5512 */
4380f74e101Schristos 
4390f74e101Schristos #define BGP_EXT_COM_OSPF_RID    0x0107  /* OSPF Router ID,Format RouterID(4B):Unused(2B) */
440c74ad251Schristos #define BGP_EXT_COM_OSPF_RID2   0x8001  /* duplicate - keep for backwards compatibility */
4410f74e101Schristos 
4420f74e101Schristos #define BGP_EXT_COM_L2INFO      0x800a  /* draft-kompella-ppvpn-l2vpn */
4430f74e101Schristos 
4440e9868baSchristos #define BGP_EXT_COM_SOURCE_AS   0x0009  /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */
4450e9868baSchristos #define BGP_EXT_COM_VRF_RT_IMP  0x010b  /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */
4460e9868baSchristos #define BGP_EXT_COM_L2VPN_RT_0  0x000a  /* L2VPN Identifier,Format AS(2bytes):AN(4bytes) */
4470e9868baSchristos #define BGP_EXT_COM_L2VPN_RT_1  0xF10a  /* L2VPN Identifier,Format IP address:AN(2bytes) */
4480e9868baSchristos 
449c74ad251Schristos /* https://www.cisco.com/en/US/tech/tk436/tk428/technologies_tech_note09186a00801eb09a.shtml  */
4500f74e101Schristos #define BGP_EXT_COM_EIGRP_GEN                    0x8800
4510f74e101Schristos #define BGP_EXT_COM_EIGRP_METRIC_AS_DELAY        0x8801
4520f74e101Schristos #define BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW       0x8802
4530f74e101Schristos #define BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU        0x8803
4540f74e101Schristos #define BGP_EXT_COM_EIGRP_EXT_REMAS_REMID        0x8804
4550f74e101Schristos #define BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC 0x8805
4560f74e101Schristos 
457870189d2Schristos static const struct tok bgp_extd_comm_flag_values[] = {
4580f74e101Schristos     { 0x8000,                  "vendor-specific"},
4590f74e101Schristos     { 0x4000,                  "non-transitive"},
4600f74e101Schristos     { 0, NULL},
4610f74e101Schristos };
4620f74e101Schristos 
463870189d2Schristos static const struct tok bgp_extd_comm_subtype_values[] = {
4640f74e101Schristos     { BGP_EXT_COM_RT_0,        "target"},
4650f74e101Schristos     { BGP_EXT_COM_RT_1,        "target"},
4660f74e101Schristos     { BGP_EXT_COM_RT_2,        "target"},
4670f74e101Schristos     { BGP_EXT_COM_RO_0,        "origin"},
4680f74e101Schristos     { BGP_EXT_COM_RO_1,        "origin"},
4690f74e101Schristos     { BGP_EXT_COM_RO_2,        "origin"},
4700f74e101Schristos     { BGP_EXT_COM_LINKBAND,    "link-BW"},
4710f74e101Schristos     { BGP_EXT_COM_VPN_ORIGIN,  "ospf-domain"},
4720f74e101Schristos     { BGP_EXT_COM_VPN_ORIGIN2, "ospf-domain"},
4730f74e101Schristos     { BGP_EXT_COM_VPN_ORIGIN3, "ospf-domain"},
4740f74e101Schristos     { BGP_EXT_COM_VPN_ORIGIN4, "ospf-domain"},
4750f74e101Schristos     { BGP_EXT_COM_OSPF_RTYPE,  "ospf-route-type"},
4760f74e101Schristos     { BGP_EXT_COM_OSPF_RTYPE2, "ospf-route-type"},
477c74ad251Schristos     { BGP_EXT_COM_ENCAP,       "encapsulation"},
4780f74e101Schristos     { BGP_EXT_COM_OSPF_RID,    "ospf-router-id"},
4790f74e101Schristos     { BGP_EXT_COM_OSPF_RID2,   "ospf-router-id"},
4800f74e101Schristos     { BGP_EXT_COM_L2INFO,      "layer2-info"},
4810f74e101Schristos     { BGP_EXT_COM_EIGRP_GEN,   "eigrp-general-route (flag, tag)" },
4820f74e101Schristos     { BGP_EXT_COM_EIGRP_METRIC_AS_DELAY, "eigrp-route-metric (AS, delay)" },
4830f74e101Schristos     { BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW, "eigrp-route-metric (reliability, nexthop, bandwidth)" },
4840f74e101Schristos     { BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU, "eigrp-route-metric (load, MTU)" },
4850f74e101Schristos     { BGP_EXT_COM_EIGRP_EXT_REMAS_REMID, "eigrp-external-route (remote-AS, remote-ID)" },
4860f74e101Schristos     { BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC, "eigrp-external-route (remote-proto, remote-metric)" },
4870f74e101Schristos     { BGP_EXT_COM_SOURCE_AS, "source-AS" },
4880f74e101Schristos     { BGP_EXT_COM_VRF_RT_IMP, "vrf-route-import"},
4890e9868baSchristos     { BGP_EXT_COM_L2VPN_RT_0, "l2vpn-id"},
4900e9868baSchristos     { BGP_EXT_COM_L2VPN_RT_1, "l2vpn-id"},
4910f74e101Schristos     { 0, NULL},
4920f74e101Schristos };
4930f74e101Schristos 
494c74ad251Schristos /* RFC RFC5512 BGP Tunnel Encapsulation Attribute Tunnel Types */
495c74ad251Schristos #define BGP_ENCAP_TUNNEL_L2TPV3_IP  1
496c74ad251Schristos #define BGP_ENCAP_TUNNEL_GRE        2
497c74ad251Schristos #define BGP_ENCAP_TUNNEL_TRANSMIT   3
498c74ad251Schristos #define BGP_ENCAP_TUNNEL_IPSEC      4
499c74ad251Schristos #define BGP_ENCAP_TUNNEL_IP_IPSEC   5
500c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS_IP    6
501c74ad251Schristos #define BGP_ENCAP_TUNNEL_IP_IP      7
502c74ad251Schristos #define BGP_ENCAP_TUNNEL_VXLAN      8
503c74ad251Schristos #define BGP_ENCAP_TUNNEL_NVGRE      9
504c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS       10
505c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS_GRE   11
506c74ad251Schristos #define BGP_ENCAP_TUNNEL_VXLAN_GPE  12
507c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS_UDP   13
508c74ad251Schristos #define BGP_ENCAP_TUNNEL_IPV6       14
509c74ad251Schristos #define BGP_ENCAP_TUNNEL_SR_TE      15
510c74ad251Schristos #define BGP_ENCAP_TUNNEL_BARE       16
511c74ad251Schristos #define BGP_ENCAP_TUNNEL_SR         17
512c74ad251Schristos 
513c74ad251Schristos static const struct tok bgp_extd_comm_encap_tunnel_values[] = {
514c74ad251Schristos     { BGP_ENCAP_TUNNEL_L2TPV3_IP,    "L2TPv3 over IP"},
515c74ad251Schristos     { BGP_ENCAP_TUNNEL_GRE,          "GRE"},
516c74ad251Schristos     { BGP_ENCAP_TUNNEL_TRANSMIT,     "Transmit Tunnel"},
517c74ad251Schristos     { BGP_ENCAP_TUNNEL_IPSEC,        "IPsec"},
518c74ad251Schristos     { BGP_ENCAP_TUNNEL_IP_IPSEC,     "IP in IP with IPsec"},
519c74ad251Schristos     { BGP_ENCAP_TUNNEL_MPLS_IP,      "MPLS in IP with IPsec"},
520c74ad251Schristos     { BGP_ENCAP_TUNNEL_IP_IP,        "IP in IP"},
521c74ad251Schristos     { BGP_ENCAP_TUNNEL_VXLAN,        "VXLAN"},
522c74ad251Schristos     { BGP_ENCAP_TUNNEL_NVGRE,        "NVGRE"},
523c74ad251Schristos     { BGP_ENCAP_TUNNEL_MPLS,         "MPLS"},
524c74ad251Schristos     { BGP_ENCAP_TUNNEL_MPLS_GRE,     "MPLS in GRE"},
525c74ad251Schristos     { BGP_ENCAP_TUNNEL_VXLAN_GPE,    "VXLAN GPE"},
526c74ad251Schristos     { BGP_ENCAP_TUNNEL_MPLS_UDP,     "MPLS in UDP"},
527c74ad251Schristos     { BGP_ENCAP_TUNNEL_IPV6,         "IPv6"},
528c74ad251Schristos     { BGP_ENCAP_TUNNEL_SR_TE,        "SR TE"},
529c74ad251Schristos     { BGP_ENCAP_TUNNEL_BARE,         "Bare"},
530c74ad251Schristos     { BGP_ENCAP_TUNNEL_SR,           "SR"},
531c74ad251Schristos     { 0, NULL},
532c74ad251Schristos };
533c74ad251Schristos 
5340f74e101Schristos /* OSPF codes for  BGP_EXT_COM_OSPF_RTYPE draft-rosen-vpns-ospf-bgp-mpls  */
5350f74e101Schristos #define BGP_OSPF_RTYPE_RTR      1 /* OSPF Router LSA */
5360f74e101Schristos #define BGP_OSPF_RTYPE_NET      2 /* OSPF Network LSA */
5370f74e101Schristos #define BGP_OSPF_RTYPE_SUM      3 /* OSPF Summary LSA */
5380f74e101Schristos #define BGP_OSPF_RTYPE_EXT      5 /* OSPF External LSA, note that ASBR doesn't apply to MPLS-VPN */
5390f74e101Schristos #define BGP_OSPF_RTYPE_NSSA     7 /* OSPF NSSA External*/
5400f74e101Schristos #define BGP_OSPF_RTYPE_SHAM     129 /* OSPF-MPLS-VPN Sham link */
5410f74e101Schristos #define BGP_OSPF_RTYPE_METRIC_TYPE 0x1 /* LSB of RTYPE Options Field */
5420f74e101Schristos 
543870189d2Schristos static const struct tok bgp_extd_comm_ospf_rtype_values[] = {
5440f74e101Schristos   { BGP_OSPF_RTYPE_RTR, "Router" },
5450f74e101Schristos   { BGP_OSPF_RTYPE_NET, "Network" },
5460f74e101Schristos   { BGP_OSPF_RTYPE_SUM, "Summary" },
5470f74e101Schristos   { BGP_OSPF_RTYPE_EXT, "External" },
5480f74e101Schristos   { BGP_OSPF_RTYPE_NSSA,"NSSA External" },
5490f74e101Schristos   { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" },
5500f74e101Schristos   { 0, NULL },
5510f74e101Schristos };
5520f74e101Schristos 
553fdccd7e4Schristos /* ADD-PATH Send/Receive field values */
554fdccd7e4Schristos static const struct tok bgp_add_path_recvsend[] = {
555fdccd7e4Schristos     { 1, "Receive" },
556fdccd7e4Schristos     { 2, "Send" },
557fdccd7e4Schristos     { 3, "Both" },
558fdccd7e4Schristos     { 0, NULL },
559fdccd7e4Schristos };
560fdccd7e4Schristos 
561c74ad251Schristos #define AS_STR_SIZE sizeof("xxxxx.xxxxx")
5620f74e101Schristos 
5630f74e101Schristos /*
5640f74e101Schristos  * as_printf
5650f74e101Schristos  *
5660f74e101Schristos  * Convert an AS number into a string and return string pointer.
5670f74e101Schristos  *
568b3a00663Schristos  * Depending on bflag is set or not, AS number is converted into ASDOT notation
5690f74e101Schristos  * or plain number notation.
5700f74e101Schristos  *
5710f74e101Schristos  */
5720f74e101Schristos static char *
573b3a00663Schristos as_printf(netdissect_options *ndo,
574c74ad251Schristos           char *str, size_t size, u_int asnum)
5750f74e101Schristos {
576b3a00663Schristos     if (!ndo->ndo_bflag || asnum <= 0xFFFF) {
5770f74e101Schristos         snprintf(str, size, "%u", asnum);
5780f74e101Schristos     } else {
5790f74e101Schristos         snprintf(str, size, "%u.%u", asnum >> 16, asnum & 0xFFFF);
5800f74e101Schristos     }
5810f74e101Schristos     return str;
5820f74e101Schristos }
5830f74e101Schristos 
5840e9868baSchristos #define ITEMCHECK(minlen) if (itemlen < minlen) goto badtlv;
5850e9868baSchristos 
5860f74e101Schristos int
587b3a00663Schristos decode_prefix4(netdissect_options *ndo,
588c74ad251Schristos                const u_char *pptr, u_int itemlen, char *buf, size_t buflen)
5890f74e101Schristos {
590c74ad251Schristos     nd_ipv4 addr;
5910e9868baSchristos     u_int plen, plenbytes;
5920f74e101Schristos 
5930e9868baSchristos     ITEMCHECK(1);
594c74ad251Schristos     plen = GET_U_1(pptr);
5950f74e101Schristos     if (32 < plen)
5960f74e101Schristos         return -1;
5970e9868baSchristos     itemlen -= 1;
5980f74e101Schristos 
5990f74e101Schristos     memset(&addr, 0, sizeof(addr));
6000e9868baSchristos     plenbytes = (plen + 7) / 8;
6010e9868baSchristos     ITEMCHECK(plenbytes);
602c74ad251Schristos     GET_CPY_BYTES(&addr, pptr + 1, plenbytes);
6030f74e101Schristos     if (plen % 8) {
604c74ad251Schristos         ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
6050f74e101Schristos     }
606c74ad251Schristos     snprintf(buf, buflen, "%s/%u", ipaddr_string(ndo, (const u_char *)&addr), plen);
6070e9868baSchristos     return 1 + plenbytes;
6080f74e101Schristos 
6090e9868baSchristos badtlv:
610c74ad251Schristos     return -2;
6110f74e101Schristos }
6120f74e101Schristos 
6130f74e101Schristos static int
614b3a00663Schristos decode_labeled_prefix4(netdissect_options *ndo,
615c74ad251Schristos                        const u_char *pptr, u_int itemlen, char *buf,
616c74ad251Schristos                        size_t buflen)
6170f74e101Schristos {
618c74ad251Schristos     nd_ipv4 addr;
6190e9868baSchristos     u_int plen, plenbytes;
6200f74e101Schristos 
6210e9868baSchristos     /* prefix length and label = 4 bytes */
622c74ad251Schristos     ND_TCHECK_4(pptr);
6230e9868baSchristos     ITEMCHECK(4);
624c74ad251Schristos     plen = GET_U_1(pptr);   /* get prefix length */
6250f74e101Schristos 
6260f74e101Schristos     /* this is one of the weirdnesses of rfc3107
6270f74e101Schristos        the label length (actually the label + COS bits)
6280f74e101Schristos        is added to the prefix length;
6290f74e101Schristos        we also do only read out just one label -
6300f74e101Schristos        there is no real application for advertisement of
631ba2ff121Schristos        stacked labels in a single BGP message
6320f74e101Schristos     */
6330f74e101Schristos 
6340f74e101Schristos     if (24 > plen)
6350f74e101Schristos         return -1;
6360f74e101Schristos 
6370f74e101Schristos     plen-=24; /* adjust prefixlen - labellength */
6380f74e101Schristos 
6390f74e101Schristos     if (32 < plen)
6400f74e101Schristos         return -1;
6410e9868baSchristos     itemlen -= 4;
6420f74e101Schristos 
6430f74e101Schristos     memset(&addr, 0, sizeof(addr));
6440e9868baSchristos     plenbytes = (plen + 7) / 8;
6450e9868baSchristos     ITEMCHECK(plenbytes);
646c74ad251Schristos     GET_CPY_BYTES(&addr, pptr + 4, plenbytes);
6470f74e101Schristos     if (plen % 8) {
648c74ad251Schristos         ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
6490f74e101Schristos     }
6500f74e101Schristos     /* the label may get offsetted by 4 bits so lets shift it right */
651c74ad251Schristos     snprintf(buf, buflen, "%s/%u, label:%u %s",
652c74ad251Schristos              ipaddr_string(ndo, (const u_char *)&addr),
6530f74e101Schristos              plen,
654c74ad251Schristos              GET_BE_U_3(pptr + 1)>>4,
655c74ad251Schristos              ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
6560f74e101Schristos 
6570e9868baSchristos     return 4 + plenbytes;
6580f74e101Schristos 
6590f74e101Schristos trunc:
6600f74e101Schristos     return -2;
6610e9868baSchristos 
6620e9868baSchristos badtlv:
6630e9868baSchristos     return -3;
6640f74e101Schristos }
6650f74e101Schristos 
6660f74e101Schristos /*
6670f74e101Schristos  * bgp_vpn_ip_print
6680f74e101Schristos  *
669c74ad251Schristos  * print an ipv4 or ipv6 address into a buffer dependent on address length.
6700f74e101Schristos  */
6710f74e101Schristos static char *
672b3a00663Schristos bgp_vpn_ip_print(netdissect_options *ndo,
673ba2ff121Schristos                  const u_char *pptr, u_int addr_length)
674ba2ff121Schristos {
6750f74e101Schristos 
6760f74e101Schristos     /* worst case string is s fully formatted v6 address */
6770f74e101Schristos     static char addr[sizeof("1234:5678:89ab:cdef:1234:5678:89ab:cdef")];
6780f74e101Schristos     char *pos = addr;
6790f74e101Schristos 
6800f74e101Schristos     switch(addr_length) {
681c74ad251Schristos     case (sizeof(nd_ipv4) << 3): /* 32 */
682c74ad251Schristos         snprintf(pos, sizeof(addr), "%s", GET_IPADDR_STRING(pptr));
6830f74e101Schristos         break;
684c74ad251Schristos     case (sizeof(nd_ipv6) << 3): /* 128 */
685c74ad251Schristos         snprintf(pos, sizeof(addr), "%s", GET_IP6ADDR_STRING(pptr));
6860f74e101Schristos         break;
6870f74e101Schristos     default:
6880f74e101Schristos         snprintf(pos, sizeof(addr), "bogus address length %u", addr_length);
6890f74e101Schristos         break;
6900f74e101Schristos     }
6910f74e101Schristos     pos += strlen(pos);
6920f74e101Schristos 
6930f74e101Schristos     *(pos) = '\0';
6940f74e101Schristos     return (addr);
6950f74e101Schristos }
6960f74e101Schristos 
6970f74e101Schristos /*
6980f74e101Schristos  * bgp_vpn_sg_print
6990f74e101Schristos  *
7000f74e101Schristos  * print an multicast s,g entry into a buffer.
7010f74e101Schristos  * the s,g entry is encoded like this.
7020f74e101Schristos  *
7030f74e101Schristos  * +-----------------------------------+
7040f74e101Schristos  * | Multicast Source Length (1 octet) |
7050f74e101Schristos  * +-----------------------------------+
7060f74e101Schristos  * |   Multicast Source (Variable)     |
7070f74e101Schristos  * +-----------------------------------+
7080f74e101Schristos  * |  Multicast Group Length (1 octet) |
7090f74e101Schristos  * +-----------------------------------+
7100f74e101Schristos  * |  Multicast Group   (Variable)     |
7110f74e101Schristos  * +-----------------------------------+
7120f74e101Schristos  *
7130f74e101Schristos  * return the number of bytes read from the wire.
7140f74e101Schristos  */
715c74ad251Schristos static u_int
716b3a00663Schristos bgp_vpn_sg_print(netdissect_options *ndo,
717c74ad251Schristos                  const u_char *pptr, char *buf, size_t buflen)
718ba2ff121Schristos {
719b3a00663Schristos     uint8_t addr_length;
7200f74e101Schristos     u_int total_length, offset;
7210f74e101Schristos 
7220f74e101Schristos     total_length = 0;
7230f74e101Schristos 
7240f74e101Schristos     /* Source address length, encoded in bits */
725c74ad251Schristos     addr_length = GET_U_1(pptr);
726c74ad251Schristos     pptr++;
7270f74e101Schristos 
7280f74e101Schristos     /* Source address */
729c74ad251Schristos     ND_TCHECK_LEN(pptr, (addr_length >> 3));
7300f74e101Schristos     total_length += (addr_length >> 3) + 1;
731c74ad251Schristos     offset = (u_int)strlen(buf);
7320f74e101Schristos     if (addr_length) {
7330f74e101Schristos         snprintf(buf + offset, buflen - offset, ", Source %s",
734b3a00663Schristos              bgp_vpn_ip_print(ndo, pptr, addr_length));
7350f74e101Schristos         pptr += (addr_length >> 3);
7360f74e101Schristos     }
7370f74e101Schristos 
7380f74e101Schristos     /* Group address length, encoded in bits */
739c74ad251Schristos     addr_length = GET_U_1(pptr);
740c74ad251Schristos     pptr++;
7410f74e101Schristos 
7420f74e101Schristos     /* Group address */
743c74ad251Schristos     ND_TCHECK_LEN(pptr, (addr_length >> 3));
7440f74e101Schristos     total_length += (addr_length >> 3) + 1;
745c74ad251Schristos     offset = (u_int)strlen(buf);
7460f74e101Schristos     if (addr_length) {
7470f74e101Schristos         snprintf(buf + offset, buflen - offset, ", Group %s",
748b3a00663Schristos              bgp_vpn_ip_print(ndo, pptr, addr_length));
7490f74e101Schristos         pptr += (addr_length >> 3);
7500f74e101Schristos     }
7510f74e101Schristos 
7520f74e101Schristos trunc:
7530f74e101Schristos     return (total_length);
7540f74e101Schristos }
7550f74e101Schristos 
756c74ad251Schristos /* Print an RFC 4364 Route Distinguisher */
757c74ad251Schristos const char *
758b3a00663Schristos bgp_vpn_rd_print(netdissect_options *ndo,
759ba2ff121Schristos                  const u_char *pptr)
760ba2ff121Schristos {
7610f74e101Schristos     /* allocate space for the largest possible string */
762c74ad251Schristos     static char rd[sizeof("xxxxx.xxxxx:xxxxx (xxx.xxx.xxx.xxx:xxxxx)")];
7630f74e101Schristos     char *pos = rd;
764c74ad251Schristos     /* allocate space for the largest possible string */
765c74ad251Schristos     char astostr[AS_STR_SIZE];
7660f74e101Schristos 
7670f74e101Schristos     /* ok lets load the RD format */
768c74ad251Schristos     switch (GET_BE_U_2(pptr)) {
7690f74e101Schristos 
7700f74e101Schristos     case 0:
771c74ad251Schristos         /* 2-byte-AS:number fmt */
7720f74e101Schristos         snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (= %u.%u.%u.%u)",
773c74ad251Schristos                     GET_BE_U_2(pptr + 2),
774c74ad251Schristos                     GET_BE_U_4(pptr + 4),
775c74ad251Schristos                     GET_U_1(pptr + 4), GET_U_1(pptr + 5),
776c74ad251Schristos                     GET_U_1(pptr + 6), GET_U_1(pptr + 7));
7770f74e101Schristos         break;
7780f74e101Schristos 
7790f74e101Schristos     case 1:
780c74ad251Schristos         /* IP-address:AS fmt */
7810f74e101Schristos         snprintf(pos, sizeof(rd) - (pos - rd), "%u.%u.%u.%u:%u",
782c74ad251Schristos                     GET_U_1(pptr + 2), GET_U_1(pptr + 3),
783c74ad251Schristos                     GET_U_1(pptr + 4), GET_U_1(pptr + 5),
784c74ad251Schristos                     GET_BE_U_2(pptr + 6));
7850f74e101Schristos         break;
7860f74e101Schristos 
7870f74e101Schristos     case 2:
788c74ad251Schristos         /* 4-byte-AS:number fmt */
7890f74e101Schristos         snprintf(pos, sizeof(rd) - (pos - rd), "%s:%u (%u.%u.%u.%u:%u)",
790c74ad251Schristos                     as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 2)),
791c74ad251Schristos                     GET_BE_U_2(pptr + 6), GET_U_1(pptr + 2),
792c74ad251Schristos                     GET_U_1(pptr + 3), GET_U_1(pptr + 4),
793c74ad251Schristos                     GET_U_1(pptr + 5), GET_BE_U_2(pptr + 6));
7940f74e101Schristos         break;
7950f74e101Schristos     default:
7960f74e101Schristos         snprintf(pos, sizeof(rd) - (pos - rd), "unknown RD format");
7970f74e101Schristos         break;
7980f74e101Schristos     }
7990f74e101Schristos     pos += strlen(pos);
8000f74e101Schristos     *(pos) = '\0';
8010f74e101Schristos     return (rd);
8020f74e101Schristos }
8030f74e101Schristos 
804c74ad251Schristos /*
805c74ad251Schristos  * Print an RFC 4360 Extended Community.
806c74ad251Schristos  */
807c74ad251Schristos static void
808c74ad251Schristos bgp_extended_community_print(netdissect_options *ndo,
809c74ad251Schristos                              const u_char *pptr)
810c74ad251Schristos {
811c74ad251Schristos     union { /* copy buffer for bandwidth values */
812c74ad251Schristos         float f;
813c74ad251Schristos         uint32_t i;
814c74ad251Schristos     } bw;
815c74ad251Schristos     /* allocate space for the largest possible string */
816c74ad251Schristos     char astostr[AS_STR_SIZE];
817c74ad251Schristos 
818c74ad251Schristos     switch (GET_BE_U_2(pptr)) {
819c74ad251Schristos 
820c74ad251Schristos     case BGP_EXT_COM_RT_0:
821c74ad251Schristos     case BGP_EXT_COM_RO_0:
822c74ad251Schristos     case BGP_EXT_COM_L2VPN_RT_0:
823c74ad251Schristos         ND_PRINT("%u:%u (= %s)",
824c74ad251Schristos                  GET_BE_U_2(pptr + 2),
825c74ad251Schristos                  GET_BE_U_4(pptr + 4),
826c74ad251Schristos                  GET_IPADDR_STRING(pptr+4));
827c74ad251Schristos         break;
828c74ad251Schristos 
829c74ad251Schristos     case BGP_EXT_COM_RT_1:
830c74ad251Schristos     case BGP_EXT_COM_RO_1:
831c74ad251Schristos     case BGP_EXT_COM_L2VPN_RT_1:
832c74ad251Schristos     case BGP_EXT_COM_VRF_RT_IMP:
833c74ad251Schristos         ND_PRINT("%s:%u",
834c74ad251Schristos                  GET_IPADDR_STRING(pptr+2),
835c74ad251Schristos                  GET_BE_U_2(pptr + 6));
836c74ad251Schristos         break;
837c74ad251Schristos 
838c74ad251Schristos     case BGP_EXT_COM_RT_2:
839c74ad251Schristos         case BGP_EXT_COM_RO_2:
840c74ad251Schristos             ND_PRINT("%s:%u",
841c74ad251Schristos                      as_printf(ndo, astostr, sizeof(astostr),
842c74ad251Schristos                      GET_BE_U_4(pptr + 2)), GET_BE_U_2(pptr + 6));
843c74ad251Schristos             break;
844c74ad251Schristos 
845c74ad251Schristos     case BGP_EXT_COM_LINKBAND:
846c74ad251Schristos             bw.i = GET_BE_U_4(pptr + 4);
847c74ad251Schristos             ND_PRINT("bandwidth: %.3f Mbps",
848c74ad251Schristos                      bw.f*8/1000000);
849c74ad251Schristos             break;
850c74ad251Schristos 
851c74ad251Schristos     case BGP_EXT_COM_VPN_ORIGIN:
852c74ad251Schristos     case BGP_EXT_COM_VPN_ORIGIN2:
853c74ad251Schristos     case BGP_EXT_COM_VPN_ORIGIN3:
854c74ad251Schristos     case BGP_EXT_COM_VPN_ORIGIN4:
855c74ad251Schristos     case BGP_EXT_COM_OSPF_RID:
856c74ad251Schristos     case BGP_EXT_COM_OSPF_RID2:
857c74ad251Schristos         ND_PRINT("%s", GET_IPADDR_STRING(pptr+2));
858c74ad251Schristos         break;
859c74ad251Schristos 
860c74ad251Schristos     case BGP_EXT_COM_OSPF_RTYPE:
861c74ad251Schristos     case BGP_EXT_COM_OSPF_RTYPE2:
862c74ad251Schristos         ND_PRINT("area:%s, router-type:%s, metric-type:%s%s",
863c74ad251Schristos                  GET_IPADDR_STRING(pptr+2),
864c74ad251Schristos                  tok2str(bgp_extd_comm_ospf_rtype_values,
865c74ad251Schristos                          "unknown (0x%02x)",
866c74ad251Schristos                          GET_U_1((pptr + 6))),
867c74ad251Schristos                  (GET_U_1(pptr + 7) &  BGP_OSPF_RTYPE_METRIC_TYPE) ? "E2" : "",
868c74ad251Schristos                  ((GET_U_1(pptr + 6) == BGP_OSPF_RTYPE_EXT) || (GET_U_1(pptr + 6) == BGP_OSPF_RTYPE_NSSA)) ? "E1" : "");
869c74ad251Schristos         break;
870c74ad251Schristos 
871c74ad251Schristos     case BGP_EXT_COM_L2INFO:
872c74ad251Schristos         ND_PRINT("%s Control Flags [0x%02x]:MTU %u",
873c74ad251Schristos                  tok2str(l2vpn_encaps_values,
874c74ad251Schristos                          "unknown encaps",
875c74ad251Schristos                          GET_U_1((pptr + 2))),
876c74ad251Schristos                  GET_U_1((pptr + 3)),
877c74ad251Schristos                  GET_BE_U_2(pptr + 4));
878c74ad251Schristos         break;
879c74ad251Schristos 
880c74ad251Schristos     case BGP_EXT_COM_SOURCE_AS:
881c74ad251Schristos         ND_PRINT("AS %u", GET_BE_U_2(pptr + 2));
882c74ad251Schristos         break;
883c74ad251Schristos 
884c74ad251Schristos     case BGP_EXT_COM_ENCAP:
885c74ad251Schristos         ND_PRINT("Tunnel type: %s", tok2str(bgp_extd_comm_encap_tunnel_values,
886c74ad251Schristos                                            "unknown encaps",
887c74ad251Schristos                                            GET_BE_U_2(pptr + 6)));
888c74ad251Schristos         break;
889c74ad251Schristos 
890c74ad251Schristos     default:
891c74ad251Schristos         ND_PRINT("%02x%02x%02x%02x%02x%02x",
892c74ad251Schristos                  GET_U_1(pptr + 2),
893c74ad251Schristos                  GET_U_1(pptr + 3),
894c74ad251Schristos                  GET_U_1(pptr + 4),
895c74ad251Schristos                  GET_U_1(pptr + 5),
896c74ad251Schristos                  GET_U_1(pptr + 6),
897c74ad251Schristos                  GET_U_1(pptr + 7));
898c74ad251Schristos         break;
899c74ad251Schristos     }
900c74ad251Schristos }
901c74ad251Schristos 
902c74ad251Schristos /*
903c74ad251Schristos  * RFC4684 (Section 4)/RFC2858 (Section 4).
904c74ad251Schristos  * RTC membership prefix is structured as follows
905c74ad251Schristos  * [prefix-len] [origin-as] [route-target]
906c74ad251Schristos  * The route-target is encoded as RT ext-comms.
907c74ad251Schristos  * Prefix-len may be 0, 32..96
908c74ad251Schristos  *
909c74ad251Schristos  * Note that pptr is not packet data - it is
910c74ad251Schristos  * a buffer owned by our caller - therefore GET_*
911c74ad251Schristos  * macros can not be used.
912c74ad251Schristos  */
913c74ad251Schristos static char *
914c74ad251Schristos bgp_rt_prefix_print(netdissect_options *ndo,
915c74ad251Schristos                     const u_char *pptr,
916c74ad251Schristos                     u_int plen)
917c74ad251Schristos {
918c74ad251Schristos     /* allocate space for the largest possible string */
919c74ad251Schristos     char rtc_prefix_in_hex[sizeof("0000 0000 0000 0000")] = "";
920c74ad251Schristos     u_int rtc_prefix_in_hex_len = 0;
921c74ad251Schristos     static char output[61]; /* max response string */
922c74ad251Schristos     /* allocate space for the largest possible string */
923c74ad251Schristos     char astostr[AS_STR_SIZE];
924c74ad251Schristos     uint16_t ec_type = 0;
925c74ad251Schristos     u_int octet_count;
926c74ad251Schristos     u_int i;
927c74ad251Schristos 
928c74ad251Schristos     if (plen == 0) {
929c74ad251Schristos         snprintf(output, sizeof(output), "route-target: 0:0/0");
930c74ad251Schristos         return (output);
931c74ad251Schristos     }
932c74ad251Schristos 
933c74ad251Schristos     /* hex representation of the prefix */
934c74ad251Schristos     octet_count = (plen+7)/8;
935c74ad251Schristos     for (i=0; i<octet_count; i++) {
936c74ad251Schristos         rtc_prefix_in_hex_len += snprintf(rtc_prefix_in_hex+rtc_prefix_in_hex_len,
937c74ad251Schristos                                 sizeof(rtc_prefix_in_hex)-rtc_prefix_in_hex_len,
938c74ad251Schristos                                 "%02x%s", *(pptr+i),
939c74ad251Schristos                                 ((i%2 == 1) && (i<octet_count-1)) ? " " : "");
940c74ad251Schristos             }
941c74ad251Schristos 
942c74ad251Schristos     if (plen < 16) {
943c74ad251Schristos 	/*
944c74ad251Schristos 	 * The prefix is too short to include the full ext-comm type,
945c74ad251Schristos 	 * so we have no way to parse it further.
946c74ad251Schristos 	 */
947c74ad251Schristos         snprintf(output, sizeof(output), "route-target: partial-type: (%s/%d)",
948c74ad251Schristos                  rtc_prefix_in_hex, plen);
949c74ad251Schristos         return (output);
950c74ad251Schristos     }
951c74ad251Schristos 
952c74ad251Schristos     /*
953c74ad251Schristos      * get the ext-comm type
954c74ad251Schristos      * Note: pptr references a static 8 octet buffer with unused bits set to 0,
955c74ad251Schristos      * hence EXTRACT_*() macros are safe.
956c74ad251Schristos      */
957c74ad251Schristos     ec_type = EXTRACT_BE_U_2(pptr);
958c74ad251Schristos     switch (ec_type) {
959c74ad251Schristos     case BGP_EXT_COM_RT_0:
960c74ad251Schristos         /* 2-byte-AS:number fmt */
961c74ad251Schristos         snprintf(output, sizeof(output), "route-target: %u:%u/%d (%s)",
962c74ad251Schristos                  EXTRACT_BE_U_2(pptr+2),
963c74ad251Schristos                  EXTRACT_BE_U_4(pptr+4),
964c74ad251Schristos                  plen, rtc_prefix_in_hex);
965c74ad251Schristos         break;
966c74ad251Schristos 
967c74ad251Schristos     case BGP_EXT_COM_RT_1:
968c74ad251Schristos         /* IP-address:AS fmt */
969c74ad251Schristos         snprintf(output, sizeof(output), "route-target: %u.%u.%u.%u:%u/%d (%s)",
970c74ad251Schristos                  *(pptr+2), *(pptr+3), *(pptr+4), *(pptr+5),
971c74ad251Schristos                  EXTRACT_BE_U_2(pptr+6), plen, rtc_prefix_in_hex);
972c74ad251Schristos         break;
973c74ad251Schristos 
974c74ad251Schristos     case BGP_EXT_COM_RT_2:
975c74ad251Schristos         /* 4-byte-AS:number fmt */
976c74ad251Schristos         snprintf(output, sizeof(output), "route-target: %s:%u/%d (%s)",
977c74ad251Schristos                  as_printf(ndo, astostr, sizeof(astostr), EXTRACT_BE_U_4(pptr+2)),
978c74ad251Schristos                  EXTRACT_BE_U_2(pptr+6), plen, rtc_prefix_in_hex);
979c74ad251Schristos         break;
980c74ad251Schristos 
981c74ad251Schristos     default:
982c74ad251Schristos         snprintf(output, sizeof(output), "route target: unknown-type(%04x) (%s/%d)",
983c74ad251Schristos                  ec_type,
984c74ad251Schristos                  rtc_prefix_in_hex, plen);
985c74ad251Schristos         break;
986c74ad251Schristos     }
987c74ad251Schristos     return (output);
988c74ad251Schristos }
989c74ad251Schristos 
990c74ad251Schristos /* RFC 4684 */
9910f74e101Schristos static int
992b3a00663Schristos decode_rt_routing_info(netdissect_options *ndo,
993c74ad251Schristos                        const u_char *pptr)
9940f74e101Schristos {
995b3a00663Schristos     uint8_t route_target[8];
9960f74e101Schristos     u_int plen;
997c74ad251Schristos     /* allocate space for the largest possible string */
998c74ad251Schristos     char astostr[AS_STR_SIZE];
999c74ad251Schristos     u_int num_octets;
10000f74e101Schristos 
100172c96ff3Schristos     /* NLRI "prefix length" from RFC 2858 Section 4. */
1002c74ad251Schristos     plen = GET_U_1(pptr);   /* get prefix length */
10030f74e101Schristos 
100472c96ff3Schristos     /* NLRI "prefix" (ibid), valid lengths are { 0, 32, 33, ..., 96 } bits.
100572c96ff3Schristos      * RFC 4684 Section 4 defines the layout of "origin AS" and "route
100672c96ff3Schristos      * target" fields inside the "prefix" depending on its length.
100772c96ff3Schristos      */
1008ba2ff121Schristos     if (0 == plen) {
100972c96ff3Schristos         /* Without "origin AS", without "route target". */
1010c74ad251Schristos         ND_PRINT("\n\t      default route target");
1011ba2ff121Schristos         return 1;
1012ba2ff121Schristos     }
10130f74e101Schristos 
1014c74ad251Schristos     if (32 > plen) {
1015c74ad251Schristos         ND_PRINT("\n\t      (illegal prefix length)");
10160f74e101Schristos         return -1;
1017c74ad251Schristos     }
10180f74e101Schristos 
101972c96ff3Schristos     /* With at least "origin AS", possibly with "route target". */
1020c74ad251Schristos     as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 1));
102172c96ff3Schristos 
10220f74e101Schristos     plen -= 32; /* adjust prefix length */
10230f74e101Schristos 
1024c74ad251Schristos     if (64 < plen) {
1025c74ad251Schristos         ND_PRINT("\n\t      (illegal prefix length)");
10260f74e101Schristos         return -1;
1027c74ad251Schristos     }
10280f74e101Schristos 
102972c96ff3Schristos     /* From now on (plen + 7) / 8 evaluates to { 0, 1, 2, ..., 8 }
103072c96ff3Schristos      * and gives the number of octets in the variable-length "route
103172c96ff3Schristos      * target" field inside this NLRI "prefix". Look for it.
103272c96ff3Schristos      */
10330f74e101Schristos     memset(&route_target, 0, sizeof(route_target));
1034c74ad251Schristos     num_octets = (plen + 7) / 8;
1035c74ad251Schristos     GET_CPY_BYTES(&route_target, pptr + 5, num_octets);
1036c74ad251Schristos     /* If mask-len is not on octet boundary, ensure all extra bits are 0 */
10370f74e101Schristos     if (plen % 8) {
1038c74ad251Schristos         ((u_char *)&route_target)[num_octets - 1] &=
10390f74e101Schristos             ((0xff00 >> (plen % 8)) & 0xff);
10400f74e101Schristos     }
1041c74ad251Schristos     ND_PRINT("\n\t      origin AS: %s, %s",
1042c74ad251Schristos              astostr,
1043c74ad251Schristos              bgp_rt_prefix_print(ndo, (u_char *)&route_target, plen));
10440f74e101Schristos 
1045c74ad251Schristos     return 5 + num_octets;
10460f74e101Schristos }
10470f74e101Schristos 
10480f74e101Schristos static int
1049b3a00663Schristos decode_labeled_vpn_prefix4(netdissect_options *ndo,
1050c74ad251Schristos                            const u_char *pptr, char *buf, size_t buflen)
10510f74e101Schristos {
1052c74ad251Schristos     nd_ipv4 addr;
10530f74e101Schristos     u_int plen;
10540f74e101Schristos 
1055c74ad251Schristos     plen = GET_U_1(pptr);   /* get prefix length */
10560f74e101Schristos 
10570f74e101Schristos     if ((24+64) > plen)
10580f74e101Schristos         return -1;
10590f74e101Schristos 
10600f74e101Schristos     plen -= (24+64); /* adjust prefixlen - labellength - RD len*/
10610f74e101Schristos 
10620f74e101Schristos     if (32 < plen)
10630f74e101Schristos         return -1;
10640f74e101Schristos 
10650f74e101Schristos     memset(&addr, 0, sizeof(addr));
1066c74ad251Schristos     GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
10670f74e101Schristos     if (plen % 8) {
10680f74e101Schristos         ((u_char *)&addr)[(plen + 7) / 8 - 1] &=
10690f74e101Schristos             ((0xff00 >> (plen % 8)) & 0xff);
10700f74e101Schristos     }
10710f74e101Schristos     /* the label may get offsetted by 4 bits so lets shift it right */
1072c74ad251Schristos     snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s",
1073b3a00663Schristos                 bgp_vpn_rd_print(ndo, pptr+4),
1074c74ad251Schristos                 ipaddr_string(ndo, (const u_char *)&addr),
10750f74e101Schristos                 plen,
1076c74ad251Schristos                 GET_BE_U_3(pptr + 1)>>4,
1077c74ad251Schristos                 ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
10780f74e101Schristos 
10790f74e101Schristos     return 12 + (plen + 7) / 8;
10800f74e101Schristos }
10810f74e101Schristos 
10820f74e101Schristos /*
10830f74e101Schristos  * +-------------------------------+
10840f74e101Schristos  * |                               |
10850f74e101Schristos  * |  RD:IPv4-address (12 octets)  |
10860f74e101Schristos  * |                               |
10870f74e101Schristos  * +-------------------------------+
10880f74e101Schristos  * |  MDT Group-address (4 octets) |
10890f74e101Schristos  * +-------------------------------+
10900f74e101Schristos  */
10910f74e101Schristos 
10920f74e101Schristos #define MDT_VPN_NLRI_LEN 16
10930f74e101Schristos 
10940f74e101Schristos static int
1095b3a00663Schristos decode_mdt_vpn_nlri(netdissect_options *ndo,
1096c74ad251Schristos                     const u_char *pptr, char *buf, size_t buflen)
10970f74e101Schristos {
10980f74e101Schristos     const u_char *rd;
10990f74e101Schristos     const u_char *vpn_ip;
11000f74e101Schristos 
11010f74e101Schristos     /* if the NLRI is not predefined length, quit.*/
1102c74ad251Schristos     if (GET_U_1(pptr) != MDT_VPN_NLRI_LEN * 8)
11030f74e101Schristos         return -1;
11040f74e101Schristos     pptr++;
11050f74e101Schristos 
11060f74e101Schristos     /* RD */
1107c74ad251Schristos     ND_TCHECK_8(pptr);
11080f74e101Schristos     rd = pptr;
11090f74e101Schristos     pptr += 8;
11100f74e101Schristos 
11110f74e101Schristos     /* IPv4 address */
11120f74e101Schristos     vpn_ip = pptr;
1113c74ad251Schristos     pptr += sizeof(nd_ipv4);
11140f74e101Schristos 
11150f74e101Schristos     /* MDT Group Address */
11160f74e101Schristos     snprintf(buf, buflen, "RD: %s, VPN IP Address: %s, MC Group Address: %s",
1117c74ad251Schristos                 bgp_vpn_rd_print(ndo, rd), GET_IPADDR_STRING(vpn_ip), GET_IPADDR_STRING(pptr));
11180f74e101Schristos 
11190f74e101Schristos     return MDT_VPN_NLRI_LEN + 1;
11200f74e101Schristos 
11210f74e101Schristos  trunc:
11220f74e101Schristos     return -2;
11230f74e101Schristos }
11240f74e101Schristos 
11250f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI   1
11260f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI   2
11270f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI            3
11280f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF 4
11290f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE     5
11300f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN  6
11310f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN  7
11320f74e101Schristos 
1133870189d2Schristos static const struct tok bgp_multicast_vpn_route_type_values[] = {
11340f74e101Schristos     { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI, "Intra-AS I-PMSI"},
11350f74e101Schristos     { BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI, "Inter-AS I-PMSI"},
11360f74e101Schristos     { BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI, "S-PMSI"},
11370f74e101Schristos     { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF, "Intra-AS Segment-Leaf"},
11380f74e101Schristos     { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE, "Source-Active"},
11390f74e101Schristos     { BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN, "Shared Tree Join"},
11400f74e101Schristos     { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN, "Source Tree Join"},
114172c96ff3Schristos     { 0, NULL}
11420f74e101Schristos };
11430f74e101Schristos 
1144a8e08e94Skamil UNALIGNED_OK
11450f74e101Schristos static int
1146b3a00663Schristos decode_multicast_vpn(netdissect_options *ndo,
1147c74ad251Schristos                      const u_char *pptr, char *buf, size_t buflen)
11480f74e101Schristos {
1149c74ad251Schristos     /* allocate space for the largest possible string */
1150c74ad251Schristos     char astostr[AS_STR_SIZE];
1151c74ad251Schristos     uint8_t route_type, route_length;
1152c74ad251Schristos     u_int addr_length, sg_length;
11530f74e101Schristos     u_int offset;
11540f74e101Schristos 
1155c74ad251Schristos     route_type = GET_U_1(pptr);
1156c74ad251Schristos     pptr++;
1157c74ad251Schristos     route_length = GET_U_1(pptr);
1158c74ad251Schristos     pptr++;
11590f74e101Schristos 
11600f74e101Schristos     snprintf(buf, buflen, "Route-Type: %s (%u), length: %u",
11610f74e101Schristos          tok2str(bgp_multicast_vpn_route_type_values,
11620f74e101Schristos                  "Unknown", route_type),
11630f74e101Schristos          route_type, route_length);
11640f74e101Schristos 
11650f74e101Schristos     switch(route_type) {
11660f74e101Schristos     case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI:
1167c74ad251Schristos         ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN);
1168*26ba0b50Schristos         if (route_length < BGP_VPN_RD_LEN)
1169*26ba0b50Schristos             goto trunc;
1170c74ad251Schristos         offset = (u_int)strlen(buf);
11710f74e101Schristos         snprintf(buf + offset, buflen - offset, ", RD: %s, Originator %s",
1172b3a00663Schristos                     bgp_vpn_rd_print(ndo, pptr),
1173b3a00663Schristos                     bgp_vpn_ip_print(ndo, pptr + BGP_VPN_RD_LEN,
11740f74e101Schristos                                      (route_length - BGP_VPN_RD_LEN) << 3));
11750f74e101Schristos         break;
11760f74e101Schristos     case BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI:
1177c74ad251Schristos         ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4);
1178c74ad251Schristos         offset = (u_int)strlen(buf);
11790f74e101Schristos         snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s",
1180b3a00663Schristos         bgp_vpn_rd_print(ndo, pptr),
1181b3a00663Schristos         as_printf(ndo, astostr, sizeof(astostr),
1182c74ad251Schristos         GET_BE_U_4(pptr + BGP_VPN_RD_LEN)));
11830f74e101Schristos         break;
11840f74e101Schristos 
11850f74e101Schristos     case BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI:
1186c74ad251Schristos         ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN);
1187c74ad251Schristos         offset = (u_int)strlen(buf);
11880f74e101Schristos         snprintf(buf + offset, buflen - offset, ", RD: %s",
1189b3a00663Schristos                     bgp_vpn_rd_print(ndo, pptr));
11900f74e101Schristos         pptr += BGP_VPN_RD_LEN;
11910f74e101Schristos 
1192b3a00663Schristos         sg_length = bgp_vpn_sg_print(ndo, pptr, buf, buflen);
11930f74e101Schristos         addr_length =  route_length - sg_length;
11940f74e101Schristos 
1195c74ad251Schristos         ND_TCHECK_LEN(pptr, addr_length);
1196c74ad251Schristos         offset = (u_int)strlen(buf);
11970f74e101Schristos         snprintf(buf + offset, buflen - offset, ", Originator %s",
1198b3a00663Schristos                     bgp_vpn_ip_print(ndo, pptr, addr_length << 3));
11990f74e101Schristos         break;
12000f74e101Schristos 
12010f74e101Schristos     case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE:
1202c74ad251Schristos         ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN);
1203c74ad251Schristos         offset = (u_int)strlen(buf);
12040f74e101Schristos         snprintf(buf + offset, buflen - offset, ", RD: %s",
1205b3a00663Schristos                     bgp_vpn_rd_print(ndo, pptr));
12060f74e101Schristos         pptr += BGP_VPN_RD_LEN;
12070f74e101Schristos 
1208b3a00663Schristos         bgp_vpn_sg_print(ndo, pptr, buf, buflen);
12090f74e101Schristos         break;
12100f74e101Schristos 
12110f74e101Schristos     case BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN: /* fall through */
12120f74e101Schristos     case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN:
1213c74ad251Schristos         ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4);
1214c74ad251Schristos         offset = (u_int)strlen(buf);
12150f74e101Schristos         snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s",
1216b3a00663Schristos                     bgp_vpn_rd_print(ndo, pptr),
1217b3a00663Schristos                     as_printf(ndo, astostr, sizeof(astostr),
1218c74ad251Schristos                     GET_BE_U_4(pptr + BGP_VPN_RD_LEN)));
121972c96ff3Schristos         pptr += BGP_VPN_RD_LEN + 4;
12200f74e101Schristos 
1221b3a00663Schristos         bgp_vpn_sg_print(ndo, pptr, buf, buflen);
12220f74e101Schristos         break;
12230f74e101Schristos 
12240f74e101Schristos         /*
12250f74e101Schristos          * no per route-type printing yet.
12260f74e101Schristos          */
12270f74e101Schristos     case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF:
12280f74e101Schristos     default:
12290f74e101Schristos         break;
12300f74e101Schristos     }
12310f74e101Schristos 
12320f74e101Schristos     return route_length + 2;
12330f74e101Schristos 
12340f74e101Schristos trunc:
12350f74e101Schristos     return -2;
12360f74e101Schristos }
12370f74e101Schristos 
12380f74e101Schristos /*
12390f74e101Schristos  * As I remember, some versions of systems have an snprintf() that
12400f74e101Schristos  * returns -1 if the buffer would have overflowed.  If the return
12410f74e101Schristos  * value is negative, set buflen to 0, to indicate that we've filled
12420f74e101Schristos  * the buffer up.
12430f74e101Schristos  *
12440f74e101Schristos  * If the return value is greater than buflen, that means that
12450f74e101Schristos  * the buffer would have overflowed; again, set buflen to 0 in
12460f74e101Schristos  * that case.
12470f74e101Schristos  */
1248fdccd7e4Schristos #define UPDATE_BUF_BUFLEN(buf, buflen, stringlen) \
1249fdccd7e4Schristos     if (stringlen<0) \
12500f74e101Schristos         buflen=0; \
1251fdccd7e4Schristos     else if ((u_int)stringlen>buflen) \
12520f74e101Schristos         buflen=0; \
12530f74e101Schristos     else { \
1254fdccd7e4Schristos         buflen-=stringlen; \
1255fdccd7e4Schristos         buf+=stringlen; \
12560f74e101Schristos     }
12570f74e101Schristos 
12580f74e101Schristos static int
1259b3a00663Schristos decode_labeled_vpn_l2(netdissect_options *ndo,
1260c74ad251Schristos                       const u_char *pptr, char *buf, size_t buflen)
12610f74e101Schristos {
1262c74ad251Schristos     u_int plen, tlen, tlv_type, tlv_len, ttlv_len;
1263c74ad251Schristos     int stringlen;
12640f74e101Schristos 
1265c74ad251Schristos     plen = GET_BE_U_2(pptr);
12660f74e101Schristos     tlen = plen;
12670f74e101Schristos     pptr += 2;
12680e9868baSchristos     /* Old and new L2VPN NLRI share AFI/SAFI
12690e9868baSchristos      *   -> Assume a 12 Byte-length NLRI is auto-discovery-only
12700e9868baSchristos      *      and > 17 as old format. Complain for the middle case
12710e9868baSchristos      */
12720e9868baSchristos     if (plen == 12) {
12730e9868baSchristos         /* assume AD-only with RD, BGPNH */
1274c74ad251Schristos         ND_TCHECK_LEN(pptr, 12);
12750e9868baSchristos         buf[0] = '\0';
1276fdccd7e4Schristos         stringlen = snprintf(buf, buflen, "RD: %s, BGPNH: %s",
1277b3a00663Schristos                                 bgp_vpn_rd_print(ndo, pptr),
1278c74ad251Schristos                                 GET_IPADDR_STRING(pptr+8));
1279fdccd7e4Schristos         UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
12800e9868baSchristos         pptr += 12;
12810e9868baSchristos         tlen -= 12;
1282c74ad251Schristos         return plen + 2;
12830e9868baSchristos     } else if (plen > 17) {
12840e9868baSchristos         /* assume old format */
12850e9868baSchristos         /* RD, ID, LBLKOFF, LBLBASE */
12860e9868baSchristos 
1287c74ad251Schristos         ND_TCHECK_LEN(pptr, 15);
12880f74e101Schristos         buf[0] = '\0';
1289fdccd7e4Schristos         stringlen = snprintf(buf, buflen, "RD: %s, CE-ID: %u, Label-Block Offset: %u, Label Base %u",
1290b3a00663Schristos                                 bgp_vpn_rd_print(ndo, pptr),
1291c74ad251Schristos                                 GET_BE_U_2(pptr + 8),
1292c74ad251Schristos                                 GET_BE_U_2(pptr + 10),
1293c74ad251Schristos                                 GET_BE_U_3(pptr + 12)>>4); /* the label is offsetted by 4 bits so lets shift it right */
1294fdccd7e4Schristos         UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
12950f74e101Schristos         pptr += 15;
12960f74e101Schristos         tlen -= 15;
12970f74e101Schristos 
12980f74e101Schristos         /* ok now the variable part - lets read out TLVs*/
1299c74ad251Schristos         while (tlen != 0) {
1300c74ad251Schristos             if (tlen < 3) {
1301c74ad251Schristos                 if (buflen != 0) {
1302c74ad251Schristos                     stringlen=snprintf(buf,buflen, "\n\t\tran past the end");
1303c74ad251Schristos                     UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1304c74ad251Schristos                 }
1305c74ad251Schristos                 return plen + 2;
1306c74ad251Schristos             }
1307c74ad251Schristos             tlv_type = GET_U_1(pptr);
1308c74ad251Schristos             pptr++;
1309c74ad251Schristos             tlv_len = GET_BE_U_2(pptr);  /* length, in *bits* */
1310c74ad251Schristos             ttlv_len = (tlv_len + 7)/8;      /* length, in *bytes* */
13110f74e101Schristos             pptr += 2;
13120f74e101Schristos 
13130f74e101Schristos             switch(tlv_type) {
13140f74e101Schristos             case 1:
13150f74e101Schristos                 if (buflen != 0) {
1316fdccd7e4Schristos                     stringlen=snprintf(buf,buflen, "\n\t\tcircuit status vector (%u) length: %u: 0x",
13170f74e101Schristos                                           tlv_type,
13180f74e101Schristos                                           tlv_len);
1319fdccd7e4Schristos                     UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
13200f74e101Schristos                 }
1321c74ad251Schristos                 while (ttlv_len != 0) {
1322c74ad251Schristos                     if (tlen < 1) {
13230f74e101Schristos                         if (buflen != 0) {
1324c74ad251Schristos                             stringlen=snprintf(buf,buflen, " (ran past the end)");
1325c74ad251Schristos                             UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
1326c74ad251Schristos                         }
1327c74ad251Schristos                         return plen + 2;
1328c74ad251Schristos                     }
1329c74ad251Schristos                     ND_TCHECK_1(pptr);
1330c74ad251Schristos                     if (buflen != 0) {
1331c74ad251Schristos                         stringlen=snprintf(buf,buflen, "%02x",
1332c74ad251Schristos                                               GET_U_1(pptr));
1333c74ad251Schristos                         pptr++;
1334fdccd7e4Schristos                         UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
13350f74e101Schristos                     }
13360f74e101Schristos                     ttlv_len--;
1337c74ad251Schristos                     tlen--;
13380f74e101Schristos                 }
13390f74e101Schristos                 break;
13400f74e101Schristos             default:
13410f74e101Schristos                 if (buflen != 0) {
1342fdccd7e4Schristos                     stringlen=snprintf(buf,buflen, "\n\t\tunknown TLV #%u, length: %u",
13430f74e101Schristos                                           tlv_type,
13440f74e101Schristos                                           tlv_len);
1345fdccd7e4Schristos                     UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
13460f74e101Schristos                 }
1347c74ad251Schristos                 if (tlen < ttlv_len) {
1348c74ad251Schristos                     if (buflen != 0) {
1349c74ad251Schristos                         stringlen=snprintf(buf,buflen, " (ran past the end)");
1350c74ad251Schristos                         UPDATE_BUF_BUFLEN(buf, buflen, stringlen);
13510f74e101Schristos                     }
13520f74e101Schristos                     return plen + 2;
1353c74ad251Schristos                 }
1354c74ad251Schristos                 tlen -= ttlv_len;
1355c74ad251Schristos                 break;
1356c74ad251Schristos             }
1357c74ad251Schristos         }
1358c74ad251Schristos         return plen + 2;
13590e9868baSchristos     } else {
13600e9868baSchristos         /* complain bitterly ? */
13610e9868baSchristos         /* fall through */
13620e9868baSchristos         goto trunc;
13630e9868baSchristos     }
13640e9868baSchristos 
13650f74e101Schristos trunc:
13660f74e101Schristos     return -2;
13670f74e101Schristos }
13680f74e101Schristos 
13690f74e101Schristos int
1370b3a00663Schristos decode_prefix6(netdissect_options *ndo,
1371c74ad251Schristos                const u_char *pd, u_int itemlen, char *buf, size_t buflen)
13720f74e101Schristos {
1373c74ad251Schristos     nd_ipv6 addr;
13740e9868baSchristos     u_int plen, plenbytes;
13750f74e101Schristos 
13760e9868baSchristos     ITEMCHECK(1);
1377c74ad251Schristos     plen = GET_U_1(pd);
13780f74e101Schristos     if (128 < plen)
13790f74e101Schristos         return -1;
13800e9868baSchristos     itemlen -= 1;
13810f74e101Schristos 
13820f74e101Schristos     memset(&addr, 0, sizeof(addr));
13830e9868baSchristos     plenbytes = (plen + 7) / 8;
13840e9868baSchristos     ITEMCHECK(plenbytes);
1385c74ad251Schristos     GET_CPY_BYTES(&addr, pd + 1, plenbytes);
13860f74e101Schristos     if (plen % 8) {
1387c74ad251Schristos         addr[plenbytes - 1] &=
13880f74e101Schristos             ((0xff00 >> (plen % 8)) & 0xff);
13890f74e101Schristos     }
1390c74ad251Schristos     snprintf(buf, buflen, "%s/%u", ip6addr_string(ndo, (const u_char *)&addr), plen);
13910e9868baSchristos     return 1 + plenbytes;
13920f74e101Schristos 
13930e9868baSchristos badtlv:
1394c74ad251Schristos     return -2;
13950f74e101Schristos }
13960f74e101Schristos 
13970f74e101Schristos static int
1398b3a00663Schristos decode_labeled_prefix6(netdissect_options *ndo,
1399c74ad251Schristos                const u_char *pptr, u_int itemlen, char *buf, size_t buflen)
14000f74e101Schristos {
1401c74ad251Schristos     nd_ipv6 addr;
14020e9868baSchristos     u_int plen, plenbytes;
14030f74e101Schristos 
14040e9868baSchristos     /* prefix length and label = 4 bytes */
1405c74ad251Schristos     ND_TCHECK_4(pptr);
14060e9868baSchristos     ITEMCHECK(4);
1407c74ad251Schristos     plen = GET_U_1(pptr); /* get prefix length */
14080f74e101Schristos 
14090f74e101Schristos     if (24 > plen)
14100f74e101Schristos         return -1;
14110f74e101Schristos 
14120f74e101Schristos     plen -= 24; /* adjust prefixlen - labellength */
14130f74e101Schristos 
14140f74e101Schristos     if (128 < plen)
14150f74e101Schristos         return -1;
14160e9868baSchristos     itemlen -= 4;
14170f74e101Schristos 
14180f74e101Schristos     memset(&addr, 0, sizeof(addr));
14190e9868baSchristos     plenbytes = (plen + 7) / 8;
1420c74ad251Schristos     GET_CPY_BYTES(&addr, pptr + 4, plenbytes);
14210f74e101Schristos     if (plen % 8) {
1422c74ad251Schristos         addr[plenbytes - 1] &=
14230f74e101Schristos             ((0xff00 >> (plen % 8)) & 0xff);
14240f74e101Schristos     }
14250f74e101Schristos     /* the label may get offsetted by 4 bits so lets shift it right */
1426c74ad251Schristos     snprintf(buf, buflen, "%s/%u, label:%u %s",
1427c74ad251Schristos                 ip6addr_string(ndo, (const u_char *)&addr),
14280f74e101Schristos                 plen,
1429c74ad251Schristos                 GET_BE_U_3(pptr + 1)>>4,
1430c74ad251Schristos                 ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
14310f74e101Schristos 
14320e9868baSchristos     return 4 + plenbytes;
14330f74e101Schristos 
14340f74e101Schristos trunc:
14350f74e101Schristos     return -2;
14360e9868baSchristos 
14370e9868baSchristos badtlv:
14380e9868baSchristos     return -3;
14390f74e101Schristos }
14400f74e101Schristos 
14410f74e101Schristos static int
1442b3a00663Schristos decode_labeled_vpn_prefix6(netdissect_options *ndo,
1443c74ad251Schristos                            const u_char *pptr, char *buf, size_t buflen)
14440f74e101Schristos {
1445c74ad251Schristos     nd_ipv6 addr;
14460f74e101Schristos     u_int plen;
14470f74e101Schristos 
1448c74ad251Schristos     plen = GET_U_1(pptr);   /* get prefix length */
14490f74e101Schristos 
14500f74e101Schristos     if ((24+64) > plen)
14510f74e101Schristos         return -1;
14520f74e101Schristos 
14530f74e101Schristos     plen -= (24+64); /* adjust prefixlen - labellength - RD len*/
14540f74e101Schristos 
14550f74e101Schristos     if (128 < plen)
14560f74e101Schristos         return -1;
14570f74e101Schristos 
14580f74e101Schristos     memset(&addr, 0, sizeof(addr));
1459c74ad251Schristos     GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
14600f74e101Schristos     if (plen % 8) {
1461c74ad251Schristos         addr[(plen + 7) / 8 - 1] &=
14620f74e101Schristos             ((0xff00 >> (plen % 8)) & 0xff);
14630f74e101Schristos     }
14640f74e101Schristos     /* the label may get offsetted by 4 bits so lets shift it right */
1465c74ad251Schristos     snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s",
1466b3a00663Schristos                 bgp_vpn_rd_print(ndo, pptr+4),
1467c74ad251Schristos                 ip6addr_string(ndo, (const u_char *)&addr),
14680f74e101Schristos                 plen,
1469c74ad251Schristos                 GET_BE_U_3(pptr + 1)>>4,
1470c74ad251Schristos                 ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
14710f74e101Schristos 
14720f74e101Schristos     return 12 + (plen + 7) / 8;
14730f74e101Schristos }
14740f74e101Schristos 
14750f74e101Schristos static int
1476b3a00663Schristos decode_clnp_prefix(netdissect_options *ndo,
1477c74ad251Schristos                    const u_char *pptr, char *buf, size_t buflen)
14780f74e101Schristos {
1479b3a00663Schristos     uint8_t addr[19];
14800f74e101Schristos     u_int plen;
14810f74e101Schristos 
1482c74ad251Schristos     plen = GET_U_1(pptr); /* get prefix length */
14830f74e101Schristos 
14840f74e101Schristos     if (152 < plen)
14850f74e101Schristos         return -1;
14860f74e101Schristos 
14870f74e101Schristos     memset(&addr, 0, sizeof(addr));
1488c74ad251Schristos     GET_CPY_BYTES(&addr, pptr + 4, (plen + 7) / 8);
14890f74e101Schristos     if (plen % 8) {
14900f74e101Schristos         addr[(plen + 7) / 8 - 1] &=
14910f74e101Schristos             ((0xff00 >> (plen % 8)) & 0xff);
14920f74e101Schristos     }
1493c74ad251Schristos     /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */
1494c74ad251Schristos     snprintf(buf, buflen, "%s/%u",
1495fdccd7e4Schristos                 isonsap_string(ndo, addr,(plen + 7) / 8),
14960f74e101Schristos                 plen);
14970f74e101Schristos 
14980f74e101Schristos     return 1 + (plen + 7) / 8;
14990f74e101Schristos }
15000f74e101Schristos 
15010f74e101Schristos static int
1502b3a00663Schristos decode_labeled_vpn_clnp_prefix(netdissect_options *ndo,
1503c74ad251Schristos                                const u_char *pptr, char *buf, size_t buflen)
15040f74e101Schristos {
1505b3a00663Schristos     uint8_t addr[19];
15060f74e101Schristos     u_int plen;
15070f74e101Schristos 
1508c74ad251Schristos     plen = GET_U_1(pptr);   /* get prefix length */
15090f74e101Schristos 
15100f74e101Schristos     if ((24+64) > plen)
15110f74e101Schristos         return -1;
15120f74e101Schristos 
15130f74e101Schristos     plen -= (24+64); /* adjust prefixlen - labellength - RD len*/
15140f74e101Schristos 
15150f74e101Schristos     if (152 < plen)
15160f74e101Schristos         return -1;
15170f74e101Schristos 
15180f74e101Schristos     memset(&addr, 0, sizeof(addr));
1519c74ad251Schristos     GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8);
15200f74e101Schristos     if (plen % 8) {
1521c74ad251Schristos         addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
15220f74e101Schristos     }
15230f74e101Schristos     /* the label may get offsetted by 4 bits so lets shift it right */
1524c74ad251Schristos     /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */
1525c74ad251Schristos     snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s",
1526b3a00663Schristos                 bgp_vpn_rd_print(ndo, pptr+4),
1527fdccd7e4Schristos                 isonsap_string(ndo, addr,(plen + 7) / 8),
15280f74e101Schristos                 plen,
1529c74ad251Schristos                 GET_BE_U_3(pptr + 1)>>4,
1530c74ad251Schristos                 ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" );
15310f74e101Schristos 
15320f74e101Schristos     return 12 + (plen + 7) / 8;
15330f74e101Schristos }
15340f74e101Schristos 
15350f74e101Schristos /*
15360f74e101Schristos  * bgp_attr_get_as_size
15370f74e101Schristos  *
15380f74e101Schristos  * Try to find the size of the ASs encoded in an as-path. It is not obvious, as
15390f74e101Schristos  * both Old speakers that do not support 4 byte AS, and the new speakers that do
15400f74e101Schristos  * support, exchange AS-Path with the same path-attribute type value 0x02.
15410f74e101Schristos  */
1542c74ad251Schristos static u_int
1543b3a00663Schristos bgp_attr_get_as_size(netdissect_options *ndo,
1544c74ad251Schristos                      uint8_t bgpa_type, const u_char *pptr, u_int len)
15450f74e101Schristos {
15460f74e101Schristos     const u_char *tptr = pptr;
15470f74e101Schristos 
15480f74e101Schristos     /*
15490f74e101Schristos      * If the path attribute is the optional AS4 path type, then we already
15500f74e101Schristos      * know, that ASs must be encoded in 4 byte format.
15510f74e101Schristos      */
15520f74e101Schristos     if (bgpa_type == BGPTYPE_AS4_PATH) {
15530f74e101Schristos         return 4;
15540f74e101Schristos     }
15550f74e101Schristos 
15560f74e101Schristos     /*
15570f74e101Schristos      * Let us assume that ASs are of 2 bytes in size, and check if the AS-Path
15580f74e101Schristos      * TLV is good. If not, ask the caller to try with AS encoded as 4 bytes
15590f74e101Schristos      * each.
15600f74e101Schristos      */
15610f74e101Schristos     while (tptr < pptr + len) {
15620f74e101Schristos         /*
15630f74e101Schristos          * If we do not find a valid segment type, our guess might be wrong.
15640f74e101Schristos          */
1565c74ad251Schristos         if (GET_U_1(tptr) < BGP_AS_SEG_TYPE_MIN || GET_U_1(tptr) > BGP_AS_SEG_TYPE_MAX) {
15660f74e101Schristos             goto trunc;
15670f74e101Schristos         }
1568c74ad251Schristos         tptr += 2 + GET_U_1(tptr + 1) * 2;
15690f74e101Schristos     }
15700f74e101Schristos 
15710f74e101Schristos     /*
15720f74e101Schristos      * If we correctly reached end of the AS path attribute data content,
15730f74e101Schristos      * then most likely ASs were indeed encoded as 2 bytes.
15740f74e101Schristos      */
15750f74e101Schristos     if (tptr == pptr + len) {
15760f74e101Schristos         return 2;
15770f74e101Schristos     }
15780f74e101Schristos 
15790f74e101Schristos trunc:
15800f74e101Schristos 
15810f74e101Schristos     /*
15820f74e101Schristos      * We can come here, either we did not have enough data, or if we
15830f74e101Schristos      * try to decode 4 byte ASs in 2 byte format. Either way, return 4,
1584*26ba0b50Schristos      * so that caller can try to decode each AS as of 4 bytes. If indeed
15850f74e101Schristos      * there was not enough data, it will crib and end the parse anyways.
15860f74e101Schristos      */
15870f74e101Schristos     return 4;
15880f74e101Schristos }
15890f74e101Schristos 
1590c74ad251Schristos /*
1591c74ad251Schristos  * The only way to know that a BGP UPDATE message is using add path is
1592c74ad251Schristos  * by checking if the capability is in the OPEN message which we may have missed.
1593c74ad251Schristos  * So this function checks if it is possible that the update could contain add path
1594c74ad251Schristos  * and if so it checks that standard BGP doesn't make sense.
1595c74ad251Schristos  */
1596c74ad251Schristos static int
1597c74ad251Schristos check_add_path(netdissect_options *ndo, const u_char *pptr, u_int length,
1598c74ad251Schristos                u_int max_prefix_length)
1599c74ad251Schristos {
1600c74ad251Schristos     u_int offset, prefix_length;
1601c74ad251Schristos 
1602c74ad251Schristos     if (length < 5) {
1603c74ad251Schristos         return 0;
1604c74ad251Schristos     }
1605c74ad251Schristos 
1606c74ad251Schristos     /*
1607*26ba0b50Schristos      * Scan through the NLRI information under the assumption that
1608c74ad251Schristos      * it doesn't have path IDs.
1609c74ad251Schristos      */
1610c74ad251Schristos     for (offset = 0; offset < length;) {
1611c74ad251Schristos         offset += 4;
1612c74ad251Schristos         if (!ND_TTEST_1(pptr + offset)) {
1613c74ad251Schristos             /* We ran out of captured data; quit scanning. */
1614c74ad251Schristos             break;
1615c74ad251Schristos         }
1616c74ad251Schristos         prefix_length = GET_U_1(pptr + offset);
1617c74ad251Schristos         /*
1618c74ad251Schristos          * Add 4 to cover the path id
1619c74ad251Schristos          * and check the prefix length isn't greater than 32/128.
1620c74ad251Schristos          */
1621c74ad251Schristos         if (prefix_length > max_prefix_length) {
1622c74ad251Schristos             return 0;
1623c74ad251Schristos         }
1624c74ad251Schristos         /* Add 1 for the prefix_length byte and prefix_length to cover the address */
1625c74ad251Schristos         offset += 1 + ((prefix_length + 7) / 8);
1626c74ad251Schristos     }
1627c74ad251Schristos     /* check we haven't gone past the end of the section */
1628c74ad251Schristos     if (offset > length) {
1629c74ad251Schristos         return 0;
1630c74ad251Schristos     }
1631c74ad251Schristos 
1632c74ad251Schristos     /* check it's not standard BGP */
1633c74ad251Schristos     for (offset = 0; offset < length; ) {
1634c74ad251Schristos         if (!ND_TTEST_1(pptr + offset)) {
1635c74ad251Schristos             /* We ran out of captured data; quit scanning. */
1636c74ad251Schristos             break;
1637c74ad251Schristos         }
1638c74ad251Schristos         prefix_length = GET_U_1(pptr + offset);
1639c74ad251Schristos         /*
1640c74ad251Schristos          * If the prefix_length is zero (0.0.0.0/0)
1641c74ad251Schristos          * and since it's not the only address (length >= 5)
1642c74ad251Schristos          * then it is add-path
1643c74ad251Schristos          */
1644c74ad251Schristos         if (prefix_length < 1 || prefix_length > max_prefix_length) {
1645c74ad251Schristos             return 1;
1646c74ad251Schristos         }
1647c74ad251Schristos         offset += 1 + ((prefix_length + 7) / 8);
1648c74ad251Schristos     }
1649c74ad251Schristos     if (offset > length) {
1650c74ad251Schristos         return 1;
1651c74ad251Schristos     }
1652c74ad251Schristos 
1653c74ad251Schristos     /* assume not add-path by default */
1654c74ad251Schristos     return 0;
1655c74ad251Schristos }
1656c74ad251Schristos 
1657c74ad251Schristos static int
1658c74ad251Schristos bgp_mp_af_print(netdissect_options *ndo,
1659c74ad251Schristos 	        const u_char *tptr, u_int tlen,
1660c74ad251Schristos 		uint16_t *afp, uint8_t *safip)
1661c74ad251Schristos {
1662c74ad251Schristos 	uint16_t af;
1663c74ad251Schristos 	uint8_t safi;
1664c74ad251Schristos 
1665c74ad251Schristos         af = GET_BE_U_2(tptr);
1666c74ad251Schristos 	*afp = af;
1667c74ad251Schristos         safi = GET_U_1(tptr + 2);
1668c74ad251Schristos 	*safip = safi;
1669c74ad251Schristos 
1670c74ad251Schristos         ND_PRINT("\n\t    AFI: %s (%u), %sSAFI: %s (%u)",
1671c74ad251Schristos                   tok2str(af_values, "Unknown AFI", af),
1672c74ad251Schristos                   af,
1673c74ad251Schristos                   (safi>128) ? "vendor specific " : "", /* 128 is meanwhile wellknown */
1674c74ad251Schristos                   tok2str(bgp_safi_values, "Unknown SAFI", safi),
1675c74ad251Schristos                   safi);
1676c74ad251Schristos 
1677c74ad251Schristos         switch(af<<8 | safi) {
1678c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1679c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1680c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1681c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1682c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
1683c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1684c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1685c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1686c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
1687c74ad251Schristos         case (AFNUM_INET<<8 | SAFNUM_MDT):
1688c74ad251Schristos         case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1689c74ad251Schristos         case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1690c74ad251Schristos         case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1691c74ad251Schristos         case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1692c74ad251Schristos         case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1693c74ad251Schristos         case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1694c74ad251Schristos         case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
1695c74ad251Schristos         case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1696c74ad251Schristos         case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1697c74ad251Schristos         case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1698c74ad251Schristos         case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1699c74ad251Schristos         case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1700c74ad251Schristos         case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1701c74ad251Schristos         case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1702c74ad251Schristos         case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1703c74ad251Schristos         case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1704c74ad251Schristos         case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1705c74ad251Schristos             break;
1706c74ad251Schristos         default:
1707c74ad251Schristos             ND_TCHECK_LEN(tptr, tlen);
1708c74ad251Schristos             ND_PRINT("\n\t    no AFI %u / SAFI %u decoder", af, safi);
1709c74ad251Schristos             if (ndo->ndo_vflag <= 1)
1710c74ad251Schristos                 print_unknown_data(ndo, tptr, "\n\t    ", tlen);
1711c74ad251Schristos             return -1;
1712c74ad251Schristos         }
1713c74ad251Schristos 	return 0;
1714c74ad251Schristos trunc:
1715c74ad251Schristos 	return -2;
1716c74ad251Schristos }
1717c74ad251Schristos 
1718c74ad251Schristos static int
1719c74ad251Schristos bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi,
1720c74ad251Schristos 	       const u_char *tptr, u_int len,
1721c74ad251Schristos 	       char *buf, size_t buflen,
1722c74ad251Schristos 	       int add_path4, int add_path6)
1723c74ad251Schristos {
1724c74ad251Schristos 	int advance;
1725c74ad251Schristos 	u_int path_id = 0;
1726c74ad251Schristos 
1727c74ad251Schristos 	switch (af<<8 | safi) {
1728c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_UNICAST):
1729c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
1730c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
1731c74ad251Schristos                 if (add_path4) {
1732c74ad251Schristos                     path_id = GET_BE_U_4(tptr);
1733c74ad251Schristos                     tptr += 4;
1734c74ad251Schristos                 }
1735c74ad251Schristos                 advance = decode_prefix4(ndo, tptr, len, buf, buflen);
1736c74ad251Schristos                 if (advance == -1)
1737c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1738c74ad251Schristos                 else if (advance == -2)
1739c74ad251Schristos                     break; /* bytes left, but not enough */
1740c74ad251Schristos                 else
1741c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1742c74ad251Schristos                 if (add_path4) {
1743c74ad251Schristos                     ND_PRINT("   Path Id: %u", path_id);
1744c74ad251Schristos 		    advance += 4;
1745c74ad251Schristos                 }
1746c74ad251Schristos                 break;
1747c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
1748c74ad251Schristos                 advance = decode_labeled_prefix4(ndo, tptr, len, buf, buflen);
1749c74ad251Schristos                 if (advance == -1)
1750c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1751c74ad251Schristos                 else if (advance == -2)
1752c74ad251Schristos                     goto trunc;
1753c74ad251Schristos                 else if (advance == -3)
1754c74ad251Schristos                     break; /* bytes left, but not enough */
1755c74ad251Schristos                 else
1756c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1757c74ad251Schristos                 break;
1758c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
1759c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
1760c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
1761c74ad251Schristos                 advance = decode_labeled_vpn_prefix4(ndo, tptr, buf, buflen);
1762c74ad251Schristos                 if (advance == -1)
1763c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1764c74ad251Schristos                 else
1765c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1766c74ad251Schristos                 break;
1767c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
1768c74ad251Schristos                 advance = decode_rt_routing_info(ndo, tptr);
1769c74ad251Schristos                 break;
1770c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */
1771c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN):
1772c74ad251Schristos                 advance = decode_multicast_vpn(ndo, tptr, buf, buflen);
1773c74ad251Schristos                 if (advance == -1)
1774c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1775c74ad251Schristos                 else if (advance == -2)
1776c74ad251Schristos                     goto trunc;
1777c74ad251Schristos                 else
1778c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1779c74ad251Schristos                 break;
1780c74ad251Schristos 
1781c74ad251Schristos             case (AFNUM_INET<<8 | SAFNUM_MDT):
1782c74ad251Schristos                 advance = decode_mdt_vpn_nlri(ndo, tptr, buf, buflen);
1783c74ad251Schristos                 if (advance == -1)
1784c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1785c74ad251Schristos                 else if (advance == -2)
1786c74ad251Schristos                     goto trunc;
1787c74ad251Schristos                 else
1788c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1789c74ad251Schristos                 break;
1790c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
1791c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
1792c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
1793c74ad251Schristos                 if (add_path6) {
1794c74ad251Schristos                     path_id = GET_BE_U_4(tptr);
1795c74ad251Schristos                     tptr += 4;
1796c74ad251Schristos                 }
1797c74ad251Schristos                 advance = decode_prefix6(ndo, tptr, len, buf, buflen);
1798c74ad251Schristos                 if (advance == -1)
1799c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1800c74ad251Schristos                 else if (advance == -2)
1801c74ad251Schristos                     break; /* bytes left, but not enough */
1802c74ad251Schristos                 else
1803c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1804c74ad251Schristos                 if (add_path6) {
1805c74ad251Schristos                     ND_PRINT("   Path Id: %u", path_id);
1806c74ad251Schristos 		    advance += 4;
1807c74ad251Schristos                 }
1808c74ad251Schristos                 break;
1809c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
1810c74ad251Schristos                 advance = decode_labeled_prefix6(ndo, tptr, len, buf, buflen);
1811c74ad251Schristos                 if (advance == -1)
1812c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1813c74ad251Schristos                 else if (advance == -2)
1814c74ad251Schristos                     goto trunc;
1815c74ad251Schristos                 else if (advance == -3)
1816c74ad251Schristos                     break; /* bytes left, but not enough */
1817c74ad251Schristos                 else
1818c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1819c74ad251Schristos                 break;
1820c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
1821c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
1822c74ad251Schristos             case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
1823c74ad251Schristos                 advance = decode_labeled_vpn_prefix6(ndo, tptr, buf, buflen);
1824c74ad251Schristos                 if (advance == -1)
1825c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1826c74ad251Schristos                 else
1827c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1828c74ad251Schristos                 break;
1829c74ad251Schristos             case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
1830c74ad251Schristos             case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
1831c74ad251Schristos             case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
1832c74ad251Schristos             case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
1833c74ad251Schristos                 advance = decode_labeled_vpn_l2(ndo, tptr, buf, buflen);
1834c74ad251Schristos                 if (advance == -1)
1835c74ad251Schristos                     ND_PRINT("\n\t    (illegal length)");
1836c74ad251Schristos                 else if (advance == -2)
1837c74ad251Schristos                     goto trunc;
1838c74ad251Schristos                 else
1839c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1840c74ad251Schristos                 break;
1841c74ad251Schristos             case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
1842c74ad251Schristos             case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
1843c74ad251Schristos             case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
1844c74ad251Schristos                 advance = decode_clnp_prefix(ndo, tptr, buf, buflen);
1845c74ad251Schristos                 if (advance == -1)
1846c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1847c74ad251Schristos                 else
1848c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1849c74ad251Schristos                 break;
1850c74ad251Schristos             case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
1851c74ad251Schristos             case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
1852c74ad251Schristos             case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
1853c74ad251Schristos                 advance = decode_labeled_vpn_clnp_prefix(ndo, tptr, buf, buflen);
1854c74ad251Schristos                 if (advance == -1)
1855c74ad251Schristos                     ND_PRINT("\n\t    (illegal prefix length)");
1856c74ad251Schristos                 else
1857c74ad251Schristos                     ND_PRINT("\n\t      %s", buf);
1858c74ad251Schristos                 break;
1859c74ad251Schristos             default:
1860c74ad251Schristos 		/*
1861c74ad251Schristos 		 * This should not happen, we should have been protected
1862c74ad251Schristos 		 * by bgp_mp_af_print()'s return value.
1863c74ad251Schristos 		 */
1864c74ad251Schristos                 ND_PRINT("\n\t    ERROR: no AFI %u / SAFI %u decoder", af, safi);
1865c74ad251Schristos                 advance = -4;
1866c74ad251Schristos                 break;
1867c74ad251Schristos 	}
1868c74ad251Schristos 	return advance;
1869c74ad251Schristos trunc:	/* we rely on the caller to recognize -2 return value */
1870c74ad251Schristos 	return -2;
1871c74ad251Schristos }
1872c74ad251Schristos 
18730f74e101Schristos static int
1874b3a00663Schristos bgp_attr_print(netdissect_options *ndo,
1875c74ad251Schristos                uint8_t atype, const u_char *pptr, u_int len,
1876c74ad251Schristos                const unsigned attr_set_level)
18770f74e101Schristos {
1878c74ad251Schristos     /* allocate space for the largest possible string */
1879c74ad251Schristos     char astostr[AS_STR_SIZE];
1880c74ad251Schristos     u_int i;
1881b3a00663Schristos     uint16_t af;
1882b3a00663Schristos     uint8_t safi, snpa, nhlen;
18830f74e101Schristos     int advance;
18840e9868baSchristos     u_int tlen;
18850f74e101Schristos     const u_char *tptr;
18860f74e101Schristos     char buf[MAXHOSTNAMELEN + 100];
1887c74ad251Schristos     u_int as_size;
1888c74ad251Schristos     int add_path4, add_path6;
1889c74ad251Schristos     int ret;
18900f74e101Schristos 
18910f74e101Schristos     tptr = pptr;
18920f74e101Schristos     tlen = len;
18930f74e101Schristos 
18940e9868baSchristos     switch (atype) {
18950f74e101Schristos     case BGPTYPE_ORIGIN:
18960f74e101Schristos         if (len != 1)
1897c74ad251Schristos             ND_PRINT("invalid len");
18980f74e101Schristos         else {
1899c74ad251Schristos             ND_PRINT("%s", tok2str(bgp_origin_values,
19000f74e101Schristos                       "Unknown Origin Typecode",
1901c74ad251Schristos                       GET_U_1(tptr)));
19020f74e101Schristos         }
19030f74e101Schristos         break;
19040f74e101Schristos 
19050f74e101Schristos     /*
19060f74e101Schristos      * Process AS4 byte path and AS2 byte path attributes here.
19070f74e101Schristos      */
19080f74e101Schristos     case BGPTYPE_AS4_PATH:
19090f74e101Schristos     case BGPTYPE_AS_PATH:
19100f74e101Schristos         if (len % 2) {
1911c74ad251Schristos             ND_PRINT("invalid len");
19120f74e101Schristos             break;
19130f74e101Schristos         }
19140f74e101Schristos         if (!len) {
1915c74ad251Schristos             ND_PRINT("empty");
19160f74e101Schristos             break;
19170f74e101Schristos         }
19180f74e101Schristos 
19190f74e101Schristos         /*
19200f74e101Schristos          * BGP updates exchanged between New speakers that support 4
19210f74e101Schristos          * byte AS, ASs are always encoded in 4 bytes. There is no
19220f74e101Schristos          * definitive way to find this, just by the packet's
19230f74e101Schristos          * contents. So, check for packet's TLV's sanity assuming
19240f74e101Schristos          * 2 bytes first, and it does not pass, assume that ASs are
19250f74e101Schristos          * encoded in 4 bytes format and move on.
19260f74e101Schristos          */
1927b3a00663Schristos         as_size = bgp_attr_get_as_size(ndo, atype, pptr, len);
19280f74e101Schristos 
19290f74e101Schristos         while (tptr < pptr + len) {
1930c74ad251Schristos             ND_PRINT("%s", tok2str(bgp_as_path_segment_open_values,
1931c74ad251Schristos                       "?", GET_U_1(tptr)));
1932c74ad251Schristos             for (i = 0; i < GET_U_1(tptr + 1) * as_size; i += as_size) {
1933c74ad251Schristos                 ND_TCHECK_LEN(tptr + 2 + i, as_size);
1934c74ad251Schristos                 ND_PRINT("%s ",
1935b3a00663Schristos                           as_printf(ndo, astostr, sizeof(astostr),
19360f74e101Schristos                           as_size == 2 ?
1937c74ad251Schristos                               GET_BE_U_2(tptr + i + 2) :
1938c74ad251Schristos                               GET_BE_U_4(tptr + i + 2)));
19390f74e101Schristos             }
1940c74ad251Schristos             ND_PRINT("%s", tok2str(bgp_as_path_segment_close_values,
1941c74ad251Schristos                       "?", GET_U_1(tptr)));
1942c74ad251Schristos             tptr += 2 + GET_U_1(tptr + 1) * as_size;
19430f74e101Schristos         }
19440f74e101Schristos         break;
19450f74e101Schristos     case BGPTYPE_NEXT_HOP:
19460f74e101Schristos         if (len != 4)
1947c74ad251Schristos             ND_PRINT("invalid len");
19480f74e101Schristos         else {
1949c74ad251Schristos             ND_PRINT("%s", GET_IPADDR_STRING(tptr));
19500f74e101Schristos         }
19510f74e101Schristos         break;
19520f74e101Schristos     case BGPTYPE_MULTI_EXIT_DISC:
19530f74e101Schristos     case BGPTYPE_LOCAL_PREF:
19540f74e101Schristos         if (len != 4)
1955c74ad251Schristos             ND_PRINT("invalid len");
19560f74e101Schristos         else {
1957c74ad251Schristos             ND_PRINT("%u", GET_BE_U_4(tptr));
19580f74e101Schristos         }
19590f74e101Schristos         break;
19600f74e101Schristos     case BGPTYPE_ATOMIC_AGGREGATE:
19610f74e101Schristos         if (len != 0)
1962c74ad251Schristos             ND_PRINT("invalid len");
19630f74e101Schristos         break;
19640f74e101Schristos     case BGPTYPE_AGGREGATOR:
19650f74e101Schristos 
19660f74e101Schristos         /*
19670f74e101Schristos          * Depending on the AS encoded is of 2 bytes or of 4 bytes,
19680f74e101Schristos          * the length of this PA can be either 6 bytes or 8 bytes.
19690f74e101Schristos          */
19700f74e101Schristos         if (len != 6 && len != 8) {
1971c74ad251Schristos             ND_PRINT("invalid len");
19720f74e101Schristos             break;
19730f74e101Schristos         }
1974c74ad251Schristos         ND_TCHECK_LEN(tptr, len);
19750f74e101Schristos         if (len == 6) {
1976c74ad251Schristos             ND_PRINT(" AS #%s, origin %s",
1977c74ad251Schristos                       as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(tptr)),
1978c74ad251Schristos                       GET_IPADDR_STRING(tptr + 2));
19790f74e101Schristos         } else {
1980c74ad251Schristos             ND_PRINT(" AS #%s, origin %s",
1981b3a00663Schristos                       as_printf(ndo, astostr, sizeof(astostr),
1982c74ad251Schristos                       GET_BE_U_4(tptr)), GET_IPADDR_STRING(tptr + 4));
19830f74e101Schristos         }
19840f74e101Schristos         break;
19850f74e101Schristos     case BGPTYPE_AGGREGATOR4:
19860f74e101Schristos         if (len != 8) {
1987c74ad251Schristos             ND_PRINT("invalid len");
19880f74e101Schristos             break;
19890f74e101Schristos         }
1990c74ad251Schristos         ND_PRINT(" AS #%s, origin %s",
1991c74ad251Schristos                   as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(tptr)),
1992c74ad251Schristos                   GET_IPADDR_STRING(tptr + 4));
19930f74e101Schristos         break;
19940f74e101Schristos     case BGPTYPE_COMMUNITIES:
19950f74e101Schristos         if (len % 4) {
1996c74ad251Schristos             ND_PRINT("invalid len");
19970f74e101Schristos             break;
19980f74e101Schristos         }
1999c74ad251Schristos         while (tlen != 0) {
2000b3a00663Schristos             uint32_t comm;
2001c74ad251Schristos             ND_TCHECK_4(tptr);
2002c74ad251Schristos             if (tlen < 4)
2003c74ad251Schristos                 goto trunc;
2004c74ad251Schristos             comm = GET_BE_U_4(tptr);
20050f74e101Schristos             switch (comm) {
20060f74e101Schristos             case BGP_COMMUNITY_NO_EXPORT:
2007c74ad251Schristos                 ND_PRINT(" NO_EXPORT");
20080f74e101Schristos                 break;
20090f74e101Schristos             case BGP_COMMUNITY_NO_ADVERT:
2010c74ad251Schristos                 ND_PRINT(" NO_ADVERTISE");
20110f74e101Schristos                 break;
20120f74e101Schristos             case BGP_COMMUNITY_NO_EXPORT_SUBCONFED:
2013c74ad251Schristos                 ND_PRINT(" NO_EXPORT_SUBCONFED");
20140f74e101Schristos                 break;
20150f74e101Schristos             default:
2016c74ad251Schristos                 ND_PRINT("%u:%u%s",
20170f74e101Schristos                          (comm >> 16) & 0xffff,
20180f74e101Schristos                          comm & 0xffff,
2019c74ad251Schristos                          (tlen>4) ? ", " : "");
20200f74e101Schristos                 break;
20210f74e101Schristos             }
20220f74e101Schristos             tlen -=4;
20230f74e101Schristos             tptr +=4;
20240f74e101Schristos         }
20250f74e101Schristos         break;
20260f74e101Schristos     case BGPTYPE_ORIGINATOR_ID:
20270f74e101Schristos         if (len != 4) {
2028c74ad251Schristos             ND_PRINT("invalid len");
20290f74e101Schristos             break;
20300f74e101Schristos         }
2031c74ad251Schristos         ND_PRINT("%s",GET_IPADDR_STRING(tptr));
20320f74e101Schristos         break;
20330f74e101Schristos     case BGPTYPE_CLUSTER_LIST:
20340f74e101Schristos         if (len % 4) {
2035c74ad251Schristos             ND_PRINT("invalid len");
20360f74e101Schristos             break;
20370f74e101Schristos         }
2038c74ad251Schristos         while (tlen != 0) {
2039c74ad251Schristos             if (tlen < 4)
2040c74ad251Schristos                 goto trunc;
2041c74ad251Schristos             ND_PRINT("%s%s",
2042c74ad251Schristos                       GET_IPADDR_STRING(tptr),
2043c74ad251Schristos                       (tlen>4) ? ", " : "");
20440f74e101Schristos             tlen -=4;
20450f74e101Schristos             tptr +=4;
20460f74e101Schristos         }
20470f74e101Schristos         break;
20480f74e101Schristos     case BGPTYPE_MP_REACH_NLRI:
2049c74ad251Schristos         ND_TCHECK_3(tptr);
2050c74ad251Schristos         if (tlen < 3)
2051c74ad251Schristos             goto trunc;
2052c74ad251Schristos 	ret = bgp_mp_af_print(ndo, tptr, tlen, &af, &safi);
2053c74ad251Schristos 	if (ret == -2)
2054c74ad251Schristos 	    goto trunc;
2055c74ad251Schristos 	if (ret < 0)
20560f74e101Schristos 	    break;
20570f74e101Schristos 
20580f74e101Schristos         tptr += 3;
2059c74ad251Schristos         tlen -= 3;
20600f74e101Schristos 
2061c74ad251Schristos         ND_TCHECK_1(tptr);
2062c74ad251Schristos         if (tlen < 1)
2063c74ad251Schristos             goto trunc;
2064c74ad251Schristos         nhlen = GET_U_1(tptr);
20650f74e101Schristos         tptr++;
2066c74ad251Schristos         tlen--;
20670f74e101Schristos 
2068c74ad251Schristos         if (nhlen) {
2069c74ad251Schristos             u_int nnh = 0;
2070c74ad251Schristos             uint8_t tnhlen = nhlen;
2071c74ad251Schristos             if (tlen < tnhlen)
2072c74ad251Schristos                 goto trunc;
2073c74ad251Schristos             ND_PRINT("\n\t    nexthop: ");
2074c74ad251Schristos             while (tnhlen != 0) {
2075870189d2Schristos                 if (nnh++ > 0) {
2076c74ad251Schristos                     ND_PRINT(", " );
2077870189d2Schristos                 }
20780f74e101Schristos                 switch(af<<8 | safi) {
20790f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_UNICAST):
20800f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_MULTICAST):
20810f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST):
20820f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_LABUNICAST):
20830f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO):
20840f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN):
20850f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_MDT):
2086c74ad251Schristos                     if (tnhlen < sizeof(nd_ipv4)) {
2087c74ad251Schristos                         ND_PRINT("invalid len");
2088c74ad251Schristos                         tptr += tnhlen;
2089c74ad251Schristos                         tlen -= tnhlen;
2090c74ad251Schristos                         tnhlen = 0;
20910f74e101Schristos                     } else {
2092c74ad251Schristos                         ND_PRINT("%s",GET_IPADDR_STRING(tptr));
2093c74ad251Schristos                         tptr += sizeof(nd_ipv4);
2094c74ad251Schristos                         tnhlen -= sizeof(nd_ipv4);
2095c74ad251Schristos                         tlen -= sizeof(nd_ipv4);
20960f74e101Schristos                     }
20970f74e101Schristos                     break;
20980f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST):
20990f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST):
21000f74e101Schristos                 case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST):
2101c74ad251Schristos                     if (tnhlen < sizeof(nd_ipv4)+BGP_VPN_RD_LEN) {
2102c74ad251Schristos                         ND_PRINT("invalid len");
2103c74ad251Schristos                         tptr += tnhlen;
2104c74ad251Schristos                         tlen -= tnhlen;
2105c74ad251Schristos                         tnhlen = 0;
21060f74e101Schristos                     } else {
2107c74ad251Schristos                         ND_PRINT("RD: %s, %s",
2108b3a00663Schristos                                   bgp_vpn_rd_print(ndo, tptr),
2109c74ad251Schristos                                   GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN));
2110c74ad251Schristos                         tptr += (sizeof(nd_ipv4)+BGP_VPN_RD_LEN);
2111c74ad251Schristos                         tlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN);
2112c74ad251Schristos                         tnhlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN);
21130f74e101Schristos                     }
21140f74e101Schristos                     break;
21150f74e101Schristos                 case (AFNUM_INET6<<8 | SAFNUM_UNICAST):
21160f74e101Schristos                 case (AFNUM_INET6<<8 | SAFNUM_MULTICAST):
21170f74e101Schristos                 case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST):
21180f74e101Schristos                 case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST):
2119c74ad251Schristos                     if (tnhlen < sizeof(nd_ipv6)) {
2120c74ad251Schristos                         ND_PRINT("invalid len");
2121c74ad251Schristos                         tptr += tnhlen;
2122c74ad251Schristos                         tlen -= tnhlen;
2123c74ad251Schristos                         tnhlen = 0;
21240f74e101Schristos                     } else {
2125c74ad251Schristos                         ND_PRINT("%s", GET_IP6ADDR_STRING(tptr));
2126c74ad251Schristos                         tptr += sizeof(nd_ipv6);
2127c74ad251Schristos                         tlen -= sizeof(nd_ipv6);
2128c74ad251Schristos                         tnhlen -= sizeof(nd_ipv6);
21290f74e101Schristos                     }
21300f74e101Schristos                     break;
21310f74e101Schristos                 case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST):
21320f74e101Schristos                 case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST):
21330f74e101Schristos                 case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST):
2134c74ad251Schristos                     if (tnhlen < sizeof(nd_ipv6)+BGP_VPN_RD_LEN) {
2135c74ad251Schristos                         ND_PRINT("invalid len");
2136c74ad251Schristos                         tptr += tnhlen;
2137c74ad251Schristos                         tlen -= tnhlen;
2138c74ad251Schristos                         tnhlen = 0;
21390f74e101Schristos                     } else {
2140c74ad251Schristos                         ND_PRINT("RD: %s, %s",
2141b3a00663Schristos                                   bgp_vpn_rd_print(ndo, tptr),
2142c74ad251Schristos                                   GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN));
2143c74ad251Schristos                         tptr += (sizeof(nd_ipv6)+BGP_VPN_RD_LEN);
2144c74ad251Schristos                         tlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN);
2145c74ad251Schristos                         tnhlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN);
21460f74e101Schristos                     }
21470f74e101Schristos                     break;
21480f74e101Schristos                 case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
21490f74e101Schristos                 case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST):
21500f74e101Schristos                 case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
21510f74e101Schristos                 case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
2152c74ad251Schristos                     if (tnhlen < sizeof(nd_ipv4)) {
2153c74ad251Schristos                         ND_PRINT("invalid len");
2154c74ad251Schristos                         tptr += tnhlen;
2155c74ad251Schristos                         tlen -= tnhlen;
2156c74ad251Schristos                         tnhlen = 0;
21570f74e101Schristos                     } else {
2158c74ad251Schristos                         ND_PRINT("%s", GET_IPADDR_STRING(tptr));
2159c74ad251Schristos                         tptr += (sizeof(nd_ipv4));
2160c74ad251Schristos                         tlen -= (sizeof(nd_ipv4));
2161c74ad251Schristos                         tnhlen -= (sizeof(nd_ipv4));
21620f74e101Schristos                     }
21630f74e101Schristos                     break;
21640f74e101Schristos                 case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
21650f74e101Schristos                 case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
21660f74e101Schristos                 case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
2167c74ad251Schristos                     ND_PRINT("%s", GET_ISONSAP_STRING(tptr, tnhlen));
2168c74ad251Schristos                     tptr += tnhlen;
2169c74ad251Schristos                     tlen -= tnhlen;
2170c74ad251Schristos                     tnhlen = 0;
21710f74e101Schristos                     break;
21720f74e101Schristos 
21730f74e101Schristos                 case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST):
21740f74e101Schristos                 case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST):
21750f74e101Schristos                 case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST):
2176c74ad251Schristos                     if (tnhlen < BGP_VPN_RD_LEN+1) {
2177c74ad251Schristos                         ND_PRINT("invalid len");
2178c74ad251Schristos                         tptr += tnhlen;
2179c74ad251Schristos                         tlen -= tnhlen;
2180c74ad251Schristos                         tnhlen = 0;
21810f74e101Schristos                     } else {
2182c74ad251Schristos                         ND_TCHECK_LEN(tptr, tnhlen);
2183c74ad251Schristos                         ND_PRINT("RD: %s, %s",
2184b3a00663Schristos                                   bgp_vpn_rd_print(ndo, tptr),
2185c74ad251Schristos                                   GET_ISONSAP_STRING(tptr+BGP_VPN_RD_LEN,tnhlen-BGP_VPN_RD_LEN));
21860f74e101Schristos                         /* rfc986 mapped IPv4 address ? */
2187c74ad251Schristos                         if (GET_BE_U_4(tptr + BGP_VPN_RD_LEN) ==  0x47000601)
2188c74ad251Schristos                             ND_PRINT(" = %s", GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN+4));
21890f74e101Schristos                         /* rfc1888 mapped IPv6 address ? */
2190c74ad251Schristos                         else if (GET_BE_U_3(tptr + BGP_VPN_RD_LEN) ==  0x350000)
2191c74ad251Schristos                             ND_PRINT(" = %s", GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN+3));
2192c74ad251Schristos                         tptr += tnhlen;
2193c74ad251Schristos                         tlen -= tnhlen;
2194c74ad251Schristos                         tnhlen = 0;
21950f74e101Schristos                     }
21960f74e101Schristos                     break;
21970f74e101Schristos                 default:
2198c74ad251Schristos 		    /*
2199c74ad251Schristos 		     * bgp_mp_af_print() should have saved us from
2200c74ad251Schristos 		     * an unsupported AFI/SAFI.
2201c74ad251Schristos 		     */
2202c74ad251Schristos                     ND_PRINT("ERROR: no AFI %u/SAFI %u nexthop decoder", af, safi);
2203c74ad251Schristos                     tptr += tnhlen;
2204c74ad251Schristos                     tlen -= tnhlen;
2205c74ad251Schristos                     tnhlen = 0;
22060f74e101Schristos                     goto done;
22070f74e101Schristos                     break;
22080f74e101Schristos                 }
22090f74e101Schristos             }
22100f74e101Schristos         }
2211c74ad251Schristos         ND_PRINT(", nh-length: %u", nhlen);
22120f74e101Schristos 
2213c74ad251Schristos         /* As per RFC 2858; this is reserved in RFC 4760 */
2214c74ad251Schristos         if (tlen < 1)
2215c74ad251Schristos             goto trunc;
2216c74ad251Schristos         snpa = GET_U_1(tptr);
22170f74e101Schristos         tptr++;
2218c74ad251Schristos         tlen--;
22190f74e101Schristos 
22200f74e101Schristos         if (snpa) {
2221c74ad251Schristos             ND_PRINT("\n\t    %u SNPA", snpa);
2222c74ad251Schristos             for (/*nothing*/; snpa != 0; snpa--) {
2223c74ad251Schristos                 uint8_t snpalen;
2224c74ad251Schristos 		if (tlen < 1)
2225c74ad251Schristos 		    goto trunc;
2226c74ad251Schristos                 snpalen = GET_U_1(tptr);
2227c74ad251Schristos                 ND_PRINT("\n\t      %u bytes", snpalen);
2228c74ad251Schristos                 tptr++;
2229c74ad251Schristos                 tlen--;
2230c74ad251Schristos                 if (tlen < snpalen)
2231c74ad251Schristos                     goto trunc;
2232c74ad251Schristos                 ND_TCHECK_LEN(tptr, snpalen);
2233c74ad251Schristos                 tptr += snpalen;
2234c74ad251Schristos                 tlen -= snpalen;
22350f74e101Schristos             }
22360f74e101Schristos         } else {
2237c74ad251Schristos             ND_PRINT(", no SNPA");
22380f74e101Schristos         }
22390f74e101Schristos 
2240*26ba0b50Schristos         add_path4 = check_add_path(ndo, tptr,
2241*26ba0b50Schristos                                    (len-ND_BYTES_BETWEEN(pptr, tptr)), 32);
2242*26ba0b50Schristos         add_path6 = check_add_path(ndo, tptr,
2243*26ba0b50Schristos                                    (len-ND_BYTES_BETWEEN(pptr, tptr)), 128);
2244c74ad251Schristos 
224572c96ff3Schristos         while (tptr < pptr + len) {
2246c74ad251Schristos             advance = bgp_nlri_print(ndo, af, safi, tptr, len, buf, sizeof(buf),
2247c74ad251Schristos                     add_path4, add_path6);
2248c74ad251Schristos             if (advance == -2)
22490f74e101Schristos                 goto trunc;
22500f74e101Schristos             if (advance < 0)
22510f74e101Schristos                 break;
22520f74e101Schristos             tptr += advance;
22530f74e101Schristos         }
22540f74e101Schristos         break;
22550f74e101Schristos 
22560f74e101Schristos     case BGPTYPE_MP_UNREACH_NLRI:
2257c74ad251Schristos         ND_TCHECK_LEN(tptr, BGP_MP_NLRI_MINSIZE);
2258c74ad251Schristos 	ret = bgp_mp_af_print(ndo, tptr, tlen, &af, &safi);
2259c74ad251Schristos 	if (ret == -2)
2260c74ad251Schristos 	    goto trunc;
2261c74ad251Schristos 	if (ret < 0)
2262c74ad251Schristos 	    break;
22630f74e101Schristos 
22640f74e101Schristos         if (len == BGP_MP_NLRI_MINSIZE)
2265c74ad251Schristos             ND_PRINT("\n\t      End-of-Rib Marker (empty NLRI)");
22660f74e101Schristos 
22670f74e101Schristos         tptr += 3;
22680f74e101Schristos 
2269*26ba0b50Schristos         add_path4 = check_add_path(ndo, tptr,
2270*26ba0b50Schristos                                    (len-ND_BYTES_BETWEEN(pptr, tptr)), 32);
2271*26ba0b50Schristos         add_path6 = check_add_path(ndo, tptr,
2272*26ba0b50Schristos                                    (len-ND_BYTES_BETWEEN(pptr, tptr)), 128);
2273c74ad251Schristos 
227472c96ff3Schristos         while (tptr < pptr + len) {
2275c74ad251Schristos             advance = bgp_nlri_print(ndo, af, safi, tptr, len, buf, sizeof(buf),
2276c74ad251Schristos                     add_path4, add_path6);
2277c74ad251Schristos             if (advance == -2)
22780f74e101Schristos                 goto trunc;
22790f74e101Schristos             if (advance < 0)
22800f74e101Schristos                 break;
22810f74e101Schristos             tptr += advance;
22820f74e101Schristos         }
22830f74e101Schristos         break;
22840f74e101Schristos     case BGPTYPE_EXTD_COMMUNITIES:
22850f74e101Schristos         if (len % 8) {
2286c74ad251Schristos             ND_PRINT("invalid len");
22870f74e101Schristos             break;
22880f74e101Schristos         }
2289c74ad251Schristos         while (tlen != 0) {
2290b3a00663Schristos             uint16_t extd_comm;
22910f74e101Schristos 
2292c74ad251Schristos             ND_TCHECK_2(tptr);
2293c74ad251Schristos             if (tlen < 2)
2294c74ad251Schristos                 goto trunc;
2295c74ad251Schristos             extd_comm=GET_BE_U_2(tptr);
22960f74e101Schristos 
2297c74ad251Schristos             ND_PRINT("\n\t    %s (0x%04x), Flags [%s]",
2298fdccd7e4Schristos                       tok2str(bgp_extd_comm_subtype_values,
22990f74e101Schristos                               "unknown extd community typecode",
2300fdccd7e4Schristos                               extd_comm),
23010f74e101Schristos                       extd_comm,
2302c74ad251Schristos                       bittok2str(bgp_extd_comm_flag_values, "none", extd_comm));
23030f74e101Schristos 
2304c74ad251Schristos             ND_TCHECK_8(tptr);
2305c74ad251Schristos             if (tlen < 8)
2306c74ad251Schristos                 goto trunc;
2307c74ad251Schristos             ND_PRINT(": ");
2308c74ad251Schristos             bgp_extended_community_print(ndo, tptr);
23090f74e101Schristos             tlen -= 8;
23100f74e101Schristos             tptr += 8;
23110f74e101Schristos         }
23120f74e101Schristos         break;
23130f74e101Schristos 
23140f74e101Schristos     case BGPTYPE_PMSI_TUNNEL:
23150f74e101Schristos     {
2316b3a00663Schristos         uint8_t tunnel_type, flags;
23170f74e101Schristos 
2318c74ad251Schristos         ND_TCHECK_5(tptr);
2319c74ad251Schristos         if (tlen < 5)
2320c74ad251Schristos             goto trunc;
2321c74ad251Schristos         flags = GET_U_1(tptr);
2322c74ad251Schristos         tunnel_type = GET_U_1(tptr + 1);
23230f74e101Schristos 
2324c74ad251Schristos         ND_PRINT("\n\t    Tunnel-type %s (%u), Flags [%s], MPLS Label %u",
23250f74e101Schristos                   tok2str(bgp_pmsi_tunnel_values, "Unknown", tunnel_type),
23260f74e101Schristos                   tunnel_type,
23270f74e101Schristos                   bittok2str(bgp_pmsi_flag_values, "none", flags),
2328c74ad251Schristos                   GET_BE_U_3(tptr + 2)>>4);
23290f74e101Schristos 
23300f74e101Schristos         tptr +=5;
23310f74e101Schristos         tlen -= 5;
23320f74e101Schristos 
23330f74e101Schristos         switch (tunnel_type) {
23340f74e101Schristos         case BGP_PMSI_TUNNEL_PIM_SM: /* fall through */
23350f74e101Schristos         case BGP_PMSI_TUNNEL_PIM_BIDIR:
2336c74ad251Schristos             ND_PRINT("\n\t      Sender %s, P-Group %s",
2337c74ad251Schristos                       GET_IPADDR_STRING(tptr),
2338c74ad251Schristos                       GET_IPADDR_STRING(tptr+4));
23390f74e101Schristos             break;
23400f74e101Schristos 
23410f74e101Schristos         case BGP_PMSI_TUNNEL_PIM_SSM:
2342c74ad251Schristos             ND_PRINT("\n\t      Root-Node %s, P-Group %s",
2343c74ad251Schristos                       GET_IPADDR_STRING(tptr),
2344c74ad251Schristos                       GET_IPADDR_STRING(tptr+4));
23450f74e101Schristos             break;
23460f74e101Schristos         case BGP_PMSI_TUNNEL_INGRESS:
2347c74ad251Schristos             ND_PRINT("\n\t      Tunnel-Endpoint %s",
2348c74ad251Schristos                       GET_IPADDR_STRING(tptr));
23490f74e101Schristos             break;
23500f74e101Schristos         case BGP_PMSI_TUNNEL_LDP_P2MP: /* fall through */
23510f74e101Schristos         case BGP_PMSI_TUNNEL_LDP_MP2MP:
2352c74ad251Schristos             ND_PRINT("\n\t      Root-Node %s, LSP-ID 0x%08x",
2353c74ad251Schristos                       GET_IPADDR_STRING(tptr),
2354c74ad251Schristos                       GET_BE_U_4(tptr + 4));
23550f74e101Schristos             break;
23560f74e101Schristos         case BGP_PMSI_TUNNEL_RSVP_P2MP:
2357c74ad251Schristos             ND_PRINT("\n\t      Extended-Tunnel-ID %s, P2MP-ID 0x%08x",
2358c74ad251Schristos                       GET_IPADDR_STRING(tptr),
2359c74ad251Schristos                       GET_BE_U_4(tptr + 4));
23600f74e101Schristos             break;
23610f74e101Schristos         default:
2362b3a00663Schristos             if (ndo->ndo_vflag <= 1) {
2363b3a00663Schristos                 print_unknown_data(ndo, tptr, "\n\t      ", tlen);
23640f74e101Schristos             }
23650f74e101Schristos         }
23660f74e101Schristos         break;
23670f74e101Schristos     }
2368fdccd7e4Schristos     case BGPTYPE_AIGP:
2369fdccd7e4Schristos     {
2370fdccd7e4Schristos         uint8_t type;
2371fdccd7e4Schristos         uint16_t length;
2372fdccd7e4Schristos 
2373fdccd7e4Schristos         while (tlen >= 3) {
2374c74ad251Schristos             type = GET_U_1(tptr);
2375c74ad251Schristos             length = GET_BE_U_2(tptr + 1);
237672c96ff3Schristos             tptr += 3;
237772c96ff3Schristos             tlen -= 3;
2378fdccd7e4Schristos 
2379c74ad251Schristos             ND_PRINT("\n\t    %s TLV (%u), length %u",
2380fdccd7e4Schristos                       tok2str(bgp_aigp_values, "Unknown", type),
2381c74ad251Schristos                       type, length);
2382fdccd7e4Schristos 
238372c96ff3Schristos             if (length < 3)
238472c96ff3Schristos                 goto trunc;
238572c96ff3Schristos             length -= 3;
238672c96ff3Schristos 
2387fdccd7e4Schristos             /*
2388fdccd7e4Schristos              * Check if we can read the TLV data.
2389fdccd7e4Schristos              */
2390c74ad251Schristos             if (tlen < length)
2391c74ad251Schristos                 goto trunc;
2392fdccd7e4Schristos 
2393fdccd7e4Schristos             switch (type) {
2394fdccd7e4Schristos 
2395fdccd7e4Schristos             case BGP_AIGP_TLV:
239672c96ff3Schristos                 if (length < 8)
239772c96ff3Schristos                     goto trunc;
2398c74ad251Schristos                 ND_PRINT(", metric %" PRIu64,
2399c74ad251Schristos                           GET_BE_U_8(tptr));
2400fdccd7e4Schristos                 break;
2401fdccd7e4Schristos 
2402fdccd7e4Schristos             default:
2403fdccd7e4Schristos                 if (ndo->ndo_vflag <= 1) {
240472c96ff3Schristos                     print_unknown_data(ndo, tptr,"\n\t      ", length);
2405fdccd7e4Schristos                 }
2406fdccd7e4Schristos             }
2407fdccd7e4Schristos 
2408fdccd7e4Schristos             tptr += length;
2409fdccd7e4Schristos             tlen -= length;
2410fdccd7e4Schristos         }
2411fdccd7e4Schristos         break;
2412fdccd7e4Schristos     }
24130f74e101Schristos     case BGPTYPE_ATTR_SET:
2414c74ad251Schristos         ND_TCHECK_4(tptr);
24150e9868baSchristos         if (len < 4)
24160e9868baSchristos             goto trunc;
2417c74ad251Schristos         ND_PRINT("\n\t    Origin AS: %s",
2418c74ad251Schristos                   as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(tptr)));
24190f74e101Schristos         tptr += 4;
24200f74e101Schristos         len -= 4;
24210f74e101Schristos 
24220e9868baSchristos         while (len) {
2423fdccd7e4Schristos             u_int aflags, alenlen, alen;
24240f74e101Schristos 
2425c74ad251Schristos             ND_TCHECK_2(tptr);
2426c74ad251Schristos             if (len < 2) {
2427c74ad251Schristos                 ND_PRINT(" [path attr too short]");
2428c74ad251Schristos                 tptr += len;
2429c74ad251Schristos                 break;
2430c74ad251Schristos             }
2431c74ad251Schristos             aflags = GET_U_1(tptr);
2432c74ad251Schristos             atype = GET_U_1(tptr + 1);
24330e9868baSchristos             tptr += 2;
24340e9868baSchristos             len -= 2;
24350e9868baSchristos             alenlen = bgp_attr_lenlen(aflags, tptr);
2436c74ad251Schristos             ND_TCHECK_LEN(tptr, alenlen);
2437c74ad251Schristos             if (len < alenlen) {
2438c74ad251Schristos                 ND_PRINT(" [path attr too short]");
2439c74ad251Schristos                 tptr += len;
2440c74ad251Schristos                 break;
2441c74ad251Schristos             }
24420e9868baSchristos             alen = bgp_attr_len(aflags, tptr);
24430e9868baSchristos             tptr += alenlen;
24440e9868baSchristos             len -= alenlen;
24450f74e101Schristos 
2446c74ad251Schristos             ND_PRINT("\n\t      %s (%u), length: %u",
2447fdccd7e4Schristos                       tok2str(bgp_attr_values,
2448fdccd7e4Schristos                               "Unknown Attribute", atype),
24490e9868baSchristos                       atype,
2450c74ad251Schristos                       alen);
24510f74e101Schristos 
24520e9868baSchristos             if (aflags) {
2453c74ad251Schristos                 ND_PRINT(", Flags [%s%s%s%s",
24540e9868baSchristos                           aflags & 0x80 ? "O" : "",
24550e9868baSchristos                           aflags & 0x40 ? "T" : "",
24560e9868baSchristos                           aflags & 0x20 ? "P" : "",
2457c74ad251Schristos                           aflags & 0x10 ? "E" : "");
24580e9868baSchristos                 if (aflags & 0xf)
2459c74ad251Schristos                     ND_PRINT("+%x", aflags & 0xf);
2460c74ad251Schristos                 ND_PRINT("]");
24610f74e101Schristos             }
2462c74ad251Schristos             ND_PRINT(": ");
2463c74ad251Schristos             if (len < alen) {
2464c74ad251Schristos                 ND_PRINT(" [path attr too short]");
2465c74ad251Schristos                 tptr += len;
2466c74ad251Schristos                 break;
2467c74ad251Schristos             }
2468c74ad251Schristos             /*
2469c74ad251Schristos              * The protocol encoding per se allows ATTR_SET to be nested
2470c74ad251Schristos              * as many times as the message can accommodate. This printer
2471c74ad251Schristos              * used to be able to recurse into ATTR_SET contents until the
2472c74ad251Schristos              * stack exhaustion, but now there is a limit on that (if live
2473c74ad251Schristos              * protocol exchange goes that many levels deep, something is
2474c74ad251Schristos              * probably wrong anyway). Feel free to refine this value if
2475817e9a7eSchristos              * you can find the spec with respective normative text.
2476817e9a7eSchristos              */
2477817e9a7eSchristos             if (attr_set_level == 10)
2478c74ad251Schristos                 ND_PRINT("(too many nested levels, not recursing)");
2479817e9a7eSchristos             else if (!bgp_attr_print(ndo, atype, tptr, alen, attr_set_level + 1))
24800f74e101Schristos                 return 0;
24810f74e101Schristos             tptr += alen;
24820f74e101Schristos             len -= alen;
24830f74e101Schristos         }
24840f74e101Schristos         break;
24850f74e101Schristos 
2486dc860a36Sspz     case BGPTYPE_LARGE_COMMUNITY:
2487dc860a36Sspz         if (len == 0 || len % 12) {
2488c74ad251Schristos             ND_PRINT("invalid len");
2489dc860a36Sspz             break;
2490dc860a36Sspz         }
2491c74ad251Schristos         ND_PRINT("\n\t    ");
2492c74ad251Schristos         while (len != 0) {
2493c74ad251Schristos             ND_PRINT("%u:%u:%u%s",
2494c74ad251Schristos                       GET_BE_U_4(tptr),
2495c74ad251Schristos                       GET_BE_U_4(tptr + 4),
2496c74ad251Schristos                       GET_BE_U_4(tptr + 8),
2497c74ad251Schristos                       (len > 12) ? ", " : "");
2498dc860a36Sspz             tptr += 12;
2499c74ad251Schristos             /*
2500c74ad251Schristos              * len will always be a multiple of 12, as per the above,
2501c74ad251Schristos              * so this will never underflow.
2502c74ad251Schristos              */
2503dc860a36Sspz             len -= 12;
2504dc860a36Sspz         }
2505dc860a36Sspz         break;
25060f74e101Schristos     default:
2507c74ad251Schristos         ND_TCHECK_LEN(pptr, len);
2508c74ad251Schristos         ND_PRINT("\n\t    no Attribute %u decoder", atype); /* we have no decoder for the attribute */
2509b3a00663Schristos         if (ndo->ndo_vflag <= 1)
2510b3a00663Schristos             print_unknown_data(ndo, pptr, "\n\t    ", len);
25110f74e101Schristos         break;
25120f74e101Schristos     }
2513c74ad251Schristos done:
2514b3a00663Schristos     if (ndo->ndo_vflag > 1 && len) { /* omit zero length attributes*/
2515c74ad251Schristos         ND_TCHECK_LEN(pptr, len);
2516b3a00663Schristos         print_unknown_data(ndo, pptr, "\n\t    ", len);
25170f74e101Schristos     }
25180f74e101Schristos     return 1;
25190f74e101Schristos 
25200f74e101Schristos trunc:
25210f74e101Schristos     return 0;
25220f74e101Schristos }
25230f74e101Schristos 
25240f74e101Schristos static void
2525b3a00663Schristos bgp_capabilities_print(netdissect_options *ndo,
2526c74ad251Schristos                        const u_char *opt, u_int caps_len)
25270e9868baSchristos {
2528c74ad251Schristos     /* allocate space for the largest possible string */
2529c74ad251Schristos     char astostr[AS_STR_SIZE];
2530c74ad251Schristos     u_int cap_type, cap_len, tcap_len, cap_offset;
2531c74ad251Schristos     u_int i = 0;
25320e9868baSchristos 
25330e9868baSchristos     while (i < caps_len) {
2534c74ad251Schristos         ND_TCHECK_LEN(opt + i, BGP_CAP_HEADER_SIZE);
2535c74ad251Schristos         cap_type=GET_U_1(opt + i);
2536c74ad251Schristos         cap_len=GET_U_1(opt + i + 1);
2537c74ad251Schristos         ND_PRINT("\n\t      %s (%u), length: %u",
2538c74ad251Schristos                   tok2str(bgp_capcode_values, "Unknown", cap_type),
25390e9868baSchristos                   cap_type,
2540c74ad251Schristos                   cap_len);
2541c74ad251Schristos         ND_TCHECK_LEN(opt + 2 + i, cap_len);
25420e9868baSchristos         switch (cap_type) {
25430e9868baSchristos         case BGP_CAPCODE_MP:
2544817e9a7eSchristos             /* AFI (16 bits), Reserved (8 bits), SAFI (8 bits) */
2545c74ad251Schristos             if (cap_len < 4) {
2546c74ad251Schristos                 ND_PRINT(" (too short, < 4)");
2547c74ad251Schristos                 return;
2548c74ad251Schristos             }
2549c74ad251Schristos             ND_PRINT("\n\t\tAFI %s (%u), SAFI %s (%u)",
2550c74ad251Schristos                tok2str(af_values, "Unknown", GET_BE_U_2(opt + i + 2)),
2551c74ad251Schristos                GET_BE_U_2(opt + i + 2),
2552c74ad251Schristos                tok2str(bgp_safi_values, "Unknown", GET_U_1(opt + i + 5)),
2553c74ad251Schristos                GET_U_1(opt + i + 5));
2554c74ad251Schristos             break;
2555c74ad251Schristos         case BGP_CAPCODE_ML:
2556c74ad251Schristos             cap_offset = 2;
2557c74ad251Schristos             tcap_len = cap_len;
2558c74ad251Schristos             while (tcap_len >= 4) {
2559c74ad251Schristos                 ND_PRINT( "\n\t\tAFI %s (%u), SAFI %s (%u), Count: %u",
2560fdccd7e4Schristos                        tok2str(af_values, "Unknown",
2561c74ad251Schristos                                   GET_BE_U_2(opt + i + cap_offset)),
2562c74ad251Schristos                        GET_BE_U_2(opt + i + cap_offset),
2563fdccd7e4Schristos                        tok2str(bgp_safi_values, "Unknown",
2564c74ad251Schristos                                   GET_U_1(opt + i + cap_offset + 2)),
2565c74ad251Schristos                        GET_U_1(opt + i + cap_offset + 2),
2566c74ad251Schristos                        GET_U_1(opt + i + cap_offset + 3));
2567c74ad251Schristos                 tcap_len -= 4;
2568c74ad251Schristos                 cap_offset += 4;
2569c74ad251Schristos             }
25700e9868baSchristos             break;
25710e9868baSchristos         case BGP_CAPCODE_RESTART:
2572817e9a7eSchristos             /* Restart Flags (4 bits), Restart Time in seconds (12 bits) */
2573c74ad251Schristos             if (cap_len < 2) {
2574c74ad251Schristos                 ND_PRINT(" (too short, < 2)");
2575c74ad251Schristos                 return;
2576c74ad251Schristos             }
2577c74ad251Schristos             tcap_len=cap_len;
2578c74ad251Schristos             ND_PRINT("\n\t\tRestart Flags: [%s], Restart Time %us",
2579c74ad251Schristos                       ((GET_U_1(opt + i + 2))&0x80) ? "R" : "none",
2580c74ad251Schristos                       GET_BE_U_2(opt + i + 2)&0xfff);
25810e9868baSchristos             tcap_len-=2;
25820e9868baSchristos             cap_offset=4;
25830e9868baSchristos             while(tcap_len>=4) {
2584c74ad251Schristos                 ND_PRINT("\n\t\t  AFI %s (%u), SAFI %s (%u), Forwarding state preserved: %s",
2585fdccd7e4Schristos                           tok2str(af_values,"Unknown",
2586c74ad251Schristos                                   GET_BE_U_2(opt + i + cap_offset)),
2587c74ad251Schristos                           GET_BE_U_2(opt + i + cap_offset),
2588fdccd7e4Schristos                           tok2str(bgp_safi_values,"Unknown",
2589c74ad251Schristos                                   GET_U_1(opt + i + cap_offset + 2)),
2590c74ad251Schristos                           GET_U_1(opt + (i + cap_offset + 2)),
2591c74ad251Schristos                           ((GET_U_1(opt + (i + cap_offset + 3)))&0x80) ? "yes" : "no" );
25920e9868baSchristos                 tcap_len -= 4;
25930e9868baSchristos                 cap_offset += 4;
25940e9868baSchristos             }
25950e9868baSchristos             break;
25960e9868baSchristos         case BGP_CAPCODE_RR:
2597c74ad251Schristos         case BGP_CAPCODE_LLGR:
25980e9868baSchristos         case BGP_CAPCODE_RR_CISCO:
25990e9868baSchristos             break;
26000e9868baSchristos         case BGP_CAPCODE_AS_NEW:
26010e9868baSchristos             /*
26020e9868baSchristos              * Extract the 4 byte AS number encoded.
26030e9868baSchristos              */
2604c74ad251Schristos             if (cap_len < 4) {
2605c74ad251Schristos                 ND_PRINT(" (too short, < 4)");
2606c74ad251Schristos                 return;
26070e9868baSchristos             }
2608c74ad251Schristos             ND_PRINT("\n\t\t 4 Byte AS %s",
2609c74ad251Schristos                       as_printf(ndo, astostr, sizeof(astostr),
2610c74ad251Schristos                       GET_BE_U_4(opt + i + 2)));
26110e9868baSchristos             break;
2612fdccd7e4Schristos         case BGP_CAPCODE_ADD_PATH:
2613c74ad251Schristos             if (cap_len == 0) {
2614c74ad251Schristos                 ND_PRINT(" (bogus)"); /* length */
2615c74ad251Schristos                 break;
2616c74ad251Schristos             }
2617c74ad251Schristos             tcap_len=cap_len;
2618fdccd7e4Schristos             cap_offset=2;
2619c74ad251Schristos             while (tcap_len != 0) {
2620fdccd7e4Schristos                 if (tcap_len < 4) {
2621c74ad251Schristos                     nd_print_invalid(ndo);
2622fdccd7e4Schristos                     break;
2623fdccd7e4Schristos                 }
2624c74ad251Schristos                 ND_PRINT("\n\t\tAFI %s (%u), SAFI %s (%u), Send/Receive: %s",
2625c74ad251Schristos                           tok2str(af_values,"Unknown",GET_BE_U_2(opt + i + cap_offset)),
2626c74ad251Schristos                           GET_BE_U_2(opt + i + cap_offset),
2627c74ad251Schristos                           tok2str(bgp_safi_values,"Unknown",GET_U_1(opt + i + cap_offset + 2)),
2628c74ad251Schristos                           GET_U_1(opt + (i + cap_offset + 2)),
2629c74ad251Schristos                           tok2str(bgp_add_path_recvsend,"Bogus (0x%02x)",GET_U_1(opt + i + cap_offset + 3))
2630c74ad251Schristos                 );
2631fdccd7e4Schristos                 tcap_len -= 4;
2632fdccd7e4Schristos                 cap_offset += 4;
2633fdccd7e4Schristos             }
2634fdccd7e4Schristos             break;
26350e9868baSchristos         default:
2636c74ad251Schristos             ND_PRINT("\n\t\tno decoder for Capability %u",
2637c74ad251Schristos                       cap_type);
2638b3a00663Schristos             if (ndo->ndo_vflag <= 1)
2639c74ad251Schristos                 print_unknown_data(ndo, opt + i + 2, "\n\t\t",
2640c74ad251Schristos                                    cap_len);
26410e9868baSchristos             break;
26420e9868baSchristos         }
2643c74ad251Schristos         if (ndo->ndo_vflag > 1 && cap_len != 0) {
2644c74ad251Schristos             print_unknown_data(ndo, opt + i + 2, "\n\t\t", cap_len);
26450e9868baSchristos         }
26460e9868baSchristos         i += BGP_CAP_HEADER_SIZE + cap_len;
26470e9868baSchristos     }
26480e9868baSchristos     return;
26490e9868baSchristos 
26500e9868baSchristos trunc:
2651c74ad251Schristos     nd_print_trunc(ndo);
26520e9868baSchristos }
26530e9868baSchristos 
26540e9868baSchristos static void
2655b3a00663Schristos bgp_open_print(netdissect_options *ndo,
2656c74ad251Schristos                const u_char *dat, u_int length)
26570f74e101Schristos {
2658c74ad251Schristos     /* allocate space for the largest possible string */
2659c74ad251Schristos     char astostr[AS_STR_SIZE];
2660c74ad251Schristos     const struct bgp_open *bgp_open_header;
2661c74ad251Schristos     u_int optslen;
2662c74ad251Schristos     const struct bgp_opt *bgpopt;
26630f74e101Schristos     const u_char *opt;
2664c74ad251Schristos     u_int i;
26650f74e101Schristos 
2666c74ad251Schristos     ND_TCHECK_LEN(dat, BGP_OPEN_SIZE);
2667c74ad251Schristos     if (length < BGP_OPEN_SIZE)
2668c74ad251Schristos         goto trunc;
26690f74e101Schristos 
2670c74ad251Schristos     bgp_open_header = (const struct bgp_open *)dat;
26710f74e101Schristos 
2672c74ad251Schristos     ND_PRINT("\n\t  Version %u, ",
2673c74ad251Schristos         GET_U_1(bgp_open_header->bgpo_version));
2674c74ad251Schristos     ND_PRINT("my AS %s, ",
2675c74ad251Schristos         as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(bgp_open_header->bgpo_myas)));
2676c74ad251Schristos     ND_PRINT("Holdtime %us, ",
2677c74ad251Schristos         GET_BE_U_2(bgp_open_header->bgpo_holdtime));
2678c74ad251Schristos     ND_PRINT("ID %s", GET_IPADDR_STRING(bgp_open_header->bgpo_id));
2679c74ad251Schristos     optslen = GET_U_1(bgp_open_header->bgpo_optlen);
2680c74ad251Schristos     ND_PRINT("\n\t  Optional parameters, length: %u", optslen);
26810f74e101Schristos 
2682c74ad251Schristos     opt = dat + BGP_OPEN_SIZE;
2683c74ad251Schristos     length -= BGP_OPEN_SIZE;
26840f74e101Schristos 
26850f74e101Schristos     i = 0;
2686c74ad251Schristos     while (i < optslen) {
2687c74ad251Schristos         uint8_t opt_type, opt_len;
2688c74ad251Schristos 
2689c74ad251Schristos         ND_TCHECK_LEN(opt + i, BGP_OPT_SIZE);
2690c74ad251Schristos         if (length < BGP_OPT_SIZE + i)
2691c74ad251Schristos             goto trunc;
2692c74ad251Schristos         bgpopt = (const struct bgp_opt *)(opt + i);
2693c74ad251Schristos         opt_type = GET_U_1(bgpopt->bgpopt_type);
2694c74ad251Schristos         opt_len = GET_U_1(bgpopt->bgpopt_len);
2695c74ad251Schristos         if (BGP_OPT_SIZE + i + opt_len > optslen) {
2696c74ad251Schristos             ND_PRINT("\n\t     Option %u, length: %u, goes past the end of the options",
2697c74ad251Schristos                       opt_type, opt_len);
26980f74e101Schristos             break;
26990f74e101Schristos         }
27000f74e101Schristos 
2701c74ad251Schristos         ND_PRINT("\n\t    Option %s (%u), length: %u",
2702c74ad251Schristos                   tok2str(bgp_opt_values,"Unknown",opt_type),
2703c74ad251Schristos                   opt_type,
2704c74ad251Schristos                   opt_len);
27050f74e101Schristos 
27060e9868baSchristos         /* now let's decode the options we know*/
2707c74ad251Schristos         switch(opt_type) {
27080f74e101Schristos 
27090e9868baSchristos         case BGP_OPT_CAP:
2710c74ad251Schristos             bgp_capabilities_print(ndo, opt + BGP_OPT_SIZE + i,
2711c74ad251Schristos                                    opt_len);
27120f74e101Schristos             break;
27130e9868baSchristos 
27140f74e101Schristos         case BGP_OPT_AUTH:
27150f74e101Schristos         default:
2716c74ad251Schristos                ND_PRINT("\n\t      no decoder for option %u",
2717c74ad251Schristos                opt_type);
27180f74e101Schristos                break;
27190f74e101Schristos         }
2720c74ad251Schristos         i += BGP_OPT_SIZE + opt_len;
27210f74e101Schristos     }
27220f74e101Schristos     return;
27230f74e101Schristos trunc:
2724c74ad251Schristos     nd_print_trunc(ndo);
27250f74e101Schristos }
27260f74e101Schristos 
27270f74e101Schristos static void
2728b3a00663Schristos bgp_update_print(netdissect_options *ndo,
2729c74ad251Schristos                  const u_char *dat, u_int length)
27300f74e101Schristos {
27310f74e101Schristos     const u_char *p;
2732c74ad251Schristos     u_int withdrawn_routes_len;
2733c74ad251Schristos     char buf[MAXHOSTNAMELEN + 100];
2734c74ad251Schristos     int wpfx;
2735c74ad251Schristos     u_int len;
27360f74e101Schristos     int i;
2737c74ad251Schristos     int add_path;
2738c74ad251Schristos     u_int path_id = 0;
27390f74e101Schristos 
2740c74ad251Schristos     ND_TCHECK_LEN(dat, BGP_SIZE);
27410e9868baSchristos     if (length < BGP_SIZE)
27420e9868baSchristos         goto trunc;
2743c74ad251Schristos     p = dat + BGP_SIZE;
27440e9868baSchristos     length -= BGP_SIZE;
27450f74e101Schristos 
27460f74e101Schristos     /* Unfeasible routes */
2747c74ad251Schristos     ND_TCHECK_2(p);
27480e9868baSchristos     if (length < 2)
27490e9868baSchristos         goto trunc;
2750c74ad251Schristos     withdrawn_routes_len = GET_BE_U_2(p);
27510e9868baSchristos     p += 2;
27520e9868baSchristos     length -= 2;
2753c74ad251Schristos     if (withdrawn_routes_len > 1) {
27540f74e101Schristos         /*
27550f74e101Schristos          * Without keeping state from the original NLRI message,
27560f74e101Schristos          * it's not possible to tell if this a v4 or v6 route,
27570f74e101Schristos          * so only try to decode it if we're not v6 enabled.
27580f74e101Schristos          */
2759c74ad251Schristos         ND_TCHECK_LEN(p, withdrawn_routes_len);
27600e9868baSchristos         if (length < withdrawn_routes_len)
27610e9868baSchristos             goto trunc;
2762c74ad251Schristos         ND_PRINT("\n\t  Withdrawn routes:");
2763c74ad251Schristos         add_path = check_add_path(ndo, p, withdrawn_routes_len, 32);
2764c74ad251Schristos         while (withdrawn_routes_len != 0) {
2765c74ad251Schristos             if (add_path) {
2766c74ad251Schristos                 if (withdrawn_routes_len < 4) {
2767c74ad251Schristos                     p += withdrawn_routes_len;
2768c74ad251Schristos                     length -= withdrawn_routes_len;
2769c74ad251Schristos                     break;
2770c74ad251Schristos                 }
2771c74ad251Schristos                 path_id = GET_BE_U_4(p);
2772c74ad251Schristos                 p += 4;
2773c74ad251Schristos                 length -= 4;
2774c74ad251Schristos                 withdrawn_routes_len -= 4;
2775c74ad251Schristos             }
2776c74ad251Schristos             wpfx = decode_prefix4(ndo, p, withdrawn_routes_len, buf, sizeof(buf));
2777c74ad251Schristos             if (wpfx == -1) {
2778c74ad251Schristos                 ND_PRINT("\n\t    (illegal prefix length)");
2779c74ad251Schristos                 break;
2780c74ad251Schristos             } else if (wpfx == -2)
2781c74ad251Schristos                 goto trunc; /* bytes left, but not enough */
2782c74ad251Schristos             else {
2783c74ad251Schristos                 ND_PRINT("\n\t    %s", buf);
2784c74ad251Schristos                 if (add_path) {
2785c74ad251Schristos                     ND_PRINT("   Path Id: %u", path_id);
2786c74ad251Schristos                 }
2787c74ad251Schristos                 p += wpfx;
2788c74ad251Schristos                 length -= wpfx;
2789c74ad251Schristos                 withdrawn_routes_len -= wpfx;
2790c74ad251Schristos             }
2791c74ad251Schristos         }
2792c74ad251Schristos     } else {
2793c74ad251Schristos         ND_TCHECK_LEN(p, withdrawn_routes_len);
2794c74ad251Schristos         if (length < withdrawn_routes_len)
2795c74ad251Schristos             goto trunc;
27960e9868baSchristos         p += withdrawn_routes_len;
27970e9868baSchristos         length -= withdrawn_routes_len;
27980f74e101Schristos     }
27990f74e101Schristos 
2800c74ad251Schristos     ND_TCHECK_2(p);
28010e9868baSchristos     if (length < 2)
28020e9868baSchristos         goto trunc;
2803c74ad251Schristos     len = GET_BE_U_2(p);
28040e9868baSchristos     p += 2;
28050e9868baSchristos     length -= 2;
28060f74e101Schristos 
28070e9868baSchristos     if (withdrawn_routes_len == 0 && len == 0 && length == 0) {
28080e9868baSchristos         /* No withdrawn routes, no path attributes, no NLRI */
2809c74ad251Schristos         ND_PRINT("\n\t  End-of-Rib Marker (empty NLRI)");
28100f74e101Schristos         return;
28110f74e101Schristos     }
28120f74e101Schristos 
28130f74e101Schristos     if (len) {
2814c74ad251Schristos         /* Make sure the path attributes don't go past the end of the packet */
2815c74ad251Schristos         if (length < len)
2816c74ad251Schristos             goto trunc;
28170f74e101Schristos         /* do something more useful!*/
28180e9868baSchristos         while (len) {
2819c74ad251Schristos             uint8_t aflags, atype, alenlen;
2820c74ad251Schristos             uint16_t alen;
28210f74e101Schristos 
2822c74ad251Schristos             ND_TCHECK_2(p);
28230e9868baSchristos             if (length < 2)
28240e9868baSchristos                 goto trunc;
2825c74ad251Schristos             if (len < 2) {
2826c74ad251Schristos                 ND_PRINT("\n\t  [path attrs too short]");
2827c74ad251Schristos                 p += len;
2828c74ad251Schristos                 length -= len;
2829c74ad251Schristos                 break;
2830c74ad251Schristos             }
2831c74ad251Schristos             aflags = GET_U_1(p);
2832c74ad251Schristos             atype = GET_U_1(p + 1);
28330e9868baSchristos             p += 2;
28340e9868baSchristos             len -= 2;
28350e9868baSchristos             length -= 2;
28360e9868baSchristos             alenlen = bgp_attr_lenlen(aflags, p);
2837c74ad251Schristos             ND_TCHECK_LEN(p, alenlen);
28380e9868baSchristos             if (length < alenlen)
28390e9868baSchristos                 goto trunc;
2840c74ad251Schristos             if (len < alenlen) {
2841c74ad251Schristos                 ND_PRINT("\n\t  [path attrs too short]");
2842c74ad251Schristos                 p += len;
2843c74ad251Schristos                 length -= len;
2844c74ad251Schristos                 break;
2845c74ad251Schristos             }
28460e9868baSchristos             alen = bgp_attr_len(aflags, p);
28470e9868baSchristos             p += alenlen;
28480e9868baSchristos             len -= alenlen;
28490e9868baSchristos             length -= alenlen;
28500f74e101Schristos 
2851c74ad251Schristos             ND_PRINT("\n\t  %s (%u), length: %u",
2852c74ad251Schristos                       tok2str(bgp_attr_values, "Unknown Attribute", atype),
28530e9868baSchristos                       atype,
2854c74ad251Schristos                       alen);
28550f74e101Schristos 
28560e9868baSchristos             if (aflags) {
2857c74ad251Schristos                 ND_PRINT(", Flags [%s%s%s%s",
28580e9868baSchristos                           aflags & 0x80 ? "O" : "",
28590e9868baSchristos                           aflags & 0x40 ? "T" : "",
28600e9868baSchristos                           aflags & 0x20 ? "P" : "",
2861c74ad251Schristos                           aflags & 0x10 ? "E" : "");
28620e9868baSchristos                 if (aflags & 0xf)
2863c74ad251Schristos                     ND_PRINT("+%x", aflags & 0xf);
2864c74ad251Schristos                 ND_PRINT("]: ");
28650f74e101Schristos             }
2866c74ad251Schristos             if (len < alen) {
2867c74ad251Schristos                 ND_PRINT(" [path attrs too short]");
2868c74ad251Schristos                 p += len;
2869c74ad251Schristos                 length -= len;
2870c74ad251Schristos                 break;
2871c74ad251Schristos             }
28720e9868baSchristos             if (length < alen)
28730e9868baSchristos                 goto trunc;
2874817e9a7eSchristos             if (!bgp_attr_print(ndo, atype, p, alen, 0))
28750e9868baSchristos                 goto trunc;
28760e9868baSchristos             p += alen;
28770e9868baSchristos             len -= alen;
28780e9868baSchristos             length -= alen;
28790f74e101Schristos         }
28800f74e101Schristos     }
28810f74e101Schristos 
28820e9868baSchristos     if (length) {
2883c74ad251Schristos         add_path = check_add_path(ndo, p, length, 32);
2884c74ad251Schristos         ND_PRINT("\n\t  Updated routes:");
2885c74ad251Schristos         while (length != 0) {
2886c74ad251Schristos             if (add_path) {
2887c74ad251Schristos                 ND_TCHECK_4(p);
2888c74ad251Schristos                 if (length < 4)
2889c74ad251Schristos                     goto trunc;
2890c74ad251Schristos                 path_id = GET_BE_U_4(p);
2891c74ad251Schristos                 p += 4;
2892c74ad251Schristos                 length -= 4;
2893c74ad251Schristos             }
2894b3a00663Schristos             i = decode_prefix4(ndo, p, length, buf, sizeof(buf));
28950f74e101Schristos             if (i == -1) {
2896c74ad251Schristos                 ND_PRINT("\n\t    (illegal prefix length)");
28970f74e101Schristos                 break;
28980f74e101Schristos             } else if (i == -2)
28990e9868baSchristos                 goto trunc; /* bytes left, but not enough */
29000f74e101Schristos             else {
2901c74ad251Schristos                 ND_PRINT("\n\t    %s", buf);
2902c74ad251Schristos                 if (add_path) {
2903c74ad251Schristos                     ND_PRINT("   Path Id: %u", path_id);
2904c74ad251Schristos                 }
29050f74e101Schristos                 p += i;
29060e9868baSchristos                 length -= i;
29070f74e101Schristos             }
29080f74e101Schristos         }
29090f74e101Schristos     }
29100f74e101Schristos     return;
29110f74e101Schristos trunc:
2912c74ad251Schristos     nd_print_trunc(ndo);
29130f74e101Schristos }
29140f74e101Schristos 
29150f74e101Schristos static void
2916b3a00663Schristos bgp_notification_print(netdissect_options *ndo,
2917c74ad251Schristos                        const u_char *dat, u_int length)
29180f74e101Schristos {
2919c74ad251Schristos     const struct bgp_notification *bgp_notification_header;
29200f74e101Schristos     const u_char *tptr;
2921c74ad251Schristos     uint8_t bgpn_major, bgpn_minor;
29220f74e101Schristos 
2923c74ad251Schristos     ND_TCHECK_LEN(dat, BGP_NOTIFICATION_SIZE);
29240f74e101Schristos     if (length<BGP_NOTIFICATION_SIZE)
29250f74e101Schristos         return;
29260f74e101Schristos 
2927c74ad251Schristos     bgp_notification_header = (const struct bgp_notification *)dat;
2928c74ad251Schristos     bgpn_major = GET_U_1(bgp_notification_header->bgpn_major);
2929c74ad251Schristos     bgpn_minor = GET_U_1(bgp_notification_header->bgpn_minor);
29300f74e101Schristos 
2931c74ad251Schristos     ND_PRINT(", %s (%u)",
2932c74ad251Schristos               tok2str(bgp_notify_major_values, "Unknown Error",
2933c74ad251Schristos                       bgpn_major),
2934c74ad251Schristos               bgpn_major);
2935c74ad251Schristos 
2936c74ad251Schristos     switch (bgpn_major) {
29370f74e101Schristos 
29380f74e101Schristos     case BGP_NOTIFY_MAJOR_MSG:
2939c74ad251Schristos         ND_PRINT(", subcode %s (%u)",
2940fdccd7e4Schristos                   tok2str(bgp_notify_minor_msg_values, "Unknown",
2941c74ad251Schristos                           bgpn_minor),
2942c74ad251Schristos                   bgpn_minor);
29430f74e101Schristos         break;
29440f74e101Schristos     case BGP_NOTIFY_MAJOR_OPEN:
2945c74ad251Schristos         ND_PRINT(", subcode %s (%u)",
2946fdccd7e4Schristos                   tok2str(bgp_notify_minor_open_values, "Unknown",
2947c74ad251Schristos                           bgpn_minor),
2948c74ad251Schristos                   bgpn_minor);
29490f74e101Schristos         break;
29500f74e101Schristos     case BGP_NOTIFY_MAJOR_UPDATE:
2951c74ad251Schristos         ND_PRINT(", subcode %s (%u)",
2952fdccd7e4Schristos                   tok2str(bgp_notify_minor_update_values, "Unknown",
2953c74ad251Schristos                           bgpn_minor),
2954c74ad251Schristos                   bgpn_minor);
29550f74e101Schristos         break;
2956dc860a36Sspz     case BGP_NOTIFY_MAJOR_FSM:
2957c74ad251Schristos         ND_PRINT(" subcode %s (%u)",
2958dc860a36Sspz                   tok2str(bgp_notify_minor_fsm_values, "Unknown",
2959c74ad251Schristos                           bgpn_minor),
2960c74ad251Schristos                   bgpn_minor);
2961dc860a36Sspz         break;
29620f74e101Schristos     case BGP_NOTIFY_MAJOR_CAP:
2963c74ad251Schristos         ND_PRINT(" subcode %s (%u)",
2964fdccd7e4Schristos                   tok2str(bgp_notify_minor_cap_values, "Unknown",
2965c74ad251Schristos                           bgpn_minor),
2966c74ad251Schristos                   bgpn_minor);
2967dc860a36Sspz         break;
29680f74e101Schristos     case BGP_NOTIFY_MAJOR_CEASE:
2969c74ad251Schristos         ND_PRINT(", subcode %s (%u)",
2970fdccd7e4Schristos                   tok2str(bgp_notify_minor_cease_values, "Unknown",
2971c74ad251Schristos                           bgpn_minor),
2972c74ad251Schristos                   bgpn_minor);
29730f74e101Schristos 
2974c74ad251Schristos         /* RFC 4486 mentions optionally 7 bytes
29750f74e101Schristos          * for the maxprefix subtype, which may contain AFI, SAFI and MAXPREFIXES
29760f74e101Schristos          */
2977c74ad251Schristos         if(bgpn_minor == BGP_NOTIFY_MINOR_CEASE_MAXPRFX && length >= BGP_NOTIFICATION_SIZE + 7) {
29780f74e101Schristos             tptr = dat + BGP_NOTIFICATION_SIZE;
2979c74ad251Schristos             ND_PRINT(", AFI %s (%u), SAFI %s (%u), Max Prefixes: %u",
2980c74ad251Schristos                       tok2str(af_values, "Unknown", GET_BE_U_2(tptr)),
2981c74ad251Schristos                       GET_BE_U_2(tptr),
2982c74ad251Schristos                       tok2str(bgp_safi_values, "Unknown", GET_U_1((tptr + 2))),
2983c74ad251Schristos                       GET_U_1((tptr + 2)),
2984c74ad251Schristos                       GET_BE_U_4(tptr + 3));
2985c74ad251Schristos         }
2986c74ad251Schristos         /*
2987c74ad251Schristos          * RFC 9003 describes a method to send a communication
2988c74ad251Schristos          * intended for human consumption regarding the Administrative Shutdown
2989c74ad251Schristos          */
2990c74ad251Schristos         if ((bgpn_minor == BGP_NOTIFY_MINOR_CEASE_SHUT ||
2991c74ad251Schristos              bgpn_minor == BGP_NOTIFY_MINOR_CEASE_RESET) &&
2992c74ad251Schristos              length >= BGP_NOTIFICATION_SIZE + 1) {
2993c74ad251Schristos             tptr = dat + BGP_NOTIFICATION_SIZE;
2994c74ad251Schristos             uint8_t shutdown_comm_length = GET_U_1(tptr);
2995c74ad251Schristos             uint8_t remainder_offset = 0;
2996c74ad251Schristos             /* garbage, hexdump it all */
2997c74ad251Schristos             if (shutdown_comm_length > length - (BGP_NOTIFICATION_SIZE + 1)) {
2998c74ad251Schristos                 ND_PRINT(", invalid Shutdown Communication length");
2999*26ba0b50Schristos             } else if (shutdown_comm_length == 0) {
3000c74ad251Schristos                 ND_PRINT(", empty Shutdown Communication");
3001c74ad251Schristos                 remainder_offset += 1;
3002c74ad251Schristos             }
3003c74ad251Schristos             /* a proper shutdown communication */
3004c74ad251Schristos             else {
3005c74ad251Schristos                 ND_PRINT(", Shutdown Communication (length: %u): \"", shutdown_comm_length);
3006c74ad251Schristos                 (void)nd_printn(ndo, tptr+1, shutdown_comm_length, NULL);
3007c74ad251Schristos                 ND_PRINT("\"");
3008c74ad251Schristos                 remainder_offset += shutdown_comm_length + 1;
3009c74ad251Schristos             }
3010c74ad251Schristos             /* if there is trailing data, hexdump it */
3011c74ad251Schristos             if(length - (remainder_offset + BGP_NOTIFICATION_SIZE) > 0) {
3012c74ad251Schristos                 ND_PRINT(", Data: (length: %u)", length - (remainder_offset + BGP_NOTIFICATION_SIZE));
3013c74ad251Schristos                 hex_print(ndo, "\n\t\t", tptr + remainder_offset, length - (remainder_offset + BGP_NOTIFICATION_SIZE));
3014c74ad251Schristos             }
30150f74e101Schristos         }
30160f74e101Schristos         break;
30170f74e101Schristos     default:
30180f74e101Schristos         break;
30190f74e101Schristos     }
30200f74e101Schristos 
30210f74e101Schristos     return;
30220f74e101Schristos trunc:
3023c74ad251Schristos     nd_print_trunc(ndo);
30240f74e101Schristos }
30250f74e101Schristos 
30260f74e101Schristos static void
3027b3a00663Schristos bgp_route_refresh_print(netdissect_options *ndo,
3028c74ad251Schristos                         const u_char *pptr, u_int len)
3029ba2ff121Schristos {
30300f74e101Schristos     const struct bgp_route_refresh *bgp_route_refresh_header;
30310f74e101Schristos 
3032c74ad251Schristos     ND_TCHECK_LEN(pptr, BGP_ROUTE_REFRESH_SIZE);
30330f74e101Schristos 
30340f74e101Schristos     /* some little sanity checking */
30350f74e101Schristos     if (len<BGP_ROUTE_REFRESH_SIZE)
30360f74e101Schristos         return;
30370f74e101Schristos 
30380f74e101Schristos     bgp_route_refresh_header = (const struct bgp_route_refresh *)pptr;
30390f74e101Schristos 
3040c74ad251Schristos     ND_PRINT("\n\t  AFI %s (%u), SAFI %s (%u)",
3041fdccd7e4Schristos               tok2str(af_values,"Unknown",
3042c74ad251Schristos                       GET_BE_U_2(bgp_route_refresh_header->afi)),
3043c74ad251Schristos               GET_BE_U_2(bgp_route_refresh_header->afi),
3044fdccd7e4Schristos               tok2str(bgp_safi_values,"Unknown",
3045c74ad251Schristos                       GET_U_1(bgp_route_refresh_header->safi)),
3046c74ad251Schristos               GET_U_1(bgp_route_refresh_header->safi));
30470f74e101Schristos 
3048b3a00663Schristos     if (ndo->ndo_vflag > 1) {
3049c74ad251Schristos         ND_TCHECK_LEN(pptr, len);
3050b3a00663Schristos         print_unknown_data(ndo, pptr, "\n\t  ", len);
30510f74e101Schristos     }
30520f74e101Schristos 
30530f74e101Schristos     return;
30540f74e101Schristos trunc:
3055c74ad251Schristos     nd_print_trunc(ndo);
30560f74e101Schristos }
30570f74e101Schristos 
30580f74e101Schristos static int
3059c74ad251Schristos bgp_pdu_print(netdissect_options *ndo,
3060c74ad251Schristos               const u_char *dat, u_int length)
30610f74e101Schristos {
3062c74ad251Schristos     const struct bgp *bgp_header;
3063c74ad251Schristos     uint8_t bgp_type;
30640f74e101Schristos 
3065c74ad251Schristos     ND_TCHECK_LEN(dat, BGP_SIZE);
3066c74ad251Schristos     bgp_header = (const struct bgp *)dat;
3067c74ad251Schristos     bgp_type = GET_U_1(bgp_header->bgp_type);
30680f74e101Schristos 
3069c74ad251Schristos     ND_PRINT("\n\t%s Message (%u), length: %u",
3070c74ad251Schristos               tok2str(bgp_msg_values, "Unknown", bgp_type),
3071c74ad251Schristos               bgp_type,
3072c74ad251Schristos               length);
3073c74ad251Schristos 
3074c74ad251Schristos     switch (bgp_type) {
30750f74e101Schristos     case BGP_OPEN:
3076b3a00663Schristos         bgp_open_print(ndo, dat, length);
30770f74e101Schristos         break;
30780f74e101Schristos     case BGP_UPDATE:
3079b3a00663Schristos         bgp_update_print(ndo, dat, length);
30800f74e101Schristos         break;
30810f74e101Schristos     case BGP_NOTIFICATION:
3082b3a00663Schristos         bgp_notification_print(ndo, dat, length);
30830f74e101Schristos         break;
30840f74e101Schristos     case BGP_KEEPALIVE:
30850f74e101Schristos         break;
30860f74e101Schristos     case BGP_ROUTE_REFRESH:
3087b3a00663Schristos         bgp_route_refresh_print(ndo, dat, length);
30880f74e101Schristos         break;
30890f74e101Schristos     default:
30900f74e101Schristos         /* we have no decoder for the BGP message */
3091c74ad251Schristos         ND_TCHECK_LEN(dat, length);
3092c74ad251Schristos         ND_PRINT("\n\t  no Message %u decoder", bgp_type);
3093b3a00663Schristos         print_unknown_data(ndo, dat, "\n\t  ", length);
30940f74e101Schristos         break;
30950f74e101Schristos     }
30960f74e101Schristos     return 1;
30970f74e101Schristos trunc:
3098c74ad251Schristos     nd_print_trunc(ndo);
30990f74e101Schristos     return 0;
31000f74e101Schristos }
31010f74e101Schristos 
31020f74e101Schristos void
3103b3a00663Schristos bgp_print(netdissect_options *ndo,
3104c74ad251Schristos           const u_char *dat, u_int length _U_)
31050f74e101Schristos {
31060f74e101Schristos     const u_char *p;
3107c74ad251Schristos     const u_char *ep = ndo->ndo_snapend;
31080f74e101Schristos     const u_char *start;
31090f74e101Schristos     const u_char marker[] = {
31100f74e101Schristos         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31110f74e101Schristos         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31120f74e101Schristos     };
3113c74ad251Schristos     const struct bgp *bgp_header;
3114b3a00663Schristos     uint16_t hlen;
31150f74e101Schristos 
3116c74ad251Schristos     ndo->ndo_protocol = "bgp";
3117c74ad251Schristos     ND_PRINT(": BGP");
31180f74e101Schristos 
3119b3a00663Schristos     if (ndo->ndo_vflag < 1) /* lets be less chatty */
31200f74e101Schristos         return;
31210f74e101Schristos 
31220f74e101Schristos     p = dat;
31230f74e101Schristos     start = p;
31240f74e101Schristos     while (p < ep) {
3125c74ad251Schristos         if (!ND_TTEST_1(p))
31260f74e101Schristos             break;
3127c74ad251Schristos         if (GET_U_1(p) != 0xff) {
31280f74e101Schristos             p++;
31290f74e101Schristos             continue;
31300f74e101Schristos         }
31310f74e101Schristos 
3132c74ad251Schristos         if (!ND_TTEST_LEN(p, sizeof(marker)))
31330f74e101Schristos             break;
31340f74e101Schristos         if (memcmp(p, marker, sizeof(marker)) != 0) {
31350f74e101Schristos             p++;
31360f74e101Schristos             continue;
31370f74e101Schristos         }
31380f74e101Schristos 
31390f74e101Schristos         /* found BGP header */
3140c74ad251Schristos         ND_TCHECK_LEN(p, BGP_SIZE);
3141c74ad251Schristos         bgp_header = (const struct bgp *)p;
31420f74e101Schristos 
31430f74e101Schristos         if (start != p)
3144c74ad251Schristos             nd_print_trunc(ndo);
31450f74e101Schristos 
3146c74ad251Schristos         hlen = GET_BE_U_2(bgp_header->bgp_len);
31470f74e101Schristos         if (hlen < BGP_SIZE) {
3148c74ad251Schristos             ND_PRINT("\nmessage length %u < %u", hlen, BGP_SIZE);
3149c74ad251Schristos             nd_print_invalid(ndo);
31500f74e101Schristos             break;
31510f74e101Schristos         }
31520f74e101Schristos 
3153c74ad251Schristos         if (ND_TTEST_LEN(p, hlen)) {
3154c74ad251Schristos             if (!bgp_pdu_print(ndo, p, hlen))
31550f74e101Schristos                 return;
31560f74e101Schristos             p += hlen;
31570f74e101Schristos             start = p;
31580f74e101Schristos         } else {
3159c74ad251Schristos             ND_PRINT("\n[|BGP %s]",
3160fdccd7e4Schristos                       tok2str(bgp_msg_values,
31610f74e101Schristos                               "Unknown Message Type",
3162c74ad251Schristos                               GET_U_1(bgp_header->bgp_type)));
31630f74e101Schristos             break;
31640f74e101Schristos         }
31650f74e101Schristos     }
31660f74e101Schristos 
31670f74e101Schristos     return;
31680f74e101Schristos 
31690f74e101Schristos trunc:
3170c74ad251Schristos     nd_print_trunc(ndo);
31710f74e101Schristos }
3172