1685295f4SBill Fenner /* 2685295f4SBill Fenner * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997 3685295f4SBill Fenner * The Regents of the University of California. All rights reserved. 4685295f4SBill Fenner * 5685295f4SBill Fenner * Redistribution and use in source and binary forms, with or without 6685295f4SBill Fenner * modification, are permitted provided that: (1) source code distributions 7685295f4SBill Fenner * retain the above copyright notice and this paragraph in its entirety, (2) 8685295f4SBill Fenner * distributions including binary code include the above copyright notice and 9685295f4SBill Fenner * this paragraph in its entirety in the documentation or other materials 10685295f4SBill Fenner * provided with the distribution, and (3) all advertising materials mentioning 11685295f4SBill Fenner * features or use of this software display the following acknowledgement: 12685295f4SBill Fenner * ``This product includes software developed by the University of California, 13685295f4SBill Fenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14685295f4SBill Fenner * the University nor the names of its contributors may be used to endorse 15685295f4SBill Fenner * or promote products derived from this software without specific prior 16685295f4SBill Fenner * written permission. 17685295f4SBill Fenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18685295f4SBill Fenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19685295f4SBill Fenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20685295f4SBill Fenner * 21685295f4SBill Fenner * Code by Gert Doering, SpaceNet GmbH, gert@space.net 22685295f4SBill Fenner * 23685295f4SBill Fenner * Reference documentation: 24ee67461eSJoseph Mingrone * https://web.archive.org/web/20000914194913/http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.pdf 25685295f4SBill Fenner */ 26685295f4SBill Fenner 273340d773SGleb Smirnoff /* \summary: Cisco Discovery Protocol (CDP) printer */ 283340d773SGleb Smirnoff 29ee67461eSJoseph Mingrone #include <config.h> 30685295f4SBill Fenner 31ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 32685295f4SBill Fenner 33685295f4SBill Fenner #include <string.h> 34685295f4SBill Fenner 35ee67461eSJoseph Mingrone #define ND_LONGJMP_FROM_TCHECK 363340d773SGleb Smirnoff #include "netdissect.h" 37685295f4SBill Fenner #include "addrtoname.h" 383340d773SGleb Smirnoff #include "extract.h" 391de50e9fSSam Leffler #include "nlpid.h" 40685295f4SBill Fenner 413c602fabSXin LI 425b0fe478SBruce M Simpson #define CDP_HEADER_LEN 4 438bdc5a62SPatrick Kelsey #define CDP_HEADER_VERSION_OFFSET 0 448bdc5a62SPatrick Kelsey #define CDP_HEADER_TTL_OFFSET 1 458bdc5a62SPatrick Kelsey #define CDP_HEADER_CHECKSUM_OFFSET 2 468bdc5a62SPatrick Kelsey 478bdc5a62SPatrick Kelsey #define CDP_TLV_HEADER_LEN 4 488bdc5a62SPatrick Kelsey #define CDP_TLV_TYPE_OFFSET 0 498bdc5a62SPatrick Kelsey #define CDP_TLV_LEN_OFFSET 2 505b0fe478SBruce M Simpson 513c602fabSXin LI static const struct tok cdp_capability_values[] = { 525b0fe478SBruce M Simpson { 0x01, "Router" }, 535b0fe478SBruce M Simpson { 0x02, "Transparent Bridge" }, 545b0fe478SBruce M Simpson { 0x04, "Source Route Bridge" }, 555b0fe478SBruce M Simpson { 0x08, "L2 Switch" }, 565b0fe478SBruce M Simpson { 0x10, "L3 capable" }, 575b0fe478SBruce M Simpson { 0x20, "IGMP snooping" }, 585b0fe478SBruce M Simpson { 0x40, "L1 capable" }, 595b0fe478SBruce M Simpson { 0, NULL } 605b0fe478SBruce M Simpson }; 615b0fe478SBruce M Simpson 62ee67461eSJoseph Mingrone static void cdp_print_addr(netdissect_options *, const u_char *, u_int); 63ee67461eSJoseph Mingrone static void cdp_print_prefixes(netdissect_options *, const u_char *, u_int); 64ee67461eSJoseph Mingrone 65ee67461eSJoseph Mingrone static void 66ee67461eSJoseph Mingrone cdp_print_string(netdissect_options *ndo, 67ee67461eSJoseph Mingrone const u_char *cp, const u_int len) 68ee67461eSJoseph Mingrone { 69ee67461eSJoseph Mingrone ND_PRINT("'"); 70ee67461eSJoseph Mingrone (void)nd_printn(ndo, cp, len, NULL); 71ee67461eSJoseph Mingrone ND_PRINT("'"); 72ee67461eSJoseph Mingrone } 73ee67461eSJoseph Mingrone 74ee67461eSJoseph Mingrone static void 75ee67461eSJoseph Mingrone cdp_print_power(netdissect_options *ndo, 76ee67461eSJoseph Mingrone const u_char *cp, const u_int len) 77ee67461eSJoseph Mingrone { 78ee67461eSJoseph Mingrone u_int val = 0; 79ee67461eSJoseph Mingrone 80ee67461eSJoseph Mingrone switch (len) { 81ee67461eSJoseph Mingrone case 1: 82ee67461eSJoseph Mingrone val = GET_U_1(cp); 83ee67461eSJoseph Mingrone break; 84ee67461eSJoseph Mingrone case 2: 85ee67461eSJoseph Mingrone val = GET_BE_U_2(cp); 86ee67461eSJoseph Mingrone break; 87ee67461eSJoseph Mingrone case 3: 88ee67461eSJoseph Mingrone val = GET_BE_U_3(cp); 89ee67461eSJoseph Mingrone break; 90ee67461eSJoseph Mingrone } 91ee67461eSJoseph Mingrone ND_PRINT("%1.2fW", val / 1000.0); 92ee67461eSJoseph Mingrone } 93ee67461eSJoseph Mingrone 94ee67461eSJoseph Mingrone static void 95ee67461eSJoseph Mingrone cdp_print_capability(netdissect_options *ndo, 96ee67461eSJoseph Mingrone const u_char *cp, const u_int len _U_) 97ee67461eSJoseph Mingrone { 98ee67461eSJoseph Mingrone uint32_t val = GET_BE_U_4(cp); 99ee67461eSJoseph Mingrone 100ee67461eSJoseph Mingrone ND_PRINT("(0x%08x): %s", val, 101ee67461eSJoseph Mingrone bittok2str(cdp_capability_values, "none", val)); 102ee67461eSJoseph Mingrone } 103ee67461eSJoseph Mingrone 104ee67461eSJoseph Mingrone /* Rework the version string to get a nice indentation. */ 105ee67461eSJoseph Mingrone static void 106ee67461eSJoseph Mingrone cdp_print_version(netdissect_options *ndo, 107ee67461eSJoseph Mingrone const u_char *cp, const u_int len) 108ee67461eSJoseph Mingrone { 109ee67461eSJoseph Mingrone unsigned i; 110ee67461eSJoseph Mingrone 111ee67461eSJoseph Mingrone ND_PRINT("\n\t "); 112ee67461eSJoseph Mingrone for (i = 0; i < len; i++) { 113ee67461eSJoseph Mingrone u_char c = GET_U_1(cp + i); 114ee67461eSJoseph Mingrone 115ee67461eSJoseph Mingrone if (c == '\n') 116ee67461eSJoseph Mingrone ND_PRINT("\n\t "); 117ee67461eSJoseph Mingrone else 118ee67461eSJoseph Mingrone fn_print_char(ndo, c); 119ee67461eSJoseph Mingrone } 120ee67461eSJoseph Mingrone } 121ee67461eSJoseph Mingrone 122ee67461eSJoseph Mingrone static void 123ee67461eSJoseph Mingrone cdp_print_uint16(netdissect_options *ndo, 124ee67461eSJoseph Mingrone const u_char *cp, const u_int len _U_) 125ee67461eSJoseph Mingrone { 126ee67461eSJoseph Mingrone ND_PRINT("%u", GET_BE_U_2(cp)); 127ee67461eSJoseph Mingrone } 128ee67461eSJoseph Mingrone 129ee67461eSJoseph Mingrone static void 130ee67461eSJoseph Mingrone cdp_print_duplex(netdissect_options *ndo, 131ee67461eSJoseph Mingrone const u_char *cp, const u_int len _U_) 132ee67461eSJoseph Mingrone { 133ee67461eSJoseph Mingrone ND_PRINT("%s", GET_U_1(cp) ? "full": "half"); 134ee67461eSJoseph Mingrone } 135ee67461eSJoseph Mingrone 136ee67461eSJoseph Mingrone /* https://www.cisco.com/c/en/us/td/docs/voice_ip_comm/cata/186/2_12_m/english/release/notes/186rn21m.html 137ee67461eSJoseph Mingrone * plus more details from other sources 138ee67461eSJoseph Mingrone * 139ee67461eSJoseph Mingrone * There are apparently versions of the request with both 140ee67461eSJoseph Mingrone * 2 bytes and 3 bytes of value. The 3 bytes of value 141ee67461eSJoseph Mingrone * appear to be a 1-byte application type followed by a 142ee67461eSJoseph Mingrone * 2-byte VLAN ID; the 2 bytes of value are unknown 143ee67461eSJoseph Mingrone * (they're 0x20 0x00 in some captures I've seen; that 144ee67461eSJoseph Mingrone * is not a valid VLAN ID, as VLAN IDs are 12 bits). 145ee67461eSJoseph Mingrone * 146ee67461eSJoseph Mingrone * The replies all appear to be 3 bytes long. 147ee67461eSJoseph Mingrone */ 148ee67461eSJoseph Mingrone static void 149ee67461eSJoseph Mingrone cdp_print_ata186(netdissect_options *ndo, 150ee67461eSJoseph Mingrone const u_char *cp, const u_int len) 151ee67461eSJoseph Mingrone { 152ee67461eSJoseph Mingrone if (len == 2) 153ee67461eSJoseph Mingrone ND_PRINT("unknown 0x%04x", GET_BE_U_2(cp)); 154ee67461eSJoseph Mingrone else 155ee67461eSJoseph Mingrone ND_PRINT("app %u, vlan %u", GET_U_1(cp), GET_BE_U_2(cp + 1)); 156ee67461eSJoseph Mingrone } 157ee67461eSJoseph Mingrone 158ee67461eSJoseph Mingrone static void 159ee67461eSJoseph Mingrone cdp_print_mtu(netdissect_options *ndo, 160ee67461eSJoseph Mingrone const u_char *cp, const u_int len _U_) 161ee67461eSJoseph Mingrone { 162ee67461eSJoseph Mingrone ND_PRINT("%u bytes", GET_BE_U_4(cp)); 163ee67461eSJoseph Mingrone } 164ee67461eSJoseph Mingrone 165ee67461eSJoseph Mingrone static void 166ee67461eSJoseph Mingrone cdp_print_uint8x(netdissect_options *ndo, 167ee67461eSJoseph Mingrone const u_char *cp, const u_int len _U_) 168ee67461eSJoseph Mingrone { 169ee67461eSJoseph Mingrone ND_PRINT("0x%02x", GET_U_1(cp)); 170ee67461eSJoseph Mingrone } 171ee67461eSJoseph Mingrone 172ee67461eSJoseph Mingrone static void 173ee67461eSJoseph Mingrone cdp_print_phys_loc(netdissect_options *ndo, 174ee67461eSJoseph Mingrone const u_char *cp, const u_int len) 175ee67461eSJoseph Mingrone { 176ee67461eSJoseph Mingrone ND_PRINT("0x%02x", GET_U_1(cp)); 177ee67461eSJoseph Mingrone if (len > 1) { 178ee67461eSJoseph Mingrone ND_PRINT("/"); 179ee67461eSJoseph Mingrone (void)nd_printn(ndo, cp + 1, len - 1, NULL); 180ee67461eSJoseph Mingrone } 181ee67461eSJoseph Mingrone } 182ee67461eSJoseph Mingrone 183ee67461eSJoseph Mingrone struct cdp_tlvinfo { 184ee67461eSJoseph Mingrone const char *name; 185ee67461eSJoseph Mingrone void (*printer)(netdissect_options *ndo, const u_char *, u_int); 186ee67461eSJoseph Mingrone int min_len, max_len; 187ee67461eSJoseph Mingrone }; 188ee67461eSJoseph Mingrone 189ee67461eSJoseph Mingrone #define T_DEV_ID 0x01 190ee67461eSJoseph Mingrone #define T_MAX 0x17 191ee67461eSJoseph Mingrone static const struct cdp_tlvinfo cdptlvs[T_MAX + 1] = { 192ee67461eSJoseph Mingrone /* 0x00 */ 193ee67461eSJoseph Mingrone [ T_DEV_ID ] = { "Device-ID", cdp_print_string, -1, -1 }, 194ee67461eSJoseph Mingrone [ 0x02 ] = { "Address", cdp_print_addr, -1, -1 }, 195ee67461eSJoseph Mingrone [ 0x03 ] = { "Port-ID", cdp_print_string, -1, -1 }, 196ee67461eSJoseph Mingrone [ 0x04 ] = { "Capability", cdp_print_capability, 4, 4 }, 197ee67461eSJoseph Mingrone [ 0x05 ] = { "Version String", cdp_print_version, -1, -1 }, 198ee67461eSJoseph Mingrone [ 0x06 ] = { "Platform", cdp_print_string, -1, -1 }, 199ee67461eSJoseph Mingrone [ 0x07 ] = { "Prefixes", cdp_print_prefixes, -1, -1 }, 200ee67461eSJoseph Mingrone /* not documented */ 201ee67461eSJoseph Mingrone [ 0x08 ] = { "Protocol-Hello option", NULL, -1, -1 }, 202ee67461eSJoseph Mingrone /* CDPv2 */ 203ee67461eSJoseph Mingrone [ 0x09 ] = { "VTP Management Domain", cdp_print_string, -1, -1 }, 204ee67461eSJoseph Mingrone /* CDPv2 */ 205ee67461eSJoseph Mingrone [ 0x0a ] = { "Native VLAN ID", cdp_print_uint16, 2, 2 }, 206ee67461eSJoseph Mingrone /* CDPv2 */ 207ee67461eSJoseph Mingrone [ 0x0b ] = { "Duplex", cdp_print_duplex, 1, 1 }, 208ee67461eSJoseph Mingrone /* 0x0c */ 209ee67461eSJoseph Mingrone /* 0x0d */ 210ee67461eSJoseph Mingrone /* incomplete doc. */ 211ee67461eSJoseph Mingrone [ 0x0e ] = { "ATA-186 VoIP VLAN assignment", cdp_print_ata186, 3, 3 }, 212ee67461eSJoseph Mingrone /* incomplete doc. */ 213ee67461eSJoseph Mingrone [ 0x0f ] = { "ATA-186 VoIP VLAN request", cdp_print_ata186, 2, 3 }, 214ee67461eSJoseph Mingrone /* not documented */ 215ee67461eSJoseph Mingrone [ 0x10 ] = { "power consumption", cdp_print_power, 1, 3 }, 216ee67461eSJoseph Mingrone /* not documented */ 217ee67461eSJoseph Mingrone [ 0x11 ] = { "MTU", cdp_print_mtu, 4, 4 }, 218ee67461eSJoseph Mingrone /* not documented */ 219ee67461eSJoseph Mingrone [ 0x12 ] = { "AVVID trust bitmap", cdp_print_uint8x, 1, 1 }, 220ee67461eSJoseph Mingrone /* not documented */ 221ee67461eSJoseph Mingrone [ 0x13 ] = { "AVVID untrusted ports CoS", cdp_print_uint8x, 1, 1 }, 222ee67461eSJoseph Mingrone /* not documented */ 223ee67461eSJoseph Mingrone [ 0x14 ] = { "System Name", cdp_print_string, -1, -1 }, 224ee67461eSJoseph Mingrone /* not documented */ 225ee67461eSJoseph Mingrone [ 0x15 ] = { "System Object ID (not decoded)", NULL, -1, -1 }, 226ee67461eSJoseph Mingrone [ 0x16 ] = { "Management Addresses", cdp_print_addr, 4, -1 }, 227ee67461eSJoseph Mingrone /* not documented */ 228ee67461eSJoseph Mingrone [ 0x17 ] = { "Physical Location", cdp_print_phys_loc, 1, -1 }, 229ee67461eSJoseph Mingrone }; 230685295f4SBill Fenner 231685295f4SBill Fenner void 2323c602fabSXin LI cdp_print(netdissect_options *ndo, 233ee67461eSJoseph Mingrone const u_char *tptr, u_int length) 234685295f4SBill Fenner { 235ee67461eSJoseph Mingrone u_int orig_length = length; 236ee67461eSJoseph Mingrone uint16_t checksum; 237685295f4SBill Fenner 238ee67461eSJoseph Mingrone ndo->ndo_protocol = "cdp"; 239ee67461eSJoseph Mingrone 240ee67461eSJoseph Mingrone if (length < CDP_HEADER_LEN) { 241ee67461eSJoseph Mingrone ND_PRINT(" (packet length %u < %u)", length, CDP_HEADER_LEN); 242ee67461eSJoseph Mingrone goto invalid; 243685295f4SBill Fenner } 244ee67461eSJoseph Mingrone ND_PRINT("CDPv%u, ttl: %us", 245ee67461eSJoseph Mingrone GET_U_1(tptr + CDP_HEADER_VERSION_OFFSET), 246ee67461eSJoseph Mingrone GET_U_1(tptr + CDP_HEADER_TTL_OFFSET)); 247ee67461eSJoseph Mingrone checksum = GET_BE_U_2(tptr + CDP_HEADER_CHECKSUM_OFFSET); 2483c602fabSXin LI if (ndo->ndo_vflag) 249ee67461eSJoseph Mingrone ND_PRINT(", checksum: 0x%04x (unverified), length %u", 250ee67461eSJoseph Mingrone checksum, orig_length); 2515b0fe478SBruce M Simpson tptr += CDP_HEADER_LEN; 252ee67461eSJoseph Mingrone length -= CDP_HEADER_LEN; 253685295f4SBill Fenner 254ee67461eSJoseph Mingrone while (length) { 255ee67461eSJoseph Mingrone u_int type, len; 256ee67461eSJoseph Mingrone const struct cdp_tlvinfo *info; 257ee67461eSJoseph Mingrone const char *name; 258ee67461eSJoseph Mingrone u_char covered = 0; 259ee67461eSJoseph Mingrone 260ee67461eSJoseph Mingrone if (length < CDP_TLV_HEADER_LEN) { 261ee67461eSJoseph Mingrone ND_PRINT(" (remaining packet length %u < %u)", 262ee67461eSJoseph Mingrone length, CDP_TLV_HEADER_LEN); 263ee67461eSJoseph Mingrone goto invalid; 264ee67461eSJoseph Mingrone } 265ee67461eSJoseph Mingrone type = GET_BE_U_2(tptr + CDP_TLV_TYPE_OFFSET); 266ee67461eSJoseph Mingrone len = GET_BE_U_2(tptr + CDP_TLV_LEN_OFFSET); /* object length includes the 4 bytes header length */ 267ee67461eSJoseph Mingrone info = type <= T_MAX ? &cdptlvs[type] : NULL; 268ee67461eSJoseph Mingrone name = (info && info->name) ? info->name : "unknown field type"; 2698bdc5a62SPatrick Kelsey if (len < CDP_TLV_HEADER_LEN) { 2708bdc5a62SPatrick Kelsey if (ndo->ndo_vflag) 271ee67461eSJoseph Mingrone ND_PRINT("\n\t%s (0x%02x), TLV length: %u byte%s (too short)", 272ee67461eSJoseph Mingrone name, type, len, PLURAL_SUFFIX(len)); 2738bdc5a62SPatrick Kelsey else 274ee67461eSJoseph Mingrone ND_PRINT(", %s TLV length %u too short", 275ee67461eSJoseph Mingrone name, len); 276ee67461eSJoseph Mingrone goto invalid; 277ee67461eSJoseph Mingrone } 278ee67461eSJoseph Mingrone if (len > length) { 279ee67461eSJoseph Mingrone ND_PRINT(" (TLV length %u > %u)", len, length); 280ee67461eSJoseph Mingrone goto invalid; 2818bdc5a62SPatrick Kelsey } 2828bdc5a62SPatrick Kelsey tptr += CDP_TLV_HEADER_LEN; 283ee67461eSJoseph Mingrone length -= CDP_TLV_HEADER_LEN; 2848bdc5a62SPatrick Kelsey len -= CDP_TLV_HEADER_LEN; 2855b0fe478SBruce M Simpson 286ee67461eSJoseph Mingrone /* In non-verbose mode just print Device-ID. */ 287ee67461eSJoseph Mingrone if (!ndo->ndo_vflag && type == T_DEV_ID) 288ee67461eSJoseph Mingrone ND_PRINT(", Device-ID "); 289ee67461eSJoseph Mingrone else if (ndo->ndo_vflag) 290ee67461eSJoseph Mingrone ND_PRINT("\n\t%s (0x%02x), value length: %u byte%s: ", 291ee67461eSJoseph Mingrone name, type, len, PLURAL_SUFFIX(len)); 2925b0fe478SBruce M Simpson 293ee67461eSJoseph Mingrone if (info) { 294ee67461eSJoseph Mingrone if ((info->min_len > 0 && len < (unsigned)info->min_len) || 295ee67461eSJoseph Mingrone (info->max_len > 0 && len > (unsigned)info->max_len)) 296ee67461eSJoseph Mingrone ND_PRINT(" (malformed TLV)"); 297ee67461eSJoseph Mingrone else if (ndo->ndo_vflag || type == T_DEV_ID) { 298ee67461eSJoseph Mingrone if (info->printer) 299ee67461eSJoseph Mingrone info->printer(ndo, tptr, len); 3003340d773SGleb Smirnoff else 301ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, len); 302ee67461eSJoseph Mingrone /* 303ee67461eSJoseph Mingrone * When the type is defined without a printer, 304ee67461eSJoseph Mingrone * do not print the hex dump. 3055b0fe478SBruce M Simpson */ 306ee67461eSJoseph Mingrone covered = 1; 30727df3f5dSRui Paulo } 308ee67461eSJoseph Mingrone } 309ee67461eSJoseph Mingrone 310*0a7e5f1fSJoseph Mingrone if (ndo->ndo_vflag && !covered) { 311ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, len); 3123c602fabSXin LI print_unknown_data(ndo, tptr, "\n\t ", len); 313685295f4SBill Fenner } 314ee67461eSJoseph Mingrone tptr += len; 315ee67461eSJoseph Mingrone length -= len; 316685295f4SBill Fenner } 3173c602fabSXin LI if (ndo->ndo_vflag < 1) 318ee67461eSJoseph Mingrone ND_PRINT(", length %u", orig_length); 319a90e161bSBill Fenner 320a90e161bSBill Fenner return; 321ee67461eSJoseph Mingrone invalid: 322ee67461eSJoseph Mingrone nd_print_invalid(ndo); 323ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, length); 324685295f4SBill Fenner } 325685295f4SBill Fenner 326a90e161bSBill Fenner /* 327a90e161bSBill Fenner * Protocol type values. 328a90e161bSBill Fenner * 329a90e161bSBill Fenner * PT_NLPID means that the protocol type field contains an OSI NLPID. 330a90e161bSBill Fenner * 331a90e161bSBill Fenner * PT_IEEE_802_2 means that the protocol type field contains an IEEE 802.2 332a90e161bSBill Fenner * LLC header that specifies that the payload is for that protocol. 333a90e161bSBill Fenner */ 334a90e161bSBill Fenner #define PT_NLPID 1 /* OSI NLPID */ 335a90e161bSBill Fenner #define PT_IEEE_802_2 2 /* IEEE 802.2 LLC header */ 336a90e161bSBill Fenner 337ee67461eSJoseph Mingrone static void 3383c602fabSXin LI cdp_print_addr(netdissect_options *ndo, 339ee67461eSJoseph Mingrone const u_char * p, u_int l) 340685295f4SBill Fenner { 341ee67461eSJoseph Mingrone u_int num; 3423c602fabSXin LI static const u_char prot_ipv6[] = { 343a90e161bSBill Fenner 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x86, 0xdd 344a90e161bSBill Fenner }; 345685295f4SBill Fenner 346ee67461eSJoseph Mingrone if (l < 4) { 347ee67461eSJoseph Mingrone ND_PRINT(" (not enough space for num)"); 348ee67461eSJoseph Mingrone goto invalid; 349ee67461eSJoseph Mingrone } 350ee67461eSJoseph Mingrone num = GET_BE_U_4(p); 351685295f4SBill Fenner p += 4; 352ee67461eSJoseph Mingrone l -= 4; 353685295f4SBill Fenner 354ee67461eSJoseph Mingrone while (num) { 355ee67461eSJoseph Mingrone u_int pt, pl, al; 356ee67461eSJoseph Mingrone 357ee67461eSJoseph Mingrone if (l < 2) { 358ee67461eSJoseph Mingrone ND_PRINT(" (not enough space for PT+PL)"); 359ee67461eSJoseph Mingrone goto invalid; 360ee67461eSJoseph Mingrone } 361ee67461eSJoseph Mingrone pt = GET_U_1(p); /* type of "protocol" field */ 362ee67461eSJoseph Mingrone pl = GET_U_1(p + 1); /* length of "protocol" field */ 363685295f4SBill Fenner p += 2; 364ee67461eSJoseph Mingrone l -= 2; 365685295f4SBill Fenner 366ee67461eSJoseph Mingrone if (l < pl + 2) { 367ee67461eSJoseph Mingrone ND_PRINT(" (not enough space for P+AL)"); 368ee67461eSJoseph Mingrone goto invalid; 369ee67461eSJoseph Mingrone } 370ee67461eSJoseph Mingrone /* Skip the protocol for now. */ 371ee67461eSJoseph Mingrone al = GET_BE_U_2(p + pl); /* address length */ 372a90e161bSBill Fenner 373ee67461eSJoseph Mingrone if (pt == PT_NLPID && pl == 1 && GET_U_1(p) == NLPID_IP && 374ee67461eSJoseph Mingrone al == 4) { 375a90e161bSBill Fenner /* 376a90e161bSBill Fenner * IPv4: protocol type = NLPID, protocol length = 1 377a90e161bSBill Fenner * (1-byte NLPID), protocol = 0xcc (NLPID for IPv4), 378a90e161bSBill Fenner * address length = 4 379a90e161bSBill Fenner */ 380ee67461eSJoseph Mingrone p += pl + 2; 381ee67461eSJoseph Mingrone l -= pl + 2; 382ee67461eSJoseph Mingrone /* p is just beyond al now. */ 383ee67461eSJoseph Mingrone if (l < al) { 384ee67461eSJoseph Mingrone ND_PRINT(" (not enough space for A)"); 385ee67461eSJoseph Mingrone goto invalid; 386ee67461eSJoseph Mingrone } 387ee67461eSJoseph Mingrone ND_PRINT("IPv4 (%u) %s", num, GET_IPADDR_STRING(p)); 388ee67461eSJoseph Mingrone p += al; 389ee67461eSJoseph Mingrone l -= al; 390*0a7e5f1fSJoseph Mingrone } else if (pt == PT_IEEE_802_2 && pl == 8 && 391a90e161bSBill Fenner memcmp(p, prot_ipv6, 8) == 0 && al == 16) { 392a90e161bSBill Fenner /* 393a90e161bSBill Fenner * IPv6: protocol type = IEEE 802.2 header, 394a90e161bSBill Fenner * protocol length = 8 (size of LLC+SNAP header), 395a90e161bSBill Fenner * protocol = LLC+SNAP header with the IPv6 396a90e161bSBill Fenner * Ethertype, address length = 16 397a90e161bSBill Fenner */ 398ee67461eSJoseph Mingrone p += pl + 2; 399ee67461eSJoseph Mingrone l -= pl + 2; 400ee67461eSJoseph Mingrone /* p is just beyond al now. */ 401ee67461eSJoseph Mingrone if (l < al) { 402ee67461eSJoseph Mingrone ND_PRINT(" (not enough space for A)"); 403ee67461eSJoseph Mingrone goto invalid; 404ee67461eSJoseph Mingrone } 405ee67461eSJoseph Mingrone ND_PRINT("IPv6 (%u) %s", num, GET_IP6ADDR_STRING(p)); 406a90e161bSBill Fenner p += al; 407ee67461eSJoseph Mingrone l -= al; 408*0a7e5f1fSJoseph Mingrone } else { 409a90e161bSBill Fenner /* 410a90e161bSBill Fenner * Generic case: just print raw data 411a90e161bSBill Fenner */ 412ee67461eSJoseph Mingrone ND_PRINT("pt=0x%02x, pl=%u, pb=", pt, pl); 413ee67461eSJoseph Mingrone while (pl != 0) { 414ee67461eSJoseph Mingrone ND_PRINT(" %02x", GET_U_1(p)); 415ee67461eSJoseph Mingrone p++; 416ee67461eSJoseph Mingrone l--; 417ee67461eSJoseph Mingrone pl--; 418ee67461eSJoseph Mingrone } 419ee67461eSJoseph Mingrone ND_PRINT(", al=%u, a=", al); 420685295f4SBill Fenner p += 2; 421ee67461eSJoseph Mingrone l -= 2; 422ee67461eSJoseph Mingrone /* p is just beyond al now. */ 423ee67461eSJoseph Mingrone if (l < al) { 424ee67461eSJoseph Mingrone ND_PRINT(" (not enough space for A)"); 425ee67461eSJoseph Mingrone goto invalid; 426ee67461eSJoseph Mingrone } 427ee67461eSJoseph Mingrone while (al != 0) { 428ee67461eSJoseph Mingrone ND_PRINT(" %02x", GET_U_1(p)); 429ee67461eSJoseph Mingrone p++; 430ee67461eSJoseph Mingrone l--; 431ee67461eSJoseph Mingrone al--; 432ee67461eSJoseph Mingrone } 433685295f4SBill Fenner } 434685295f4SBill Fenner num--; 435a90e161bSBill Fenner if (num) 436ee67461eSJoseph Mingrone ND_PRINT(" "); 437ee67461eSJoseph Mingrone } 438ee67461eSJoseph Mingrone if (l) 439ee67461eSJoseph Mingrone ND_PRINT(" (%u bytes of stray data)", l); 440ee67461eSJoseph Mingrone return; 441ee67461eSJoseph Mingrone 442ee67461eSJoseph Mingrone invalid: 443ee67461eSJoseph Mingrone ND_TCHECK_LEN(p, l); 444685295f4SBill Fenner } 445a90e161bSBill Fenner 446ee67461eSJoseph Mingrone static void 4473c602fabSXin LI cdp_print_prefixes(netdissect_options *ndo, 448ee67461eSJoseph Mingrone const u_char * p, u_int l) 449685295f4SBill Fenner { 450ee67461eSJoseph Mingrone if (l % 5) { 451ee67461eSJoseph Mingrone ND_PRINT(" [length %u is not a multiple of 5]", l); 452ee67461eSJoseph Mingrone goto invalid; 453ee67461eSJoseph Mingrone } 454a90e161bSBill Fenner 455ee67461eSJoseph Mingrone ND_PRINT(" IPv4 Prefixes (%u):", l / 5); 456685295f4SBill Fenner 457685295f4SBill Fenner while (l > 0) { 458ee67461eSJoseph Mingrone ND_PRINT(" %u.%u.%u.%u/%u", 459ee67461eSJoseph Mingrone GET_U_1(p), GET_U_1(p + 1), GET_U_1(p + 2), 460ee67461eSJoseph Mingrone GET_U_1(p + 3), GET_U_1(p + 4)); 461a90e161bSBill Fenner l -= 5; 462a90e161bSBill Fenner p += 5; 463685295f4SBill Fenner } 464ee67461eSJoseph Mingrone return; 465a90e161bSBill Fenner 466ee67461eSJoseph Mingrone invalid: 467ee67461eSJoseph Mingrone ND_TCHECK_LEN(p, l); 4685b0fe478SBruce M Simpson } 469