xref: /netbsd-src/external/bsd/tcpdump/dist/print-udld.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /*
2  * Copyright (c) 1998-2007 The TCPDUMP project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that: (1) source code
6  * distributions retain the above copyright notice and this paragraph
7  * in its entirety, and (2) distributions including binary code include
8  * the above copyright notice and this paragraph in its entirety in
9  * the documentation or other materials provided with the distribution.
10  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13  * FOR A PARTICULAR PURPOSE.
14  *
15  * Original code by Carles Kishimoto <carles.kishimoto@gmail.com>
16  */
17 
18 /* \summary: Cisco UniDirectional Link Detection (UDLD) protocol printer */
19 
20 /* specification: RFC 5171 */
21 
22 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-udld.c,v 1.4 2023/08/17 20:19:40 christos Exp $");
25 #endif
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include "netdissect-stdinc.h"
32 
33 #define ND_LONGJMP_FROM_TCHECK
34 #include "netdissect.h"
35 #include "extract.h"
36 
37 
38 #define UDLD_HEADER_LEN			4
39 #define UDLD_TLV_HEADER_LEN		4
40 #define UDLD_DEVICE_ID_TLV		0x0001
41 #define UDLD_PORT_ID_TLV		0x0002
42 #define UDLD_ECHO_TLV			0x0003
43 #define UDLD_MESSAGE_INTERVAL_TLV	0x0004
44 #define UDLD_TIMEOUT_INTERVAL_TLV	0x0005
45 #define UDLD_DEVICE_NAME_TLV		0x0006
46 #define UDLD_SEQ_NUMBER_TLV		0x0007
47 
48 static const struct tok udld_tlv_values[] = {
49     { UDLD_DEVICE_ID_TLV, "Device-ID TLV"},
50     { UDLD_PORT_ID_TLV, "Port-ID TLV"},
51     { UDLD_ECHO_TLV, "Echo TLV"},
52     { UDLD_MESSAGE_INTERVAL_TLV, "Message Interval TLV"},
53     { UDLD_TIMEOUT_INTERVAL_TLV, "Timeout Interval TLV"},
54     { UDLD_DEVICE_NAME_TLV, "Device Name TLV"},
55     { UDLD_SEQ_NUMBER_TLV,"Sequence Number TLV"},
56     { 0, NULL}
57 };
58 
59 static const struct tok udld_code_values[] = {
60     { 0x00, "Reserved"},
61     { 0x01, "Probe message"},
62     { 0x02, "Echo message"},
63     { 0x03, "Flush message"},
64     { 0, NULL}
65 };
66 
67 static const struct tok udld_flags_bitmap_str[] = {
68     { 1U << 0, "RT"    },
69     { 1U << 1, "RSY"   },
70     { 1U << 2, "MBZ-2" },
71     { 1U << 3, "MBZ-3" },
72     { 1U << 4, "MBZ-4" },
73     { 1U << 5, "MBZ-5" },
74     { 1U << 6, "MBZ-6" },
75     { 1U << 7, "MBZ-7" },
76     { 0, NULL}
77 };
78 
79 /*
80  * UDLD's Protocol Data Unit format:
81  *
82  *  0                   1                   2                   3
83  *  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
84  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85  * | Ver | Opcode  |     Flags     |           Checksum            |
86  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87  * |               List of TLVs (variable length list)             |
88  * |                              ...                              |
89  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90  *
91  * TLV format:
92  *
93  *  0                   1                   2                   3
94  *  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
95  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96  * |             TYPE              |            LENGTH             |
97  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98  * |                             VALUE                             |
99  * |                              ...                              |
100  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101  *
102  * LENGTH: Length in bytes of the Type, Length, and Value fields.
103  */
104 
105 #define	UDLD_EXTRACT_VERSION(x) (((x)&0xe0)>>5)
106 #define	UDLD_EXTRACT_OPCODE(x) ((x)&0x1f)
107 
108 void
109 udld_print(netdissect_options *ndo,
110            const u_char *tptr, u_int length)
111 {
112     uint8_t ver, code, flags;
113 
114     ndo->ndo_protocol = "udld";
115     if (length < UDLD_HEADER_LEN)
116         goto invalid;
117 
118     ver = UDLD_EXTRACT_VERSION(GET_U_1(tptr));
119     code = UDLD_EXTRACT_OPCODE(GET_U_1(tptr));
120     tptr += 1;
121     length -= 1;
122 
123     flags = GET_U_1(tptr);
124     tptr += 1;
125     length -= 1;
126 
127     ND_PRINT("UDLDv%u, Code %s (%x), Flags [%s] (0x%02x), length %u",
128            ver,
129            tok2str(udld_code_values, "Reserved", code),
130            code,
131            bittok2str(udld_flags_bitmap_str, "none", flags),
132            flags,
133            length + 2);
134 
135     /*
136      * In non-verbose mode, just print version and opcode type
137      */
138     if (ndo->ndo_vflag < 1) {
139         goto tcheck_remainder;
140     }
141 
142     ND_PRINT("\n\tChecksum 0x%04x (unverified)", GET_BE_U_2(tptr));
143     tptr += 2;
144     length -= 2;
145 
146     while (length) {
147         uint16_t type, len;
148 
149         if (length < UDLD_TLV_HEADER_LEN)
150             goto invalid;
151 
152 	type = GET_BE_U_2(tptr);
153         tptr += 2;
154         length -= 2;
155 
156         len  = GET_BE_U_2(tptr);
157         tptr += 2;
158         length -= 2;
159 
160         ND_PRINT("\n\t%s (0x%04x) TLV, length %u",
161                tok2str(udld_tlv_values, "Unknown", type),
162                type, len);
163 
164         /* infinite loop check */
165         if (len <= UDLD_TLV_HEADER_LEN)
166             goto invalid;
167 
168         len -= UDLD_TLV_HEADER_LEN;
169         if (length < len)
170             goto invalid;
171 
172         switch (type) {
173         case UDLD_DEVICE_ID_TLV:
174         case UDLD_PORT_ID_TLV:
175         case UDLD_DEVICE_NAME_TLV:
176             ND_PRINT(", ");
177             nd_printjnp(ndo, tptr, len);
178             break;
179 
180         case UDLD_ECHO_TLV:
181             ND_PRINT(", ");
182             (void)nd_printn(ndo, tptr, len, NULL);
183             break;
184 
185         case UDLD_MESSAGE_INTERVAL_TLV:
186         case UDLD_TIMEOUT_INTERVAL_TLV:
187             if (len != 1)
188                 goto invalid;
189             ND_PRINT(", %us", (GET_U_1(tptr)));
190             break;
191 
192         case UDLD_SEQ_NUMBER_TLV:
193             if (len != 4)
194                 goto invalid;
195             ND_PRINT(", %u", GET_BE_U_4(tptr));
196             break;
197 
198         default:
199             ND_TCHECK_LEN(tptr, len);
200             break;
201         }
202         tptr += len;
203         length -= len;
204     }
205 
206     return;
207 
208 invalid:
209     nd_print_invalid(ndo);
210 tcheck_remainder:
211     ND_TCHECK_LEN(tptr, length);
212 }
213