JP Abgrall | 53f17a9 | 2014-02-12 14:02:41 -0800 | [diff] [blame] | 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 | * VLAN TRUNKING PROTOCOL (VTP) |
| 16 | * |
| 17 | * Reference documentation: |
| 18 | * http://www.cisco.com/en/US/tech/tk389/tk689/technologies_tech_note09186a0080094c52.shtml |
| 19 | * http://www.cisco.com/warp/public/473/21.html |
| 20 | * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm |
| 21 | * |
| 22 | * Original code ode by Carles Kishimoto <carles.kishimoto@gmail.com> |
| 23 | */ |
| 24 | |
| 25 | #ifdef HAVE_CONFIG_H |
| 26 | #include "config.h" |
| 27 | #endif |
| 28 | |
| 29 | #include <tcpdump-stdinc.h> |
| 30 | |
| 31 | #include <stdio.h> |
| 32 | #include <string.h> |
| 33 | |
| 34 | #include "interface.h" |
| 35 | #include "addrtoname.h" |
| 36 | #include "extract.h" |
| 37 | #include "nlpid.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_OFFSET 12 |
| 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 | u_int8_t len; |
| 52 | u_int8_t status; |
| 53 | u_int8_t type; |
| 54 | u_int8_t name_len; |
| 55 | u_int16_t vlanid; |
| 56 | u_int16_t mtu; |
| 57 | u_int32_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 (const u_char *pptr, u_int length) |
| 125 | { |
| 126 | int type, len, tlv_len, tlv_value; |
| 127 | const u_char *tptr; |
| 128 | const struct vtp_vlan_ *vtp_vlan; |
| 129 | |
| 130 | if (length < VTP_HEADER_LEN) |
| 131 | goto trunc; |
| 132 | |
| 133 | tptr = pptr; |
| 134 | |
| 135 | if (!TTEST2(*tptr, VTP_HEADER_LEN)) |
| 136 | goto trunc; |
| 137 | |
| 138 | type = *(tptr+1); |
| 139 | printf("VTPv%u, Message %s (0x%02x), length %u", |
| 140 | *tptr, |
| 141 | tok2str(vtp_message_type_values,"Unknown message type", type), |
| 142 | *(tptr+1), |
| 143 | length); |
| 144 | |
| 145 | /* In non-verbose mode, just print version and message type */ |
| 146 | if (vflag < 1) { |
| 147 | return; |
| 148 | } |
| 149 | |
| 150 | /* verbose mode print all fields */ |
| 151 | printf("\n\tDomain name: %s, %s: %u", |
| 152 | (tptr+4), |
| 153 | tok2str(vtp_header_values,"Unknown",*(tptr+1)), |
| 154 | *(tptr+2)); |
| 155 | |
| 156 | tptr += VTP_HEADER_LEN; |
| 157 | |
| 158 | switch (type) { |
| 159 | |
| 160 | case VTP_SUMMARY_ADV: |
| 161 | |
| 162 | /* |
| 163 | * SUMMARY ADVERTISEMENT |
| 164 | * |
| 165 | * 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 |
| 166 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 167 | * | Version | Code | Followers | MmgtD Len | |
| 168 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 169 | * | Management Domain Name | |
| 170 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 171 | * | Configuration revision number | |
| 172 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 173 | * | Updater Identity IP address | |
| 174 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 175 | * | Update Timestamp (12 bytes) | |
| 176 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 177 | * | MD5 digest (16 bytes) | |
| 178 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 179 | * |
| 180 | */ |
| 181 | |
| 182 | printf("\n\t Config Rev %x, Updater %s", |
| 183 | EXTRACT_32BITS(tptr), |
| 184 | ipaddr_string(tptr+4)); |
| 185 | tptr += 8; |
| 186 | printf(", Timestamp 0x%08x 0x%08x 0x%08x", |
| 187 | EXTRACT_32BITS(tptr), |
| 188 | EXTRACT_32BITS(tptr + 4), |
| 189 | EXTRACT_32BITS(tptr + 8)); |
| 190 | tptr += VTP_UPDATE_TIMESTAMP_LEN; |
| 191 | printf(", MD5 digest: %08x%08x%08x%08x", |
| 192 | EXTRACT_32BITS(tptr), |
| 193 | EXTRACT_32BITS(tptr + 4), |
| 194 | EXTRACT_32BITS(tptr + 8), |
| 195 | EXTRACT_32BITS(tptr + 12)); |
| 196 | tptr += VTP_MD5_DIGEST_LEN; |
| 197 | break; |
| 198 | |
| 199 | case VTP_SUBSET_ADV: |
| 200 | |
| 201 | /* |
| 202 | * SUBSET ADVERTISEMENT |
| 203 | * |
| 204 | * 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 |
| 205 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 206 | * | Version | Code | Seq number | MmgtD Len | |
| 207 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 208 | * | Management Domain Name | |
| 209 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 210 | * | Configuration revision number | |
| 211 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 212 | * | VLAN info field 1 | |
| 213 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 214 | * | ................ | |
| 215 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 216 | * | VLAN info field N | |
| 217 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 218 | * |
| 219 | */ |
| 220 | |
| 221 | printf(", Config Rev %x", EXTRACT_32BITS(tptr)); |
| 222 | |
| 223 | /* |
| 224 | * VLAN INFORMATION |
| 225 | * 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 |
| 226 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 227 | * | V info len | Status | VLAN type | VLAN name len | |
| 228 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 229 | * | ISL vlan id | MTU size | |
| 230 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 231 | * | 802.10 index (SAID) | |
| 232 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 233 | * | VLAN name | |
| 234 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 235 | * |
| 236 | */ |
| 237 | |
| 238 | tptr += 4; |
| 239 | while (tptr < (pptr+length)) { |
| 240 | |
| 241 | len = *tptr; |
| 242 | if (len == 0) |
| 243 | break; |
| 244 | |
| 245 | if (!TTEST2(*tptr, len)) |
| 246 | goto trunc; |
| 247 | |
| 248 | vtp_vlan = (struct vtp_vlan_*)tptr; |
| 249 | printf("\n\tVLAN info status %s, type %s, VLAN-id %u, MTU %u, SAID 0x%08x, Name %s", |
| 250 | tok2str(vtp_vlan_status,"Unknown",vtp_vlan->status), |
| 251 | tok2str(vtp_vlan_type_values,"Unknown",vtp_vlan->type), |
| 252 | EXTRACT_16BITS(&vtp_vlan->vlanid), |
| 253 | EXTRACT_16BITS(&vtp_vlan->mtu), |
| 254 | EXTRACT_32BITS(&vtp_vlan->index), |
| 255 | (tptr + VTP_VLAN_INFO_OFFSET)); |
| 256 | |
| 257 | /* |
| 258 | * Vlan names are aligned to 32-bit boundaries. |
| 259 | */ |
| 260 | len -= VTP_VLAN_INFO_OFFSET + 4*((vtp_vlan->name_len + 3)/4); |
| 261 | tptr += VTP_VLAN_INFO_OFFSET + 4*((vtp_vlan->name_len + 3)/4); |
| 262 | |
| 263 | /* TLV information follows */ |
| 264 | |
| 265 | while (len > 0) { |
| 266 | |
| 267 | /* |
| 268 | * Cisco specs says 2 bytes for type + 2 bytes for length, take only 1 |
| 269 | * See: http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm |
| 270 | */ |
| 271 | type = *tptr; |
| 272 | tlv_len = *(tptr+1); |
| 273 | |
| 274 | printf("\n\t\t%s (0x%04x) TLV", |
| 275 | tok2str(vtp_vlan_tlv_values, "Unknown", type), |
| 276 | type); |
| 277 | |
| 278 | /* |
| 279 | * infinite loop check |
| 280 | */ |
| 281 | if (type == 0 || tlv_len == 0) { |
| 282 | return; |
| 283 | } |
| 284 | |
| 285 | if (!TTEST2(*tptr, tlv_len*2 +2)) |
| 286 | goto trunc; |
| 287 | |
| 288 | tlv_value = EXTRACT_16BITS(tptr+2); |
| 289 | |
| 290 | switch (type) { |
| 291 | case VTP_VLAN_STE_HOP_COUNT: |
| 292 | printf(", %u", tlv_value); |
| 293 | break; |
| 294 | |
| 295 | case VTP_VLAN_PRUNING: |
| 296 | printf(", %s (%u)", |
| 297 | tlv_value == 1 ? "Enabled" : "Disabled", |
| 298 | tlv_value); |
| 299 | break; |
| 300 | |
| 301 | case VTP_VLAN_STP_TYPE: |
| 302 | printf(", %s (%u)", |
| 303 | tok2str(vtp_stp_type_values, "Unknown", tlv_value), |
| 304 | tlv_value); |
| 305 | break; |
| 306 | |
| 307 | case VTP_VLAN_BRIDGE_TYPE: |
| 308 | printf(", %s (%u)", |
| 309 | tlv_value == 1 ? "SRB" : "SRT", |
| 310 | tlv_value); |
| 311 | break; |
| 312 | |
| 313 | case VTP_VLAN_BACKUP_CRF_MODE: |
| 314 | printf(", %s (%u)", |
| 315 | tlv_value == 1 ? "Backup" : "Not backup", |
| 316 | tlv_value); |
| 317 | break; |
| 318 | |
| 319 | /* |
| 320 | * FIXME those are the defined TLVs that lack a decoder |
| 321 | * you are welcome to contribute code ;-) |
| 322 | */ |
| 323 | |
| 324 | case VTP_VLAN_SOURCE_ROUTING_RING_NUMBER: |
| 325 | case VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER: |
| 326 | case VTP_VLAN_PARENT_VLAN: |
| 327 | case VTP_VLAN_TRANS_BRIDGED_VLAN: |
| 328 | case VTP_VLAN_ARP_HOP_COUNT: |
| 329 | default: |
| 330 | print_unknown_data(tptr, "\n\t\t ", 2 + tlv_len*2); |
| 331 | break; |
| 332 | } |
| 333 | len -= 2 + tlv_len*2; |
| 334 | tptr += 2 + tlv_len*2; |
| 335 | } |
| 336 | } |
| 337 | break; |
| 338 | |
| 339 | case VTP_ADV_REQUEST: |
| 340 | |
| 341 | /* |
| 342 | * ADVERTISEMENT REQUEST |
| 343 | * |
| 344 | * 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 |
| 345 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 346 | * | Version | Code | Reserved | MmgtD Len | |
| 347 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 348 | * | Management Domain Name | |
| 349 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 350 | * | Start value | |
| 351 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 352 | * |
| 353 | */ |
| 354 | |
| 355 | printf("\n\tStart value: %u", EXTRACT_32BITS(tptr)); |
| 356 | break; |
| 357 | |
| 358 | case VTP_JOIN_MESSAGE: |
| 359 | |
| 360 | /* FIXME - Could not find message format */ |
| 361 | break; |
| 362 | |
| 363 | default: |
| 364 | break; |
| 365 | } |
| 366 | |
| 367 | return; |
| 368 | |
| 369 | trunc: |
| 370 | printf("[|vtp]"); |
| 371 | } |
| 372 | |
| 373 | /* |
| 374 | * Local Variables: |
| 375 | * c-style: whitesmith |
| 376 | * c-basic-offset: 4 |
| 377 | * End: |
| 378 | */ |