1a5779b6eSRui Paulo /* 2a5779b6eSRui Paulo * Copyright (c) 1998-2007 The TCPDUMP project 3a5779b6eSRui Paulo * 4a5779b6eSRui Paulo * Redistribution and use in source and binary forms, with or without 5a5779b6eSRui Paulo * modification, are permitted provided that: (1) source code 6a5779b6eSRui Paulo * distributions retain the above copyright notice and this paragraph 7a5779b6eSRui Paulo * in its entirety, and (2) distributions including binary code include 8a5779b6eSRui Paulo * the above copyright notice and this paragraph in its entirety in 9a5779b6eSRui Paulo * the documentation or other materials provided with the distribution. 10a5779b6eSRui Paulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 11a5779b6eSRui Paulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 12a5779b6eSRui Paulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13a5779b6eSRui Paulo * FOR A PARTICULAR PURPOSE. 14a5779b6eSRui Paulo * 15a5779b6eSRui Paulo * Original code by Carles Kishimoto <carles.kishimoto@gmail.com> 16a5779b6eSRui Paulo */ 17a5779b6eSRui Paulo 183340d773SGleb Smirnoff /* \summary: Cisco UniDirectional Link Detection (UDLD) protocol printer */ 193340d773SGleb Smirnoff 203340d773SGleb Smirnoff /* specification: RFC 5171 */ 213340d773SGleb Smirnoff 22*ee67461eSJoseph Mingrone #include <config.h> 23a5779b6eSRui Paulo 24*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 25a5779b6eSRui Paulo 26*ee67461eSJoseph Mingrone #define ND_LONGJMP_FROM_TCHECK 273340d773SGleb Smirnoff #include "netdissect.h" 28a5779b6eSRui Paulo #include "extract.h" 29a5779b6eSRui Paulo 303340d773SGleb Smirnoff 31a5779b6eSRui Paulo #define UDLD_HEADER_LEN 4 32*ee67461eSJoseph Mingrone #define UDLD_TLV_HEADER_LEN 4 33a5779b6eSRui Paulo #define UDLD_DEVICE_ID_TLV 0x0001 34a5779b6eSRui Paulo #define UDLD_PORT_ID_TLV 0x0002 35a5779b6eSRui Paulo #define UDLD_ECHO_TLV 0x0003 36a5779b6eSRui Paulo #define UDLD_MESSAGE_INTERVAL_TLV 0x0004 37a5779b6eSRui Paulo #define UDLD_TIMEOUT_INTERVAL_TLV 0x0005 38a5779b6eSRui Paulo #define UDLD_DEVICE_NAME_TLV 0x0006 39a5779b6eSRui Paulo #define UDLD_SEQ_NUMBER_TLV 0x0007 40a5779b6eSRui Paulo 413c602fabSXin LI static const struct tok udld_tlv_values[] = { 42a5779b6eSRui Paulo { UDLD_DEVICE_ID_TLV, "Device-ID TLV"}, 43a5779b6eSRui Paulo { UDLD_PORT_ID_TLV, "Port-ID TLV"}, 44a5779b6eSRui Paulo { UDLD_ECHO_TLV, "Echo TLV"}, 45a5779b6eSRui Paulo { UDLD_MESSAGE_INTERVAL_TLV, "Message Interval TLV"}, 46a5779b6eSRui Paulo { UDLD_TIMEOUT_INTERVAL_TLV, "Timeout Interval TLV"}, 47a5779b6eSRui Paulo { UDLD_DEVICE_NAME_TLV, "Device Name TLV"}, 48a5779b6eSRui Paulo { UDLD_SEQ_NUMBER_TLV,"Sequence Number TLV"}, 49a5779b6eSRui Paulo { 0, NULL} 50a5779b6eSRui Paulo }; 51a5779b6eSRui Paulo 523c602fabSXin LI static const struct tok udld_code_values[] = { 53a5779b6eSRui Paulo { 0x00, "Reserved"}, 54a5779b6eSRui Paulo { 0x01, "Probe message"}, 55a5779b6eSRui Paulo { 0x02, "Echo message"}, 56a5779b6eSRui Paulo { 0x03, "Flush message"}, 57a5779b6eSRui Paulo { 0, NULL} 58a5779b6eSRui Paulo }; 59a5779b6eSRui Paulo 60*ee67461eSJoseph Mingrone static const struct tok udld_flags_bitmap_str[] = { 61*ee67461eSJoseph Mingrone { 1U << 0, "RT" }, 62*ee67461eSJoseph Mingrone { 1U << 1, "RSY" }, 63*ee67461eSJoseph Mingrone { 1U << 2, "MBZ-2" }, 64*ee67461eSJoseph Mingrone { 1U << 3, "MBZ-3" }, 65*ee67461eSJoseph Mingrone { 1U << 4, "MBZ-4" }, 66*ee67461eSJoseph Mingrone { 1U << 5, "MBZ-5" }, 67*ee67461eSJoseph Mingrone { 1U << 6, "MBZ-6" }, 68*ee67461eSJoseph Mingrone { 1U << 7, "MBZ-7" }, 69a5779b6eSRui Paulo { 0, NULL} 70a5779b6eSRui Paulo }; 71a5779b6eSRui Paulo 72a5779b6eSRui Paulo /* 733340d773SGleb Smirnoff * UDLD's Protocol Data Unit format: 74a5779b6eSRui Paulo * 75a5779b6eSRui Paulo * 0 1 2 3 76a5779b6eSRui Paulo * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 77a5779b6eSRui Paulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 78a5779b6eSRui Paulo * | Ver | Opcode | Flags | Checksum | 79a5779b6eSRui Paulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 80a5779b6eSRui Paulo * | List of TLVs (variable length list) | 81a5779b6eSRui Paulo * | ... | 82a5779b6eSRui Paulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83a5779b6eSRui Paulo * 843340d773SGleb Smirnoff * TLV format: 853340d773SGleb Smirnoff * 863340d773SGleb Smirnoff * 0 1 2 3 873340d773SGleb Smirnoff * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 883340d773SGleb Smirnoff * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 893340d773SGleb Smirnoff * | TYPE | LENGTH | 903340d773SGleb Smirnoff * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 913340d773SGleb Smirnoff * | VALUE | 923340d773SGleb Smirnoff * | ... | 933340d773SGleb Smirnoff * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 943340d773SGleb Smirnoff * 953340d773SGleb Smirnoff * LENGTH: Length in bytes of the Type, Length, and Value fields. 96a5779b6eSRui Paulo */ 97a5779b6eSRui Paulo 98a5779b6eSRui Paulo #define UDLD_EXTRACT_VERSION(x) (((x)&0xe0)>>5) 99a5779b6eSRui Paulo #define UDLD_EXTRACT_OPCODE(x) ((x)&0x1f) 100a5779b6eSRui Paulo 101a5779b6eSRui Paulo void 102*ee67461eSJoseph Mingrone udld_print(netdissect_options *ndo, 103*ee67461eSJoseph Mingrone const u_char *tptr, u_int length) 104a5779b6eSRui Paulo { 105*ee67461eSJoseph Mingrone uint8_t ver, code, flags; 106a5779b6eSRui Paulo 107*ee67461eSJoseph Mingrone ndo->ndo_protocol = "udld"; 108a5779b6eSRui Paulo if (length < UDLD_HEADER_LEN) 109*ee67461eSJoseph Mingrone goto invalid; 110a5779b6eSRui Paulo 111*ee67461eSJoseph Mingrone ver = UDLD_EXTRACT_VERSION(GET_U_1(tptr)); 112*ee67461eSJoseph Mingrone code = UDLD_EXTRACT_OPCODE(GET_U_1(tptr)); 113*ee67461eSJoseph Mingrone tptr += 1; 114*ee67461eSJoseph Mingrone length -= 1; 115a5779b6eSRui Paulo 116*ee67461eSJoseph Mingrone flags = GET_U_1(tptr); 117*ee67461eSJoseph Mingrone tptr += 1; 118*ee67461eSJoseph Mingrone length -= 1; 119a5779b6eSRui Paulo 120*ee67461eSJoseph Mingrone ND_PRINT("UDLDv%u, Code %s (%x), Flags [%s] (0x%02x), length %u", 121*ee67461eSJoseph Mingrone ver, 122a5779b6eSRui Paulo tok2str(udld_code_values, "Reserved", code), 123a5779b6eSRui Paulo code, 124*ee67461eSJoseph Mingrone bittok2str(udld_flags_bitmap_str, "none", flags), 125*ee67461eSJoseph Mingrone flags, 126*ee67461eSJoseph Mingrone length + 2); 127a5779b6eSRui Paulo 128a5779b6eSRui Paulo /* 129a5779b6eSRui Paulo * In non-verbose mode, just print version and opcode type 130a5779b6eSRui Paulo */ 1313c602fabSXin LI if (ndo->ndo_vflag < 1) { 132*ee67461eSJoseph Mingrone goto tcheck_remainder; 133a5779b6eSRui Paulo } 134a5779b6eSRui Paulo 135*ee67461eSJoseph Mingrone ND_PRINT("\n\tChecksum 0x%04x (unverified)", GET_BE_U_2(tptr)); 136*ee67461eSJoseph Mingrone tptr += 2; 137*ee67461eSJoseph Mingrone length -= 2; 138a5779b6eSRui Paulo 139*ee67461eSJoseph Mingrone while (length) { 140*ee67461eSJoseph Mingrone uint16_t type, len; 141a5779b6eSRui Paulo 142*ee67461eSJoseph Mingrone if (length < UDLD_TLV_HEADER_LEN) 1433340d773SGleb Smirnoff goto invalid; 1443340d773SGleb Smirnoff 145*ee67461eSJoseph Mingrone type = GET_BE_U_2(tptr); 146*ee67461eSJoseph Mingrone tptr += 2; 147*ee67461eSJoseph Mingrone length -= 2; 148*ee67461eSJoseph Mingrone 149*ee67461eSJoseph Mingrone len = GET_BE_U_2(tptr); 150*ee67461eSJoseph Mingrone tptr += 2; 151*ee67461eSJoseph Mingrone length -= 2; 152*ee67461eSJoseph Mingrone 153*ee67461eSJoseph Mingrone ND_PRINT("\n\t%s (0x%04x) TLV, length %u", 154*ee67461eSJoseph Mingrone tok2str(udld_tlv_values, "Unknown", type), 155*ee67461eSJoseph Mingrone type, len); 156*ee67461eSJoseph Mingrone 1573340d773SGleb Smirnoff /* infinite loop check */ 158*ee67461eSJoseph Mingrone if (len <= UDLD_TLV_HEADER_LEN) 1593340d773SGleb Smirnoff goto invalid; 1603340d773SGleb Smirnoff 161*ee67461eSJoseph Mingrone len -= UDLD_TLV_HEADER_LEN; 162*ee67461eSJoseph Mingrone if (length < len) 163*ee67461eSJoseph Mingrone goto invalid; 1643340d773SGleb Smirnoff 165a5779b6eSRui Paulo switch (type) { 166a5779b6eSRui Paulo case UDLD_DEVICE_ID_TLV: 167a5779b6eSRui Paulo case UDLD_PORT_ID_TLV: 168a5779b6eSRui Paulo case UDLD_DEVICE_NAME_TLV: 169*ee67461eSJoseph Mingrone ND_PRINT(", "); 170*ee67461eSJoseph Mingrone nd_printjnp(ndo, tptr, len); 1713340d773SGleb Smirnoff break; 1723340d773SGleb Smirnoff 1733340d773SGleb Smirnoff case UDLD_ECHO_TLV: 174*ee67461eSJoseph Mingrone ND_PRINT(", "); 175*ee67461eSJoseph Mingrone (void)nd_printn(ndo, tptr, len, NULL); 176a5779b6eSRui Paulo break; 177a5779b6eSRui Paulo 178a5779b6eSRui Paulo case UDLD_MESSAGE_INTERVAL_TLV: 179a5779b6eSRui Paulo case UDLD_TIMEOUT_INTERVAL_TLV: 1803340d773SGleb Smirnoff if (len != 1) 1813340d773SGleb Smirnoff goto invalid; 182*ee67461eSJoseph Mingrone ND_PRINT(", %us", (GET_U_1(tptr))); 183a5779b6eSRui Paulo break; 184a5779b6eSRui Paulo 185a5779b6eSRui Paulo case UDLD_SEQ_NUMBER_TLV: 1863340d773SGleb Smirnoff if (len != 4) 1873340d773SGleb Smirnoff goto invalid; 188*ee67461eSJoseph Mingrone ND_PRINT(", %u", GET_BE_U_4(tptr)); 189a5779b6eSRui Paulo break; 190a5779b6eSRui Paulo 191a5779b6eSRui Paulo default: 192*ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, len); 193a5779b6eSRui Paulo break; 194a5779b6eSRui Paulo } 195a5779b6eSRui Paulo tptr += len; 196*ee67461eSJoseph Mingrone length -= len; 197a5779b6eSRui Paulo } 198a5779b6eSRui Paulo 199a5779b6eSRui Paulo return; 200a5779b6eSRui Paulo 2013340d773SGleb Smirnoff invalid: 202*ee67461eSJoseph Mingrone nd_print_invalid(ndo); 203*ee67461eSJoseph Mingrone tcheck_remainder: 204*ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, length); 205a5779b6eSRui Paulo } 206