xref: /netbsd-src/external/bsd/tcpdump/dist/print-udld.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
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