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