175115Sfenner/* 275115Sfenner * Copyright (c) 2000 Lennert Buytenhek 375115Sfenner * 475115Sfenner * This software may be distributed either under the terms of the 575115Sfenner * BSD-style license that accompanies tcpdump or the GNU General 675115Sfenner * Public License 775115Sfenner * 875115Sfenner * Format and print IEEE 802.1d spanning tree protocol packets. 975115Sfenner * Contributed by Lennert Buytenhek <buytenh@gnu.org> 1075115Sfenner */ 1175115Sfenner 1275115Sfenner#ifndef lint 13127668Sbmsstatic const char rcsid[] _U_ = 14190207Srpaulo"@(#) $Header: /tcpdump/master/tcpdump/print-stp.c,v 1.20 2007-03-18 17:11:46 hannes Exp $"; 1575115Sfenner#endif 1675115Sfenner 1775115Sfenner#ifdef HAVE_CONFIG_H 1875115Sfenner#include "config.h" 1975115Sfenner#endif 2075115Sfenner 21127668Sbms#include <tcpdump-stdinc.h> 2275115Sfenner 2375115Sfenner#include <stdlib.h> 2475115Sfenner#include <stdio.h> 2575115Sfenner#include <string.h> 2675115Sfenner 2775115Sfenner#include "interface.h" 2875115Sfenner#include "addrtoname.h" 2975115Sfenner#include "extract.h" 3075115Sfenner 31168371Sthompsa#define RSTP_EXTRACT_PORT_ROLE(x) (((x)&0x0C)>>2) 32168371Sthompsa/* STP timers are expressed in multiples of 1/256th second */ 33168371Sthompsa#define STP_TIME_BASE 256 34168371Sthompsa#define STP_BPDU_MSTP_MIN_LEN 102 35168371Sthompsa 36168371Sthompsastruct stp_bpdu_ { 37168371Sthompsa u_int8_t protocol_id[2]; 38168371Sthompsa u_int8_t protocol_version; 39168371Sthompsa u_int8_t bpdu_type; 40168371Sthompsa u_int8_t flags; 41168371Sthompsa u_int8_t root_id[8]; 42168371Sthompsa u_int8_t root_path_cost[4]; 43168371Sthompsa u_int8_t bridge_id[8]; 44168371Sthompsa u_int8_t port_id[2]; 45168371Sthompsa u_int8_t message_age[2]; 46168371Sthompsa u_int8_t max_age[2]; 47168371Sthompsa u_int8_t hello_time[2]; 48168371Sthompsa u_int8_t forward_delay[2]; 49168371Sthompsa u_int8_t v1_length; 50168371Sthompsa}; 51168371Sthompsa 52168371Sthompsa#define STP_PROTO_REGULAR 0x00 53168371Sthompsa#define STP_PROTO_RAPID 0x02 54168371Sthompsa#define STP_PROTO_MSTP 0x03 55251158Sdelphij#define STP_PROTO_SPB 0x04 56168371Sthompsa 57168371Sthompsastruct tok stp_proto_values[] = { 58168371Sthompsa { STP_PROTO_REGULAR, "802.1d" }, 59168371Sthompsa { STP_PROTO_RAPID, "802.1w" }, 60168371Sthompsa { STP_PROTO_MSTP, "802.1s" }, 61251158Sdelphij { STP_PROTO_SPB, "802.1aq" }, 62168371Sthompsa { 0, NULL} 63168371Sthompsa}; 64168371Sthompsa 65168371Sthompsa#define STP_BPDU_TYPE_CONFIG 0x00 66168371Sthompsa#define STP_BPDU_TYPE_RSTP 0x02 67168371Sthompsa#define STP_BPDU_TYPE_TOPO_CHANGE 0x80 68168371Sthompsa 69168371Sthompsastruct tok stp_bpdu_flag_values[] = { 70168371Sthompsa { 0x01, "Topology change" }, 71168371Sthompsa { 0x02, "Proposal" }, 72168371Sthompsa { 0x10, "Learn" }, 73168371Sthompsa { 0x20, "Forward" }, 74168371Sthompsa { 0x40, "Agreement" }, 75168371Sthompsa { 0x80, "Topology change ACK" }, 76168371Sthompsa { 0, NULL} 77168371Sthompsa}; 78168371Sthompsa 79168371Sthompsastruct tok stp_bpdu_type_values[] = { 80168371Sthompsa { STP_BPDU_TYPE_CONFIG, "Config" }, 81168371Sthompsa { STP_BPDU_TYPE_RSTP, "Rapid STP" }, 82168371Sthompsa { STP_BPDU_TYPE_TOPO_CHANGE, "Topology Change" }, 83168371Sthompsa { 0, NULL} 84168371Sthompsa}; 85168371Sthompsa 86168371Sthompsastruct tok rstp_obj_port_role_values[] = { 87168371Sthompsa { 0x00, "Unknown" }, 88168371Sthompsa { 0x01, "Alternate" }, 89168371Sthompsa { 0x02, "Root" }, 90168371Sthompsa { 0x03, "Designated" }, 91168371Sthompsa { 0, NULL} 92168371Sthompsa}; 93168371Sthompsa 94168371Sthompsastatic char * 9575115Sfennerstp_print_bridge_id(const u_char *p) 9675115Sfenner{ 97168371Sthompsa static char bridge_id_str[sizeof("pppp.aa:bb:cc:dd:ee:ff")]; 98168371Sthompsa 99168371Sthompsa snprintf(bridge_id_str, sizeof(bridge_id_str), 100168371Sthompsa "%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 101168371Sthompsa p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 102168371Sthompsa 103168371Sthompsa return bridge_id_str; 10475115Sfenner} 10575115Sfenner 10675115Sfennerstatic void 107168371Sthompsastp_print_config_bpdu(const struct stp_bpdu_ *stp_bpdu, u_int length) 10875115Sfenner{ 109168371Sthompsa printf(", Flags [%s]", 110168371Sthompsa bittok2str(stp_bpdu_flag_values, "none", stp_bpdu->flags)); 11175115Sfenner 112168371Sthompsa printf(", bridge-id %s.%04x, length %u", 113168371Sthompsa stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id), 114168371Sthompsa EXTRACT_16BITS(&stp_bpdu->port_id), length); 11575115Sfenner 116168371Sthompsa /* in non-verbose mode just print the bridge-id */ 117168371Sthompsa if (!vflag) { 118168371Sthompsa return; 119168371Sthompsa } 12075115Sfenner 121168371Sthompsa printf("\n\tmessage-age %.2fs, max-age %.2fs" 122168371Sthompsa ", hello-time %.2fs, forwarding-delay %.2fs", 123168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->message_age) / STP_TIME_BASE, 124168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->max_age) / STP_TIME_BASE, 125168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->hello_time) / STP_TIME_BASE, 126168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->forward_delay) / STP_TIME_BASE); 12775115Sfenner 128168371Sthompsa printf("\n\troot-id %s, root-pathcost %u", 129168371Sthompsa stp_print_bridge_id((const u_char *)&stp_bpdu->root_id), 130168371Sthompsa EXTRACT_32BITS(&stp_bpdu->root_path_cost)); 131168371Sthompsa 132168371Sthompsa /* Port role is only valid for 802.1w */ 133168371Sthompsa if (stp_bpdu->protocol_version == STP_PROTO_RAPID) { 134168371Sthompsa printf(", port-role %s", 135168371Sthompsa tok2str(rstp_obj_port_role_values, "Unknown", 136168371Sthompsa RSTP_EXTRACT_PORT_ROLE(stp_bpdu->flags))); 137168371Sthompsa } 13875115Sfenner} 13975115Sfenner 140168371Sthompsa/* 141168371Sthompsa * MSTP packet format 142168371Sthompsa * Ref. IEEE 802.1Q 2003 Ed. Section 14 143168371Sthompsa * 144168371Sthompsa * MSTP BPDU 145168371Sthompsa * 146168371Sthompsa * 2 - bytes Protocol Id 147168371Sthompsa * 1 - byte Protocol Ver. 148168371Sthompsa * 1 - byte BPDU tye 149168371Sthompsa * 1 - byte Flags 150168371Sthompsa * 8 - bytes CIST Root Identifier 151168371Sthompsa * 4 - bytes CIST External Path Cost 152168371Sthompsa * 8 - bytes CIST Regional Root Identifier 153168371Sthompsa * 2 - bytes CIST Port Identifier 154168371Sthompsa * 2 - bytes Message Age 155168371Sthompsa * 2 - bytes Max age 156168371Sthompsa * 2 - bytes Hello Time 157168371Sthompsa * 2 - bytes Forward delay 158168371Sthompsa * 1 - byte Version 1 length. Must be 0 159168371Sthompsa * 2 - bytes Version 3 length 160168371Sthompsa * 1 - byte Config Identifier 161168371Sthompsa * 32 - bytes Config Name 162168371Sthompsa * 2 - bytes Revision level 163168371Sthompsa * 16 - bytes Config Digest [MD5] 164168371Sthompsa * 4 - bytes CIST Internal Root Path Cost 165168371Sthompsa * 8 - bytes CIST Bridge Identifier 166168371Sthompsa * 1 - byte CIST Remaining Hops 167168371Sthompsa * 16 - bytes MSTI information [Max 64 MSTI, each 16 bytes] 168168371Sthompsa * 169251158Sdelphij * 170251158Sdelphij * SPB BPDU 171251158Sdelphij * Ref. IEEE 802.1aq. Section 14 172251158Sdelphij * 173251158Sdelphij * 2 - bytes Version 4 length 174251158Sdelphij * 1 - byte Aux Config Identifier 175251158Sdelphij * 32 - bytes Aux Config Name 176251158Sdelphij * 2 - bytes Aux Revision level 177251158Sdelphij * 16 - bytes Aux Config Digest [MD5] 178251158Sdelphij * 1 - byte (1 - 2) Agreement Number 179251158Sdelphij * (3 - 4) Discarded Agreement Number 180251158Sdelphij * (5) Agreement Valid Flag 181251158Sdelphij * (6) Restricted Role Flag 182251158Sdelphij * (7 - 8) Unused sent zero 183251158Sdelphij * 1 - byte Unused 184251158Sdelphij * 1 - byte (1 - 4) Agreement Digest Format Identifier 185251158Sdelphij * (5 - 8) Agreement Digest Format Capabilities 186251158Sdelphij * 1 - byte (1 - 4) Agreement Digest Convention Identifier 187251158Sdelphij * (5 - 8) Agreement Digest Convention Capabilities 188251158Sdelphij * 2 - bytes Agreement Digest Edge Count 189251158Sdelphij * 8 - byte Reserved Set 190251158Sdelphij * 20 - bytes Computed Topology Digest 191251158Sdelphij * 192251158Sdelphij * 193168371Sthompsa * MSTI Payload 194168371Sthompsa * 195168371Sthompsa * 1 - byte MSTI flag 196168371Sthompsa * 8 - bytes MSTI Regional Root Identifier 197168371Sthompsa * 4 - bytes MSTI Regional Path Cost 198168371Sthompsa * 1 - byte MSTI Bridge Priority 199168371Sthompsa * 1 - byte MSTI Port Priority 200168371Sthompsa * 1 - byte MSTI Remaining Hops 201251158Sdelphij * 202168371Sthompsa */ 203168371Sthompsa 204168371Sthompsa#define MST_BPDU_MSTI_LENGTH 16 205168371Sthompsa#define MST_BPDU_CONFIG_INFO_LENGTH 64 206168371Sthompsa 207168371Sthompsa/* Offsets of fields from the begginning for the packet */ 208168371Sthompsa#define MST_BPDU_VER3_LEN_OFFSET 36 209168371Sthompsa#define MST_BPDU_CONFIG_NAME_OFFSET 39 210168371Sthompsa#define MST_BPDU_CONFIG_DIGEST_OFFSET 73 211168371Sthompsa#define MST_BPDU_CIST_INT_PATH_COST_OFFSET 89 212168371Sthompsa#define MST_BPDU_CIST_BRIDGE_ID_OFFSET 93 213168371Sthompsa#define MST_BPDU_CIST_REMAIN_HOPS_OFFSET 101 214168371Sthompsa#define MST_BPDU_MSTI_OFFSET 102 215168371Sthompsa/* Offsets within an MSTI */ 216168371Sthompsa#define MST_BPDU_MSTI_ROOT_PRIO_OFFSET 1 217168371Sthompsa#define MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET 9 218168371Sthompsa#define MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET 13 219168371Sthompsa#define MST_BPDU_MSTI_PORT_PRIO_OFFSET 14 220168371Sthompsa#define MST_BPDU_MSTI_REMAIN_HOPS_OFFSET 15 221168371Sthompsa 222251158Sdelphij#define SPB_BPDU_MIN_LEN 87 223251158Sdelphij#define SPB_BPDU_CONFIG_NAME_OFFSET 3 224251158Sdelphij#define SPB_BPDU_CONFIG_REV_OFFSET SPB_BPDU_CONFIG_NAME_OFFSET + 32 225251158Sdelphij#define SPB_BPDU_CONFIG_DIGEST_OFFSET SPB_BPDU_CONFIG_REV_OFFSET + 2 226251158Sdelphij#define SPB_BPDU_AGREEMENT_OFFSET SPB_BPDU_CONFIG_DIGEST_OFFSET + 16 227251158Sdelphij#define SPB_BPDU_AGREEMENT_UNUSED_OFFSET SPB_BPDU_AGREEMENT_OFFSET + 1 228251158Sdelphij#define SPB_BPDU_AGREEMENT_FORMAT_OFFSET SPB_BPDU_AGREEMENT_UNUSED_OFFSET + 1 229251158Sdelphij#define SPB_BPDU_AGREEMENT_CON_OFFSET SPB_BPDU_AGREEMENT_FORMAT_OFFSET + 1 230251158Sdelphij#define SPB_BPDU_AGREEMENT_EDGE_OFFSET SPB_BPDU_AGREEMENT_CON_OFFSET + 1 231251158Sdelphij#define SPB_BPDU_AGREEMENT_RES1_OFFSET SPB_BPDU_AGREEMENT_EDGE_OFFSET + 2 232251158Sdelphij#define SPB_BPDU_AGREEMENT_RES2_OFFSET SPB_BPDU_AGREEMENT_RES1_OFFSET + 4 233251158Sdelphij#define SPB_BPDU_AGREEMENT_DIGEST_OFFSET SPB_BPDU_AGREEMENT_RES2_OFFSET + 4 234251158Sdelphij 235251158Sdelphij 23675115Sfennerstatic void 237168371Sthompsastp_print_mstp_bpdu(const struct stp_bpdu_ *stp_bpdu, u_int length) 23875115Sfenner{ 239251158Sdelphij const u_char *ptr; 240168371Sthompsa u_int16_t v3len; 241168371Sthompsa u_int16_t len; 242168371Sthompsa u_int16_t msti; 243168371Sthompsa u_int16_t offset; 244168371Sthompsa 245168371Sthompsa ptr = (const u_char *)stp_bpdu; 246251158Sdelphij printf(", CIST Flags [%s], length %u", 247251158Sdelphij bittok2str(stp_bpdu_flag_values, "none", stp_bpdu->flags), length); 248168371Sthompsa 249168371Sthompsa /* 250168371Sthompsa * in non-verbose mode just print the flags. We dont read that much 251168371Sthompsa * of the packet (DEFAULT_SNAPLEN) to print out cist bridge-id 252168371Sthompsa */ 253168371Sthompsa if (!vflag) { 254168371Sthompsa return; 255168371Sthompsa } 256168371Sthompsa 257251158Sdelphij printf("\n\tport-role %s, ", 258251158Sdelphij tok2str(rstp_obj_port_role_values, "Unknown", 259251158Sdelphij RSTP_EXTRACT_PORT_ROLE(stp_bpdu->flags))); 260168371Sthompsa 261251158Sdelphij printf("CIST root-id %s, CIST ext-pathcost %u ", 262251158Sdelphij stp_print_bridge_id((const u_char *)&stp_bpdu->root_id), 263251158Sdelphij EXTRACT_32BITS(&stp_bpdu->root_path_cost)); 264168371Sthompsa 265251158Sdelphij printf("\n\tCIST regional-root-id %s, ", 266251158Sdelphij stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id)); 267251158Sdelphij 268251158Sdelphij printf("CIST port-id %04x, ", EXTRACT_16BITS(&stp_bpdu->port_id)); 269251158Sdelphij 270168371Sthompsa printf("\n\tmessage-age %.2fs, max-age %.2fs" 271168371Sthompsa ", hello-time %.2fs, forwarding-delay %.2fs", 272168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->message_age) / STP_TIME_BASE, 273168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->max_age) / STP_TIME_BASE, 274168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->hello_time) / STP_TIME_BASE, 275168371Sthompsa (float)EXTRACT_16BITS(&stp_bpdu->forward_delay) / STP_TIME_BASE); 276168371Sthompsa 277251158Sdelphij printf ("\n\tv3len %d, ", EXTRACT_16BITS(ptr + MST_BPDU_VER3_LEN_OFFSET)); 278251158Sdelphij printf("MCID Name %s, rev %u, " 279251158Sdelphij "\n\t\tdigest %08x%08x%08x%08x, ", 280251158Sdelphij ptr + MST_BPDU_CONFIG_NAME_OFFSET, 281251158Sdelphij EXTRACT_16BITS(ptr + MST_BPDU_CONFIG_NAME_OFFSET + 32), 282251158Sdelphij EXTRACT_32BITS(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET), 283251158Sdelphij EXTRACT_32BITS(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 4), 284251158Sdelphij EXTRACT_32BITS(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 8), 285251158Sdelphij EXTRACT_32BITS(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12)); 286168371Sthompsa 287251158Sdelphij printf ("CIST int-root-pathcost %u, ", 288251158Sdelphij EXTRACT_32BITS(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET)); 289168371Sthompsa 290251158Sdelphij printf("\n\tCIST bridge-id %s, ", 291251158Sdelphij stp_print_bridge_id(ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET)); 292168371Sthompsa 293251158Sdelphij printf("CIST remaining-hops %d", ptr[MST_BPDU_CIST_REMAIN_HOPS_OFFSET]); 294168371Sthompsa 295168371Sthompsa /* Dump all MSTI's */ 296168371Sthompsa v3len = EXTRACT_16BITS(ptr + MST_BPDU_VER3_LEN_OFFSET); 297168371Sthompsa if (v3len > MST_BPDU_CONFIG_INFO_LENGTH) { 298168371Sthompsa len = v3len - MST_BPDU_CONFIG_INFO_LENGTH; 299168371Sthompsa offset = MST_BPDU_MSTI_OFFSET; 300168371Sthompsa while (len >= MST_BPDU_MSTI_LENGTH) { 301168371Sthompsa msti = EXTRACT_16BITS(ptr + offset + 302168371Sthompsa MST_BPDU_MSTI_ROOT_PRIO_OFFSET); 303168371Sthompsa msti = msti & 0x0FFF; 304168371Sthompsa 305168371Sthompsa printf("\n\tMSTI %d, Flags [%s], port-role %s", 306168371Sthompsa msti, bittok2str(stp_bpdu_flag_values, "none", ptr[offset]), 307168371Sthompsa tok2str(rstp_obj_port_role_values, "Unknown", 308168371Sthompsa RSTP_EXTRACT_PORT_ROLE(ptr[offset]))); 309168371Sthompsa printf("\n\t\tMSTI regional-root-id %s, pathcost %u", 310168371Sthompsa stp_print_bridge_id(ptr + offset + 311168371Sthompsa MST_BPDU_MSTI_ROOT_PRIO_OFFSET), 312168371Sthompsa EXTRACT_32BITS(ptr + offset + 313168371Sthompsa MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET)); 314168371Sthompsa printf("\n\t\tMSTI bridge-prio %d, port-prio %d, hops %d", 315168371Sthompsa ptr[offset + MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET] >> 4, 316168371Sthompsa ptr[offset + MST_BPDU_MSTI_PORT_PRIO_OFFSET] >> 4, 317168371Sthompsa ptr[offset + MST_BPDU_MSTI_REMAIN_HOPS_OFFSET]); 318168371Sthompsa 319168371Sthompsa len -= MST_BPDU_MSTI_LENGTH; 320168371Sthompsa offset += MST_BPDU_MSTI_LENGTH; 321168371Sthompsa } 322168371Sthompsa } 323251158Sdelphij 324251158Sdelphij if ((length-offset) >= SPB_BPDU_MIN_LEN) 325251158Sdelphij { 326251158Sdelphij printf("\n\tv4len %d AUXMCID Name %s, Rev %u, \n\t\tdigest %08x%08x%08x%08x", 327251158Sdelphij EXTRACT_16BITS (ptr + offset), 328251158Sdelphij ptr + offset + SPB_BPDU_CONFIG_NAME_OFFSET, 329251158Sdelphij EXTRACT_16BITS(ptr + offset + SPB_BPDU_CONFIG_REV_OFFSET), 330251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET), 331251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 4), 332251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 8), 333251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_CONFIG_DIGEST_OFFSET + 12)); 334251158Sdelphij 335251158Sdelphij printf("\n\tAgreement num %d, Discarded Agreement num %d, Agreement valid-" 336251158Sdelphij "flag %d, \n\tRestricted role-flag: %d, Format id %d cap %d, " 337251158Sdelphij "Convention id %d cap %d, \n\tEdge count %d, " 338251158Sdelphij "Agreement digest %08x%08x%08x%08x%08x\n", 339251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_OFFSET]>>6, 340251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_OFFSET]>>4 & 0x3, 341251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_OFFSET]>>3 & 0x1, 342251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_OFFSET]>>2 & 0x1, 343251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_FORMAT_OFFSET]>>4, 344251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_FORMAT_OFFSET]&0x00ff, 345251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_CON_OFFSET]>>4, 346251158Sdelphij ptr[offset + SPB_BPDU_AGREEMENT_CON_OFFSET]&0x00ff, 347251158Sdelphij EXTRACT_16BITS(ptr + offset + SPB_BPDU_AGREEMENT_EDGE_OFFSET), 348251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET), 349251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET)+4, 350251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET)+8, 351251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET)+12, 352251158Sdelphij EXTRACT_32BITS(ptr + offset + SPB_BPDU_AGREEMENT_DIGEST_OFFSET)+16); 353251158Sdelphij } 35475115Sfenner} 35575115Sfenner 35675115Sfenner/* 357251158Sdelphij * Print 802.1d / 802.1w / 802.1q (mstp) / 802.1aq (spb) packets. 35875115Sfenner */ 35975115Sfennervoid 36075115Sfennerstp_print(const u_char *p, u_int length) 36175115Sfenner{ 362168371Sthompsa const struct stp_bpdu_ *stp_bpdu; 363168371Sthompsa u_int16_t mstp_len; 364251158Sdelphij u_int16_t spb_len; 365168371Sthompsa 366168371Sthompsa stp_bpdu = (struct stp_bpdu_*)p; 36775115Sfenner 368168371Sthompsa /* Minimum STP Frame size. */ 369168371Sthompsa if (length < 4) 370168371Sthompsa goto trunc; 371168371Sthompsa 372168371Sthompsa if (EXTRACT_16BITS(&stp_bpdu->protocol_id)) { 373168371Sthompsa printf("unknown STP version, length %u", length); 374168371Sthompsa return; 375168371Sthompsa } 376127668Sbms 377168371Sthompsa printf("STP %s", tok2str(stp_proto_values, "Unknown STP protocol (0x%02x)", 378168371Sthompsa stp_bpdu->protocol_version)); 37975115Sfenner 380168371Sthompsa switch (stp_bpdu->protocol_version) { 381168371Sthompsa case STP_PROTO_REGULAR: 382168371Sthompsa case STP_PROTO_RAPID: 383168371Sthompsa case STP_PROTO_MSTP: 384251158Sdelphij case STP_PROTO_SPB: 385168371Sthompsa break; 386168371Sthompsa default: 387168371Sthompsa return; 388168371Sthompsa } 38975115Sfenner 390168371Sthompsa printf(", %s", tok2str(stp_bpdu_type_values, "Unknown BPDU Type (0x%02x)", 391168371Sthompsa stp_bpdu->bpdu_type)); 39275115Sfenner 393168371Sthompsa switch (stp_bpdu->bpdu_type) { 394168371Sthompsa case STP_BPDU_TYPE_CONFIG: 395168371Sthompsa if (length < sizeof(struct stp_bpdu_) - 1) { 396168371Sthompsa goto trunc; 397168371Sthompsa } 398168371Sthompsa stp_print_config_bpdu(stp_bpdu, length); 399168371Sthompsa break; 400168371Sthompsa 401168371Sthompsa case STP_BPDU_TYPE_RSTP: 402168371Sthompsa if (stp_bpdu->protocol_version == STP_PROTO_RAPID) { 403168371Sthompsa if (length < sizeof(struct stp_bpdu_)) { 404168371Sthompsa goto trunc; 405168371Sthompsa } 406168371Sthompsa stp_print_config_bpdu(stp_bpdu, length); 407251158Sdelphij } else if (stp_bpdu->protocol_version == STP_PROTO_MSTP || 408251158Sdelphij stp_bpdu->protocol_version == STP_PROTO_SPB) { 409168371Sthompsa if (length < STP_BPDU_MSTP_MIN_LEN) { 410168371Sthompsa goto trunc; 411168371Sthompsa } 412251158Sdelphij 413168371Sthompsa if (stp_bpdu->v1_length != 0) { 414168371Sthompsa /* FIX ME: Emit a message here ? */ 415168371Sthompsa goto trunc; 416168371Sthompsa } 417251158Sdelphij 418168371Sthompsa /* Validate v3 length */ 419168371Sthompsa mstp_len = EXTRACT_16BITS(p + MST_BPDU_VER3_LEN_OFFSET); 420168371Sthompsa mstp_len += 2; /* length encoding itself is 2 bytes */ 421168371Sthompsa if (length < (sizeof(struct stp_bpdu_) + mstp_len)) { 422168371Sthompsa goto trunc; 423168371Sthompsa } 424251158Sdelphij 425251158Sdelphij if (stp_bpdu->protocol_version == STP_PROTO_SPB) 426251158Sdelphij { 427251158Sdelphij /* Validate v4 length */ 428251158Sdelphij spb_len = EXTRACT_16BITS (p + MST_BPDU_VER3_LEN_OFFSET + mstp_len); 429251158Sdelphij spb_len += 2; 430251158Sdelphij if (length < (sizeof(struct stp_bpdu_) + mstp_len + spb_len) || 431251158Sdelphij spb_len < SPB_BPDU_MIN_LEN) { 432251158Sdelphij goto trunc; 433251158Sdelphij } 434251158Sdelphij } 435251158Sdelphij 436168371Sthompsa stp_print_mstp_bpdu(stp_bpdu, length); 437168371Sthompsa } 438168371Sthompsa break; 439168371Sthompsa 440168371Sthompsa case STP_BPDU_TYPE_TOPO_CHANGE: 441168371Sthompsa /* always empty message - just break out */ 442168371Sthompsa break; 443168371Sthompsa 444168371Sthompsa default: 445168371Sthompsa break; 446168371Sthompsa } 447168371Sthompsa 448168371Sthompsa return; 449168371Sthompsa trunc: 450168371Sthompsa printf("[|stp %d]", length); 45175115Sfenner} 452168371Sthompsa 453168371Sthompsa/* 454168371Sthompsa * Local Variables: 455168371Sthompsa * c-style: whitesmith 456168371Sthompsa * c-basic-offset: 4 457168371Sthompsa * End: 458168371Sthompsa */ 459