1259698Sdim/*	$OpenBSD: bridgestp.c,v 1.77 2021/03/10 10:21:47 jsg Exp $	*/
2259698Sdim
3259698Sdim/*
4259698Sdim * Copyright (c) 2000 Jason L. Wright (jason@thought.net)
5259698Sdim * Copyright (c) 2006 Andrew Thompson (thompsa@FreeBSD.org)
6259698Sdim * All rights reserved.
7259698Sdim *
8259698Sdim * Redistribution and use in source and binary forms, with or without
9259698Sdim * modification, are permitted provided that the following conditions
10259698Sdim * are met:
11259698Sdim * 1. Redistributions of source code must retain the above copyright
12259698Sdim *    notice, this list of conditions and the following disclaimer.
13259698Sdim * 2. Redistributions in binary form must reproduce the above copyright
14259698Sdim *    notice, this list of conditions and the following disclaimer in the
15259698Sdim *    documentation and/or other materials provided with the distribution.
16259698Sdim *
17259698Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18259698Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19259698Sdim * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20259698Sdim * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21259698Sdim * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22259698Sdim * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23259698Sdim * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24259698Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25259698Sdim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26259698Sdim * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27259698Sdim * POSSIBILITY OF SUCH DAMAGE.
28259698Sdim */
29259698Sdim
30259698Sdim/*
31259698Sdim * Implementation of the spanning tree protocol as defined in
32259698Sdim * ISO/IEC 802.1D-2004, June 9, 2004.
33259698Sdim */
34259698Sdim
35259698Sdim#include <sys/param.h>
36259698Sdim#include <sys/systm.h>
37259698Sdim#include <sys/mbuf.h>
38259698Sdim#include <sys/socket.h>
39259698Sdim#include <sys/ioctl.h>
40259698Sdim#include <sys/device.h>
41259698Sdim#include <sys/kernel.h>
42259698Sdim#include <sys/timeout.h>
43259698Sdim
44259698Sdim#include <net/if.h>
45259698Sdim#include <net/if_types.h>
46259698Sdim#include <net/if_dl.h>
47259698Sdim#include <net/if_llc.h>
48259698Sdim#include <net/netisr.h>
49259698Sdim
50259698Sdim#include <netinet/in.h>
51259698Sdim#include <netinet/ip.h>
52259698Sdim#include <netinet/if_ether.h>
53259698Sdim
54259698Sdim#include <net/if_bridge.h>
55259698Sdim
56259698Sdim/* STP port states */
57259698Sdim#define	BSTP_IFSTATE_DISABLED	0
58259698Sdim#define	BSTP_IFSTATE_LISTENING	1
59259698Sdim#define	BSTP_IFSTATE_LEARNING	2
60259698Sdim#define	BSTP_IFSTATE_FORWARDING	3
61259698Sdim#define	BSTP_IFSTATE_BLOCKING	4
62259698Sdim#define	BSTP_IFSTATE_DISCARDING	5
63259698Sdim
64259698Sdim#define	BSTP_TCSTATE_ACTIVE	1
65259698Sdim#define	BSTP_TCSTATE_DETECTED	2
66259698Sdim#define	BSTP_TCSTATE_INACTIVE	3
67259698Sdim#define	BSTP_TCSTATE_LEARNING	4
68259698Sdim#define	BSTP_TCSTATE_PROPAG	5
69259698Sdim#define	BSTP_TCSTATE_ACK	6
70259698Sdim#define	BSTP_TCSTATE_TC		7
71259698Sdim#define	BSTP_TCSTATE_TCN	8
72259698Sdim
73259698Sdim#define	BSTP_ROLE_DISABLED	0
74259698Sdim#define	BSTP_ROLE_ROOT		1
75259698Sdim#define	BSTP_ROLE_DESIGNATED	2
76259698Sdim#define	BSTP_ROLE_ALTERNATE	3
77259698Sdim#define	BSTP_ROLE_BACKUP	4
78259698Sdim
79259698Sdim/* STP port flags */
80259698Sdim#define	BSTP_PORT_CANMIGRATE	0x0001
81259698Sdim#define	BSTP_PORT_NEWINFO	0x0002
82259698Sdim#define	BSTP_PORT_DISPUTED	0x0004
83259698Sdim#define	BSTP_PORT_ADMCOST	0x0008
84259698Sdim#define	BSTP_PORT_AUTOEDGE	0x0010
85259698Sdim
86259698Sdim/* BPDU priority */
87259698Sdim#define	BSTP_PDU_SUPERIOR	1
88259698Sdim#define	BSTP_PDU_REPEATED	2
89259698Sdim#define	BSTP_PDU_INFERIOR	3
90259698Sdim#define	BSTP_PDU_INFERIORALT	4
91259698Sdim#define	BSTP_PDU_OTHER		5
92259698Sdim
93259698Sdim/* BPDU flags */
94259698Sdim#define	BSTP_PDU_PRMASK		0x0c		/* Port Role */
95259698Sdim#define	BSTP_PDU_PRSHIFT	2		/* Port Role offset */
96259698Sdim#define	BSTP_PDU_F_UNKN		0x00		/* Unknown port    (00) */
97259698Sdim#define	BSTP_PDU_F_ALT		0x01		/* Alt/Backup port (01) */
98259698Sdim#define	BSTP_PDU_F_ROOT		0x02		/* Root port       (10) */
99259698Sdim#define	BSTP_PDU_F_DESG		0x03		/* Designated port (11) */
100259698Sdim
101259698Sdim#define	BSTP_PDU_STPMASK	0x81		/* strip unused STP flags */
102259698Sdim#define	BSTP_PDU_RSTPMASK	0x7f		/* strip unused RSTP flags */
103259698Sdim#define	BSTP_PDU_F_TC		0x01		/* Topology change */
104259698Sdim#define	BSTP_PDU_F_P		0x02		/* Proposal flag */
105259698Sdim#define	BSTP_PDU_F_L		0x10		/* Learning flag */
106259698Sdim#define	BSTP_PDU_F_F		0x20		/* Forwarding flag */
107259698Sdim#define	BSTP_PDU_F_A		0x40		/* Agreement flag */
108259698Sdim#define	BSTP_PDU_F_TCA		0x80		/* Topology change ack */
109259698Sdim
110259698Sdim/*
111259698Sdim * Spanning tree defaults.
112259698Sdim */
113259698Sdim#define	BSTP_DEFAULT_MAX_AGE		(20 * 256)
114259698Sdim#define	BSTP_DEFAULT_HELLO_TIME		(2 * 256)
115259698Sdim#define	BSTP_DEFAULT_FORWARD_DELAY	(15 * 256)
116259698Sdim#define	BSTP_DEFAULT_HOLD_TIME		(1 * 256)
117259698Sdim#define	BSTP_DEFAULT_MIGRATE_DELAY	(3 * 256)
118259698Sdim#define	BSTP_DEFAULT_HOLD_COUNT		6
119259698Sdim#define	BSTP_DEFAULT_BRIDGE_PRIORITY	0x8000
120259698Sdim#define	BSTP_DEFAULT_PORT_PRIORITY	0x80
121259698Sdim#define	BSTP_DEFAULT_PATH_COST		55
122259698Sdim#define	BSTP_MIN_HELLO_TIME		(1 * 256)
123259698Sdim#define	BSTP_MIN_MAX_AGE		(6 * 256)
124259698Sdim#define	BSTP_MIN_FORWARD_DELAY		(4 * 256)
125259698Sdim#define	BSTP_MIN_HOLD_COUNT		1
126259698Sdim#define	BSTP_MAX_HELLO_TIME		(2 * 256)
127259698Sdim#define	BSTP_MAX_MAX_AGE		(40 * 256)
128259698Sdim#define	BSTP_MAX_FORWARD_DELAY		(30 * 256)
129259698Sdim#define	BSTP_MAX_HOLD_COUNT		10
130259698Sdim#define	BSTP_MAX_PRIORITY		61440
131259698Sdim#define	BSTP_MAX_PORT_PRIORITY		240
132259698Sdim#define	BSTP_MAX_PATH_COST		200000000
133259698Sdim
134259698Sdim/* BPDU message types */
135259698Sdim#define	BSTP_MSGTYPE_CFG	0x00		/* Configuration */
136259698Sdim#define	BSTP_MSGTYPE_RSTP	0x02		/* Rapid STP */
137259698Sdim#define	BSTP_MSGTYPE_TCN	0x80		/* Topology chg notification */
138259698Sdim
139259698Sdim#define	BSTP_INFO_RECEIVED	1
140259698Sdim#define	BSTP_INFO_MINE		2
141259698Sdim#define	BSTP_INFO_AGED		3
142259698Sdim#define	BSTP_INFO_DISABLED	4
143259698Sdim
144259698Sdim#define	BSTP_MESSAGE_AGE_INCR	(1 * 256)	/* in 256ths of a second */
145259698Sdim#define	BSTP_TICK_VAL		(1 * 256)	/* in 256ths of a second */
146259698Sdim#define	BSTP_LINK_TIMER		(BSTP_TICK_VAL * 15)
147259698Sdim
148259698Sdim#ifdef	BRIDGESTP_DEBUG
149259698Sdim#define	DPRINTF(bp, fmt, arg...) \
150259698Sdimdo { \
151259698Sdim	struct ifnet *__ifp = if_get((bp)->bp_ifindex); \
152259698Sdim	printf("bstp: %s" fmt, __ifp? __ifp->if_xname : "Unknown", ##arg); \
153259698Sdim	if_put(__ifp); \
154259698Sdim} while (0)
155259698Sdim#else
156259698Sdim#define	DPRINTF(bp, fmt, arg...)
157259698Sdim#endif
158259698Sdim
159259698Sdim#define	PV2ADDR(pv, eaddr)	do {		\
160259698Sdim	eaddr[0] = pv >> 40;			\
161259698Sdim	eaddr[1] = pv >> 32;			\
162259698Sdim	eaddr[2] = pv >> 24;			\
163259698Sdim	eaddr[3] = pv >> 16;			\
164259698Sdim	eaddr[4] = pv >> 8;			\
165259698Sdim	eaddr[5] = pv >> 0;			\
166259698Sdim} while (0)
167259698Sdim
168259698Sdim#define	INFO_BETTER	1
169259698Sdim#define	INFO_SAME	0
170259698Sdim#define	INFO_WORSE	-1
171259698Sdim
172259698Sdim#define	BSTP_IFQ_PRIO	6
173259698Sdim
174259698Sdim/*
175259698Sdim * Because BPDU's do not make nicely aligned structures, two different
176259698Sdim * declarations are used: bstp_?bpdu (wire representation, packed) and
177259698Sdim * bstp_*_unit (internal, nicely aligned version).
178259698Sdim */
179259698Sdim
180259698Sdim/* configuration bridge protocol data unit */
181259698Sdimstruct bstp_cbpdu {
182259698Sdim	u_int8_t	cbu_dsap;		/* LLC: destination sap */
183259698Sdim	u_int8_t	cbu_ssap;		/* LLC: source sap */
184259698Sdim	u_int8_t	cbu_ctl;		/* LLC: control */
185259698Sdim	u_int16_t	cbu_protoid;		/* protocol id */
186259698Sdim	u_int8_t	cbu_protover;		/* protocol version */
187259698Sdim	u_int8_t	cbu_bpdutype;		/* message type */
188259698Sdim	u_int8_t	cbu_flags;		/* flags (below) */
189259698Sdim
190259698Sdim	/* root id */
191259698Sdim	u_int16_t	cbu_rootpri;		/* root priority */
192259698Sdim	u_int8_t	cbu_rootaddr[6];	/* root address */
193259698Sdim
194259698Sdim	u_int32_t	cbu_rootpathcost;	/* root path cost */
195259698Sdim
196259698Sdim	/* bridge id */
197259698Sdim	u_int16_t	cbu_bridgepri;		/* bridge priority */
198259698Sdim	u_int8_t	cbu_bridgeaddr[6];	/* bridge address */
199259698Sdim
200259698Sdim	u_int16_t	cbu_portid;		/* port id */
201259698Sdim	u_int16_t	cbu_messageage;		/* current message age */
202259698Sdim	u_int16_t	cbu_maxage;		/* maximum age */
203259698Sdim	u_int16_t	cbu_hellotime;		/* hello time */
204259698Sdim	u_int16_t	cbu_forwarddelay;	/* forwarding delay */
205259698Sdim	u_int8_t	cbu_versionlen;		/* version 1 length */
206259698Sdim} __packed;
207259698Sdim
208259698Sdim#define	BSTP_BPDU_STP_LEN	(3 + 35)	/* LLC + STP pdu */
209259698Sdim#define	BSTP_BPDU_RSTP_LEN	(3 + 36)	/* LLC + RSTP pdu */
210259698Sdim
211259698Sdim/* topology change notification bridge protocol data unit */
212259698Sdimstruct bstp_tbpdu {
213259698Sdim	u_int8_t	tbu_dsap;		/* LLC: destination sap */
214259698Sdim	u_int8_t	tbu_ssap;		/* LLC: source sap */
215259698Sdim	u_int8_t	tbu_ctl;		/* LLC: control */
216259698Sdim	u_int16_t	tbu_protoid;		/* protocol id */
217259698Sdim	u_int8_t	tbu_protover;		/* protocol version */
218259698Sdim	u_int8_t	tbu_bpdutype;		/* message type */
219259698Sdim} __packed;
220259698Sdim
221259698Sdimconst u_int8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
222259698Sdim
223259698Sdim
224259698Sdimvoid	bstp_transmit(struct bstp_state *, struct bstp_port *);
225259698Sdimvoid	bstp_transmit_bpdu(struct bstp_state *, struct bstp_port *);
226259698Sdimvoid	bstp_transmit_tcn(struct bstp_state *, struct bstp_port *);
227259698Sdimvoid	bstp_decode_bpdu(struct bstp_port *, struct bstp_cbpdu *,
228259698Sdim	    struct bstp_config_unit *);
229259698Sdimvoid	bstp_send_bpdu(struct bstp_state *, struct bstp_port *,
230259698Sdim	    struct bstp_cbpdu *);
231259698Sdimint	bstp_pdu_flags(struct bstp_port *);
232259698Sdimvoid	bstp_received_stp(struct bstp_state *, struct bstp_port *,
233259698Sdim	    struct mbuf **, struct bstp_tbpdu *);
234259698Sdimvoid	bstp_received_rstp(struct bstp_state *, struct bstp_port *,
235259698Sdim	    struct mbuf **, struct bstp_tbpdu *);
236259698Sdimvoid	bstp_received_tcn(struct bstp_state *, struct bstp_port *,
237259698Sdim	    struct bstp_tcn_unit *);
238259698Sdimvoid	bstp_received_bpdu(struct bstp_state *, struct bstp_port *,
239259698Sdim	    struct bstp_config_unit *);
240259698Sdimint	bstp_pdu_rcvtype(struct bstp_port *, struct bstp_config_unit *);
241259698Sdimint	bstp_pdu_bettersame(struct bstp_port *, int);
242259698Sdimint	bstp_info_cmp(struct bstp_pri_vector *,
243259698Sdim	    struct bstp_pri_vector *);
244259698Sdimint	bstp_info_superior(struct bstp_pri_vector *,
245259698Sdim	    struct bstp_pri_vector *);
246259698Sdimvoid	bstp_assign_roles(struct bstp_state *);
247259698Sdimvoid	bstp_update_roles(struct bstp_state *, struct bstp_port *);
248259698Sdimvoid	bstp_update_state(struct bstp_state *, struct bstp_port *);
249259698Sdimvoid	bstp_update_tc(struct bstp_port *);
250259698Sdimvoid	bstp_update_info(struct bstp_port *);
251259698Sdimvoid	bstp_set_other_tcprop(struct bstp_port *);
252259698Sdimvoid	bstp_set_all_reroot(struct bstp_state *);
253259698Sdimvoid	bstp_set_all_sync(struct bstp_state *);
254259698Sdimvoid	bstp_set_port_state(struct bstp_port *, int);
255259698Sdimvoid	bstp_set_port_role(struct bstp_port *, int);
256259698Sdimvoid	bstp_set_port_proto(struct bstp_port *, int);
257259698Sdimvoid	bstp_set_port_tc(struct bstp_port *, int);
258259698Sdimvoid	bstp_set_timer_tc(struct bstp_port *);
259259698Sdimvoid	bstp_set_timer_msgage(struct bstp_port *);
260259698Sdimvoid	bstp_reset(struct bstp_state *);
261259698Sdimint	bstp_rerooted(struct bstp_state *, struct bstp_port *);
262259698Sdimu_int32_t	bstp_calc_path_cost(struct bstp_port *);
263259698Sdimvoid	bstp_notify_rtage(struct bstp_port *, int);
264259698Sdimvoid	bstp_ifupdstatus(struct bstp_state *, struct bstp_port *);
265259698Sdimvoid	bstp_enable_port(struct bstp_state *, struct bstp_port *);
266259698Sdimvoid	bstp_disable_port(struct bstp_state *, struct bstp_port *);
267259698Sdimvoid	bstp_tick(void *);
268259698Sdimvoid	bstp_timer_start(struct bstp_timer *, u_int16_t);
269259698Sdimvoid	bstp_timer_stop(struct bstp_timer *);
270259698Sdimvoid	bstp_timer_latch(struct bstp_timer *);
271259698Sdimint	bstp_timer_expired(struct bstp_timer *);
272259698Sdimvoid	bstp_hello_timer_expiry(struct bstp_state *,
273259698Sdim		    struct bstp_port *);
274259698Sdimvoid	bstp_message_age_expiry(struct bstp_state *,
275259698Sdim		    struct bstp_port *);
276259698Sdimvoid	bstp_migrate_delay_expiry(struct bstp_state *,
277259698Sdim		    struct bstp_port *);
278259698Sdimvoid	bstp_edge_delay_expiry(struct bstp_state *,
279259698Sdim		    struct bstp_port *);
280259698Sdimint	bstp_addr_cmp(const u_int8_t *, const u_int8_t *);
281259698Sdimint	bstp_same_bridgeid(u_int64_t, u_int64_t);
282259698Sdim
283259698Sdim
284259698Sdimvoid
285259698Sdimbstp_transmit(struct bstp_state *bs, struct bstp_port *bp)
286259698Sdim{
287259698Sdim	struct ifnet *ifp;
288259698Sdim
289259698Sdim	if ((ifp = if_get(bs->bs_ifindex)) == NULL)
290259698Sdim		return;
291259698Sdim
292259698Sdim	if ((ifp->if_flags & IFF_RUNNING) == 0 || bp == NULL) {
293259698Sdim		if_put(ifp);
294259698Sdim		return;
295259698Sdim	}
296259698Sdim	if_put(ifp);
297259698Sdim
298259698Sdim	/*
299259698Sdim	 * a PDU can only be sent if we have tx quota left and the
300259698Sdim	 * hello timer is running.
301259698Sdim	 */
302259698Sdim	if (bp->bp_hello_timer.active == 0) {
303259698Sdim		/* Test if it needs to be reset */
304259698Sdim		bstp_hello_timer_expiry(bs, bp);
305259698Sdim		return;
306259698Sdim	}
307259698Sdim	if (bp->bp_txcount > bs->bs_txholdcount)
308259698Sdim		/* Ran out of karma */
309259698Sdim		return;
310259698Sdim
311259698Sdim	if (bp->bp_protover == BSTP_PROTO_RSTP) {
312259698Sdim		bstp_transmit_bpdu(bs, bp);
313259698Sdim		bp->bp_tc_ack = 0;
314259698Sdim	} else { /* STP */
315259698Sdim		switch (bp->bp_role) {
316259698Sdim		case BSTP_ROLE_DESIGNATED:
317259698Sdim			bstp_transmit_bpdu(bs, bp);
318259698Sdim			bp->bp_tc_ack = 0;
319259698Sdim			break;
320259698Sdim
321259698Sdim		case BSTP_ROLE_ROOT:
322259698Sdim			bstp_transmit_tcn(bs, bp);
323259698Sdim			break;
324259698Sdim		}
325259698Sdim	}
326259698Sdim	bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
327259698Sdim	bp->bp_flags &= ~BSTP_PORT_NEWINFO;
328259698Sdim}
329259698Sdim
330259698Sdimvoid
331259698Sdimbstp_transmit_bpdu(struct bstp_state *bs, struct bstp_port *bp)
332259698Sdim{
333259698Sdim	struct bstp_cbpdu bpdu;
334259698Sdim
335259698Sdim	bpdu.cbu_rootpri = htons(bp->bp_desg_pv.pv_root_id >> 48);
336259698Sdim	PV2ADDR(bp->bp_desg_pv.pv_root_id, bpdu.cbu_rootaddr);
337259698Sdim
338259698Sdim	bpdu.cbu_rootpathcost = htonl(bp->bp_desg_pv.pv_cost);
339259698Sdim
340259698Sdim	bpdu.cbu_bridgepri = htons(bp->bp_desg_pv.pv_dbridge_id >> 48);
341259698Sdim	PV2ADDR(bp->bp_desg_pv.pv_dbridge_id, bpdu.cbu_bridgeaddr);
342259698Sdim
343259698Sdim	bpdu.cbu_portid = htons(bp->bp_port_id);
344259698Sdim	bpdu.cbu_messageage = htons(bp->bp_desg_msg_age);
345259698Sdim	bpdu.cbu_maxage = htons(bp->bp_desg_max_age);
346259698Sdim	bpdu.cbu_hellotime = htons(bp->bp_desg_htime);
347259698Sdim	bpdu.cbu_forwarddelay = htons(bp->bp_desg_fdelay);
348259698Sdim
349259698Sdim	bpdu.cbu_flags = bstp_pdu_flags(bp);
350259698Sdim
351259698Sdim	switch (bp->bp_protover) {
352259698Sdim	case BSTP_PROTO_STP:
353259698Sdim		bpdu.cbu_bpdutype = BSTP_MSGTYPE_CFG;
354259698Sdim		break;
355259698Sdim	case BSTP_PROTO_RSTP:
356259698Sdim		bpdu.cbu_bpdutype = BSTP_MSGTYPE_RSTP;
357259698Sdim		break;
358259698Sdim	}
359259698Sdim
360259698Sdim	bstp_send_bpdu(bs, bp, &bpdu);
361259698Sdim}
362259698Sdim
363259698Sdimvoid
364259698Sdimbstp_transmit_tcn(struct bstp_state *bs, struct bstp_port *bp)
365259698Sdim{
366259698Sdim	struct bstp_tbpdu bpdu;
367259698Sdim	struct ifnet *ifp;
368259698Sdim	struct ether_header *eh;
369259698Sdim	struct mbuf *m;
370259698Sdim
371259698Sdim	if ((ifp = if_get(bp->bp_ifindex)) == NULL)
372259698Sdim		return;
373259698Sdim	if ((ifp->if_flags & IFF_RUNNING) == 0)
374259698Sdim		goto rele;
375259698Sdim
376259698Sdim	MGETHDR(m, M_DONTWAIT, MT_DATA);
377259698Sdim	if (m == NULL)
378259698Sdim		goto rele;
379259698Sdim	m->m_pkthdr.ph_ifidx = ifp->if_index;
380259698Sdim	m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
381259698Sdim	m->m_pkthdr.pf.prio = BSTP_IFQ_PRIO;
382259698Sdim	m->m_len = m->m_pkthdr.len;
383259698Sdim
384259698Sdim	eh = mtod(m, struct ether_header *);
385259698Sdim	bcopy(LLADDR(ifp->if_sadl), eh->ether_shost, ETHER_ADDR_LEN);
386259698Sdim	bcopy(bstp_etheraddr, eh->ether_dhost, ETHER_ADDR_LEN);
387259698Sdim	eh->ether_type = htons(sizeof(bpdu));
388259698Sdim
389259698Sdim	bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
390259698Sdim	bpdu.tbu_ctl = LLC_UI;
391259698Sdim	bpdu.tbu_protoid = 0;
392259698Sdim	bpdu.tbu_protover = 0;
393259698Sdim	bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
394259698Sdim	bcopy(&bpdu, mtod(m, caddr_t) + sizeof(*eh), sizeof(bpdu));
395259698Sdim
396259698Sdim	bp->bp_txcount++;
397259698Sdim	if_enqueue(ifp, m);
398259698Sdimrele:
399259698Sdim	if_put(ifp);
400259698Sdim}
401259698Sdim
402259698Sdimvoid
403259698Sdimbstp_decode_bpdu(struct bstp_port *bp, struct bstp_cbpdu *cpdu,
404259698Sdim    struct bstp_config_unit *cu)
405259698Sdim{
406259698Sdim	int flags;
407259698Sdim
408259698Sdim	cu->cu_pv.pv_root_id =
409259698Sdim	    (((u_int64_t)ntohs(cpdu->cbu_rootpri)) << 48) |
410259698Sdim	    (((u_int64_t)cpdu->cbu_rootaddr[0]) << 40) |
411259698Sdim	    (((u_int64_t)cpdu->cbu_rootaddr[1]) << 32) |
412259698Sdim	    (((u_int64_t)cpdu->cbu_rootaddr[2]) << 24) |
413259698Sdim	    (((u_int64_t)cpdu->cbu_rootaddr[3]) << 16) |
414259698Sdim	    (((u_int64_t)cpdu->cbu_rootaddr[4]) << 8) |
415259698Sdim	    (((u_int64_t)cpdu->cbu_rootaddr[5]) << 0);
416259698Sdim
417259698Sdim	cu->cu_pv.pv_dbridge_id =
418259698Sdim	    (((u_int64_t)ntohs(cpdu->cbu_bridgepri)) << 48) |
419259698Sdim	    (((u_int64_t)cpdu->cbu_bridgeaddr[0]) << 40) |
420259698Sdim	    (((u_int64_t)cpdu->cbu_bridgeaddr[1]) << 32) |
421259698Sdim	    (((u_int64_t)cpdu->cbu_bridgeaddr[2]) << 24) |
422259698Sdim	    (((u_int64_t)cpdu->cbu_bridgeaddr[3]) << 16) |
423259698Sdim	    (((u_int64_t)cpdu->cbu_bridgeaddr[4]) << 8) |
424259698Sdim	    (((u_int64_t)cpdu->cbu_bridgeaddr[5]) << 0);
425259698Sdim
426259698Sdim	cu->cu_pv.pv_cost = ntohl(cpdu->cbu_rootpathcost);
427259698Sdim	cu->cu_message_age = ntohs(cpdu->cbu_messageage);
428259698Sdim	cu->cu_max_age = ntohs(cpdu->cbu_maxage);
429259698Sdim	cu->cu_hello_time = ntohs(cpdu->cbu_hellotime);
430259698Sdim	cu->cu_forward_delay = ntohs(cpdu->cbu_forwarddelay);
431259698Sdim	cu->cu_pv.pv_dport_id = ntohs(cpdu->cbu_portid);
432259698Sdim	cu->cu_pv.pv_port_id = bp->bp_port_id;
433259698Sdim	cu->cu_message_type = cpdu->cbu_bpdutype;
434259698Sdim
435259698Sdim	/* Strip off unused flags in STP mode */
436259698Sdim	flags = cpdu->cbu_flags;
437259698Sdim	switch (cpdu->cbu_protover) {
438259698Sdim	case BSTP_PROTO_STP:
439259698Sdim		flags &= BSTP_PDU_STPMASK;
440259698Sdim		/* A STP BPDU explicitly conveys a Designated Port */
441259698Sdim		cu->cu_role = BSTP_ROLE_DESIGNATED;
442259698Sdim		break;
443259698Sdim	case BSTP_PROTO_RSTP:
444259698Sdim		flags &= BSTP_PDU_RSTPMASK;
445259698Sdim		break;
446259698Sdim	}
447259698Sdim
448259698Sdim	cu->cu_topology_change_ack =
449259698Sdim		(flags & BSTP_PDU_F_TCA) ? 1 : 0;
450259698Sdim	cu->cu_proposal =
451259698Sdim		(flags & BSTP_PDU_F_P) ? 1 : 0;
452259698Sdim	cu->cu_agree =
453259698Sdim		(flags & BSTP_PDU_F_A) ? 1 : 0;
454259698Sdim	cu->cu_learning =
455259698Sdim		(flags & BSTP_PDU_F_L) ? 1 : 0;
456259698Sdim	cu->cu_forwarding =
457259698Sdim		(flags & BSTP_PDU_F_F) ? 1 : 0;
458259698Sdim	cu->cu_topology_change =
459259698Sdim		(flags & BSTP_PDU_F_TC) ? 1 : 0;
460259698Sdim
461259698Sdim	switch ((flags & BSTP_PDU_PRMASK) >> BSTP_PDU_PRSHIFT) {
462259698Sdim	case BSTP_PDU_F_ROOT:
463259698Sdim		cu->cu_role = BSTP_ROLE_ROOT;
464259698Sdim		break;
465259698Sdim	case BSTP_PDU_F_ALT:
466259698Sdim		cu->cu_role = BSTP_ROLE_ALTERNATE;
467259698Sdim		break;
468259698Sdim	case BSTP_PDU_F_DESG:
469259698Sdim		cu->cu_role = BSTP_ROLE_DESIGNATED;
470259698Sdim		break;
471259698Sdim	}
472259698Sdim}
473259698Sdim
474259698Sdimvoid
475259698Sdimbstp_send_bpdu(struct bstp_state *bs, struct bstp_port *bp,
476259698Sdim    struct bstp_cbpdu *bpdu)
477259698Sdim{
478259698Sdim	struct ifnet *ifp;
479259698Sdim	struct mbuf *m;
480259698Sdim	struct ether_header *eh;
481259698Sdim	int s;
482259698Sdim
483259698Sdim	s = splnet();
484259698Sdim	if ((ifp = if_get(bp->bp_ifindex)) == NULL)
485259698Sdim		goto done;
486259698Sdim	if ((ifp->if_flags & IFF_RUNNING) == 0)
487259698Sdim		goto rele;
488259698Sdim
489259698Sdim	MGETHDR(m, M_DONTWAIT, MT_DATA);
490259698Sdim	if (m == NULL)
491259698Sdim		goto rele;
492259698Sdim
493259698Sdim	eh = mtod(m, struct ether_header *);
494259698Sdim
495259698Sdim	bpdu->cbu_ssap = bpdu->cbu_dsap = LLC_8021D_LSAP;
496259698Sdim	bpdu->cbu_ctl = LLC_UI;
497259698Sdim	bpdu->cbu_protoid = htons(BSTP_PROTO_ID);
498259698Sdim
499259698Sdim	memcpy(eh->ether_shost, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
500259698Sdim	memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
501259698Sdim
502259698Sdim	switch (bpdu->cbu_bpdutype) {
503259698Sdim	case BSTP_MSGTYPE_CFG:
504259698Sdim		bpdu->cbu_protover = BSTP_PROTO_STP;
505259698Sdim		m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_STP_LEN;
506259698Sdim		eh->ether_type = htons(BSTP_BPDU_STP_LEN);
507259698Sdim		memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
508259698Sdim		    BSTP_BPDU_STP_LEN);
509259698Sdim		break;
510259698Sdim	case BSTP_MSGTYPE_RSTP:
511259698Sdim		bpdu->cbu_protover = BSTP_PROTO_RSTP;
512259698Sdim		bpdu->cbu_versionlen = htons(0);
513259698Sdim		m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_RSTP_LEN;
514259698Sdim		eh->ether_type = htons(BSTP_BPDU_RSTP_LEN);
515259698Sdim		memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
516259698Sdim		    BSTP_BPDU_RSTP_LEN);
517259698Sdim		break;
518259698Sdim	default:
519259698Sdim		panic("not implemented");
520259698Sdim	}
521259698Sdim	m->m_pkthdr.ph_ifidx = ifp->if_index;
522	m->m_len = m->m_pkthdr.len;
523	m->m_pkthdr.pf.prio = BSTP_IFQ_PRIO;
524
525	bp->bp_txcount++;
526	if_enqueue(ifp, m);
527rele:
528	if_put(ifp);
529done:
530	splx(s);
531}
532
533int
534bstp_pdu_flags(struct bstp_port *bp)
535{
536	int flags = 0;
537
538	if (bp->bp_proposing && bp->bp_state != BSTP_IFSTATE_FORWARDING)
539		flags |= BSTP_PDU_F_P;
540
541	if (bp->bp_agree)
542		flags |= BSTP_PDU_F_A;
543
544	if (bp->bp_tc_timer.active)
545		flags |= BSTP_PDU_F_TC;
546
547	if (bp->bp_tc_ack)
548		flags |= BSTP_PDU_F_TCA;
549
550	switch (bp->bp_state) {
551	case BSTP_IFSTATE_LEARNING:
552		flags |= BSTP_PDU_F_L;
553		break;
554	case BSTP_IFSTATE_FORWARDING:
555		flags |= (BSTP_PDU_F_L | BSTP_PDU_F_F);
556		break;
557	}
558
559	switch (bp->bp_role) {
560	case BSTP_ROLE_ROOT:
561		flags |= (BSTP_PDU_F_ROOT << BSTP_PDU_PRSHIFT);
562		break;
563	case BSTP_ROLE_ALTERNATE:
564	case BSTP_ROLE_BACKUP:
565		flags |= (BSTP_PDU_F_ALT << BSTP_PDU_PRSHIFT);
566		break;
567	case BSTP_ROLE_DESIGNATED:
568		flags |= (BSTP_PDU_F_DESG << BSTP_PDU_PRSHIFT);
569		break;
570	}
571
572	/* Strip off unused flags in either mode */
573	switch (bp->bp_protover) {
574	case BSTP_PROTO_STP:
575		flags &= BSTP_PDU_STPMASK;
576		break;
577	case BSTP_PROTO_RSTP:
578		flags &= BSTP_PDU_RSTPMASK;
579		break;
580	}
581	return (flags);
582}
583
584struct mbuf *
585bstp_input(struct bstp_state *bs, struct bstp_port *bp,
586    struct ether_header *eh, struct mbuf *m)
587{
588	struct bstp_tbpdu tpdu;
589	u_int16_t len;
590
591	if (bs == NULL || bp == NULL || bp->bp_active == 0)
592		return (m);
593
594	len = ntohs(eh->ether_type);
595	if (len < sizeof(tpdu))
596		goto out;
597
598	m_adj(m, ETHER_HDR_LEN);
599
600	if (m->m_pkthdr.len > len)
601		m_adj(m, len - m->m_pkthdr.len);
602	if ((m = m_pullup(m, sizeof(tpdu))) == NULL)
603		goto out;
604	bcopy(mtod(m, struct tpdu *), &tpdu, sizeof(tpdu));
605
606	if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
607	    tpdu.tbu_ssap != LLC_8021D_LSAP ||
608	    tpdu.tbu_ctl != LLC_UI)
609		goto out;
610	if (tpdu.tbu_protoid != BSTP_PROTO_ID)
611		goto out;
612
613	/*
614	 * We can treat later versions of the PDU as the same as the maximum
615	 * version we implement. All additional parameters/flags are ignored.
616	 */
617	if (tpdu.tbu_protover > BSTP_PROTO_MAX)
618		tpdu.tbu_protover = BSTP_PROTO_MAX;
619
620	if (tpdu.tbu_protover != bp->bp_protover) {
621		/*
622		 * Wait for the migration delay timer to expire before changing
623		 * protocol version to avoid flip-flops.
624		 */
625		if (bp->bp_flags & BSTP_PORT_CANMIGRATE)
626			bstp_set_port_proto(bp, tpdu.tbu_protover);
627		else
628			goto out;
629	}
630
631	/* Clear operedge upon receiving a PDU on the port */
632	bp->bp_operedge = 0;
633	bstp_timer_start(&bp->bp_edge_delay_timer,
634	    BSTP_DEFAULT_MIGRATE_DELAY);
635
636	switch (tpdu.tbu_protover) {
637	case BSTP_PROTO_STP:
638		bstp_received_stp(bs, bp, &m, &tpdu);
639		break;
640	case BSTP_PROTO_RSTP:
641		bstp_received_rstp(bs, bp, &m, &tpdu);
642		break;
643	}
644 out:
645	m_freem(m);
646	return (NULL);
647}
648
649void
650bstp_received_stp(struct bstp_state *bs, struct bstp_port *bp,
651    struct mbuf **mp, struct bstp_tbpdu *tpdu)
652{
653	struct bstp_cbpdu cpdu;
654	struct bstp_config_unit *cu = &bp->bp_msg_cu;
655	struct bstp_tcn_unit tu;
656
657	switch (tpdu->tbu_bpdutype) {
658	case BSTP_MSGTYPE_TCN:
659		tu.tu_message_type = tpdu->tbu_bpdutype;
660		bstp_received_tcn(bs, bp, &tu);
661		break;
662	case BSTP_MSGTYPE_CFG:
663		if ((*mp)->m_len < BSTP_BPDU_STP_LEN &&
664		    (*mp = m_pullup(*mp, BSTP_BPDU_STP_LEN)) == NULL)
665			return;
666		memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_STP_LEN);
667
668		bstp_decode_bpdu(bp, &cpdu, cu);
669		bstp_received_bpdu(bs, bp, cu);
670		break;
671	}
672}
673
674void
675bstp_received_rstp(struct bstp_state *bs, struct bstp_port *bp,
676    struct mbuf **mp, struct bstp_tbpdu *tpdu)
677{
678	struct bstp_cbpdu cpdu;
679	struct bstp_config_unit *cu = &bp->bp_msg_cu;
680
681	if (tpdu->tbu_bpdutype != BSTP_MSGTYPE_RSTP)
682		return;
683
684	if ((*mp)->m_len < BSTP_BPDU_RSTP_LEN &&
685	    (*mp = m_pullup(*mp, BSTP_BPDU_RSTP_LEN)) == NULL)
686		return;
687	memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_RSTP_LEN);
688
689	bstp_decode_bpdu(bp, &cpdu, cu);
690	bstp_received_bpdu(bs, bp, cu);
691}
692
693void
694bstp_received_tcn(struct bstp_state *bs, struct bstp_port *bp,
695    struct bstp_tcn_unit *tcn)
696{
697	bp->bp_rcvdtcn = 1;
698	bstp_update_tc(bp);
699}
700
701void
702bstp_received_bpdu(struct bstp_state *bs, struct bstp_port *bp,
703    struct bstp_config_unit *cu)
704{
705	int type;
706
707	/* We need to have transitioned to INFO_MINE before proceeding */
708	switch (bp->bp_infois) {
709	case BSTP_INFO_DISABLED:
710	case BSTP_INFO_AGED:
711		return;
712	}
713
714	type = bstp_pdu_rcvtype(bp, cu);
715
716	switch (type) {
717	case BSTP_PDU_SUPERIOR:
718		bs->bs_allsynced = 0;
719		bp->bp_agreed = 0;
720		bp->bp_proposing = 0;
721
722		if (cu->cu_proposal && cu->cu_forwarding == 0)
723			bp->bp_proposed = 1;
724		if (cu->cu_topology_change)
725			bp->bp_rcvdtc = 1;
726		if (cu->cu_topology_change_ack)
727			bp->bp_rcvdtca = 1;
728
729		if (bp->bp_agree &&
730		    !bstp_pdu_bettersame(bp, BSTP_INFO_RECEIVED))
731			bp->bp_agree = 0;
732
733		/* copy the received priority and timers to the port */
734		bp->bp_port_pv = cu->cu_pv;
735		bp->bp_port_msg_age = cu->cu_message_age;
736		bp->bp_port_max_age = cu->cu_max_age;
737		bp->bp_port_fdelay = cu->cu_forward_delay;
738		bp->bp_port_htime =
739		    (cu->cu_hello_time > BSTP_MIN_HELLO_TIME ?
740		     cu->cu_hello_time : BSTP_MIN_HELLO_TIME);
741
742		/* set expiry for the new info */
743		bstp_set_timer_msgage(bp);
744
745		bp->bp_infois = BSTP_INFO_RECEIVED;
746		bstp_assign_roles(bs);
747		break;
748
749	case BSTP_PDU_REPEATED:
750		if (cu->cu_proposal && cu->cu_forwarding == 0)
751			bp->bp_proposed = 1;
752		if (cu->cu_topology_change)
753			bp->bp_rcvdtc = 1;
754		if (cu->cu_topology_change_ack)
755			bp->bp_rcvdtca = 1;
756
757		/* rearm the age timer */
758		bstp_set_timer_msgage(bp);
759		break;
760
761	case BSTP_PDU_INFERIOR:
762		if (cu->cu_learning) {
763			bp->bp_agreed = 1;
764			bp->bp_proposing = 0;
765		}
766		break;
767
768	case BSTP_PDU_INFERIORALT:
769		/*
770		 * only point to point links are allowed fast
771		 * transitions to forwarding.
772		 */
773		if (cu->cu_agree && bp->bp_ptp_link) {
774			bp->bp_agreed = 1;
775			bp->bp_proposing = 0;
776		} else
777			bp->bp_agreed = 0;
778
779		if (cu->cu_topology_change)
780			bp->bp_rcvdtc = 1;
781		if (cu->cu_topology_change_ack)
782			bp->bp_rcvdtca = 1;
783		break;
784
785	case BSTP_PDU_OTHER:
786		return;	/* do nothing */
787	}
788
789	/* update the state machines with the new data */
790	bstp_update_state(bs, bp);
791}
792
793int
794bstp_pdu_rcvtype(struct bstp_port *bp, struct bstp_config_unit *cu)
795{
796	int type;
797
798	/* default return type */
799	type = BSTP_PDU_OTHER;
800
801	switch (cu->cu_role) {
802	case BSTP_ROLE_DESIGNATED:
803		if (bstp_info_superior(&bp->bp_port_pv, &cu->cu_pv))
804			/* bpdu priority is superior */
805			type = BSTP_PDU_SUPERIOR;
806		else if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) ==
807		    INFO_SAME) {
808			if (bp->bp_port_msg_age != cu->cu_message_age ||
809			    bp->bp_port_max_age != cu->cu_max_age ||
810			    bp->bp_port_fdelay != cu->cu_forward_delay ||
811			    bp->bp_port_htime != cu->cu_hello_time)
812				/* bpdu priority is equal and timers differ */
813				type = BSTP_PDU_SUPERIOR;
814			else
815				/* bpdu is equal */
816				type = BSTP_PDU_REPEATED;
817		} else
818			/* bpdu priority is worse */
819			type = BSTP_PDU_INFERIOR;
820
821		break;
822
823	case BSTP_ROLE_ROOT:
824	case BSTP_ROLE_ALTERNATE:
825	case BSTP_ROLE_BACKUP:
826		if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) <= INFO_SAME)
827			/*
828			 * not a designated port and priority is the same or
829			 * worse
830			 */
831			type = BSTP_PDU_INFERIORALT;
832		break;
833	}
834
835	return (type);
836}
837
838int
839bstp_pdu_bettersame(struct bstp_port *bp, int newinfo)
840{
841	if (newinfo == BSTP_INFO_RECEIVED &&
842	    bp->bp_infois == BSTP_INFO_RECEIVED &&
843	    bstp_info_cmp(&bp->bp_port_pv, &bp->bp_msg_cu.cu_pv) >= INFO_SAME)
844		return (1);
845
846	if (newinfo == BSTP_INFO_MINE &&
847	    bp->bp_infois == BSTP_INFO_MINE &&
848	    bstp_info_cmp(&bp->bp_port_pv, &bp->bp_desg_pv) >= INFO_SAME)
849		return (1);
850
851	return (0);
852}
853
854int
855bstp_info_cmp(struct bstp_pri_vector *pv,
856    struct bstp_pri_vector *cpv)
857{
858	if (cpv->pv_root_id < pv->pv_root_id)
859		return (INFO_BETTER);
860	if (cpv->pv_root_id > pv->pv_root_id)
861		return (INFO_WORSE);
862
863	if (cpv->pv_cost < pv->pv_cost)
864		return (INFO_BETTER);
865	if (cpv->pv_cost > pv->pv_cost)
866		return (INFO_WORSE);
867
868	if (cpv->pv_dbridge_id < pv->pv_dbridge_id)
869		return (INFO_BETTER);
870	if (cpv->pv_dbridge_id > pv->pv_dbridge_id)
871		return (INFO_WORSE);
872
873	if (cpv->pv_dport_id < pv->pv_dport_id)
874		return (INFO_BETTER);
875	if (cpv->pv_dport_id > pv->pv_dport_id)
876		return (INFO_WORSE);
877
878	return (INFO_SAME);
879}
880
881/*
882 * This message priority vector is superior to the port priority vector and
883 * will replace it if, and only if, the message priority vector is better than
884 * the port priority vector, or the message has been transmitted from the same
885 * designated bridge and designated port as the port priority vector.
886 */
887int
888bstp_info_superior(struct bstp_pri_vector *pv,
889    struct bstp_pri_vector *cpv)
890{
891	if (bstp_info_cmp(pv, cpv) == INFO_BETTER ||
892	    (bstp_same_bridgeid(pv->pv_dbridge_id, cpv->pv_dbridge_id) &&
893	    (cpv->pv_dport_id & 0xfff) == (pv->pv_dport_id & 0xfff)))
894		return (1);
895	return (0);
896}
897
898void
899bstp_reset(struct bstp_state *bs)
900{
901	/* default to our priority vector */
902	bs->bs_root_pv = bs->bs_bridge_pv;
903	bs->bs_root_msg_age = 0;
904	bs->bs_root_max_age = bs->bs_bridge_max_age;
905	bs->bs_root_fdelay = bs->bs_bridge_fdelay;
906	bs->bs_root_htime = bs->bs_bridge_htime;
907	bs->bs_root_port = NULL;
908}
909
910void
911bstp_assign_roles(struct bstp_state *bs)
912{
913	struct bstp_port *bp, *rbp = NULL;
914	struct bstp_pri_vector pv;
915
916	bstp_reset(bs);
917
918	/* check if any received info supersedes us */
919	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
920		if (bp->bp_infois != BSTP_INFO_RECEIVED)
921			continue;
922
923		pv = bp->bp_port_pv;
924		pv.pv_cost += bp->bp_path_cost;
925
926		/*
927		 * The root priority vector is the best of the set comprising
928		 * the bridge priority vector plus all root path priority
929		 * vectors whose bridge address is not equal to us.
930		 */
931		if (bstp_same_bridgeid(pv.pv_dbridge_id,
932		    bs->bs_bridge_pv.pv_dbridge_id) == 0 &&
933		    bstp_info_cmp(&bs->bs_root_pv, &pv) == INFO_BETTER) {
934			/* the port vector replaces the root */
935			bs->bs_root_pv = pv;
936			bs->bs_root_msg_age = bp->bp_port_msg_age +
937			    BSTP_MESSAGE_AGE_INCR;
938			bs->bs_root_max_age = bp->bp_port_max_age;
939			bs->bs_root_fdelay = bp->bp_port_fdelay;
940			bs->bs_root_htime = bp->bp_port_htime;
941			rbp = bp;
942		}
943	}
944
945	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
946		/* calculate the port designated vector */
947		bp->bp_desg_pv.pv_root_id = bs->bs_root_pv.pv_root_id;
948		bp->bp_desg_pv.pv_cost = bs->bs_root_pv.pv_cost;
949		bp->bp_desg_pv.pv_dbridge_id = bs->bs_bridge_pv.pv_dbridge_id;
950		bp->bp_desg_pv.pv_dport_id = bp->bp_port_id;
951		bp->bp_desg_pv.pv_port_id = bp->bp_port_id;
952
953		/* calculate designated times */
954		bp->bp_desg_msg_age = bs->bs_root_msg_age;
955		bp->bp_desg_max_age = bs->bs_root_max_age;
956		bp->bp_desg_fdelay = bs->bs_root_fdelay;
957		bp->bp_desg_htime = bs->bs_bridge_htime;
958
959
960		switch (bp->bp_infois) {
961		case BSTP_INFO_DISABLED:
962			bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
963			break;
964
965		case BSTP_INFO_AGED:
966			bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
967			bstp_update_info(bp);
968			break;
969
970		case BSTP_INFO_MINE:
971			bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
972			/* update the port info if stale */
973			if (bstp_info_cmp(&bp->bp_port_pv,
974			    &bp->bp_desg_pv) != INFO_SAME ||
975			    (rbp != NULL &&
976			    (bp->bp_port_msg_age != rbp->bp_port_msg_age ||
977			    bp->bp_port_max_age != rbp->bp_port_max_age ||
978			    bp->bp_port_fdelay != rbp->bp_port_fdelay ||
979			    bp->bp_port_htime != rbp->bp_port_htime)))
980				bstp_update_info(bp);
981			break;
982
983		case BSTP_INFO_RECEIVED:
984			if (bp == rbp) {
985				/*
986				 * root priority is derived from this
987				 * port, make it the root port.
988				 */
989				bstp_set_port_role(bp, BSTP_ROLE_ROOT);
990				bs->bs_root_port = bp;
991			} else if (bstp_info_cmp(&bp->bp_port_pv,
992				    &bp->bp_desg_pv) == INFO_BETTER) {
993				/*
994				 * the port priority is lower than the root
995				 * port.
996				 */
997				bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
998				bstp_update_info(bp);
999			} else {
1000				if (bstp_same_bridgeid(
1001				    bp->bp_port_pv.pv_dbridge_id,
1002				    bs->bs_bridge_pv.pv_dbridge_id)) {
1003					/*
1004					 * the designated bridge refers to
1005					 * another port on this bridge.
1006					 */
1007					bstp_set_port_role(bp,
1008					    BSTP_ROLE_BACKUP);
1009				} else {
1010					/*
1011					 * the port is an inferior path to the
1012					 * root bridge.
1013					 */
1014					bstp_set_port_role(bp,
1015					    BSTP_ROLE_ALTERNATE);
1016				}
1017			}
1018			break;
1019		}
1020	}
1021}
1022
1023void
1024bstp_update_state(struct bstp_state *bs, struct bstp_port *bp)
1025{
1026	struct bstp_port *bp2;
1027	int synced;
1028
1029	/* check if all the ports have synchronized again */
1030	if (!bs->bs_allsynced) {
1031		synced = 1;
1032		LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1033			if (!(bp2->bp_synced ||
1034			     bp2->bp_role == BSTP_ROLE_ROOT)) {
1035				synced = 0;
1036				break;
1037			}
1038		}
1039		bs->bs_allsynced = synced;
1040	}
1041
1042	bstp_update_roles(bs, bp);
1043	bstp_update_tc(bp);
1044}
1045
1046void
1047bstp_update_roles(struct bstp_state *bs, struct bstp_port *bp)
1048{
1049	switch (bp->bp_role) {
1050	case BSTP_ROLE_DISABLED:
1051		/* Clear any flags if set */
1052		if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
1053			bp->bp_sync = 0;
1054			bp->bp_synced = 1;
1055			bp->bp_reroot = 0;
1056		}
1057		break;
1058
1059	case BSTP_ROLE_ALTERNATE:
1060	case BSTP_ROLE_BACKUP:
1061		if ((bs->bs_allsynced && !bp->bp_agree) ||
1062		    (bp->bp_proposed && bp->bp_agree)) {
1063			bp->bp_proposed = 0;
1064			bp->bp_agree = 1;
1065			bp->bp_flags |= BSTP_PORT_NEWINFO;
1066			DPRINTF(bp, "-> ALTERNATE_AGREED\n");
1067		}
1068
1069		if (bp->bp_proposed && !bp->bp_agree) {
1070			bstp_set_all_sync(bs);
1071			bp->bp_proposed = 0;
1072			DPRINTF(bp, "-> ALTERNATE_PROPOSED\n");
1073		}
1074
1075		/* Clear any flags if set */
1076		if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
1077			bp->bp_sync = 0;
1078			bp->bp_synced = 1;
1079			bp->bp_reroot = 0;
1080			DPRINTF(bp, "-> ALTERNATE_PORT\n");
1081		}
1082		break;
1083
1084	case BSTP_ROLE_ROOT:
1085		if (bp->bp_state != BSTP_IFSTATE_FORWARDING && !bp->bp_reroot) {
1086			bstp_set_all_reroot(bs);
1087			DPRINTF(bp, "-> ROOT_REROOT\n");
1088		}
1089
1090		if ((bs->bs_allsynced && !bp->bp_agree) ||
1091		    (bp->bp_proposed && bp->bp_agree)) {
1092			bp->bp_proposed = 0;
1093			bp->bp_sync = 0;
1094			bp->bp_agree = 1;
1095			bp->bp_flags |= BSTP_PORT_NEWINFO;
1096			DPRINTF(bp, "-> ROOT_AGREED\n");
1097		}
1098
1099		if (bp->bp_proposed && !bp->bp_agree) {
1100			bstp_set_all_sync(bs);
1101			bp->bp_proposed = 0;
1102			DPRINTF(bp, "-> ROOT_PROPOSED\n");
1103		}
1104
1105		if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1106		    (bp->bp_forward_delay_timer.active == 0 ||
1107		    (bstp_rerooted(bs, bp) &&
1108		    bp->bp_recent_backup_timer.active == 0 &&
1109		    bp->bp_protover == BSTP_PROTO_RSTP))) {
1110			switch (bp->bp_state) {
1111			case BSTP_IFSTATE_DISCARDING:
1112				bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1113				break;
1114			case BSTP_IFSTATE_LEARNING:
1115				bstp_set_port_state(bp,
1116				    BSTP_IFSTATE_FORWARDING);
1117				break;
1118			}
1119		}
1120
1121		if (bp->bp_state == BSTP_IFSTATE_FORWARDING && bp->bp_reroot) {
1122			bp->bp_reroot = 0;
1123			DPRINTF(bp, "-> ROOT_REROOTED\n");
1124		}
1125		break;
1126
1127	case BSTP_ROLE_DESIGNATED:
1128		if (bp->bp_recent_root_timer.active == 0 && bp->bp_reroot) {
1129			bp->bp_reroot = 0;
1130			DPRINTF(bp, "-> DESIGNATED_RETIRED\n");
1131		}
1132
1133		if ((bp->bp_state == BSTP_IFSTATE_DISCARDING &&
1134		    !bp->bp_synced) || (bp->bp_agreed && !bp->bp_synced) ||
1135		    (bp->bp_operedge && !bp->bp_synced) ||
1136		    (bp->bp_sync && bp->bp_synced)) {
1137			bstp_timer_stop(&bp->bp_recent_root_timer);
1138			bp->bp_synced = 1;
1139			bp->bp_sync = 0;
1140			DPRINTF(bp, "-> DESIGNATED_SYNCED\n");
1141		}
1142
1143		if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1144		    !bp->bp_agreed && !bp->bp_proposing &&
1145		    !bp->bp_operedge) {
1146			bp->bp_proposing = 1;
1147			bp->bp_flags |= BSTP_PORT_NEWINFO;
1148			bstp_timer_start(&bp->bp_edge_delay_timer,
1149			    (bp->bp_ptp_link ? BSTP_DEFAULT_MIGRATE_DELAY :
1150			     bp->bp_desg_max_age));
1151			DPRINTF(bp, "-> DESIGNATED_PROPOSE\n");
1152		}
1153
1154		if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1155		    (bp->bp_forward_delay_timer.active == 0 || bp->bp_agreed ||
1156		    bp->bp_operedge) &&
1157		    (bp->bp_recent_root_timer.active == 0 || !bp->bp_reroot) &&
1158		    !bp->bp_sync) {
1159			if (bp->bp_agreed)
1160				DPRINTF(bp, "-> AGREED\n");
1161			/*
1162			 * If agreed|operedge then go straight to forwarding,
1163			 * otherwise follow discard -> learn -> forward.
1164			 */
1165			if (bp->bp_agreed || bp->bp_operedge ||
1166			    bp->bp_state == BSTP_IFSTATE_LEARNING) {
1167				bstp_set_port_state(bp,
1168				    BSTP_IFSTATE_FORWARDING);
1169				bp->bp_agreed = bp->bp_protover;
1170			} else if (bp->bp_state == BSTP_IFSTATE_DISCARDING)
1171				bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1172		}
1173
1174		if (((bp->bp_sync && !bp->bp_synced) ||
1175		    (bp->bp_reroot && bp->bp_recent_root_timer.active) ||
1176		    (bp->bp_flags & BSTP_PORT_DISPUTED)) && !bp->bp_operedge &&
1177		    bp->bp_state != BSTP_IFSTATE_DISCARDING) {
1178			bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1179			bp->bp_flags &= ~BSTP_PORT_DISPUTED;
1180			bstp_timer_start(&bp->bp_forward_delay_timer,
1181			    bp->bp_protover == BSTP_PROTO_RSTP ?
1182			    bp->bp_desg_htime : bp->bp_desg_fdelay);
1183			DPRINTF(bp, "-> DESIGNATED_DISCARD\n");
1184		}
1185		break;
1186	}
1187
1188	if (bp->bp_flags & BSTP_PORT_NEWINFO)
1189		bstp_transmit(bs, bp);
1190}
1191
1192void
1193bstp_update_tc(struct bstp_port *bp)
1194{
1195	switch (bp->bp_tcstate) {
1196	case BSTP_TCSTATE_ACTIVE:
1197		if ((bp->bp_role != BSTP_ROLE_DESIGNATED &&
1198		    bp->bp_role != BSTP_ROLE_ROOT) || bp->bp_operedge)
1199			bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1200
1201		if (bp->bp_rcvdtcn)
1202			bstp_set_port_tc(bp, BSTP_TCSTATE_TCN);
1203		if (bp->bp_rcvdtc)
1204			bstp_set_port_tc(bp, BSTP_TCSTATE_TC);
1205
1206		if (bp->bp_tc_prop && !bp->bp_operedge)
1207			bstp_set_port_tc(bp, BSTP_TCSTATE_PROPAG);
1208
1209		if (bp->bp_rcvdtca)
1210			bstp_set_port_tc(bp, BSTP_TCSTATE_ACK);
1211		break;
1212
1213	case BSTP_TCSTATE_INACTIVE:
1214		if ((bp->bp_state == BSTP_IFSTATE_LEARNING ||
1215		    bp->bp_state == BSTP_IFSTATE_FORWARDING) &&
1216		    bp->bp_fdbflush == 0)
1217			bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1218		break;
1219
1220	case BSTP_TCSTATE_LEARNING:
1221		if (bp->bp_rcvdtc || bp->bp_rcvdtcn || bp->bp_rcvdtca ||
1222		    bp->bp_tc_prop)
1223			bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1224		else if (bp->bp_role != BSTP_ROLE_DESIGNATED &&
1225			 bp->bp_role != BSTP_ROLE_ROOT &&
1226			 bp->bp_state == BSTP_IFSTATE_DISCARDING)
1227			bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
1228
1229		if ((bp->bp_role == BSTP_ROLE_DESIGNATED ||
1230		    bp->bp_role == BSTP_ROLE_ROOT) &&
1231		    bp->bp_state == BSTP_IFSTATE_FORWARDING &&
1232		    !bp->bp_operedge)
1233			bstp_set_port_tc(bp, BSTP_TCSTATE_DETECTED);
1234		break;
1235
1236	/* these are transient states and go straight back to ACTIVE */
1237	case BSTP_TCSTATE_DETECTED:
1238	case BSTP_TCSTATE_TCN:
1239	case BSTP_TCSTATE_TC:
1240	case BSTP_TCSTATE_PROPAG:
1241	case BSTP_TCSTATE_ACK:
1242		DPRINTF(bp, "Invalid TC state\n");
1243		break;
1244	}
1245
1246}
1247
1248void
1249bstp_update_info(struct bstp_port *bp)
1250{
1251	struct bstp_state *bs = bp->bp_bs;
1252
1253	bp->bp_proposing = 0;
1254	bp->bp_proposed = 0;
1255
1256	if (bp->bp_agreed && !bstp_pdu_bettersame(bp, BSTP_INFO_MINE))
1257		bp->bp_agreed = 0;
1258
1259	if (bp->bp_synced && !bp->bp_agreed) {
1260		bp->bp_synced = 0;
1261		bs->bs_allsynced = 0;
1262	}
1263
1264	/* copy the designated pv to the port */
1265	bp->bp_port_pv = bp->bp_desg_pv;
1266	bp->bp_port_msg_age = bp->bp_desg_msg_age;
1267	bp->bp_port_max_age = bp->bp_desg_max_age;
1268	bp->bp_port_fdelay = bp->bp_desg_fdelay;
1269	bp->bp_port_htime = bp->bp_desg_htime;
1270	bp->bp_infois = BSTP_INFO_MINE;
1271
1272	/* Set transmit flag but do not immediately send */
1273	bp->bp_flags |= BSTP_PORT_NEWINFO;
1274}
1275
1276/* set tcprop on every port other than the caller */
1277void
1278bstp_set_other_tcprop(struct bstp_port *bp)
1279{
1280	struct bstp_state *bs = bp->bp_bs;
1281	struct bstp_port *bp2;
1282
1283	LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1284		if (bp2 == bp)
1285			continue;
1286		bp2->bp_tc_prop = 1;
1287	}
1288}
1289
1290void
1291bstp_set_all_reroot(struct bstp_state *bs)
1292{
1293	struct bstp_port *bp;
1294
1295	LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1296		bp->bp_reroot = 1;
1297}
1298
1299void
1300bstp_set_all_sync(struct bstp_state *bs)
1301{
1302	struct bstp_port *bp;
1303
1304	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1305		bp->bp_sync = 1;
1306		bp->bp_synced = 0;	/* Not explicit in spec */
1307	}
1308
1309	bs->bs_allsynced = 0;
1310}
1311
1312void
1313bstp_set_port_state(struct bstp_port *bp, int state)
1314{
1315	if (bp->bp_state == state)
1316		return;
1317
1318	bp->bp_state = state;
1319
1320	switch (bp->bp_state) {
1321	case BSTP_IFSTATE_DISCARDING:
1322		DPRINTF(bp, "state changed to DISCARDING\n");
1323		break;
1324
1325	case BSTP_IFSTATE_LEARNING:
1326		DPRINTF(bp, "state changed to LEARNING\n");
1327		bstp_timer_start(&bp->bp_forward_delay_timer,
1328		    bp->bp_protover == BSTP_PROTO_RSTP ?
1329		    bp->bp_desg_htime : bp->bp_desg_fdelay);
1330		break;
1331
1332	case BSTP_IFSTATE_FORWARDING:
1333		DPRINTF(bp, "state changed to FORWARDING\n");
1334		bstp_timer_stop(&bp->bp_forward_delay_timer);
1335		/* Record that we enabled forwarding */
1336		bp->bp_forward_transitions++;
1337		break;
1338	}
1339}
1340
1341void
1342bstp_set_port_role(struct bstp_port *bp, int role)
1343{
1344	struct bstp_state *bs = bp->bp_bs;
1345
1346	if (bp->bp_role == role)
1347		return;
1348
1349	/* perform pre-change tasks */
1350	switch (bp->bp_role) {
1351	case BSTP_ROLE_DISABLED:
1352		bstp_timer_start(&bp->bp_forward_delay_timer,
1353		    bp->bp_desg_max_age);
1354		break;
1355
1356	case BSTP_ROLE_BACKUP:
1357		bstp_timer_start(&bp->bp_recent_backup_timer,
1358		    bp->bp_desg_htime * 2);
1359		/* FALLTHROUGH */
1360	case BSTP_ROLE_ALTERNATE:
1361		bstp_timer_start(&bp->bp_forward_delay_timer,
1362		    bp->bp_desg_fdelay);
1363		bp->bp_sync = 0;
1364		bp->bp_synced = 1;
1365		bp->bp_reroot = 0;
1366		break;
1367
1368	case BSTP_ROLE_ROOT:
1369		bstp_timer_start(&bp->bp_recent_root_timer,
1370		    BSTP_DEFAULT_FORWARD_DELAY);
1371		break;
1372	}
1373
1374	bp->bp_role = role;
1375	/* clear values not carried between roles */
1376	bp->bp_proposing = 0;
1377	bs->bs_allsynced = 0;
1378
1379	/* initialise the new role */
1380	switch (bp->bp_role) {
1381	case BSTP_ROLE_DISABLED:
1382	case BSTP_ROLE_ALTERNATE:
1383	case BSTP_ROLE_BACKUP:
1384		DPRINTF(bp, "role -> ALT/BACK/DISABLED\n");
1385		bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1386		bstp_timer_stop(&bp->bp_recent_root_timer);
1387		bstp_timer_latch(&bp->bp_forward_delay_timer);
1388		bp->bp_sync = 0;
1389		bp->bp_synced = 1;
1390		bp->bp_reroot = 0;
1391		break;
1392
1393	case BSTP_ROLE_ROOT:
1394		DPRINTF(bp, "role -> ROOT\n");
1395		bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1396		bstp_timer_latch(&bp->bp_recent_root_timer);
1397		bp->bp_proposing = 0;
1398		break;
1399
1400	case BSTP_ROLE_DESIGNATED:
1401		DPRINTF(bp, "role -> DESIGNATED\n");
1402		bstp_timer_start(&bp->bp_hello_timer,
1403		    bp->bp_desg_htime);
1404		bp->bp_agree = 0;
1405		break;
1406	}
1407
1408	/* let the TC state know that the role changed */
1409	bstp_update_tc(bp);
1410}
1411
1412void
1413bstp_set_port_proto(struct bstp_port *bp, int proto)
1414{
1415	struct bstp_state *bs = bp->bp_bs;
1416
1417	/* supported protocol versions */
1418	switch (proto) {
1419	case BSTP_PROTO_STP:
1420		/* we can downgrade protocols only */
1421		bstp_timer_stop(&bp->bp_migrate_delay_timer);
1422		/* clear unsupported features */
1423		bp->bp_operedge = 0;
1424		break;
1425
1426	case BSTP_PROTO_RSTP:
1427		bstp_timer_start(&bp->bp_migrate_delay_timer,
1428		    bs->bs_migration_delay);
1429		break;
1430
1431	default:
1432		DPRINTF(bp, "Unsupported STP version %d\n", proto);
1433		return;
1434	}
1435
1436	bp->bp_protover = proto;
1437	bp->bp_flags &= ~BSTP_PORT_CANMIGRATE;
1438}
1439
1440void
1441bstp_set_port_tc(struct bstp_port *bp, int state)
1442{
1443	struct bstp_state *bs = bp->bp_bs;
1444
1445	bp->bp_tcstate = state;
1446
1447	/* initialise the new state */
1448	switch (bp->bp_tcstate) {
1449	case BSTP_TCSTATE_ACTIVE:
1450		DPRINTF(bp, "-> TC_ACTIVE\n");
1451		/* nothing to do */
1452		break;
1453
1454	case BSTP_TCSTATE_INACTIVE:
1455		bstp_timer_stop(&bp->bp_tc_timer);
1456		/* flush routes on the parent bridge */
1457		bp->bp_fdbflush = 1;
1458		bstp_notify_rtage(bp, 0);
1459		bp->bp_tc_ack = 0;
1460		DPRINTF(bp, "-> TC_INACTIVE\n");
1461		break;
1462
1463	case BSTP_TCSTATE_LEARNING:
1464		bp->bp_rcvdtc = 0;
1465		bp->bp_rcvdtcn = 0;
1466		bp->bp_rcvdtca = 0;
1467		bp->bp_tc_prop = 0;
1468		DPRINTF(bp, "-> TC_LEARNING\n");
1469		break;
1470
1471	case BSTP_TCSTATE_DETECTED:
1472		bstp_set_timer_tc(bp);
1473		bstp_set_other_tcprop(bp);
1474		/* send out notification */
1475		bp->bp_flags |= BSTP_PORT_NEWINFO;
1476		bstp_transmit(bs, bp);
1477		getmicrotime(&bs->bs_last_tc_time);
1478		DPRINTF(bp, "-> TC_DETECTED\n");
1479		bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1480		break;
1481
1482	case BSTP_TCSTATE_TCN:
1483		bstp_set_timer_tc(bp);
1484		DPRINTF(bp, "-> TC_TCN\n");
1485		/* FALLTHROUGH */
1486	case BSTP_TCSTATE_TC:
1487		bp->bp_rcvdtc = 0;
1488		bp->bp_rcvdtcn = 0;
1489		if (bp->bp_role == BSTP_ROLE_DESIGNATED)
1490			bp->bp_tc_ack = 1;
1491
1492		bstp_set_other_tcprop(bp);
1493		DPRINTF(bp, "-> TC_TC\n");
1494		bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1495		break;
1496
1497	case BSTP_TCSTATE_PROPAG:
1498		/* flush routes on the parent bridge */
1499		bp->bp_fdbflush = 1;
1500		bstp_notify_rtage(bp, 0);
1501		bp->bp_tc_prop = 0;
1502		bstp_set_timer_tc(bp);
1503		DPRINTF(bp, "-> TC_PROPAG\n");
1504		bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1505		break;
1506
1507	case BSTP_TCSTATE_ACK:
1508		bstp_timer_stop(&bp->bp_tc_timer);
1509		bp->bp_rcvdtca = 0;
1510		DPRINTF(bp, "-> TC_ACK\n");
1511		bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1512		break;
1513	}
1514}
1515
1516void
1517bstp_set_timer_tc(struct bstp_port *bp)
1518{
1519	struct bstp_state *bs = bp->bp_bs;
1520
1521	if (bp->bp_tc_timer.active)
1522		return;
1523
1524	switch (bp->bp_protover) {
1525	case BSTP_PROTO_RSTP:
1526		bstp_timer_start(&bp->bp_tc_timer,
1527		    bp->bp_desg_htime + BSTP_TICK_VAL);
1528		bp->bp_flags |= BSTP_PORT_NEWINFO;
1529		break;
1530	case BSTP_PROTO_STP:
1531		bstp_timer_start(&bp->bp_tc_timer,
1532		    bs->bs_root_max_age + bs->bs_root_fdelay);
1533		break;
1534	}
1535}
1536
1537void
1538bstp_set_timer_msgage(struct bstp_port *bp)
1539{
1540	if (bp->bp_port_msg_age + BSTP_MESSAGE_AGE_INCR <=
1541	    bp->bp_port_max_age) {
1542		bstp_timer_start(&bp->bp_message_age_timer,
1543		    bp->bp_port_htime * 3);
1544	} else
1545		/* expires immediately */
1546		bstp_timer_start(&bp->bp_message_age_timer, 0);
1547}
1548
1549int
1550bstp_rerooted(struct bstp_state *bs, struct bstp_port *bp)
1551{
1552	struct bstp_port *bp2;
1553	int rr_set = 0;
1554
1555	LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1556		if (bp2 == bp)
1557			continue;
1558		if (bp2->bp_recent_root_timer.active) {
1559			rr_set = 1;
1560			break;
1561		}
1562	}
1563	return (!rr_set);
1564}
1565
1566/*
1567 * Calculate the path cost according to the link speed.
1568 */
1569u_int32_t
1570bstp_calc_path_cost(struct bstp_port *bp)
1571{
1572	struct ifnet *ifp;
1573	u_int32_t path_cost;
1574
1575	/* If the priority has been manually set then retain the value */
1576	if (bp->bp_flags & BSTP_PORT_ADMCOST)
1577		return bp->bp_path_cost;
1578
1579	if ((ifp = if_get(bp->bp_ifindex)) == NULL) {
1580		return bp->bp_path_cost;
1581	}
1582
1583	if (ifp->if_baudrate < 1000) {
1584		if_put(ifp);
1585		return (BSTP_DEFAULT_PATH_COST);
1586	}
1587
1588 	/* formula from section 17.14, IEEE Std 802.1D-2004 */
1589	path_cost = 20000000000ULL / (ifp->if_baudrate / 1000);
1590	if_put(ifp);
1591
1592	if (path_cost > BSTP_MAX_PATH_COST)
1593		path_cost = BSTP_MAX_PATH_COST;
1594
1595	/* STP compat mode only uses 16 bits of the 32 */
1596	if (bp->bp_protover == BSTP_PROTO_STP && path_cost > 65535)
1597		path_cost = 65535;
1598
1599	return (path_cost);
1600}
1601
1602void
1603bstp_notify_rtage(struct bstp_port *bp, int pending)
1604{
1605	int age = 0;
1606
1607	KERNEL_ASSERT_LOCKED();
1608
1609	switch (bp->bp_protover) {
1610	case BSTP_PROTO_STP:
1611		/* convert to seconds */
1612		age = bp->bp_desg_fdelay / BSTP_TICK_VAL;
1613		break;
1614	case BSTP_PROTO_RSTP:
1615		age = 0;
1616		break;
1617	}
1618
1619	if (bp->bp_active == 1) {
1620		struct ifnet *ifp;
1621
1622		if ((ifp = if_get(bp->bp_ifindex)) != NULL)
1623			bridge_rtagenode(ifp, age);
1624		if_put(ifp);
1625	}
1626
1627	/* flush is complete */
1628	bp->bp_fdbflush = 0;
1629}
1630
1631void
1632bstp_ifstate(void *arg)
1633{
1634	struct ifnet *ifp = (struct ifnet *)arg;
1635	struct bridge_iflist *bif;
1636	struct bstp_port *bp;
1637	struct bstp_state *bs;
1638	int s;
1639
1640	if (ifp->if_type == IFT_BRIDGE)
1641		return;
1642
1643	s = splnet();
1644	if ((bif = bridge_getbif(ifp)) == NULL)
1645		goto done;
1646	if ((bif->bif_flags & IFBIF_STP) == 0)
1647		goto done;
1648	if ((bp = bif->bif_stp) == NULL)
1649		goto done;
1650	if ((bs = bp->bp_bs) == NULL)
1651		goto done;
1652
1653	/* update the link state */
1654	bstp_ifupdstatus(bs, bp);
1655	bstp_update_state(bs, bp);
1656 done:
1657	splx(s);
1658}
1659
1660void
1661bstp_ifupdstatus(struct bstp_state *bs, struct bstp_port *bp)
1662{
1663	struct ifnet *ifp;
1664
1665	if ((ifp = if_get(bp->bp_ifindex)) == NULL)
1666		return;
1667
1668	bp->bp_path_cost = bstp_calc_path_cost(bp);
1669
1670	if ((ifp->if_flags & IFF_UP) &&
1671	    ifp->if_link_state != LINK_STATE_DOWN) {
1672		if (bp->bp_flags & BSTP_PORT_AUTOPTP) {
1673			/* A full-duplex link is assumed to be ptp */
1674			bp->bp_ptp_link = ifp->if_link_state ==
1675			    LINK_STATE_FULL_DUPLEX ? 1 : 0;
1676		}
1677
1678		if (bp->bp_infois == BSTP_INFO_DISABLED)
1679			bstp_enable_port(bs, bp);
1680	} else {
1681		if (bp->bp_infois != BSTP_INFO_DISABLED)
1682			bstp_disable_port(bs, bp);
1683	}
1684
1685	if_put(ifp);
1686}
1687
1688void
1689bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp)
1690{
1691	bp->bp_infois = BSTP_INFO_AGED;
1692	bstp_assign_roles(bs);
1693}
1694
1695void
1696bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp)
1697{
1698	bp->bp_infois = BSTP_INFO_DISABLED;
1699	bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1700	bstp_assign_roles(bs);
1701}
1702
1703void
1704bstp_tick(void *arg)
1705{
1706	struct bstp_state *bs = (struct bstp_state *)arg;
1707	struct ifnet *ifp;
1708	struct bstp_port *bp;
1709	int s;
1710
1711	if ((ifp = if_get(bs->bs_ifindex)) == NULL)
1712		return;
1713
1714	s = splnet();
1715	if ((ifp->if_flags & IFF_RUNNING) == 0) {
1716		splx(s);
1717		if_put(ifp);
1718		return;
1719	}
1720
1721	/* slow timer to catch missed link events */
1722	if (bstp_timer_expired(&bs->bs_link_timer)) {
1723		LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1724			bstp_ifupdstatus(bs, bp);
1725		bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
1726	}
1727
1728	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1729		/* no events need to happen for these */
1730		bstp_timer_expired(&bp->bp_tc_timer);
1731		bstp_timer_expired(&bp->bp_recent_root_timer);
1732		bstp_timer_expired(&bp->bp_forward_delay_timer);
1733		bstp_timer_expired(&bp->bp_recent_backup_timer);
1734
1735		if (bstp_timer_expired(&bp->bp_hello_timer))
1736			bstp_hello_timer_expiry(bs, bp);
1737
1738		if (bstp_timer_expired(&bp->bp_message_age_timer))
1739			bstp_message_age_expiry(bs, bp);
1740
1741		if (bstp_timer_expired(&bp->bp_migrate_delay_timer))
1742			bstp_migrate_delay_expiry(bs, bp);
1743
1744		if (bstp_timer_expired(&bp->bp_edge_delay_timer))
1745			bstp_edge_delay_expiry(bs, bp);
1746
1747		/* update the various state machines for the port */
1748		bstp_update_state(bs, bp);
1749
1750		if (bp->bp_txcount > 0)
1751			bp->bp_txcount--;
1752	}
1753
1754	if (ifp->if_flags & IFF_RUNNING)
1755		timeout_add_sec(&bs->bs_bstptimeout, 1);
1756
1757	splx(s);
1758	if_put(ifp);
1759}
1760
1761void
1762bstp_timer_start(struct bstp_timer *t, u_int16_t v)
1763{
1764	t->value = v;
1765	t->active = 1;
1766	t->latched = 0;
1767}
1768
1769void
1770bstp_timer_stop(struct bstp_timer *t)
1771{
1772	t->value = 0;
1773	t->active = 0;
1774	t->latched = 0;
1775}
1776
1777void
1778bstp_timer_latch(struct bstp_timer *t)
1779{
1780	t->latched = 1;
1781	t->active = 1;
1782}
1783
1784int
1785bstp_timer_expired(struct bstp_timer *t)
1786{
1787	if (t->active == 0 || t->latched)
1788		return (0);
1789	t->value -= BSTP_TICK_VAL;
1790	if (t->value <= 0) {
1791		bstp_timer_stop(t);
1792		return (1);
1793	}
1794	return (0);
1795}
1796
1797void
1798bstp_hello_timer_expiry(struct bstp_state *bs, struct bstp_port *bp)
1799{
1800	if ((bp->bp_flags & BSTP_PORT_NEWINFO) ||
1801	    bp->bp_role == BSTP_ROLE_DESIGNATED ||
1802	    (bp->bp_role == BSTP_ROLE_ROOT &&
1803	     bp->bp_tc_timer.active == 1)) {
1804		bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
1805		bp->bp_flags |= BSTP_PORT_NEWINFO;
1806		bstp_transmit(bs, bp);
1807	}
1808}
1809
1810void
1811bstp_message_age_expiry(struct bstp_state *bs, struct bstp_port *bp)
1812{
1813	if (bp->bp_infois == BSTP_INFO_RECEIVED) {
1814		bp->bp_infois = BSTP_INFO_AGED;
1815		bstp_assign_roles(bs);
1816		DPRINTF(bp, "aged info\n");
1817	}
1818}
1819
1820void
1821bstp_migrate_delay_expiry(struct bstp_state *bs, struct bstp_port *bp)
1822{
1823	bp->bp_flags |= BSTP_PORT_CANMIGRATE;
1824}
1825
1826void
1827bstp_edge_delay_expiry(struct bstp_state *bs, struct bstp_port *bp)
1828{
1829	if ((bp->bp_flags & BSTP_PORT_AUTOEDGE) &&
1830	    bp->bp_protover == BSTP_PROTO_RSTP && bp->bp_proposing &&
1831	    bp->bp_role == BSTP_ROLE_DESIGNATED)
1832		bp->bp_operedge = 1;
1833}
1834
1835int
1836bstp_addr_cmp(const u_int8_t *a, const u_int8_t *b)
1837{
1838	int i, d;
1839
1840	for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
1841		d = ((int)a[i]) - ((int)b[i]);
1842	}
1843
1844	return (d);
1845}
1846
1847/*
1848 * compare the bridge address component of the bridgeid
1849 */
1850int
1851bstp_same_bridgeid(u_int64_t id1, u_int64_t id2)
1852{
1853	u_char addr1[ETHER_ADDR_LEN];
1854	u_char addr2[ETHER_ADDR_LEN];
1855
1856	PV2ADDR(id1, addr1);
1857	PV2ADDR(id2, addr2);
1858
1859	if (bstp_addr_cmp(addr1, addr2) == 0)
1860		return (1);
1861
1862	return (0);
1863}
1864
1865void
1866bstp_initialization(struct bstp_state *bs)
1867{
1868	struct bstp_port *bp;
1869	struct ifnet *mif = NULL;
1870	u_char *e_addr;
1871
1872	/*
1873	 * Search through the Ethernet interfaces and find the one
1874	 * with the lowest value.
1875	 * Make sure we take the address from an interface that is
1876	 * part of the bridge to make sure two bridges on the system
1877	 * will not use the same one. It is not possible for mif to be
1878	 * null, at this point we have at least one STP port and hence
1879	 * at least one NIC.
1880	 */
1881	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1882		struct ifnet *ifp;
1883
1884		if (mif == NULL) {
1885			mif = if_get(bp->bp_ifindex);
1886			continue;
1887		}
1888
1889		if ((ifp = if_get(bp->bp_ifindex)) == NULL)
1890			continue;
1891
1892		if (bstp_addr_cmp(LLADDR(ifp->if_sadl),
1893		    LLADDR(mif->if_sadl)) < 0) {
1894			if_put(mif);
1895			mif = ifp;
1896			continue;
1897		}
1898		if_put(ifp);
1899	}
1900
1901	if (mif == NULL) {
1902		bstp_stop(bs);
1903		bstp_reset(bs);
1904		return;
1905	}
1906
1907	e_addr = LLADDR(mif->if_sadl);
1908	if_put(mif);
1909	bs->bs_bridge_pv.pv_dbridge_id =
1910	    (((u_int64_t)bs->bs_bridge_priority) << 48) |
1911	    (((u_int64_t)e_addr[0]) << 40) |
1912	    (((u_int64_t)e_addr[1]) << 32) |
1913	    (((u_int64_t)e_addr[2]) << 24) |
1914	    (((u_int64_t)e_addr[3]) << 16) |
1915	    (((u_int64_t)e_addr[4]) << 8) |
1916	    (((u_int64_t)e_addr[5]));
1917
1918	bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id;
1919	bs->bs_bridge_pv.pv_cost = 0;
1920	bs->bs_bridge_pv.pv_dport_id = 0;
1921	bs->bs_bridge_pv.pv_port_id = 0;
1922
1923	if (!timeout_initialized(&bs->bs_bstptimeout))
1924		timeout_set(&bs->bs_bstptimeout, bstp_tick, bs);
1925	if (!timeout_pending(&bs->bs_bstptimeout))
1926		timeout_add_sec(&bs->bs_bstptimeout, 1);
1927
1928	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1929		bp->bp_port_id = (bp->bp_priority << 8) |
1930		    (bp->bp_ifindex & 0xfff);
1931		bstp_ifupdstatus(bs, bp);
1932	}
1933
1934	bstp_assign_roles(bs);
1935	bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
1936}
1937
1938struct bstp_state *
1939bstp_create(void)
1940{
1941	struct bstp_state *bs;
1942
1943	bs = malloc(sizeof(*bs), M_DEVBUF, M_WAITOK|M_ZERO);
1944	LIST_INIT(&bs->bs_bplist);
1945
1946	bs->bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
1947	bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
1948	bs->bs_bridge_fdelay = BSTP_DEFAULT_FORWARD_DELAY;
1949	bs->bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
1950	bs->bs_hold_time = BSTP_DEFAULT_HOLD_TIME;
1951	bs->bs_migration_delay = BSTP_DEFAULT_MIGRATE_DELAY;
1952	bs->bs_txholdcount = BSTP_DEFAULT_HOLD_COUNT;
1953	bs->bs_protover = BSTP_PROTO_RSTP;	/* STP instead of RSTP? */
1954
1955	getmicrotime(&bs->bs_last_tc_time);
1956
1957	return (bs);
1958}
1959
1960void
1961bstp_destroy(struct bstp_state *bs)
1962{
1963	if (bs == NULL)
1964		return;
1965
1966	if (!LIST_EMPTY(&bs->bs_bplist))
1967		panic("bstp still active");
1968
1969	free(bs, M_DEVBUF, sizeof *bs);
1970}
1971
1972void
1973bstp_enable(struct bstp_state *bs, unsigned int ifindex)
1974{
1975	bs->bs_ifindex = ifindex;
1976	bstp_initialization(bs);
1977}
1978
1979void
1980bstp_disable(struct bstp_state *bs)
1981{
1982	if (timeout_initialized(&bs->bs_bstptimeout))
1983		timeout_del(&bs->bs_bstptimeout);
1984	bs->bs_ifindex = 0;
1985}
1986
1987void
1988bstp_stop(struct bstp_state *bs)
1989{
1990	struct bstp_port *bp;
1991
1992	LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1993		bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1994
1995	if (timeout_initialized(&bs->bs_bstptimeout))
1996		timeout_del(&bs->bs_bstptimeout);
1997}
1998
1999struct bstp_port *
2000bstp_add(struct bstp_state *bs, struct ifnet *ifp)
2001{
2002	struct bstp_port *bp;
2003
2004	switch (ifp->if_type) {
2005	case IFT_ETHER:	/* These can do spanning tree. */
2006		break;
2007	default:
2008		/* Nothing else can. */
2009		return (NULL);
2010	}
2011
2012	bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT|M_ZERO);
2013	if (bp == NULL)
2014		return (NULL);
2015
2016	bp->bp_ifindex = ifp->if_index;
2017	bp->bp_bs = bs;
2018	bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY;
2019	bp->bp_txcount = 0;
2020
2021	/* Init state */
2022	bp->bp_infois = BSTP_INFO_DISABLED;
2023	bp->bp_flags = BSTP_PORT_AUTOEDGE | BSTP_PORT_AUTOPTP;
2024	bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
2025	bstp_set_port_proto(bp, bs->bs_protover);
2026	bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2027	bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
2028	bp->bp_path_cost = bstp_calc_path_cost(bp);
2029
2030	LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next);
2031
2032	bp->bp_active = 1;
2033	bp->bp_flags |= BSTP_PORT_NEWINFO;
2034	bstp_initialization(bs);
2035	bstp_update_roles(bs, bp);
2036
2037	/* Register callback for physical link state changes */
2038	task_set(&bp->bp_ltask, bstp_ifstate, ifp);
2039	if_linkstatehook_add(ifp, &bp->bp_ltask);
2040
2041	return (bp);
2042}
2043
2044void
2045bstp_delete(struct bstp_port *bp)
2046{
2047	struct bstp_state *bs = bp->bp_bs;
2048	struct ifnet *ifp;
2049
2050	if (!bp->bp_active)
2051		panic("not a bstp member");
2052
2053	if ((ifp = if_get(bp->bp_ifindex)) != NULL)
2054		if_linkstatehook_del(ifp, &bp->bp_ltask);
2055	if_put(ifp);
2056
2057	LIST_REMOVE(bp, bp_next);
2058	free(bp, M_DEVBUF, sizeof *bp);
2059	bstp_initialization(bs);
2060}
2061
2062u_int8_t
2063bstp_getstate(struct bstp_state *bs, struct bstp_port *bp)
2064{
2065	u_int8_t state = bp->bp_state;
2066
2067	if (bs->bs_protover != BSTP_PROTO_STP)
2068		return (state);
2069
2070	/*
2071	 * Translate RSTP roles and states to STP port states
2072	 * (IEEE Std 802.1D-2004 Table 17-1).
2073	 */
2074	if (bp->bp_role == BSTP_ROLE_DISABLED)
2075		state = BSTP_IFSTATE_DISABLED;
2076	else if (bp->bp_role == BSTP_ROLE_ALTERNATE ||
2077	    bp->bp_role == BSTP_ROLE_BACKUP)
2078		state = BSTP_IFSTATE_BLOCKING;
2079	else if (state == BSTP_IFSTATE_DISCARDING)
2080		state = BSTP_IFSTATE_LISTENING;
2081
2082	return (state);
2083}
2084
2085void
2086bstp_ifsflags(struct bstp_port *bp, u_int flags)
2087{
2088	struct bstp_state *bs;
2089
2090	if ((flags & IFBIF_STP) == 0)
2091		return;
2092	bs = bp->bp_bs;
2093
2094	/*
2095	 * Set edge status
2096	 */
2097	if (flags & IFBIF_BSTP_AUTOEDGE) {
2098		if ((bp->bp_flags & BSTP_PORT_AUTOEDGE) == 0) {
2099			bp->bp_flags |= BSTP_PORT_AUTOEDGE;
2100
2101			/* we may be able to transition straight to edge */
2102			if (bp->bp_edge_delay_timer.active == 0)
2103				bstp_edge_delay_expiry(bs, bp);
2104		}
2105	} else
2106		bp->bp_flags &= ~BSTP_PORT_AUTOEDGE;
2107
2108	if (flags & IFBIF_BSTP_EDGE)
2109		bp->bp_operedge = 1;
2110	else
2111		bp->bp_operedge = 0;
2112
2113	/*
2114	 * Set point to point status
2115	 */
2116	if (flags & IFBIF_BSTP_AUTOPTP) {
2117		if ((bp->bp_flags & BSTP_PORT_AUTOPTP) == 0) {
2118			bp->bp_flags |= BSTP_PORT_AUTOPTP;
2119
2120			bstp_ifupdstatus(bs, bp);
2121		}
2122	} else
2123		bp->bp_flags &= ~BSTP_PORT_AUTOPTP;
2124
2125	if (flags & IFBIF_BSTP_PTP)
2126		bp->bp_ptp_link = 1;
2127	else
2128		bp->bp_ptp_link = 0;
2129}
2130
2131int
2132bstp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
2133{
2134	struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
2135	struct bstp_state *bs = sc->sc_stp;
2136	struct ifbrparam *ifbp = (struct ifbrparam *)data;
2137	struct ifbreq *ifbr = (struct ifbreq *)data;
2138	struct bridge_iflist *bif;
2139	struct bstp_port *bp;
2140	int r = 0, err = 0, val;
2141
2142	switch (cmd) {
2143	case SIOCBRDGSIFPRIO:
2144	case SIOCBRDGSIFCOST:
2145		err = bridge_findbif(sc, ifbr->ifbr_ifsname, &bif);
2146		if (err != 0)
2147			break;
2148		if ((bif->bif_flags & IFBIF_STP) == 0) {
2149			err = EINVAL;
2150			break;
2151		}
2152		bp = bif->bif_stp;
2153		break;
2154	default:
2155		break;
2156	}
2157	if (err)
2158		return (err);
2159
2160	switch (cmd) {
2161	case SIOCBRDGGPRI:
2162		ifbp->ifbrp_prio = bs->bs_bridge_priority;
2163		break;
2164	case SIOCBRDGSPRI:
2165		val = ifbp->ifbrp_prio;
2166		if (val < 0 || val > BSTP_MAX_PRIORITY) {
2167			err = EINVAL;
2168			break;
2169		}
2170
2171		/* Limit to steps of 4096 */
2172		val -= val % 4096;
2173		bs->bs_bridge_priority = val;
2174		r = 1;
2175		break;
2176	case SIOCBRDGGMA:
2177		ifbp->ifbrp_maxage = bs->bs_bridge_max_age >> 8;
2178		break;
2179	case SIOCBRDGSMA:
2180		val = ifbp->ifbrp_maxage;
2181
2182		/* convert seconds to ticks */
2183		val *= BSTP_TICK_VAL;
2184
2185		if (val < BSTP_MIN_MAX_AGE || val > BSTP_MAX_MAX_AGE) {
2186			err = EINVAL;
2187			break;
2188		}
2189		bs->bs_bridge_max_age = val;
2190		r = 1;
2191		break;
2192	case SIOCBRDGGHT:
2193		ifbp->ifbrp_hellotime = bs->bs_bridge_htime >> 8;
2194		break;
2195	case SIOCBRDGSHT:
2196		val = ifbp->ifbrp_hellotime;
2197
2198		/* convert seconds to ticks */
2199		val *=  BSTP_TICK_VAL;
2200
2201		/* value can only be changed in legacy stp mode */
2202		if (bs->bs_protover != BSTP_PROTO_STP) {
2203			err = EPERM;
2204			break;
2205		}
2206		if (val < BSTP_MIN_HELLO_TIME || val > BSTP_MAX_HELLO_TIME) {
2207			err = EINVAL;
2208			break;
2209		}
2210		bs->bs_bridge_htime = val;
2211		r = 1;
2212		break;
2213	case SIOCBRDGGFD:
2214		ifbp->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8;
2215		break;
2216	case SIOCBRDGSFD:
2217		val = ifbp->ifbrp_fwddelay;
2218
2219		/* convert seconds to ticks */
2220		val *= BSTP_TICK_VAL;
2221
2222		if (val < BSTP_MIN_FORWARD_DELAY ||
2223		    val > BSTP_MAX_FORWARD_DELAY) {
2224			err = EINVAL;
2225			break;
2226		}
2227		bs->bs_bridge_fdelay = val;
2228		r = 1;
2229		break;
2230	case SIOCBRDGSTXHC:
2231		val = ifbp->ifbrp_txhc;
2232
2233		if (val < BSTP_MIN_HOLD_COUNT || val > BSTP_MAX_HOLD_COUNT) {
2234			err = EINVAL;
2235			break;
2236		}
2237		bs->bs_txholdcount = val;
2238		LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
2239			bp->bp_txcount = 0;
2240		break;
2241	case SIOCBRDGSIFPRIO:
2242		val = ifbr->ifbr_priority;
2243		if (val < 0 || val > BSTP_MAX_PORT_PRIORITY)
2244			return (EINVAL);
2245
2246		/* Limit to steps of 16 */
2247		val -= val % 16;
2248		bp->bp_priority = val;
2249		r = 1;
2250		break;
2251	case SIOCBRDGSIFCOST:
2252		val = ifbr->ifbr_path_cost;
2253		if (val > BSTP_MAX_PATH_COST) {
2254			err = EINVAL;
2255			break;
2256		}
2257		if (val == 0) {	/* use auto */
2258			bp->bp_flags &= ~BSTP_PORT_ADMCOST;
2259			bp->bp_path_cost = bstp_calc_path_cost(bp);
2260		} else {
2261			bp->bp_path_cost = val;
2262			bp->bp_flags |= BSTP_PORT_ADMCOST;
2263		}
2264		r = 1;
2265		break;
2266	case SIOCBRDGSPROTO:
2267		val = ifbp->ifbrp_proto;
2268
2269		/* Supported protocol versions */
2270		switch (val) {
2271		case BSTP_PROTO_STP:
2272		case BSTP_PROTO_RSTP:
2273			bs->bs_protover = val;
2274			bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
2275			LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2276				/* reinit state */
2277				bp->bp_infois = BSTP_INFO_DISABLED;
2278				bp->bp_txcount = 0;
2279				bstp_set_port_proto(bp, bs->bs_protover);
2280				bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2281				bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
2282				bstp_timer_stop(&bp->bp_recent_backup_timer);
2283			}
2284			r = 1;
2285			break;
2286		default:
2287			err = EINVAL;
2288		}
2289		break;
2290	default:
2291		break;
2292	}
2293
2294	if (r)
2295		bstp_initialization(bs);
2296
2297	return (err);
2298}
2299