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