xref: /netbsd-src/external/bsd/tcpdump/dist/print-vtp.c (revision 76c7fc5f6b13ed0b1508e6b313e88e59977ed78e)
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  * Reference documentation:
16  *  http://www.cisco.com/c/en/us/support/docs/lan-switching/vtp/10558-21.html
17  *  http://docstore.mik.ua/univercd/cc/td/doc/product/lan/trsrb/frames.htm
18  *
19  * Original code ode by Carles Kishimoto <carles.kishimoto@gmail.com>
20  */
21 
22 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-vtp.c,v 1.5 2019/10/01 16:06:16 christos Exp $");
25 #endif
26 
27 /* \summary: Cisco VLAN Trunking Protocol (VTP) printer */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <netdissect-stdinc.h>
34 
35 #include "netdissect.h"
36 #include "addrtoname.h"
37 #include "extract.h"
38 
39 #define VTP_HEADER_LEN			36
40 #define	VTP_DOMAIN_NAME_LEN		32
41 #define	VTP_MD5_DIGEST_LEN		16
42 #define VTP_UPDATE_TIMESTAMP_LEN	12
43 #define VTP_VLAN_INFO_FIXED_PART_LEN	12	/* length of VLAN info before VLAN name */
44 
45 #define VTP_SUMMARY_ADV			0x01
46 #define VTP_SUBSET_ADV			0x02
47 #define VTP_ADV_REQUEST			0x03
48 #define VTP_JOIN_MESSAGE		0x04
49 
50 struct vtp_vlan_ {
51     uint8_t  len;
52     uint8_t  status;
53     uint8_t  type;
54     uint8_t  name_len;
55     uint16_t vlanid;
56     uint16_t mtu;
57     uint32_t index;
58 };
59 
60 static const struct tok vtp_message_type_values[] = {
61     { VTP_SUMMARY_ADV, "Summary advertisement"},
62     { VTP_SUBSET_ADV, "Subset advertisement"},
63     { VTP_ADV_REQUEST, "Advertisement request"},
64     { VTP_JOIN_MESSAGE, "Join message"},
65     { 0, NULL }
66 };
67 
68 static const struct tok vtp_header_values[] = {
69     { 0x01, "Followers"}, /* On Summary advertisement, 3rd byte is Followers */
70     { 0x02, "Seq number"}, /* On Subset  advertisement, 3rd byte is Sequence number */
71     { 0x03, "Rsvd"}, /* On Adver. requests 3rd byte is Rsvd */
72     { 0x04, "Rsvd"}, /* On Adver. requests 3rd byte is Rsvd */
73     { 0, NULL }
74 };
75 
76 static const struct tok vtp_vlan_type_values[] = {
77     { 0x01, "Ethernet"},
78     { 0x02, "FDDI"},
79     { 0x03, "TrCRF"},
80     { 0x04, "FDDI-net"},
81     { 0x05, "TrBRF"},
82     { 0, NULL }
83 };
84 
85 static const struct tok vtp_vlan_status[] = {
86     { 0x00, "Operational"},
87     { 0x01, "Suspended"},
88     { 0, NULL }
89 };
90 
91 #define VTP_VLAN_SOURCE_ROUTING_RING_NUMBER      0x01
92 #define VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER    0x02
93 #define VTP_VLAN_STP_TYPE                        0x03
94 #define VTP_VLAN_PARENT_VLAN                     0x04
95 #define VTP_VLAN_TRANS_BRIDGED_VLAN              0x05
96 #define VTP_VLAN_PRUNING                         0x06
97 #define VTP_VLAN_BRIDGE_TYPE                     0x07
98 #define VTP_VLAN_ARP_HOP_COUNT                   0x08
99 #define VTP_VLAN_STE_HOP_COUNT                   0x09
100 #define VTP_VLAN_BACKUP_CRF_MODE                 0x0A
101 
102 static const struct tok vtp_vlan_tlv_values[] = {
103     { VTP_VLAN_SOURCE_ROUTING_RING_NUMBER, "Source-Routing Ring Number TLV"},
104     { VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER, "Source-Routing Bridge Number TLV"},
105     { VTP_VLAN_STP_TYPE, "STP type TLV"},
106     { VTP_VLAN_PARENT_VLAN, "Parent VLAN TLV"},
107     { VTP_VLAN_TRANS_BRIDGED_VLAN, "Translationally bridged VLANs TLV"},
108     { VTP_VLAN_PRUNING, "Pruning TLV"},
109     { VTP_VLAN_BRIDGE_TYPE, "Bridge Type TLV"},
110     { VTP_VLAN_ARP_HOP_COUNT, "Max ARP Hop Count TLV"},
111     { VTP_VLAN_STE_HOP_COUNT, "Max STE Hop Count TLV"},
112     { VTP_VLAN_BACKUP_CRF_MODE, "Backup CRF Mode TLV"},
113     { 0,                                  NULL }
114 };
115 
116 static const struct tok vtp_stp_type_values[] = {
117     { 1, "SRT"},
118     { 2, "SRB"},
119     { 3, "Auto"},
120     { 0, NULL }
121 };
122 
123 void
124 vtp_print (netdissect_options *ndo,
125            const u_char *pptr, u_int length)
126 {
127     int type, len, tlv_len, tlv_value, mgmtd_len;
128     const u_char *tptr;
129     const struct vtp_vlan_ *vtp_vlan;
130 
131     if (length < VTP_HEADER_LEN)
132         goto trunc;
133 
134     tptr = pptr;
135 
136     ND_TCHECK2(*tptr, VTP_HEADER_LEN);
137 
138     type = *(tptr+1);
139     ND_PRINT((ndo, "VTPv%u, Message %s (0x%02x), length %u",
140 	   *tptr,
141 	   tok2str(vtp_message_type_values,"Unknown message type", type),
142 	   type,
143 	   length));
144 
145     /* In non-verbose mode, just print version and message type */
146     if (ndo->ndo_vflag < 1) {
147         return;
148     }
149 
150     /* verbose mode print all fields */
151     ND_PRINT((ndo, "\n\tDomain name: "));
152     mgmtd_len = *(tptr + 3);
153     if (mgmtd_len < 1 ||  mgmtd_len > 32) {
154 	ND_PRINT((ndo, " [invalid MgmtD Len %d]", mgmtd_len));
155 	return;
156     }
157     fn_printzp(ndo, tptr + 4, mgmtd_len, NULL);
158     ND_PRINT((ndo, ", %s: %u",
159 	   tok2str(vtp_header_values, "Unknown", type),
160 	   *(tptr+2)));
161 
162     tptr += VTP_HEADER_LEN;
163 
164     switch (type) {
165 
166     case VTP_SUMMARY_ADV:
167 
168 	/*
169 	 *  SUMMARY ADVERTISEMENT
170 	 *
171 	 *  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
172 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173 	 *  |     Version   |     Code      |    Followers  |    MgmtD Len  |
174 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175 	 *  |       Management Domain Name  (zero-padded to 32 bytes)       |
176 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
177 	 *  |                    Configuration revision number              |
178 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179 	 *  |                  Updater Identity IP address                  |
180 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181 	 *  |                    Update Timestamp (12 bytes)                |
182 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
183 	 *  |                        MD5 digest (16 bytes)                  |
184 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
185 	 *
186 	 */
187 
188 	ND_TCHECK2(*tptr, 8);
189 	ND_PRINT((ndo, "\n\t  Config Rev %x, Updater %s",
190 	       EXTRACT_32BITS(tptr),
191 	       ipaddr_string(ndo, tptr+4)));
192 	tptr += 8;
193 	ND_TCHECK2(*tptr, VTP_UPDATE_TIMESTAMP_LEN);
194 	ND_PRINT((ndo, ", Timestamp 0x%08x 0x%08x 0x%08x",
195 	       EXTRACT_32BITS(tptr),
196 	       EXTRACT_32BITS(tptr + 4),
197 	       EXTRACT_32BITS(tptr + 8)));
198 	tptr += VTP_UPDATE_TIMESTAMP_LEN;
199 	ND_TCHECK2(*tptr, VTP_MD5_DIGEST_LEN);
200 	ND_PRINT((ndo, ", MD5 digest: %08x%08x%08x%08x",
201 	       EXTRACT_32BITS(tptr),
202 	       EXTRACT_32BITS(tptr + 4),
203 	       EXTRACT_32BITS(tptr + 8),
204 	       EXTRACT_32BITS(tptr + 12)));
205 	tptr += VTP_MD5_DIGEST_LEN;
206 	break;
207 
208     case VTP_SUBSET_ADV:
209 
210 	/*
211 	 *  SUBSET ADVERTISEMENT
212 	 *
213 	 *  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
214 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
215 	 *  |     Version   |     Code      |   Seq number  |    MgmtD Len  |
216 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
217 	 *  |       Management Domain Name  (zero-padded to 32 bytes)       |
218 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219 	 *  |                    Configuration revision number              |
220 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
221 	 *  |                         VLAN info field 1                     |
222 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
223 	 *  |                         ................                      |
224 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
225 	 *  |                         VLAN info field N                     |
226 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
227 	 *
228 	 */
229 
230 	ND_TCHECK_32BITS(tptr);
231 	ND_PRINT((ndo, ", Config Rev %x", EXTRACT_32BITS(tptr)));
232 
233 	/*
234 	 *  VLAN INFORMATION
235 	 *  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
236 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
237 	 *  | V info len    |    Status     |  VLAN type    | VLAN name len |
238 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239 	 *  |       ISL vlan id             |            MTU size           |
240 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
241 	 *  |                     802.10 index (SAID)                       |
242 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
243 	 *  |                         VLAN name                             |
244 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
245 	 *
246 	 */
247 
248 	tptr += 4;
249 	while ((unsigned)(tptr - pptr) < length) {
250 
251 	    ND_TCHECK_8BITS(tptr);
252 	    len = *tptr;
253 	    if (len == 0)
254 		break;
255 
256 	    ND_TCHECK2(*tptr, len);
257 
258 	    vtp_vlan = (const struct vtp_vlan_*)tptr;
259 	    if (len < VTP_VLAN_INFO_FIXED_PART_LEN)
260 		goto trunc;
261 	    ND_TCHECK(*vtp_vlan);
262 	    ND_PRINT((ndo, "\n\tVLAN info status %s, type %s, VLAN-id %u, MTU %u, SAID 0x%08x, Name ",
263 		   tok2str(vtp_vlan_status,"Unknown",vtp_vlan->status),
264 		   tok2str(vtp_vlan_type_values,"Unknown",vtp_vlan->type),
265 		   EXTRACT_16BITS(&vtp_vlan->vlanid),
266 		   EXTRACT_16BITS(&vtp_vlan->mtu),
267 		   EXTRACT_32BITS(&vtp_vlan->index)));
268 	    len  -= VTP_VLAN_INFO_FIXED_PART_LEN;
269 	    tptr += VTP_VLAN_INFO_FIXED_PART_LEN;
270 	    if (len < 4*((vtp_vlan->name_len + 3)/4))
271 		goto trunc;
272 	    ND_TCHECK2(*tptr, vtp_vlan->name_len);
273 	    fn_printzp(ndo, tptr, vtp_vlan->name_len, NULL);
274 
275 	    /*
276 	     * Vlan names are aligned to 32-bit boundaries.
277 	     */
278 	    len  -= 4*((vtp_vlan->name_len + 3)/4);
279 	    tptr += 4*((vtp_vlan->name_len + 3)/4);
280 
281             /* TLV information follows */
282 
283             while (len > 0) {
284 
285                 /*
286                  * Cisco specs say 2 bytes for type + 2 bytes for length;
287                  * see http://docstore.mik.ua/univercd/cc/td/doc/product/lan/trsrb/frames.htm
288                  * However, actual packets on the wire appear to use 1
289                  * byte for the type and 1 byte for the length, so that's
290                  * what we do.
291                  */
292                 if (len < 2)
293                     goto trunc;
294                 ND_TCHECK2(*tptr, 2);
295                 type = *tptr;
296                 tlv_len = *(tptr+1);
297 
298                 ND_PRINT((ndo, "\n\t\t%s (0x%04x) TLV",
299                        tok2str(vtp_vlan_tlv_values, "Unknown", type),
300                        type));
301 
302                 if (len < tlv_len * 2 + 2) {
303                     ND_PRINT((ndo, " (TLV goes past the end of the packet)"));
304                     return;
305                 }
306                 ND_TCHECK2(*tptr, tlv_len * 2 +2);
307 
308                 /*
309                  * We assume the value is a 2-byte integer; the length is
310                  * in units of 16-bit words.
311                  */
312                 if (tlv_len != 1) {
313                     ND_PRINT((ndo, " (invalid TLV length %u != 1)", tlv_len));
314                     return;
315                 } else {
316                     tlv_value = EXTRACT_16BITS(tptr+2);
317 
318                     switch (type) {
319                     case VTP_VLAN_STE_HOP_COUNT:
320                         ND_PRINT((ndo, ", %u", tlv_value));
321                         break;
322 
323                     case VTP_VLAN_PRUNING:
324                         ND_PRINT((ndo, ", %s (%u)",
325                                tlv_value == 1 ? "Enabled" : "Disabled",
326                                tlv_value));
327                         break;
328 
329                     case VTP_VLAN_STP_TYPE:
330                         ND_PRINT((ndo, ", %s (%u)",
331                                tok2str(vtp_stp_type_values, "Unknown", tlv_value),
332                                tlv_value));
333                         break;
334 
335                     case VTP_VLAN_BRIDGE_TYPE:
336                         ND_PRINT((ndo, ", %s (%u)",
337                                tlv_value == 1 ? "SRB" : "SRT",
338                                tlv_value));
339                         break;
340 
341                     case VTP_VLAN_BACKUP_CRF_MODE:
342                         ND_PRINT((ndo, ", %s (%u)",
343                                tlv_value == 1 ? "Backup" : "Not backup",
344                                tlv_value));
345                         break;
346 
347                         /*
348                          * FIXME those are the defined TLVs that lack a decoder
349                          * you are welcome to contribute code ;-)
350                          */
351 
352                     case VTP_VLAN_SOURCE_ROUTING_RING_NUMBER:
353                     case VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER:
354                     case VTP_VLAN_PARENT_VLAN:
355                     case VTP_VLAN_TRANS_BRIDGED_VLAN:
356                     case VTP_VLAN_ARP_HOP_COUNT:
357                     default:
358                         print_unknown_data(ndo, tptr, "\n\t\t  ", 2 + tlv_len*2);
359                         break;
360                     }
361                 }
362                 len -= 2 + tlv_len*2;
363                 tptr += 2 + tlv_len*2;
364             }
365 	}
366 	break;
367 
368     case VTP_ADV_REQUEST:
369 
370 	/*
371 	 *  ADVERTISEMENT REQUEST
372 	 *
373 	 *  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
374 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
375 	 *  |     Version   |     Code      |   Reserved    |    MgmtD Len  |
376 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
377 	 *  |       Management Domain Name  (zero-padded to 32 bytes)       |
378 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379 	 *  |                          Start value                          |
380 	 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381 	 *
382 	 */
383 
384 	ND_TCHECK2(*tptr, 4);
385 	ND_PRINT((ndo, "\n\tStart value: %u", EXTRACT_32BITS(tptr)));
386 	break;
387 
388     case VTP_JOIN_MESSAGE:
389 
390 	/* FIXME - Could not find message format */
391 	break;
392 
393     default:
394 	break;
395     }
396 
397     return;
398 
399  trunc:
400     ND_PRINT((ndo, "[|vtp]"));
401 }
402 
403 /*
404  * Local Variables:
405  * c-style: whitesmith
406  * c-basic-offset: 4
407  * End:
408  */
409