xref: /netbsd-src/external/bsd/tcpdump/dist/print-udld.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
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.3 2017/02/05 04:05:05 spz Exp $");
25 #endif
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include <netdissect-stdinc.h>
32 
33 #include "netdissect.h"
34 #include "extract.h"
35 
36 static const char tstr[] = " [|udld]";
37 
38 #define UDLD_HEADER_LEN			4
39 #define UDLD_DEVICE_ID_TLV		0x0001
40 #define UDLD_PORT_ID_TLV		0x0002
41 #define UDLD_ECHO_TLV			0x0003
42 #define UDLD_MESSAGE_INTERVAL_TLV	0x0004
43 #define UDLD_TIMEOUT_INTERVAL_TLV	0x0005
44 #define UDLD_DEVICE_NAME_TLV		0x0006
45 #define UDLD_SEQ_NUMBER_TLV		0x0007
46 
47 static const struct tok udld_tlv_values[] = {
48     { UDLD_DEVICE_ID_TLV, "Device-ID TLV"},
49     { UDLD_PORT_ID_TLV, "Port-ID TLV"},
50     { UDLD_ECHO_TLV, "Echo TLV"},
51     { UDLD_MESSAGE_INTERVAL_TLV, "Message Interval TLV"},
52     { UDLD_TIMEOUT_INTERVAL_TLV, "Timeout Interval TLV"},
53     { UDLD_DEVICE_NAME_TLV, "Device Name TLV"},
54     { UDLD_SEQ_NUMBER_TLV,"Sequence Number TLV"},
55     { 0, NULL}
56 };
57 
58 static const struct tok udld_code_values[] = {
59     { 0x00, "Reserved"},
60     { 0x01, "Probe message"},
61     { 0x02, "Echo message"},
62     { 0x03, "Flush message"},
63     { 0, NULL}
64 };
65 
66 static const struct tok udld_flags_values[] = {
67     { 0x00, "RT"},
68     { 0x01, "RSY"},
69     { 0, NULL}
70 };
71 
72 /*
73  * UDLD's Protocol Data Unit format:
74  *
75  *  0                   1                   2                   3
76  *  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
77  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78  * | Ver | Opcode  |     Flags     |           Checksum            |
79  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80  * |               List of TLVs (variable length list)             |
81  * |                              ...                              |
82  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83  *
84  * TLV format:
85  *
86  *  0                   1                   2                   3
87  *  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
88  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89  * |             TYPE              |            LENGTH             |
90  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91  * |                             VALUE                             |
92  * |                              ...                              |
93  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94  *
95  * LENGTH: Length in bytes of the Type, Length, and Value fields.
96  */
97 
98 #define	UDLD_EXTRACT_VERSION(x) (((x)&0xe0)>>5)
99 #define	UDLD_EXTRACT_OPCODE(x) ((x)&0x1f)
100 
101 void
102 udld_print (netdissect_options *ndo, const u_char *pptr, u_int length)
103 {
104     int code, type, len;
105     const u_char *tptr;
106 
107     if (length < UDLD_HEADER_LEN)
108         goto trunc;
109 
110     tptr = pptr;
111 
112     ND_TCHECK2(*tptr, UDLD_HEADER_LEN);
113 
114     code = UDLD_EXTRACT_OPCODE(*tptr);
115 
116     ND_PRINT((ndo, "UDLDv%u, Code %s (%x), Flags [%s] (0x%02x), length %u",
117            UDLD_EXTRACT_VERSION(*tptr),
118            tok2str(udld_code_values, "Reserved", code),
119            code,
120            bittok2str(udld_flags_values, "none", *(tptr+1)),
121            *(tptr+1),
122            length));
123 
124     /*
125      * In non-verbose mode, just print version and opcode type
126      */
127     if (ndo->ndo_vflag < 1) {
128 	return;
129     }
130 
131     ND_PRINT((ndo, "\n\tChecksum 0x%04x (unverified)", EXTRACT_16BITS(tptr+2)));
132 
133     tptr += UDLD_HEADER_LEN;
134 
135     while (tptr < (pptr+length)) {
136 
137         ND_TCHECK2(*tptr, 4);
138 	type = EXTRACT_16BITS(tptr);
139         len  = EXTRACT_16BITS(tptr+2);
140 
141         ND_PRINT((ndo, "\n\t%s (0x%04x) TLV, length %u",
142                tok2str(udld_tlv_values, "Unknown", type),
143                type, len));
144 
145         if (type == 0)
146             goto invalid;
147 
148         /* infinite loop check */
149         if (len <= 4)
150             goto invalid;
151 
152         len -= 4;
153         tptr += 4;
154 
155         ND_TCHECK2(*tptr, len);
156 
157         switch (type) {
158         case UDLD_DEVICE_ID_TLV:
159         case UDLD_PORT_ID_TLV:
160         case UDLD_DEVICE_NAME_TLV:
161             ND_PRINT((ndo, ", "));
162             fn_printzp(ndo, tptr, len, NULL);
163             break;
164 
165         case UDLD_ECHO_TLV:
166             ND_PRINT((ndo, ", "));
167             (void)fn_printn(ndo, tptr, len, NULL);
168             break;
169 
170         case UDLD_MESSAGE_INTERVAL_TLV:
171         case UDLD_TIMEOUT_INTERVAL_TLV:
172             if (len != 1)
173                 goto invalid;
174             ND_PRINT((ndo, ", %us", (*tptr)));
175             break;
176 
177         case UDLD_SEQ_NUMBER_TLV:
178             if (len != 4)
179                 goto invalid;
180             ND_PRINT((ndo, ", %u", EXTRACT_32BITS(tptr)));
181             break;
182 
183         default:
184             break;
185         }
186         tptr += len;
187     }
188 
189     return;
190 
191 invalid:
192     ND_PRINT((ndo, "%s", istr));
193     return;
194 trunc:
195     ND_PRINT((ndo, "%s", tstr));
196 }
197 
198 /*
199  * Local Variables:
200  * c-style: whitesmith
201  * c-basic-offset: 4
202  * End:
203  */
204