10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos * 210f74e101Schristos * Code by Gert Doering, SpaceNet GmbH, gert@space.net 220f74e101Schristos * 230f74e101Schristos * Reference documentation: 24c74ad251Schristos * https://web.archive.org/web/20000914194913/http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.pdf 250f74e101Schristos */ 260f74e101Schristos 2711b3aaa1Schristos #include <sys/cdefs.h> 280f74e101Schristos #ifndef lint 29*26ba0b50Schristos __RCSID("$NetBSD: print-cdp.c,v 1.10 2024/09/02 16:15:30 christos Exp $"); 300f74e101Schristos #endif 310f74e101Schristos 32dc860a36Sspz /* \summary: Cisco Discovery Protocol (CDP) printer */ 33dc860a36Sspz 34c74ad251Schristos #include <config.h> 350f74e101Schristos 36c74ad251Schristos #include "netdissect-stdinc.h" 370f74e101Schristos 380f74e101Schristos #include <string.h> 390f74e101Schristos 40c74ad251Schristos #define ND_LONGJMP_FROM_TCHECK 41fdccd7e4Schristos #include "netdissect.h" 420f74e101Schristos #include "addrtoname.h" 43fdccd7e4Schristos #include "extract.h" 440f74e101Schristos #include "nlpid.h" 450f74e101Schristos 46b3a00663Schristos 470f74e101Schristos #define CDP_HEADER_LEN 4 48ba2ff121Schristos #define CDP_HEADER_VERSION_OFFSET 0 49ba2ff121Schristos #define CDP_HEADER_TTL_OFFSET 1 50ba2ff121Schristos #define CDP_HEADER_CHECKSUM_OFFSET 2 51ba2ff121Schristos 52ba2ff121Schristos #define CDP_TLV_HEADER_LEN 4 53ba2ff121Schristos #define CDP_TLV_TYPE_OFFSET 0 54ba2ff121Schristos #define CDP_TLV_LEN_OFFSET 2 550f74e101Schristos 56870189d2Schristos static const struct tok cdp_capability_values[] = { 570f74e101Schristos { 0x01, "Router" }, 580f74e101Schristos { 0x02, "Transparent Bridge" }, 590f74e101Schristos { 0x04, "Source Route Bridge" }, 600f74e101Schristos { 0x08, "L2 Switch" }, 610f74e101Schristos { 0x10, "L3 capable" }, 620f74e101Schristos { 0x20, "IGMP snooping" }, 630f74e101Schristos { 0x40, "L1 capable" }, 640f74e101Schristos { 0, NULL } 650f74e101Schristos }; 660f74e101Schristos 67c74ad251Schristos static void cdp_print_addr(netdissect_options *, const u_char *, u_int); 68c74ad251Schristos static void cdp_print_prefixes(netdissect_options *, const u_char *, u_int); 69c74ad251Schristos 70c74ad251Schristos static void 71c74ad251Schristos cdp_print_string(netdissect_options *ndo, 72c74ad251Schristos const u_char *cp, const u_int len) 73c74ad251Schristos { 74c74ad251Schristos ND_PRINT("'"); 75c74ad251Schristos (void)nd_printn(ndo, cp, len, NULL); 76c74ad251Schristos ND_PRINT("'"); 77c74ad251Schristos } 78c74ad251Schristos 79c74ad251Schristos static void 80c74ad251Schristos cdp_print_power(netdissect_options *ndo, 81c74ad251Schristos const u_char *cp, const u_int len) 82c74ad251Schristos { 83c74ad251Schristos u_int val = 0; 84c74ad251Schristos 85c74ad251Schristos switch (len) { 86c74ad251Schristos case 1: 87c74ad251Schristos val = GET_U_1(cp); 88c74ad251Schristos break; 89c74ad251Schristos case 2: 90c74ad251Schristos val = GET_BE_U_2(cp); 91c74ad251Schristos break; 92c74ad251Schristos case 3: 93c74ad251Schristos val = GET_BE_U_3(cp); 94c74ad251Schristos break; 95c74ad251Schristos } 96c74ad251Schristos ND_PRINT("%1.2fW", val / 1000.0); 97c74ad251Schristos } 98c74ad251Schristos 99c74ad251Schristos static void 100c74ad251Schristos cdp_print_capability(netdissect_options *ndo, 101c74ad251Schristos const u_char *cp, const u_int len _U_) 102c74ad251Schristos { 103c74ad251Schristos uint32_t val = GET_BE_U_4(cp); 104c74ad251Schristos 105c74ad251Schristos ND_PRINT("(0x%08x): %s", val, 106c74ad251Schristos bittok2str(cdp_capability_values, "none", val)); 107c74ad251Schristos } 108c74ad251Schristos 109c74ad251Schristos /* Rework the version string to get a nice indentation. */ 110c74ad251Schristos static void 111c74ad251Schristos cdp_print_version(netdissect_options *ndo, 112c74ad251Schristos const u_char *cp, const u_int len) 113c74ad251Schristos { 114c74ad251Schristos unsigned i; 115c74ad251Schristos 116c74ad251Schristos ND_PRINT("\n\t "); 117c74ad251Schristos for (i = 0; i < len; i++) { 118c74ad251Schristos u_char c = GET_U_1(cp + i); 119c74ad251Schristos 120c74ad251Schristos if (c == '\n') 121c74ad251Schristos ND_PRINT("\n\t "); 122c74ad251Schristos else 123c74ad251Schristos fn_print_char(ndo, c); 124c74ad251Schristos } 125c74ad251Schristos } 126c74ad251Schristos 127c74ad251Schristos static void 128c74ad251Schristos cdp_print_uint16(netdissect_options *ndo, 129c74ad251Schristos const u_char *cp, const u_int len _U_) 130c74ad251Schristos { 131c74ad251Schristos ND_PRINT("%u", GET_BE_U_2(cp)); 132c74ad251Schristos } 133c74ad251Schristos 134c74ad251Schristos static void 135c74ad251Schristos cdp_print_duplex(netdissect_options *ndo, 136c74ad251Schristos const u_char *cp, const u_int len _U_) 137c74ad251Schristos { 138c74ad251Schristos ND_PRINT("%s", GET_U_1(cp) ? "full": "half"); 139c74ad251Schristos } 140c74ad251Schristos 141c74ad251Schristos /* https://www.cisco.com/c/en/us/td/docs/voice_ip_comm/cata/186/2_12_m/english/release/notes/186rn21m.html 142c74ad251Schristos * plus more details from other sources 143c74ad251Schristos * 144c74ad251Schristos * There are apparently versions of the request with both 145c74ad251Schristos * 2 bytes and 3 bytes of value. The 3 bytes of value 146c74ad251Schristos * appear to be a 1-byte application type followed by a 147c74ad251Schristos * 2-byte VLAN ID; the 2 bytes of value are unknown 148c74ad251Schristos * (they're 0x20 0x00 in some captures I've seen; that 149c74ad251Schristos * is not a valid VLAN ID, as VLAN IDs are 12 bits). 150c74ad251Schristos * 151c74ad251Schristos * The replies all appear to be 3 bytes long. 152c74ad251Schristos */ 153c74ad251Schristos static void 154c74ad251Schristos cdp_print_ata186(netdissect_options *ndo, 155c74ad251Schristos const u_char *cp, const u_int len) 156c74ad251Schristos { 157c74ad251Schristos if (len == 2) 158c74ad251Schristos ND_PRINT("unknown 0x%04x", GET_BE_U_2(cp)); 159c74ad251Schristos else 160c74ad251Schristos ND_PRINT("app %u, vlan %u", GET_U_1(cp), GET_BE_U_2(cp + 1)); 161c74ad251Schristos } 162c74ad251Schristos 163c74ad251Schristos static void 164c74ad251Schristos cdp_print_mtu(netdissect_options *ndo, 165c74ad251Schristos const u_char *cp, const u_int len _U_) 166c74ad251Schristos { 167c74ad251Schristos ND_PRINT("%u bytes", GET_BE_U_4(cp)); 168c74ad251Schristos } 169c74ad251Schristos 170c74ad251Schristos static void 171c74ad251Schristos cdp_print_uint8x(netdissect_options *ndo, 172c74ad251Schristos const u_char *cp, const u_int len _U_) 173c74ad251Schristos { 174c74ad251Schristos ND_PRINT("0x%02x", GET_U_1(cp)); 175c74ad251Schristos } 176c74ad251Schristos 177c74ad251Schristos static void 178c74ad251Schristos cdp_print_phys_loc(netdissect_options *ndo, 179c74ad251Schristos const u_char *cp, const u_int len) 180c74ad251Schristos { 181c74ad251Schristos ND_PRINT("0x%02x", GET_U_1(cp)); 182c74ad251Schristos if (len > 1) { 183c74ad251Schristos ND_PRINT("/"); 184c74ad251Schristos (void)nd_printn(ndo, cp + 1, len - 1, NULL); 185c74ad251Schristos } 186c74ad251Schristos } 187c74ad251Schristos 188c74ad251Schristos struct cdp_tlvinfo { 189c74ad251Schristos const char *name; 190c74ad251Schristos void (*printer)(netdissect_options *ndo, const u_char *, u_int); 191c74ad251Schristos int min_len, max_len; 192c74ad251Schristos }; 193c74ad251Schristos 194c74ad251Schristos #define T_DEV_ID 0x01 195c74ad251Schristos #define T_MAX 0x17 196c74ad251Schristos static const struct cdp_tlvinfo cdptlvs[T_MAX + 1] = { 197c74ad251Schristos /* 0x00 */ 198c74ad251Schristos [ T_DEV_ID ] = { "Device-ID", cdp_print_string, -1, -1 }, 199c74ad251Schristos [ 0x02 ] = { "Address", cdp_print_addr, -1, -1 }, 200c74ad251Schristos [ 0x03 ] = { "Port-ID", cdp_print_string, -1, -1 }, 201c74ad251Schristos [ 0x04 ] = { "Capability", cdp_print_capability, 4, 4 }, 202c74ad251Schristos [ 0x05 ] = { "Version String", cdp_print_version, -1, -1 }, 203c74ad251Schristos [ 0x06 ] = { "Platform", cdp_print_string, -1, -1 }, 204c74ad251Schristos [ 0x07 ] = { "Prefixes", cdp_print_prefixes, -1, -1 }, 205c74ad251Schristos /* not documented */ 206c74ad251Schristos [ 0x08 ] = { "Protocol-Hello option", NULL, -1, -1 }, 207c74ad251Schristos /* CDPv2 */ 208c74ad251Schristos [ 0x09 ] = { "VTP Management Domain", cdp_print_string, -1, -1 }, 209c74ad251Schristos /* CDPv2 */ 210c74ad251Schristos [ 0x0a ] = { "Native VLAN ID", cdp_print_uint16, 2, 2 }, 211c74ad251Schristos /* CDPv2 */ 212c74ad251Schristos [ 0x0b ] = { "Duplex", cdp_print_duplex, 1, 1 }, 213c74ad251Schristos /* 0x0c */ 214c74ad251Schristos /* 0x0d */ 215c74ad251Schristos /* incomplete doc. */ 216c74ad251Schristos [ 0x0e ] = { "ATA-186 VoIP VLAN assignment", cdp_print_ata186, 3, 3 }, 217c74ad251Schristos /* incomplete doc. */ 218c74ad251Schristos [ 0x0f ] = { "ATA-186 VoIP VLAN request", cdp_print_ata186, 2, 3 }, 219c74ad251Schristos /* not documented */ 220c74ad251Schristos [ 0x10 ] = { "power consumption", cdp_print_power, 1, 3 }, 221c74ad251Schristos /* not documented */ 222c74ad251Schristos [ 0x11 ] = { "MTU", cdp_print_mtu, 4, 4 }, 223c74ad251Schristos /* not documented */ 224c74ad251Schristos [ 0x12 ] = { "AVVID trust bitmap", cdp_print_uint8x, 1, 1 }, 225c74ad251Schristos /* not documented */ 226c74ad251Schristos [ 0x13 ] = { "AVVID untrusted ports CoS", cdp_print_uint8x, 1, 1 }, 227c74ad251Schristos /* not documented */ 228c74ad251Schristos [ 0x14 ] = { "System Name", cdp_print_string, -1, -1 }, 229c74ad251Schristos /* not documented */ 230c74ad251Schristos [ 0x15 ] = { "System Object ID (not decoded)", NULL, -1, -1 }, 231c74ad251Schristos [ 0x16 ] = { "Management Addresses", cdp_print_addr, 4, -1 }, 232c74ad251Schristos /* not documented */ 233c74ad251Schristos [ 0x17 ] = { "Physical Location", cdp_print_phys_loc, 1, -1 }, 234c74ad251Schristos }; 2350f74e101Schristos 2360f74e101Schristos void 237b3a00663Schristos cdp_print(netdissect_options *ndo, 238c74ad251Schristos const u_char *tptr, u_int length) 2390f74e101Schristos { 240c74ad251Schristos u_int orig_length = length; 241c74ad251Schristos uint16_t checksum; 2420f74e101Schristos 243c74ad251Schristos ndo->ndo_protocol = "cdp"; 244c74ad251Schristos 245c74ad251Schristos if (length < CDP_HEADER_LEN) { 246c74ad251Schristos ND_PRINT(" (packet length %u < %u)", length, CDP_HEADER_LEN); 247c74ad251Schristos goto invalid; 2480f74e101Schristos } 249c74ad251Schristos ND_PRINT("CDPv%u, ttl: %us", 250c74ad251Schristos GET_U_1(tptr + CDP_HEADER_VERSION_OFFSET), 251c74ad251Schristos GET_U_1(tptr + CDP_HEADER_TTL_OFFSET)); 252c74ad251Schristos checksum = GET_BE_U_2(tptr + CDP_HEADER_CHECKSUM_OFFSET); 253b3a00663Schristos if (ndo->ndo_vflag) 254c74ad251Schristos ND_PRINT(", checksum: 0x%04x (unverified), length %u", 255c74ad251Schristos checksum, orig_length); 2560f74e101Schristos tptr += CDP_HEADER_LEN; 257c74ad251Schristos length -= CDP_HEADER_LEN; 2580f74e101Schristos 259c74ad251Schristos while (length) { 260c74ad251Schristos u_int type, len; 261c74ad251Schristos const struct cdp_tlvinfo *info; 262c74ad251Schristos const char *name; 263c74ad251Schristos u_char covered = 0; 264c74ad251Schristos 265c74ad251Schristos if (length < CDP_TLV_HEADER_LEN) { 266c74ad251Schristos ND_PRINT(" (remaining packet length %u < %u)", 267c74ad251Schristos length, CDP_TLV_HEADER_LEN); 268c74ad251Schristos goto invalid; 269c74ad251Schristos } 270c74ad251Schristos type = GET_BE_U_2(tptr + CDP_TLV_TYPE_OFFSET); 271c74ad251Schristos len = GET_BE_U_2(tptr + CDP_TLV_LEN_OFFSET); /* object length includes the 4 bytes header length */ 272c74ad251Schristos info = type <= T_MAX ? &cdptlvs[type] : NULL; 273c74ad251Schristos name = (info && info->name) ? info->name : "unknown field type"; 274ba2ff121Schristos if (len < CDP_TLV_HEADER_LEN) { 275ba2ff121Schristos if (ndo->ndo_vflag) 276c74ad251Schristos ND_PRINT("\n\t%s (0x%02x), TLV length: %u byte%s (too short)", 277c74ad251Schristos name, type, len, PLURAL_SUFFIX(len)); 278ba2ff121Schristos else 279c74ad251Schristos ND_PRINT(", %s TLV length %u too short", 280c74ad251Schristos name, len); 281c74ad251Schristos goto invalid; 282c74ad251Schristos } 283c74ad251Schristos if (len > length) { 284c74ad251Schristos ND_PRINT(" (TLV length %u > %u)", len, length); 285c74ad251Schristos goto invalid; 286ba2ff121Schristos } 287ba2ff121Schristos tptr += CDP_TLV_HEADER_LEN; 288c74ad251Schristos length -= CDP_TLV_HEADER_LEN; 289ba2ff121Schristos len -= CDP_TLV_HEADER_LEN; 2900f74e101Schristos 291c74ad251Schristos /* In non-verbose mode just print Device-ID. */ 292c74ad251Schristos if (!ndo->ndo_vflag && type == T_DEV_ID) 293c74ad251Schristos ND_PRINT(", Device-ID "); 294c74ad251Schristos else if (ndo->ndo_vflag) 295c74ad251Schristos ND_PRINT("\n\t%s (0x%02x), value length: %u byte%s: ", 296c74ad251Schristos name, type, len, PLURAL_SUFFIX(len)); 2970f74e101Schristos 298c74ad251Schristos if (info) { 299c74ad251Schristos if ((info->min_len > 0 && len < (unsigned)info->min_len) || 300c74ad251Schristos (info->max_len > 0 && len > (unsigned)info->max_len)) 301c74ad251Schristos ND_PRINT(" (malformed TLV)"); 302c74ad251Schristos else if (ndo->ndo_vflag || type == T_DEV_ID) { 303c74ad251Schristos if (info->printer) 304c74ad251Schristos info->printer(ndo, tptr, len); 305fdccd7e4Schristos else 306c74ad251Schristos ND_TCHECK_LEN(tptr, len); 307c74ad251Schristos /* 308c74ad251Schristos * When the type is defined without a printer, 309c74ad251Schristos * do not print the hex dump. 3100f74e101Schristos */ 311c74ad251Schristos covered = 1; 3120f74e101Schristos } 313c74ad251Schristos } 314c74ad251Schristos 315*26ba0b50Schristos if (ndo->ndo_vflag && !covered) { 316c74ad251Schristos ND_TCHECK_LEN(tptr, len); 317b3a00663Schristos print_unknown_data(ndo, tptr, "\n\t ", len); 3180f74e101Schristos } 319c74ad251Schristos tptr += len; 320c74ad251Schristos length -= len; 3210f74e101Schristos } 322b3a00663Schristos if (ndo->ndo_vflag < 1) 323c74ad251Schristos ND_PRINT(", length %u", orig_length); 3240f74e101Schristos 3250f74e101Schristos return; 326c74ad251Schristos invalid: 327c74ad251Schristos nd_print_invalid(ndo); 328c74ad251Schristos ND_TCHECK_LEN(tptr, length); 3290f74e101Schristos } 3300f74e101Schristos 3310f74e101Schristos /* 3320f74e101Schristos * Protocol type values. 3330f74e101Schristos * 3340f74e101Schristos * PT_NLPID means that the protocol type field contains an OSI NLPID. 3350f74e101Schristos * 3360f74e101Schristos * PT_IEEE_802_2 means that the protocol type field contains an IEEE 802.2 3370f74e101Schristos * LLC header that specifies that the payload is for that protocol. 3380f74e101Schristos */ 3390f74e101Schristos #define PT_NLPID 1 /* OSI NLPID */ 3400f74e101Schristos #define PT_IEEE_802_2 2 /* IEEE 802.2 LLC header */ 3410f74e101Schristos 342c74ad251Schristos static void 343b3a00663Schristos cdp_print_addr(netdissect_options *ndo, 344c74ad251Schristos const u_char * p, u_int l) 3450f74e101Schristos { 346c74ad251Schristos u_int num; 347b3a00663Schristos static const u_char prot_ipv6[] = { 3480f74e101Schristos 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x86, 0xdd 3490f74e101Schristos }; 3500f74e101Schristos 351c74ad251Schristos if (l < 4) { 352c74ad251Schristos ND_PRINT(" (not enough space for num)"); 353c74ad251Schristos goto invalid; 354c74ad251Schristos } 355c74ad251Schristos num = GET_BE_U_4(p); 3560f74e101Schristos p += 4; 357c74ad251Schristos l -= 4; 3580f74e101Schristos 359c74ad251Schristos while (num) { 360c74ad251Schristos u_int pt, pl, al; 361c74ad251Schristos 362c74ad251Schristos if (l < 2) { 363c74ad251Schristos ND_PRINT(" (not enough space for PT+PL)"); 364c74ad251Schristos goto invalid; 365c74ad251Schristos } 366c74ad251Schristos pt = GET_U_1(p); /* type of "protocol" field */ 367c74ad251Schristos pl = GET_U_1(p + 1); /* length of "protocol" field */ 3680f74e101Schristos p += 2; 369c74ad251Schristos l -= 2; 3700f74e101Schristos 371c74ad251Schristos if (l < pl + 2) { 372c74ad251Schristos ND_PRINT(" (not enough space for P+AL)"); 373c74ad251Schristos goto invalid; 374c74ad251Schristos } 375c74ad251Schristos /* Skip the protocol for now. */ 376c74ad251Schristos al = GET_BE_U_2(p + pl); /* address length */ 3770f74e101Schristos 378c74ad251Schristos if (pt == PT_NLPID && pl == 1 && GET_U_1(p) == NLPID_IP && 379c74ad251Schristos al == 4) { 3800f74e101Schristos /* 3810f74e101Schristos * IPv4: protocol type = NLPID, protocol length = 1 3820f74e101Schristos * (1-byte NLPID), protocol = 0xcc (NLPID for IPv4), 3830f74e101Schristos * address length = 4 3840f74e101Schristos */ 385c74ad251Schristos p += pl + 2; 386c74ad251Schristos l -= pl + 2; 387c74ad251Schristos /* p is just beyond al now. */ 388c74ad251Schristos if (l < al) { 389c74ad251Schristos ND_PRINT(" (not enough space for A)"); 390c74ad251Schristos goto invalid; 391c74ad251Schristos } 392c74ad251Schristos ND_PRINT("IPv4 (%u) %s", num, GET_IPADDR_STRING(p)); 393c74ad251Schristos p += al; 394c74ad251Schristos l -= al; 395*26ba0b50Schristos } else if (pt == PT_IEEE_802_2 && pl == 8 && 3960f74e101Schristos memcmp(p, prot_ipv6, 8) == 0 && al == 16) { 3970f74e101Schristos /* 3980f74e101Schristos * IPv6: protocol type = IEEE 802.2 header, 3990f74e101Schristos * protocol length = 8 (size of LLC+SNAP header), 4000f74e101Schristos * protocol = LLC+SNAP header with the IPv6 4010f74e101Schristos * Ethertype, address length = 16 4020f74e101Schristos */ 403c74ad251Schristos p += pl + 2; 404c74ad251Schristos l -= pl + 2; 405c74ad251Schristos /* p is just beyond al now. */ 406c74ad251Schristos if (l < al) { 407c74ad251Schristos ND_PRINT(" (not enough space for A)"); 408c74ad251Schristos goto invalid; 409c74ad251Schristos } 410c74ad251Schristos ND_PRINT("IPv6 (%u) %s", num, GET_IP6ADDR_STRING(p)); 4110f74e101Schristos p += al; 412c74ad251Schristos l -= al; 413*26ba0b50Schristos } else { 4140f74e101Schristos /* 4150f74e101Schristos * Generic case: just print raw data 4160f74e101Schristos */ 417c74ad251Schristos ND_PRINT("pt=0x%02x, pl=%u, pb=", pt, pl); 418c74ad251Schristos while (pl != 0) { 419c74ad251Schristos ND_PRINT(" %02x", GET_U_1(p)); 420c74ad251Schristos p++; 421c74ad251Schristos l--; 422c74ad251Schristos pl--; 423c74ad251Schristos } 424c74ad251Schristos ND_PRINT(", al=%u, a=", al); 4250f74e101Schristos p += 2; 426c74ad251Schristos l -= 2; 427c74ad251Schristos /* p is just beyond al now. */ 428c74ad251Schristos if (l < al) { 429c74ad251Schristos ND_PRINT(" (not enough space for A)"); 430c74ad251Schristos goto invalid; 431c74ad251Schristos } 432c74ad251Schristos while (al != 0) { 433c74ad251Schristos ND_PRINT(" %02x", GET_U_1(p)); 434c74ad251Schristos p++; 435c74ad251Schristos l--; 436c74ad251Schristos al--; 437c74ad251Schristos } 4380f74e101Schristos } 4390f74e101Schristos num--; 4400f74e101Schristos if (num) 441c74ad251Schristos ND_PRINT(" "); 442c74ad251Schristos } 443c74ad251Schristos if (l) 444c74ad251Schristos ND_PRINT(" (%u bytes of stray data)", l); 445c74ad251Schristos return; 446c74ad251Schristos 447c74ad251Schristos invalid: 448c74ad251Schristos ND_TCHECK_LEN(p, l); 4490f74e101Schristos } 4500f74e101Schristos 451c74ad251Schristos static void 452b3a00663Schristos cdp_print_prefixes(netdissect_options *ndo, 453c74ad251Schristos const u_char * p, u_int l) 4540f74e101Schristos { 455c74ad251Schristos if (l % 5) { 456c74ad251Schristos ND_PRINT(" [length %u is not a multiple of 5]", l); 457c74ad251Schristos goto invalid; 458c74ad251Schristos } 4590f74e101Schristos 460c74ad251Schristos ND_PRINT(" IPv4 Prefixes (%u):", l / 5); 4610f74e101Schristos 4620f74e101Schristos while (l > 0) { 463c74ad251Schristos ND_PRINT(" %u.%u.%u.%u/%u", 464c74ad251Schristos GET_U_1(p), GET_U_1(p + 1), GET_U_1(p + 2), 465c74ad251Schristos GET_U_1(p + 3), GET_U_1(p + 4)); 4660f74e101Schristos l -= 5; 4670f74e101Schristos p += 5; 4680f74e101Schristos } 469c74ad251Schristos return; 4700f74e101Schristos 471c74ad251Schristos invalid: 472c74ad251Schristos ND_TCHECK_LEN(p, l); 4730f74e101Schristos } 474