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