10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1998-2007 The TCPDUMP project 30f74e101Schristos * 40f74e101Schristos * Redistribution and use in source and binary forms, with or without 50f74e101Schristos * modification, are permitted provided that: (1) source code 60f74e101Schristos * distributions retain the above copyright notice and this paragraph 70f74e101Schristos * in its entirety, and (2) distributions including binary code include 80f74e101Schristos * the above copyright notice and this paragraph in its entirety in 90f74e101Schristos * the documentation or other materials provided with the distribution. 100f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 110f74e101Schristos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 120f74e101Schristos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 130f74e101Schristos * FOR A PARTICULAR PURPOSE. 140f74e101Schristos * 150f74e101Schristos * Original code by Carles Kishimoto <carles.kishimoto@gmail.com> 160f74e101Schristos */ 170f74e101Schristos 18dc860a36Sspz /* \summary: Cisco UniDirectional Link Detection (UDLD) protocol printer */ 19dc860a36Sspz 20dc860a36Sspz /* specification: RFC 5171 */ 21dc860a36Sspz 22fdccd7e4Schristos #include <sys/cdefs.h> 23fdccd7e4Schristos #ifndef lint 24*26ba0b50Schristos __RCSID("$NetBSD: print-udld.c,v 1.5 2024/09/02 16:15:33 christos Exp $"); 25fdccd7e4Schristos #endif 26fdccd7e4Schristos 27c74ad251Schristos #include <config.h> 280f74e101Schristos 29c74ad251Schristos #include "netdissect-stdinc.h" 300f74e101Schristos 31c74ad251Schristos #define ND_LONGJMP_FROM_TCHECK 32784088dfSchristos #include "netdissect.h" 330f74e101Schristos #include "extract.h" 340f74e101Schristos 35784088dfSchristos 360f74e101Schristos #define UDLD_HEADER_LEN 4 37c74ad251Schristos #define UDLD_TLV_HEADER_LEN 4 380f74e101Schristos #define UDLD_DEVICE_ID_TLV 0x0001 390f74e101Schristos #define UDLD_PORT_ID_TLV 0x0002 400f74e101Schristos #define UDLD_ECHO_TLV 0x0003 410f74e101Schristos #define UDLD_MESSAGE_INTERVAL_TLV 0x0004 420f74e101Schristos #define UDLD_TIMEOUT_INTERVAL_TLV 0x0005 430f74e101Schristos #define UDLD_DEVICE_NAME_TLV 0x0006 440f74e101Schristos #define UDLD_SEQ_NUMBER_TLV 0x0007 450f74e101Schristos 46026d7285Schristos static const struct tok udld_tlv_values[] = { 470f74e101Schristos { UDLD_DEVICE_ID_TLV, "Device-ID TLV"}, 480f74e101Schristos { UDLD_PORT_ID_TLV, "Port-ID TLV"}, 490f74e101Schristos { UDLD_ECHO_TLV, "Echo TLV"}, 500f74e101Schristos { UDLD_MESSAGE_INTERVAL_TLV, "Message Interval TLV"}, 510f74e101Schristos { UDLD_TIMEOUT_INTERVAL_TLV, "Timeout Interval TLV"}, 520f74e101Schristos { UDLD_DEVICE_NAME_TLV, "Device Name TLV"}, 530f74e101Schristos { UDLD_SEQ_NUMBER_TLV,"Sequence Number TLV"}, 540f74e101Schristos { 0, NULL} 550f74e101Schristos }; 560f74e101Schristos 57026d7285Schristos static const struct tok udld_code_values[] = { 580f74e101Schristos { 0x00, "Reserved"}, 590f74e101Schristos { 0x01, "Probe message"}, 600f74e101Schristos { 0x02, "Echo message"}, 610f74e101Schristos { 0x03, "Flush message"}, 620f74e101Schristos { 0, NULL} 630f74e101Schristos }; 640f74e101Schristos 65c74ad251Schristos static const struct tok udld_flags_bitmap_str[] = { 66c74ad251Schristos { 1U << 0, "RT" }, 67c74ad251Schristos { 1U << 1, "RSY" }, 68c74ad251Schristos { 1U << 2, "MBZ-2" }, 69c74ad251Schristos { 1U << 3, "MBZ-3" }, 70c74ad251Schristos { 1U << 4, "MBZ-4" }, 71c74ad251Schristos { 1U << 5, "MBZ-5" }, 72c74ad251Schristos { 1U << 6, "MBZ-6" }, 73c74ad251Schristos { 1U << 7, "MBZ-7" }, 740f74e101Schristos { 0, NULL} 750f74e101Schristos }; 760f74e101Schristos 770f74e101Schristos /* 78784088dfSchristos * UDLD's Protocol Data Unit format: 790f74e101Schristos * 800f74e101Schristos * 0 1 2 3 810f74e101Schristos * 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 820f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 830f74e101Schristos * | Ver | Opcode | Flags | Checksum | 840f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 850f74e101Schristos * | List of TLVs (variable length list) | 860f74e101Schristos * | ... | 870f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 880f74e101Schristos * 89784088dfSchristos * TLV format: 90784088dfSchristos * 91784088dfSchristos * 0 1 2 3 92784088dfSchristos * 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 93784088dfSchristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 94784088dfSchristos * | TYPE | LENGTH | 95784088dfSchristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 96784088dfSchristos * | VALUE | 97784088dfSchristos * | ... | 98784088dfSchristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 99784088dfSchristos * 100784088dfSchristos * LENGTH: Length in bytes of the Type, Length, and Value fields. 1010f74e101Schristos */ 1020f74e101Schristos 1030f74e101Schristos #define UDLD_EXTRACT_VERSION(x) (((x)&0xe0)>>5) 1040f74e101Schristos #define UDLD_EXTRACT_OPCODE(x) ((x)&0x1f) 1050f74e101Schristos 1060f74e101Schristos void 107c74ad251Schristos udld_print(netdissect_options *ndo, 108c74ad251Schristos const u_char *tptr, u_int length) 1090f74e101Schristos { 110c74ad251Schristos uint8_t ver, code, flags; 1110f74e101Schristos 112c74ad251Schristos ndo->ndo_protocol = "udld"; 1130f74e101Schristos if (length < UDLD_HEADER_LEN) 114c74ad251Schristos goto invalid; 1150f74e101Schristos 116c74ad251Schristos ver = UDLD_EXTRACT_VERSION(GET_U_1(tptr)); 117c74ad251Schristos code = UDLD_EXTRACT_OPCODE(GET_U_1(tptr)); 118c74ad251Schristos tptr += 1; 119c74ad251Schristos length -= 1; 1200f74e101Schristos 121c74ad251Schristos flags = GET_U_1(tptr); 122c74ad251Schristos tptr += 1; 123c74ad251Schristos length -= 1; 1240f74e101Schristos 125c74ad251Schristos ND_PRINT("UDLDv%u, Code %s (%x), Flags [%s] (0x%02x), length %u", 126c74ad251Schristos ver, 1270f74e101Schristos tok2str(udld_code_values, "Reserved", code), 1280f74e101Schristos code, 129c74ad251Schristos bittok2str(udld_flags_bitmap_str, "none", flags), 130c74ad251Schristos flags, 131c74ad251Schristos length + 2); 1320f74e101Schristos 1330f74e101Schristos /* 1340f74e101Schristos * In non-verbose mode, just print version and opcode type 1350f74e101Schristos */ 136c47fd378Schristos if (ndo->ndo_vflag < 1) { 137c74ad251Schristos goto tcheck_remainder; 1380f74e101Schristos } 1390f74e101Schristos 140c74ad251Schristos ND_PRINT("\n\tChecksum 0x%04x (unverified)", GET_BE_U_2(tptr)); 141c74ad251Schristos tptr += 2; 142c74ad251Schristos length -= 2; 1430f74e101Schristos 144c74ad251Schristos while (length) { 145c74ad251Schristos uint16_t type, len; 1460f74e101Schristos 147c74ad251Schristos if (length < UDLD_TLV_HEADER_LEN) 148784088dfSchristos goto invalid; 149784088dfSchristos 150c74ad251Schristos type = GET_BE_U_2(tptr); 151c74ad251Schristos tptr += 2; 152c74ad251Schristos length -= 2; 153c74ad251Schristos 154c74ad251Schristos len = GET_BE_U_2(tptr); 155c74ad251Schristos tptr += 2; 156c74ad251Schristos length -= 2; 157c74ad251Schristos 158c74ad251Schristos ND_PRINT("\n\t%s (0x%04x) TLV, length %u", 159c74ad251Schristos tok2str(udld_tlv_values, "Unknown", type), 160c74ad251Schristos type, len); 161c74ad251Schristos 162784088dfSchristos /* infinite loop check */ 163c74ad251Schristos if (len <= UDLD_TLV_HEADER_LEN) 164784088dfSchristos goto invalid; 165784088dfSchristos 166c74ad251Schristos len -= UDLD_TLV_HEADER_LEN; 167c74ad251Schristos if (length < len) 168c74ad251Schristos goto invalid; 169784088dfSchristos 1700f74e101Schristos switch (type) { 1710f74e101Schristos case UDLD_DEVICE_ID_TLV: 1720f74e101Schristos case UDLD_PORT_ID_TLV: 1730f74e101Schristos case UDLD_DEVICE_NAME_TLV: 174c74ad251Schristos ND_PRINT(", "); 175c74ad251Schristos nd_printjnp(ndo, tptr, len); 176784088dfSchristos break; 177784088dfSchristos 178784088dfSchristos case UDLD_ECHO_TLV: 179c74ad251Schristos ND_PRINT(", "); 180c74ad251Schristos (void)nd_printn(ndo, tptr, len, NULL); 1810f74e101Schristos break; 1820f74e101Schristos 1830f74e101Schristos case UDLD_MESSAGE_INTERVAL_TLV: 1840f74e101Schristos case UDLD_TIMEOUT_INTERVAL_TLV: 185784088dfSchristos if (len != 1) 186784088dfSchristos goto invalid; 187c74ad251Schristos ND_PRINT(", %us", (GET_U_1(tptr))); 1880f74e101Schristos break; 1890f74e101Schristos 1900f74e101Schristos case UDLD_SEQ_NUMBER_TLV: 191784088dfSchristos if (len != 4) 192784088dfSchristos goto invalid; 193c74ad251Schristos ND_PRINT(", %u", GET_BE_U_4(tptr)); 1940f74e101Schristos break; 1950f74e101Schristos 1960f74e101Schristos default: 197c74ad251Schristos ND_TCHECK_LEN(tptr, len); 1980f74e101Schristos break; 1990f74e101Schristos } 2000f74e101Schristos tptr += len; 201c74ad251Schristos length -= len; 2020f74e101Schristos } 2030f74e101Schristos 2040f74e101Schristos return; 2050f74e101Schristos 206784088dfSchristos invalid: 207c74ad251Schristos nd_print_invalid(ndo); 208c74ad251Schristos tcheck_remainder: 209c74ad251Schristos ND_TCHECK_LEN(tptr, length); 2100f74e101Schristos } 211