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
udld_print(netdissect_options * ndo,const u_char * tptr,u_int length)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