xref: /freebsd/sys/net/bridgestp.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1 /*	$NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2000 Jason L. Wright (jason@thought.net)
7  * Copyright (c) 2006 Andrew Thompson (thompsa@FreeBSD.org)
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason Exp
32  */
33 
34 /*
35  * Implementation of the spanning tree protocol as defined in
36  * ISO/IEC 802.1D-2004, June 9, 2004.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/callout.h>
47 #include <sys/module.h>
48 #include <sys/proc.h>
49 #include <sys/lock.h>
50 #include <sys/mutex.h>
51 #include <sys/taskqueue.h>
52 
53 #include <net/if.h>
54 #include <net/if_var.h>
55 #include <net/if_private.h>
56 #include <net/if_dl.h>
57 #include <net/if_types.h>
58 #include <net/if_llc.h>
59 #include <net/if_media.h>
60 #include <net/vnet.h>
61 
62 #include <netinet/in.h>
63 #include <netinet/in_systm.h>
64 #include <netinet/in_var.h>
65 #include <netinet/if_ether.h>
66 #include <net/bridgestp.h>
67 
68 #ifdef	BRIDGESTP_DEBUG
69 #define	DPRINTF(fmt, arg...)	printf("bstp: " fmt, ##arg)
70 #else
71 #define	DPRINTF(fmt, arg...)	(void)0
72 #endif
73 
74 #define	PV2ADDR(pv, eaddr)	do {		\
75 	eaddr[0] = pv >> 40;			\
76 	eaddr[1] = pv >> 32;			\
77 	eaddr[2] = pv >> 24;			\
78 	eaddr[3] = pv >> 16;			\
79 	eaddr[4] = pv >> 8;			\
80 	eaddr[5] = pv >> 0;			\
81 } while (0)
82 
83 #define	INFO_BETTER	1
84 #define	INFO_SAME	0
85 #define	INFO_WORSE	-1
86 
87 const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
88 
89 LIST_HEAD(, bstp_state) bstp_list;
90 static struct mtx	bstp_list_mtx;
91 
92 static void	bstp_transmit(struct bstp_state *, struct bstp_port *);
93 static void	bstp_transmit_bpdu(struct bstp_state *, struct bstp_port *);
94 static void	bstp_transmit_tcn(struct bstp_state *, struct bstp_port *);
95 static void	bstp_decode_bpdu(struct bstp_port *, struct bstp_cbpdu *,
96 		    struct bstp_config_unit *);
97 static void	bstp_send_bpdu(struct bstp_state *, struct bstp_port *,
98 		    struct bstp_cbpdu *);
99 static int	bstp_pdu_flags(struct bstp_port *);
100 static void	bstp_received_stp(struct bstp_state *, struct bstp_port *,
101 		    struct mbuf **, struct bstp_tbpdu *);
102 static void	bstp_received_rstp(struct bstp_state *, struct bstp_port *,
103 		    struct mbuf **, struct bstp_tbpdu *);
104 static void	bstp_received_tcn(struct bstp_state *, struct bstp_port *,
105 		    struct bstp_tcn_unit *);
106 static void	bstp_received_bpdu(struct bstp_state *, struct bstp_port *,
107 		    struct bstp_config_unit *);
108 static int	bstp_pdu_rcvtype(struct bstp_port *, struct bstp_config_unit *);
109 static int	bstp_pdu_bettersame(struct bstp_port *, int);
110 static int	bstp_info_cmp(struct bstp_pri_vector *,
111 		    struct bstp_pri_vector *);
112 static int	bstp_info_superior(struct bstp_pri_vector *,
113 		    struct bstp_pri_vector *);
114 static void	bstp_assign_roles(struct bstp_state *);
115 static void	bstp_update_roles(struct bstp_state *, struct bstp_port *);
116 static void	bstp_update_state(struct bstp_state *, struct bstp_port *);
117 static void	bstp_update_tc(struct bstp_port *);
118 static void	bstp_update_info(struct bstp_port *);
119 static void	bstp_set_other_tcprop(struct bstp_port *);
120 static void	bstp_set_all_reroot(struct bstp_state *);
121 static void	bstp_set_all_sync(struct bstp_state *);
122 static void	bstp_set_port_state(struct bstp_port *, int);
123 static void	bstp_set_port_role(struct bstp_port *, int);
124 static void	bstp_set_port_proto(struct bstp_port *, int);
125 static void	bstp_set_port_tc(struct bstp_port *, int);
126 static void	bstp_set_timer_tc(struct bstp_port *);
127 static void	bstp_set_timer_msgage(struct bstp_port *);
128 static int	bstp_rerooted(struct bstp_state *, struct bstp_port *);
129 static uint32_t	bstp_calc_path_cost(struct bstp_port *);
130 static void	bstp_notify_state(void *, int);
131 static void	bstp_notify_rtage(void *, int);
132 static void	bstp_ifupdstatus(void *, int);
133 static void	bstp_enable_port(struct bstp_state *, struct bstp_port *);
134 static void	bstp_disable_port(struct bstp_state *, struct bstp_port *);
135 static void	bstp_tick(void *);
136 static void	bstp_timer_start(struct bstp_timer *, uint16_t);
137 static void	bstp_timer_stop(struct bstp_timer *);
138 static void	bstp_timer_latch(struct bstp_timer *);
139 static int	bstp_timer_dectest(struct bstp_timer *);
140 static void	bstp_hello_timer_expiry(struct bstp_state *,
141 		    struct bstp_port *);
142 static void	bstp_message_age_expiry(struct bstp_state *,
143 		    struct bstp_port *);
144 static void	bstp_migrate_delay_expiry(struct bstp_state *,
145 		    struct bstp_port *);
146 static void	bstp_edge_delay_expiry(struct bstp_state *,
147 		    struct bstp_port *);
148 static int	bstp_addr_cmp(const uint8_t *, const uint8_t *);
149 static int	bstp_same_bridgeid(uint64_t, uint64_t);
150 static void	bstp_reinit(struct bstp_state *);
151 
152 static void
bstp_transmit(struct bstp_state * bs,struct bstp_port * bp)153 bstp_transmit(struct bstp_state *bs, struct bstp_port *bp)
154 {
155 	NET_EPOCH_ASSERT();
156 
157 	if (bs->bs_running == 0)
158 		return;
159 
160 	/*
161 	 * a PDU can only be sent if we have tx quota left and the
162 	 * hello timer is running.
163 	 */
164 	if (bp->bp_hello_timer.active == 0) {
165 		/* Test if it needs to be reset */
166 		bstp_hello_timer_expiry(bs, bp);
167 		return;
168 	}
169 	if (bp->bp_txcount > bs->bs_txholdcount)
170 		/* Ran out of karma */
171 		return;
172 
173 	if (bp->bp_protover == BSTP_PROTO_RSTP) {
174 		bstp_transmit_bpdu(bs, bp);
175 		bp->bp_tc_ack = 0;
176 	} else { /* STP */
177 		switch (bp->bp_role) {
178 			case BSTP_ROLE_DESIGNATED:
179 				bstp_transmit_bpdu(bs, bp);
180 				bp->bp_tc_ack = 0;
181 				break;
182 
183 			case BSTP_ROLE_ROOT:
184 				bstp_transmit_tcn(bs, bp);
185 				break;
186 		}
187 	}
188 	bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
189 	bp->bp_flags &= ~BSTP_PORT_NEWINFO;
190 }
191 
192 static void
bstp_transmit_bpdu(struct bstp_state * bs,struct bstp_port * bp)193 bstp_transmit_bpdu(struct bstp_state *bs, struct bstp_port *bp)
194 {
195 	struct bstp_cbpdu bpdu;
196 
197 	BSTP_LOCK_ASSERT(bs);
198 
199 	bpdu.cbu_rootpri = htons(bp->bp_desg_pv.pv_root_id >> 48);
200 	PV2ADDR(bp->bp_desg_pv.pv_root_id, bpdu.cbu_rootaddr);
201 
202 	bpdu.cbu_rootpathcost = htonl(bp->bp_desg_pv.pv_cost);
203 
204 	bpdu.cbu_bridgepri = htons(bp->bp_desg_pv.pv_dbridge_id >> 48);
205 	PV2ADDR(bp->bp_desg_pv.pv_dbridge_id, bpdu.cbu_bridgeaddr);
206 
207 	bpdu.cbu_portid = htons(bp->bp_port_id);
208 	bpdu.cbu_messageage = htons(bp->bp_desg_msg_age);
209 	bpdu.cbu_maxage = htons(bp->bp_desg_max_age);
210 	bpdu.cbu_hellotime = htons(bp->bp_desg_htime);
211 	bpdu.cbu_forwarddelay = htons(bp->bp_desg_fdelay);
212 
213 	bpdu.cbu_flags = bstp_pdu_flags(bp);
214 
215 	switch (bp->bp_protover) {
216 		case BSTP_PROTO_STP:
217 			bpdu.cbu_bpdutype = BSTP_MSGTYPE_CFG;
218 			break;
219 
220 		case BSTP_PROTO_RSTP:
221 			bpdu.cbu_bpdutype = BSTP_MSGTYPE_RSTP;
222 			break;
223 	}
224 
225 	bstp_send_bpdu(bs, bp, &bpdu);
226 }
227 
228 static void
bstp_transmit_tcn(struct bstp_state * bs,struct bstp_port * bp)229 bstp_transmit_tcn(struct bstp_state *bs, struct bstp_port *bp)
230 {
231 	struct bstp_tbpdu bpdu;
232 	struct ifnet *ifp = bp->bp_ifp;
233 	struct ether_header *eh;
234 	struct mbuf *m;
235 
236 	KASSERT(bp == bs->bs_root_port, ("%s: bad root port\n", __func__));
237 
238 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
239 		return;
240 
241 	m = m_gethdr(M_NOWAIT, MT_DATA);
242 	if (m == NULL)
243 		return;
244 
245 	m->m_pkthdr.rcvif = ifp;
246 	m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
247 	m->m_len = m->m_pkthdr.len;
248 
249 	eh = mtod(m, struct ether_header *);
250 
251 	memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
252 	memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
253 	eh->ether_type = htons(sizeof(bpdu));
254 
255 	bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
256 	bpdu.tbu_ctl = LLC_UI;
257 	bpdu.tbu_protoid = 0;
258 	bpdu.tbu_protover = 0;
259 	bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
260 
261 	memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
262 
263 	bp->bp_txcount++;
264 	ifp->if_transmit(ifp, m);
265 }
266 
267 static void
bstp_decode_bpdu(struct bstp_port * bp,struct bstp_cbpdu * cpdu,struct bstp_config_unit * cu)268 bstp_decode_bpdu(struct bstp_port *bp, struct bstp_cbpdu *cpdu,
269     struct bstp_config_unit *cu)
270 {
271 	int flags;
272 
273 	cu->cu_pv.pv_root_id =
274 	    (((uint64_t)ntohs(cpdu->cbu_rootpri)) << 48) |
275 	    (((uint64_t)cpdu->cbu_rootaddr[0]) << 40) |
276 	    (((uint64_t)cpdu->cbu_rootaddr[1]) << 32) |
277 	    (((uint64_t)cpdu->cbu_rootaddr[2]) << 24) |
278 	    (((uint64_t)cpdu->cbu_rootaddr[3]) << 16) |
279 	    (((uint64_t)cpdu->cbu_rootaddr[4]) << 8) |
280 	    (((uint64_t)cpdu->cbu_rootaddr[5]) << 0);
281 
282 	cu->cu_pv.pv_dbridge_id =
283 	    (((uint64_t)ntohs(cpdu->cbu_bridgepri)) << 48) |
284 	    (((uint64_t)cpdu->cbu_bridgeaddr[0]) << 40) |
285 	    (((uint64_t)cpdu->cbu_bridgeaddr[1]) << 32) |
286 	    (((uint64_t)cpdu->cbu_bridgeaddr[2]) << 24) |
287 	    (((uint64_t)cpdu->cbu_bridgeaddr[3]) << 16) |
288 	    (((uint64_t)cpdu->cbu_bridgeaddr[4]) << 8) |
289 	    (((uint64_t)cpdu->cbu_bridgeaddr[5]) << 0);
290 
291 	cu->cu_pv.pv_cost = ntohl(cpdu->cbu_rootpathcost);
292 	cu->cu_message_age = ntohs(cpdu->cbu_messageage);
293 	cu->cu_max_age = ntohs(cpdu->cbu_maxage);
294 	cu->cu_hello_time = ntohs(cpdu->cbu_hellotime);
295 	cu->cu_forward_delay = ntohs(cpdu->cbu_forwarddelay);
296 	cu->cu_pv.pv_dport_id = ntohs(cpdu->cbu_portid);
297 	cu->cu_pv.pv_port_id = bp->bp_port_id;
298 	cu->cu_message_type = cpdu->cbu_bpdutype;
299 
300 	/* Strip off unused flags in STP mode */
301 	flags = cpdu->cbu_flags;
302 	switch (cpdu->cbu_protover) {
303 		case BSTP_PROTO_STP:
304 			flags &= BSTP_PDU_STPMASK;
305 			/* A STP BPDU explicitly conveys a Designated Port */
306 			cu->cu_role = BSTP_ROLE_DESIGNATED;
307 			break;
308 
309 		case BSTP_PROTO_RSTP:
310 			flags &= BSTP_PDU_RSTPMASK;
311 			break;
312 	}
313 
314 	cu->cu_topology_change_ack =
315 		(flags & BSTP_PDU_F_TCA) ? 1 : 0;
316 	cu->cu_proposal =
317 		(flags & BSTP_PDU_F_P) ? 1 : 0;
318 	cu->cu_agree =
319 		(flags & BSTP_PDU_F_A) ? 1 : 0;
320 	cu->cu_learning =
321 		(flags & BSTP_PDU_F_L) ? 1 : 0;
322 	cu->cu_forwarding =
323 		(flags & BSTP_PDU_F_F) ? 1 : 0;
324 	cu->cu_topology_change =
325 		(flags & BSTP_PDU_F_TC) ? 1 : 0;
326 
327 	switch ((flags & BSTP_PDU_PRMASK) >> BSTP_PDU_PRSHIFT) {
328 		case BSTP_PDU_F_ROOT:
329 			cu->cu_role = BSTP_ROLE_ROOT;
330 			break;
331 		case BSTP_PDU_F_ALT:
332 			cu->cu_role = BSTP_ROLE_ALTERNATE;
333 			break;
334 		case BSTP_PDU_F_DESG:
335 			cu->cu_role = BSTP_ROLE_DESIGNATED;
336 			break;
337 	}
338 }
339 
340 static void
bstp_send_bpdu(struct bstp_state * bs,struct bstp_port * bp,struct bstp_cbpdu * bpdu)341 bstp_send_bpdu(struct bstp_state *bs, struct bstp_port *bp,
342     struct bstp_cbpdu *bpdu)
343 {
344 	struct ifnet *ifp;
345 	struct mbuf *m;
346 	struct ether_header *eh;
347 
348 	BSTP_LOCK_ASSERT(bs);
349 	NET_EPOCH_ASSERT();
350 
351 	ifp = bp->bp_ifp;
352 
353 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
354 		return;
355 
356 	m = m_gethdr(M_NOWAIT, MT_DATA);
357 	if (m == NULL)
358 		return;
359 
360 	eh = mtod(m, struct ether_header *);
361 
362 	bpdu->cbu_ssap = bpdu->cbu_dsap = LLC_8021D_LSAP;
363 	bpdu->cbu_ctl = LLC_UI;
364 	bpdu->cbu_protoid = htons(BSTP_PROTO_ID);
365 
366 	memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
367 	memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
368 
369 	switch (bpdu->cbu_bpdutype) {
370 		case BSTP_MSGTYPE_CFG:
371 			bpdu->cbu_protover = BSTP_PROTO_STP;
372 			m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_STP_LEN;
373 			eh->ether_type = htons(BSTP_BPDU_STP_LEN);
374 			memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
375 			    BSTP_BPDU_STP_LEN);
376 			break;
377 
378 		case BSTP_MSGTYPE_RSTP:
379 			bpdu->cbu_protover = BSTP_PROTO_RSTP;
380 			bpdu->cbu_versionlen = htons(0);
381 			m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_RSTP_LEN;
382 			eh->ether_type = htons(BSTP_BPDU_RSTP_LEN);
383 			memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
384 			    BSTP_BPDU_RSTP_LEN);
385 			break;
386 
387 		default:
388 			panic("not implemented");
389 	}
390 	m->m_pkthdr.rcvif = ifp;
391 	m->m_len = m->m_pkthdr.len;
392 
393 	bp->bp_txcount++;
394 	ifp->if_transmit(ifp, m);
395 }
396 
397 static int
bstp_pdu_flags(struct bstp_port * bp)398 bstp_pdu_flags(struct bstp_port *bp)
399 {
400 	int flags = 0;
401 
402 	if (bp->bp_proposing && bp->bp_state != BSTP_IFSTATE_FORWARDING)
403 		flags |= BSTP_PDU_F_P;
404 
405 	if (bp->bp_agree)
406 		flags |= BSTP_PDU_F_A;
407 
408 	if (bp->bp_tc_timer.active)
409 		flags |= BSTP_PDU_F_TC;
410 
411 	if (bp->bp_tc_ack)
412 		flags |= BSTP_PDU_F_TCA;
413 
414 	switch (bp->bp_state) {
415 		case BSTP_IFSTATE_LEARNING:
416 			flags |= BSTP_PDU_F_L;
417 			break;
418 
419 		case BSTP_IFSTATE_FORWARDING:
420 			flags |= (BSTP_PDU_F_L | BSTP_PDU_F_F);
421 			break;
422 	}
423 
424 	switch (bp->bp_role) {
425 		case BSTP_ROLE_ROOT:
426 			flags |=
427 				(BSTP_PDU_F_ROOT << BSTP_PDU_PRSHIFT);
428 			break;
429 
430 		case BSTP_ROLE_ALTERNATE:
431 		case BSTP_ROLE_BACKUP:	/* fall through */
432 			flags |=
433 				(BSTP_PDU_F_ALT << BSTP_PDU_PRSHIFT);
434 			break;
435 
436 		case BSTP_ROLE_DESIGNATED:
437 			flags |=
438 				(BSTP_PDU_F_DESG << BSTP_PDU_PRSHIFT);
439 			break;
440 	}
441 
442 	/* Strip off unused flags in either mode */
443 	switch (bp->bp_protover) {
444 		case BSTP_PROTO_STP:
445 			flags &= BSTP_PDU_STPMASK;
446 			break;
447 		case BSTP_PROTO_RSTP:
448 			flags &= BSTP_PDU_RSTPMASK;
449 			break;
450 	}
451 	return (flags);
452 }
453 
454 void
bstp_input(struct bstp_port * bp,struct ifnet * ifp,struct mbuf * m)455 bstp_input(struct bstp_port *bp, struct ifnet *ifp, struct mbuf *m)
456 {
457 	struct bstp_state *bs = bp->bp_bs;
458 	struct ether_header *eh;
459 	struct bstp_tbpdu tpdu;
460 	uint16_t len;
461 
462 	if (bp->bp_active == 0) {
463 		m_freem(m);
464 		return;
465 	}
466 
467 	BSTP_LOCK(bs);
468 
469 	eh = mtod(m, struct ether_header *);
470 
471 	len = ntohs(eh->ether_type);
472 	if (len < sizeof(tpdu))
473 		goto out;
474 
475 	m_adj(m, ETHER_HDR_LEN);
476 
477 	if (m->m_pkthdr.len > len)
478 		m_adj(m, len - m->m_pkthdr.len);
479 	if (m->m_len < sizeof(tpdu) &&
480 	    (m = m_pullup(m, sizeof(tpdu))) == NULL)
481 		goto out;
482 
483 	memcpy(&tpdu, mtod(m, caddr_t), sizeof(tpdu));
484 
485 	/* basic packet checks */
486 	if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
487 	    tpdu.tbu_ssap != LLC_8021D_LSAP ||
488 	    tpdu.tbu_ctl != LLC_UI)
489 		goto out;
490 	if (tpdu.tbu_protoid != BSTP_PROTO_ID)
491 		goto out;
492 
493 	/*
494 	 * We can treat later versions of the PDU as the same as the maximum
495 	 * version we implement. All additional parameters/flags are ignored.
496 	 */
497 	if (tpdu.tbu_protover > BSTP_PROTO_MAX)
498 		tpdu.tbu_protover = BSTP_PROTO_MAX;
499 
500 	if (tpdu.tbu_protover != bp->bp_protover) {
501 		/*
502 		 * Wait for the migration delay timer to expire before changing
503 		 * protocol version to avoid flip-flops.
504 		 */
505 		if (bp->bp_flags & BSTP_PORT_CANMIGRATE)
506 			bstp_set_port_proto(bp, tpdu.tbu_protover);
507 		else
508 			goto out;
509 	}
510 
511 	/* Clear operedge upon receiving a PDU on the port */
512 	bp->bp_operedge = 0;
513 	bstp_timer_start(&bp->bp_edge_delay_timer,
514 	    BSTP_DEFAULT_MIGRATE_DELAY);
515 
516 	switch (tpdu.tbu_protover) {
517 		case BSTP_PROTO_STP:
518 			bstp_received_stp(bs, bp, &m, &tpdu);
519 			break;
520 
521 		case BSTP_PROTO_RSTP:
522 			bstp_received_rstp(bs, bp, &m, &tpdu);
523 			break;
524 	}
525 out:
526 	BSTP_UNLOCK(bs);
527 	if (m)
528 		m_freem(m);
529 }
530 
531 static void
bstp_received_stp(struct bstp_state * bs,struct bstp_port * bp,struct mbuf ** mp,struct bstp_tbpdu * tpdu)532 bstp_received_stp(struct bstp_state *bs, struct bstp_port *bp,
533     struct mbuf **mp, struct bstp_tbpdu *tpdu)
534 {
535 	struct bstp_cbpdu cpdu;
536 	struct bstp_config_unit *cu = &bp->bp_msg_cu;
537 	struct bstp_tcn_unit tu;
538 
539 	switch (tpdu->tbu_bpdutype) {
540 	case BSTP_MSGTYPE_TCN:
541 		tu.tu_message_type = tpdu->tbu_bpdutype;
542 		bstp_received_tcn(bs, bp, &tu);
543 		break;
544 	case BSTP_MSGTYPE_CFG:
545 		if ((*mp)->m_len < BSTP_BPDU_STP_LEN &&
546 		    (*mp = m_pullup(*mp, BSTP_BPDU_STP_LEN)) == NULL)
547 			return;
548 		memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_STP_LEN);
549 
550 		bstp_decode_bpdu(bp, &cpdu, cu);
551 		bstp_received_bpdu(bs, bp, cu);
552 		break;
553 	}
554 }
555 
556 static void
bstp_received_rstp(struct bstp_state * bs,struct bstp_port * bp,struct mbuf ** mp,struct bstp_tbpdu * tpdu)557 bstp_received_rstp(struct bstp_state *bs, struct bstp_port *bp,
558     struct mbuf **mp, struct bstp_tbpdu *tpdu)
559 {
560 	struct bstp_cbpdu cpdu;
561 	struct bstp_config_unit *cu = &bp->bp_msg_cu;
562 
563 	if (tpdu->tbu_bpdutype != BSTP_MSGTYPE_RSTP)
564 		return;
565 
566 	if ((*mp)->m_len < BSTP_BPDU_RSTP_LEN &&
567 	    (*mp = m_pullup(*mp, BSTP_BPDU_RSTP_LEN)) == NULL)
568 		return;
569 	memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_RSTP_LEN);
570 
571 	bstp_decode_bpdu(bp, &cpdu, cu);
572 	bstp_received_bpdu(bs, bp, cu);
573 }
574 
575 static void
bstp_received_tcn(struct bstp_state * bs,struct bstp_port * bp,struct bstp_tcn_unit * tcn)576 bstp_received_tcn(struct bstp_state *bs, struct bstp_port *bp,
577     struct bstp_tcn_unit *tcn)
578 {
579 	bp->bp_rcvdtcn = 1;
580 	bstp_update_tc(bp);
581 }
582 
583 static void
bstp_received_bpdu(struct bstp_state * bs,struct bstp_port * bp,struct bstp_config_unit * cu)584 bstp_received_bpdu(struct bstp_state *bs, struct bstp_port *bp,
585     struct bstp_config_unit *cu)
586 {
587 	int type;
588 
589 	BSTP_LOCK_ASSERT(bs);
590 
591 	/* We need to have transitioned to INFO_MINE before proceeding */
592 	switch (bp->bp_infois) {
593 		case BSTP_INFO_DISABLED:
594 		case BSTP_INFO_AGED:
595 			return;
596 	}
597 
598 	/* range checks */
599 	if (cu->cu_message_age >= cu->cu_max_age) {
600 		return;
601 	}
602 	if (cu->cu_max_age < BSTP_MIN_MAX_AGE ||
603 	    cu->cu_max_age > BSTP_MAX_MAX_AGE) {
604 		return;
605 	}
606 	if (cu->cu_forward_delay < BSTP_MIN_FORWARD_DELAY ||
607 	    cu->cu_forward_delay > BSTP_MAX_FORWARD_DELAY) {
608 		return;
609 	}
610 	if (cu->cu_hello_time < BSTP_MIN_HELLO_TIME ||
611 	    cu->cu_hello_time > BSTP_MAX_HELLO_TIME) {
612 		return;
613 	}
614 
615 	type = bstp_pdu_rcvtype(bp, cu);
616 
617 	switch (type) {
618 		case BSTP_PDU_SUPERIOR:
619 			bs->bs_allsynced = 0;
620 			bp->bp_agreed = 0;
621 			bp->bp_proposing = 0;
622 
623 			if (cu->cu_proposal && cu->cu_forwarding == 0)
624 				bp->bp_proposed = 1;
625 			if (cu->cu_topology_change)
626 				bp->bp_rcvdtc = 1;
627 			if (cu->cu_topology_change_ack)
628 				bp->bp_rcvdtca = 1;
629 
630 			if (bp->bp_agree &&
631 			    !bstp_pdu_bettersame(bp, BSTP_INFO_RECEIVED))
632 				bp->bp_agree = 0;
633 
634 			/* copy the received priority and timers to the port */
635 			bp->bp_port_pv = cu->cu_pv;
636 			bp->bp_port_msg_age = cu->cu_message_age;
637 			bp->bp_port_max_age = cu->cu_max_age;
638 			bp->bp_port_fdelay = cu->cu_forward_delay;
639 			bp->bp_port_htime =
640 				(cu->cu_hello_time > BSTP_MIN_HELLO_TIME ?
641 				 cu->cu_hello_time : BSTP_MIN_HELLO_TIME);
642 
643 			/* set expiry for the new info */
644 			bstp_set_timer_msgage(bp);
645 
646 			bp->bp_infois = BSTP_INFO_RECEIVED;
647 			bstp_assign_roles(bs);
648 			break;
649 
650 		case BSTP_PDU_REPEATED:
651 			if (cu->cu_proposal && cu->cu_forwarding == 0)
652 				bp->bp_proposed = 1;
653 			if (cu->cu_topology_change)
654 				bp->bp_rcvdtc = 1;
655 			if (cu->cu_topology_change_ack)
656 				bp->bp_rcvdtca = 1;
657 
658 			/* rearm the age timer */
659 			bstp_set_timer_msgage(bp);
660 			break;
661 
662 		case BSTP_PDU_INFERIOR:
663 			if (cu->cu_learning) {
664 				bp->bp_agreed = 1;
665 				bp->bp_proposing = 0;
666 			}
667 			break;
668 
669 		case BSTP_PDU_INFERIORALT:
670 			/*
671 			 * only point to point links are allowed fast
672 			 * transitions to forwarding.
673 			 */
674 			if (cu->cu_agree && bp->bp_ptp_link) {
675 				bp->bp_agreed = 1;
676 				bp->bp_proposing = 0;
677 			} else
678 				bp->bp_agreed = 0;
679 
680 			if (cu->cu_topology_change)
681 				bp->bp_rcvdtc = 1;
682 			if (cu->cu_topology_change_ack)
683 				bp->bp_rcvdtca = 1;
684 			break;
685 
686 		case BSTP_PDU_OTHER:
687 			return;	/* do nothing */
688 	}
689 	/* update the state machines with the new data */
690 	bstp_update_state(bs, bp);
691 }
692 
693 static int
bstp_pdu_rcvtype(struct bstp_port * bp,struct bstp_config_unit * cu)694 bstp_pdu_rcvtype(struct bstp_port *bp, struct bstp_config_unit *cu)
695 {
696 	int type;
697 
698 	/* default return type */
699 	type = BSTP_PDU_OTHER;
700 
701 	switch (cu->cu_role) {
702 	case BSTP_ROLE_DESIGNATED:
703 		if (bstp_info_superior(&bp->bp_port_pv, &cu->cu_pv))
704 			/* bpdu priority is superior */
705 			type = BSTP_PDU_SUPERIOR;
706 		else if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) ==
707 		    INFO_SAME) {
708 			if (bp->bp_port_msg_age != cu->cu_message_age ||
709 			    bp->bp_port_max_age != cu->cu_max_age ||
710 			    bp->bp_port_fdelay != cu->cu_forward_delay ||
711 			    bp->bp_port_htime != cu->cu_hello_time)
712 				/* bpdu priority is equal and timers differ */
713 				type = BSTP_PDU_SUPERIOR;
714 			else
715 				/* bpdu is equal */
716 				type = BSTP_PDU_REPEATED;
717 		} else
718 			/* bpdu priority is worse */
719 			type = BSTP_PDU_INFERIOR;
720 
721 		break;
722 
723 	case BSTP_ROLE_ROOT:
724 	case BSTP_ROLE_ALTERNATE:
725 	case BSTP_ROLE_BACKUP:
726 		if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) <= INFO_SAME)
727 			/*
728 			 * not a designated port and priority is the same or
729 			 * worse
730 			 */
731 			type = BSTP_PDU_INFERIORALT;
732 		break;
733 	}
734 
735 	return (type);
736 }
737 
738 static int
bstp_pdu_bettersame(struct bstp_port * bp,int newinfo)739 bstp_pdu_bettersame(struct bstp_port *bp, int newinfo)
740 {
741 	if (newinfo == BSTP_INFO_RECEIVED &&
742 	    bp->bp_infois == BSTP_INFO_RECEIVED &&
743 	    bstp_info_cmp(&bp->bp_port_pv, &bp->bp_msg_cu.cu_pv) >= INFO_SAME)
744 		return (1);
745 
746 	if (newinfo == BSTP_INFO_MINE &&
747 	    bp->bp_infois == BSTP_INFO_MINE &&
748 	    bstp_info_cmp(&bp->bp_port_pv, &bp->bp_desg_pv) >= INFO_SAME)
749 		return (1);
750 
751 	return (0);
752 }
753 
754 static int
bstp_info_cmp(struct bstp_pri_vector * pv,struct bstp_pri_vector * cpv)755 bstp_info_cmp(struct bstp_pri_vector *pv,
756     struct bstp_pri_vector *cpv)
757 {
758 	if (cpv->pv_root_id < pv->pv_root_id)
759 		return (INFO_BETTER);
760 	if (cpv->pv_root_id > pv->pv_root_id)
761 		return (INFO_WORSE);
762 
763 	if (cpv->pv_cost < pv->pv_cost)
764 		return (INFO_BETTER);
765 	if (cpv->pv_cost > pv->pv_cost)
766 		return (INFO_WORSE);
767 
768 	if (cpv->pv_dbridge_id < pv->pv_dbridge_id)
769 		return (INFO_BETTER);
770 	if (cpv->pv_dbridge_id > pv->pv_dbridge_id)
771 		return (INFO_WORSE);
772 
773 	if (cpv->pv_dport_id < pv->pv_dport_id)
774 		return (INFO_BETTER);
775 	if (cpv->pv_dport_id > pv->pv_dport_id)
776 		return (INFO_WORSE);
777 
778 	return (INFO_SAME);
779 }
780 
781 /*
782  * This message priority vector is superior to the port priority vector and
783  * will replace it if, and only if, the message priority vector is better than
784  * the port priority vector, or the message has been transmitted from the same
785  * designated bridge and designated port as the port priority vector.
786  */
787 static int
bstp_info_superior(struct bstp_pri_vector * pv,struct bstp_pri_vector * cpv)788 bstp_info_superior(struct bstp_pri_vector *pv,
789     struct bstp_pri_vector *cpv)
790 {
791 	if (bstp_info_cmp(pv, cpv) == INFO_BETTER ||
792 	    (bstp_same_bridgeid(pv->pv_dbridge_id, cpv->pv_dbridge_id) &&
793 	    (cpv->pv_dport_id & 0xfff) == (pv->pv_dport_id & 0xfff)))
794 		return (1);
795 	return (0);
796 }
797 
798 static void
bstp_assign_roles(struct bstp_state * bs)799 bstp_assign_roles(struct bstp_state *bs)
800 {
801 	struct bstp_port *bp, *rbp = NULL;
802 	struct bstp_pri_vector pv;
803 
804 	/* default to our priority vector */
805 	bs->bs_root_pv = bs->bs_bridge_pv;
806 	bs->bs_root_msg_age = 0;
807 	bs->bs_root_max_age = bs->bs_bridge_max_age;
808 	bs->bs_root_fdelay = bs->bs_bridge_fdelay;
809 	bs->bs_root_htime = bs->bs_bridge_htime;
810 	bs->bs_root_port = NULL;
811 
812 	/* check if any received info supersedes us */
813 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
814 		if (bp->bp_infois != BSTP_INFO_RECEIVED)
815 			continue;
816 
817 		pv = bp->bp_port_pv;
818 		pv.pv_cost += bp->bp_path_cost;
819 
820 		/*
821 		 * The root priority vector is the best of the set comprising
822 		 * the bridge priority vector plus all root path priority
823 		 * vectors whose bridge address is not equal to us.
824 		 */
825 		if (bstp_same_bridgeid(pv.pv_dbridge_id,
826 		    bs->bs_bridge_pv.pv_dbridge_id) == 0 &&
827 		    bstp_info_cmp(&bs->bs_root_pv, &pv) == INFO_BETTER) {
828 			/* the port vector replaces the root */
829 			bs->bs_root_pv = pv;
830 			bs->bs_root_msg_age = bp->bp_port_msg_age +
831 			    BSTP_MESSAGE_AGE_INCR;
832 			bs->bs_root_max_age = bp->bp_port_max_age;
833 			bs->bs_root_fdelay = bp->bp_port_fdelay;
834 			bs->bs_root_htime = bp->bp_port_htime;
835 			rbp = bp;
836 		}
837 	}
838 
839 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
840 		/* calculate the port designated vector */
841 		bp->bp_desg_pv.pv_root_id = bs->bs_root_pv.pv_root_id;
842 		bp->bp_desg_pv.pv_cost = bs->bs_root_pv.pv_cost;
843 		bp->bp_desg_pv.pv_dbridge_id = bs->bs_bridge_pv.pv_dbridge_id;
844 		bp->bp_desg_pv.pv_dport_id = bp->bp_port_id;
845 		bp->bp_desg_pv.pv_port_id = bp->bp_port_id;
846 
847 		/* calculate designated times */
848 		bp->bp_desg_msg_age = bs->bs_root_msg_age;
849 		bp->bp_desg_max_age = bs->bs_root_max_age;
850 		bp->bp_desg_fdelay = bs->bs_root_fdelay;
851 		bp->bp_desg_htime = bs->bs_bridge_htime;
852 
853 		switch (bp->bp_infois) {
854 		case BSTP_INFO_DISABLED:
855 			bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
856 			break;
857 
858 		case BSTP_INFO_AGED:
859 			bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
860 			bstp_update_info(bp);
861 			break;
862 
863 		case BSTP_INFO_MINE:
864 			bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
865 			/* update the port info if stale */
866 			if (bstp_info_cmp(&bp->bp_port_pv,
867 			    &bp->bp_desg_pv) != INFO_SAME ||
868 			    (rbp != NULL &&
869 			    (bp->bp_port_msg_age != rbp->bp_port_msg_age ||
870 			    bp->bp_port_max_age != rbp->bp_port_max_age ||
871 			    bp->bp_port_fdelay != rbp->bp_port_fdelay ||
872 			    bp->bp_port_htime != rbp->bp_port_htime)))
873 				bstp_update_info(bp);
874 			break;
875 
876 		case BSTP_INFO_RECEIVED:
877 			if (bp == rbp) {
878 				/*
879 				 * root priority is derived from this
880 				 * port, make it the root port.
881 				 */
882 				bstp_set_port_role(bp, BSTP_ROLE_ROOT);
883 				bs->bs_root_port = bp;
884 			} else if (bstp_info_cmp(&bp->bp_port_pv,
885 				    &bp->bp_desg_pv) == INFO_BETTER) {
886 				/*
887 				 * the port priority is lower than the root
888 				 * port.
889 				 */
890 				bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
891 				bstp_update_info(bp);
892 			} else {
893 				if (bstp_same_bridgeid(
894 				    bp->bp_port_pv.pv_dbridge_id,
895 				    bs->bs_bridge_pv.pv_dbridge_id)) {
896 					/*
897 					 * the designated bridge refers to
898 					 * another port on this bridge.
899 					 */
900 					bstp_set_port_role(bp,
901 					    BSTP_ROLE_BACKUP);
902 				} else {
903 					/*
904 					 * the port is an inferior path to the
905 					 * root bridge.
906 					 */
907 					bstp_set_port_role(bp,
908 					    BSTP_ROLE_ALTERNATE);
909 				}
910 			}
911 			break;
912 		}
913 	}
914 }
915 
916 static void
bstp_update_state(struct bstp_state * bs,struct bstp_port * bp)917 bstp_update_state(struct bstp_state *bs, struct bstp_port *bp)
918 {
919 	struct bstp_port *bp2;
920 	int synced;
921 
922 	BSTP_LOCK_ASSERT(bs);
923 
924 	/* check if all the ports have syncronised again */
925 	if (!bs->bs_allsynced) {
926 		synced = 1;
927 		LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
928 			if (!(bp2->bp_synced ||
929 			     bp2->bp_role == BSTP_ROLE_ROOT)) {
930 				synced = 0;
931 				break;
932 			}
933 		}
934 		bs->bs_allsynced = synced;
935 	}
936 
937 	bstp_update_roles(bs, bp);
938 	bstp_update_tc(bp);
939 }
940 
941 static void
bstp_update_roles(struct bstp_state * bs,struct bstp_port * bp)942 bstp_update_roles(struct bstp_state *bs, struct bstp_port *bp)
943 {
944 	NET_EPOCH_ASSERT();
945 
946 	switch (bp->bp_role) {
947 	case BSTP_ROLE_DISABLED:
948 		/* Clear any flags if set */
949 		if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
950 			bp->bp_sync = 0;
951 			bp->bp_synced = 1;
952 			bp->bp_reroot = 0;
953 		}
954 		break;
955 
956 	case BSTP_ROLE_ALTERNATE:
957 	case BSTP_ROLE_BACKUP:
958 		if ((bs->bs_allsynced && !bp->bp_agree) ||
959 		    (bp->bp_proposed && bp->bp_agree)) {
960 			bp->bp_proposed = 0;
961 			bp->bp_agree = 1;
962 			bp->bp_flags |= BSTP_PORT_NEWINFO;
963 			DPRINTF("%s -> ALTERNATE_AGREED\n",
964 			    bp->bp_ifp->if_xname);
965 		}
966 
967 		if (bp->bp_proposed && !bp->bp_agree) {
968 			bstp_set_all_sync(bs);
969 			bp->bp_proposed = 0;
970 			DPRINTF("%s -> ALTERNATE_PROPOSED\n",
971 			    bp->bp_ifp->if_xname);
972 		}
973 
974 		/* Clear any flags if set */
975 		if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
976 			bp->bp_sync = 0;
977 			bp->bp_synced = 1;
978 			bp->bp_reroot = 0;
979 			DPRINTF("%s -> ALTERNATE_PORT\n", bp->bp_ifp->if_xname);
980 		}
981 		break;
982 
983 	case BSTP_ROLE_ROOT:
984 		if (bp->bp_state != BSTP_IFSTATE_FORWARDING && !bp->bp_reroot) {
985 			bstp_set_all_reroot(bs);
986 			DPRINTF("%s -> ROOT_REROOT\n", bp->bp_ifp->if_xname);
987 		}
988 
989 		if ((bs->bs_allsynced && !bp->bp_agree) ||
990 		    (bp->bp_proposed && bp->bp_agree)) {
991 			bp->bp_proposed = 0;
992 			bp->bp_sync = 0;
993 			bp->bp_agree = 1;
994 			bp->bp_flags |= BSTP_PORT_NEWINFO;
995 			DPRINTF("%s -> ROOT_AGREED\n", bp->bp_ifp->if_xname);
996 		}
997 
998 		if (bp->bp_proposed && !bp->bp_agree) {
999 			bstp_set_all_sync(bs);
1000 			bp->bp_proposed = 0;
1001 			DPRINTF("%s -> ROOT_PROPOSED\n", bp->bp_ifp->if_xname);
1002 		}
1003 
1004 		if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1005 		    (bp->bp_forward_delay_timer.active == 0 ||
1006 		    (bstp_rerooted(bs, bp) &&
1007 		    bp->bp_recent_backup_timer.active == 0 &&
1008 		    bp->bp_protover == BSTP_PROTO_RSTP))) {
1009 			switch (bp->bp_state) {
1010 			case BSTP_IFSTATE_DISCARDING:
1011 				bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1012 				break;
1013 			case BSTP_IFSTATE_LEARNING:
1014 				bstp_set_port_state(bp,
1015 				    BSTP_IFSTATE_FORWARDING);
1016 				break;
1017 			}
1018 		}
1019 
1020 		if (bp->bp_state == BSTP_IFSTATE_FORWARDING && bp->bp_reroot) {
1021 			bp->bp_reroot = 0;
1022 			DPRINTF("%s -> ROOT_REROOTED\n", bp->bp_ifp->if_xname);
1023 		}
1024 		break;
1025 
1026 	case BSTP_ROLE_DESIGNATED:
1027 		if (bp->bp_recent_root_timer.active == 0 && bp->bp_reroot) {
1028 			bp->bp_reroot = 0;
1029 			DPRINTF("%s -> DESIGNATED_RETIRED\n",
1030 			    bp->bp_ifp->if_xname);
1031 		}
1032 
1033 		if ((bp->bp_state == BSTP_IFSTATE_DISCARDING &&
1034 		    !bp->bp_synced) || (bp->bp_agreed && !bp->bp_synced) ||
1035 		    (bp->bp_operedge && !bp->bp_synced) ||
1036 		    (bp->bp_sync && bp->bp_synced)) {
1037 			bstp_timer_stop(&bp->bp_recent_root_timer);
1038 			bp->bp_synced = 1;
1039 			bp->bp_sync = 0;
1040 			DPRINTF("%s -> DESIGNATED_SYNCED\n",
1041 			    bp->bp_ifp->if_xname);
1042 		}
1043 
1044 		if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1045 		    !bp->bp_agreed && !bp->bp_proposing &&
1046 		    !bp->bp_operedge) {
1047 			bp->bp_proposing = 1;
1048 			bp->bp_flags |= BSTP_PORT_NEWINFO;
1049 			bstp_timer_start(&bp->bp_edge_delay_timer,
1050 			    (bp->bp_ptp_link ? BSTP_DEFAULT_MIGRATE_DELAY :
1051 			     bp->bp_desg_max_age));
1052 			DPRINTF("%s -> DESIGNATED_PROPOSE\n",
1053 			    bp->bp_ifp->if_xname);
1054 		}
1055 
1056 		if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1057 		    (bp->bp_forward_delay_timer.active == 0 || bp->bp_agreed ||
1058 		    bp->bp_operedge) &&
1059 		    (bp->bp_recent_root_timer.active == 0 || !bp->bp_reroot) &&
1060 		    !bp->bp_sync) {
1061 			if (bp->bp_agreed)
1062 				DPRINTF("%s -> AGREED\n", bp->bp_ifp->if_xname);
1063 			/*
1064 			 * If agreed|operedge then go straight to forwarding,
1065 			 * otherwise follow discard -> learn -> forward.
1066 			 */
1067 			if (bp->bp_agreed || bp->bp_operedge ||
1068 			    bp->bp_state == BSTP_IFSTATE_LEARNING) {
1069 				bstp_set_port_state(bp,
1070 				    BSTP_IFSTATE_FORWARDING);
1071 				bp->bp_agreed = bp->bp_protover;
1072 			} else if (bp->bp_state == BSTP_IFSTATE_DISCARDING)
1073 				bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1074 		}
1075 
1076 		if (((bp->bp_sync && !bp->bp_synced) ||
1077 		    (bp->bp_reroot && bp->bp_recent_root_timer.active) ||
1078 		    (bp->bp_flags & BSTP_PORT_DISPUTED)) && !bp->bp_operedge &&
1079 		    bp->bp_state != BSTP_IFSTATE_DISCARDING) {
1080 			bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1081 			bp->bp_flags &= ~BSTP_PORT_DISPUTED;
1082 			bstp_timer_start(&bp->bp_forward_delay_timer,
1083 			    bp->bp_protover == BSTP_PROTO_RSTP ?
1084 			    bp->bp_desg_htime : bp->bp_desg_fdelay);
1085 			DPRINTF("%s -> DESIGNATED_DISCARD\n",
1086 			    bp->bp_ifp->if_xname);
1087 		}
1088 		break;
1089 	}
1090 
1091 	if (bp->bp_flags & BSTP_PORT_NEWINFO)
1092 		bstp_transmit(bs, bp);
1093 }
1094 
1095 static void
bstp_update_tc(struct bstp_port * bp)1096 bstp_update_tc(struct bstp_port *bp)
1097 {
1098 	switch (bp->bp_tcstate) {
1099 		case BSTP_TCSTATE_ACTIVE:
1100 			if ((bp->bp_role != BSTP_ROLE_DESIGNATED &&
1101 			    bp->bp_role != BSTP_ROLE_ROOT) || bp->bp_operedge)
1102 				bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1103 
1104 			if (bp->bp_rcvdtcn)
1105 				bstp_set_port_tc(bp, BSTP_TCSTATE_TCN);
1106 			if (bp->bp_rcvdtc)
1107 				bstp_set_port_tc(bp, BSTP_TCSTATE_TC);
1108 
1109 			if (bp->bp_tc_prop && !bp->bp_operedge)
1110 				bstp_set_port_tc(bp, BSTP_TCSTATE_PROPAG);
1111 
1112 			if (bp->bp_rcvdtca)
1113 				bstp_set_port_tc(bp, BSTP_TCSTATE_ACK);
1114 			break;
1115 
1116 		case BSTP_TCSTATE_INACTIVE:
1117 			if ((bp->bp_state == BSTP_IFSTATE_LEARNING ||
1118 			    bp->bp_state == BSTP_IFSTATE_FORWARDING) &&
1119 			    bp->bp_fdbflush == 0)
1120 				bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1121 			break;
1122 
1123 		case BSTP_TCSTATE_LEARNING:
1124 			if (bp->bp_rcvdtc || bp->bp_rcvdtcn || bp->bp_rcvdtca ||
1125 			    bp->bp_tc_prop)
1126 				bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1127 			else if (bp->bp_role != BSTP_ROLE_DESIGNATED &&
1128 				 bp->bp_role != BSTP_ROLE_ROOT &&
1129 				 bp->bp_state == BSTP_IFSTATE_DISCARDING)
1130 				bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
1131 
1132 			if ((bp->bp_role == BSTP_ROLE_DESIGNATED ||
1133 			    bp->bp_role == BSTP_ROLE_ROOT) &&
1134 			    bp->bp_state == BSTP_IFSTATE_FORWARDING &&
1135 			    !bp->bp_operedge)
1136 				bstp_set_port_tc(bp, BSTP_TCSTATE_DETECTED);
1137 			break;
1138 
1139 		/* these are transient states and go straight back to ACTIVE */
1140 		case BSTP_TCSTATE_DETECTED:
1141 		case BSTP_TCSTATE_TCN:
1142 		case BSTP_TCSTATE_TC:
1143 		case BSTP_TCSTATE_PROPAG:
1144 		case BSTP_TCSTATE_ACK:
1145 			DPRINTF("Invalid TC state for %s\n",
1146 			    bp->bp_ifp->if_xname);
1147 			break;
1148 	}
1149 
1150 }
1151 
1152 static void
bstp_update_info(struct bstp_port * bp)1153 bstp_update_info(struct bstp_port *bp)
1154 {
1155 	struct bstp_state *bs = bp->bp_bs;
1156 
1157 	bp->bp_proposing = 0;
1158 	bp->bp_proposed = 0;
1159 
1160 	if (bp->bp_agreed && !bstp_pdu_bettersame(bp, BSTP_INFO_MINE))
1161 		bp->bp_agreed = 0;
1162 
1163 	if (bp->bp_synced && !bp->bp_agreed) {
1164 		bp->bp_synced = 0;
1165 		bs->bs_allsynced = 0;
1166 	}
1167 
1168 	/* copy the designated pv to the port */
1169 	bp->bp_port_pv = bp->bp_desg_pv;
1170 	bp->bp_port_msg_age = bp->bp_desg_msg_age;
1171 	bp->bp_port_max_age = bp->bp_desg_max_age;
1172 	bp->bp_port_fdelay = bp->bp_desg_fdelay;
1173 	bp->bp_port_htime = bp->bp_desg_htime;
1174 	bp->bp_infois = BSTP_INFO_MINE;
1175 
1176 	/* Set transmit flag but do not immediately send */
1177 	bp->bp_flags |= BSTP_PORT_NEWINFO;
1178 }
1179 
1180 /* set tcprop on every port other than the caller */
1181 static void
bstp_set_other_tcprop(struct bstp_port * bp)1182 bstp_set_other_tcprop(struct bstp_port *bp)
1183 {
1184 	struct bstp_state *bs = bp->bp_bs;
1185 	struct bstp_port *bp2;
1186 
1187 	BSTP_LOCK_ASSERT(bs);
1188 
1189 	LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1190 		if (bp2 == bp)
1191 			continue;
1192 		bp2->bp_tc_prop = 1;
1193 	}
1194 }
1195 
1196 static void
bstp_set_all_reroot(struct bstp_state * bs)1197 bstp_set_all_reroot(struct bstp_state *bs)
1198 {
1199 	struct bstp_port *bp;
1200 
1201 	BSTP_LOCK_ASSERT(bs);
1202 
1203 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1204 		bp->bp_reroot = 1;
1205 }
1206 
1207 static void
bstp_set_all_sync(struct bstp_state * bs)1208 bstp_set_all_sync(struct bstp_state *bs)
1209 {
1210 	struct bstp_port *bp;
1211 
1212 	BSTP_LOCK_ASSERT(bs);
1213 
1214 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1215 		bp->bp_sync = 1;
1216 		bp->bp_synced = 0;	/* Not explicit in spec */
1217 	}
1218 
1219 	bs->bs_allsynced = 0;
1220 }
1221 
1222 static void
bstp_set_port_state(struct bstp_port * bp,int state)1223 bstp_set_port_state(struct bstp_port *bp, int state)
1224 {
1225 	if (bp->bp_state == state)
1226 		return;
1227 
1228 	bp->bp_state = state;
1229 
1230 	switch (bp->bp_state) {
1231 		case BSTP_IFSTATE_DISCARDING:
1232 			DPRINTF("state changed to DISCARDING on %s\n",
1233 			    bp->bp_ifp->if_xname);
1234 			break;
1235 
1236 		case BSTP_IFSTATE_LEARNING:
1237 			DPRINTF("state changed to LEARNING on %s\n",
1238 			    bp->bp_ifp->if_xname);
1239 
1240 			bstp_timer_start(&bp->bp_forward_delay_timer,
1241 			    bp->bp_protover == BSTP_PROTO_RSTP ?
1242 			    bp->bp_desg_htime : bp->bp_desg_fdelay);
1243 			break;
1244 
1245 		case BSTP_IFSTATE_FORWARDING:
1246 			DPRINTF("state changed to FORWARDING on %s\n",
1247 			    bp->bp_ifp->if_xname);
1248 
1249 			bstp_timer_stop(&bp->bp_forward_delay_timer);
1250 			/* Record that we enabled forwarding */
1251 			bp->bp_forward_transitions++;
1252 			break;
1253 	}
1254 
1255 	/* notify the parent bridge */
1256 	taskqueue_enqueue(taskqueue_swi, &bp->bp_statetask);
1257 }
1258 
1259 static void
bstp_set_port_role(struct bstp_port * bp,int role)1260 bstp_set_port_role(struct bstp_port *bp, int role)
1261 {
1262 	struct bstp_state *bs = bp->bp_bs;
1263 
1264 	if (bp->bp_role == role)
1265 		return;
1266 
1267 	/* perform pre-change tasks */
1268 	switch (bp->bp_role) {
1269 		case BSTP_ROLE_DISABLED:
1270 			bstp_timer_start(&bp->bp_forward_delay_timer,
1271 			    bp->bp_desg_max_age);
1272 			break;
1273 
1274 		case BSTP_ROLE_BACKUP:
1275 			bstp_timer_start(&bp->bp_recent_backup_timer,
1276 			    bp->bp_desg_htime * 2);
1277 			/* fall through */
1278 		case BSTP_ROLE_ALTERNATE:
1279 			bstp_timer_start(&bp->bp_forward_delay_timer,
1280 			    bp->bp_desg_fdelay);
1281 			bp->bp_sync = 0;
1282 			bp->bp_synced = 1;
1283 			bp->bp_reroot = 0;
1284 			break;
1285 
1286 		case BSTP_ROLE_ROOT:
1287 			bstp_timer_start(&bp->bp_recent_root_timer,
1288 			    BSTP_DEFAULT_FORWARD_DELAY);
1289 			break;
1290 	}
1291 
1292 	bp->bp_role = role;
1293 	/* clear values not carried between roles */
1294 	bp->bp_proposing = 0;
1295 	bs->bs_allsynced = 0;
1296 
1297 	/* initialise the new role */
1298 	switch (bp->bp_role) {
1299 		case BSTP_ROLE_DISABLED:
1300 		case BSTP_ROLE_ALTERNATE:
1301 		case BSTP_ROLE_BACKUP:
1302 			DPRINTF("%s role -> ALT/BACK/DISABLED\n",
1303 			    bp->bp_ifp->if_xname);
1304 			bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1305 			bstp_timer_stop(&bp->bp_recent_root_timer);
1306 			bstp_timer_latch(&bp->bp_forward_delay_timer);
1307 			bp->bp_sync = 0;
1308 			bp->bp_synced = 1;
1309 			bp->bp_reroot = 0;
1310 			break;
1311 
1312 		case BSTP_ROLE_ROOT:
1313 			DPRINTF("%s role -> ROOT\n",
1314 			    bp->bp_ifp->if_xname);
1315 			bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1316 			bstp_timer_latch(&bp->bp_recent_root_timer);
1317 			bp->bp_proposing = 0;
1318 			break;
1319 
1320 		case BSTP_ROLE_DESIGNATED:
1321 			DPRINTF("%s role -> DESIGNATED\n",
1322 			    bp->bp_ifp->if_xname);
1323 			bstp_timer_start(&bp->bp_hello_timer,
1324 			    bp->bp_desg_htime);
1325 			bp->bp_agree = 0;
1326 			break;
1327 	}
1328 
1329 	/* let the TC state know that the role changed */
1330 	bstp_update_tc(bp);
1331 }
1332 
1333 static void
bstp_set_port_proto(struct bstp_port * bp,int proto)1334 bstp_set_port_proto(struct bstp_port *bp, int proto)
1335 {
1336 	struct bstp_state *bs = bp->bp_bs;
1337 
1338 	/* supported protocol versions */
1339 	switch (proto) {
1340 		case BSTP_PROTO_STP:
1341 			/* we can downgrade protocols only */
1342 			bstp_timer_stop(&bp->bp_migrate_delay_timer);
1343 			/* clear unsupported features */
1344 			bp->bp_operedge = 0;
1345 			/* STP compat mode only uses 16 bits of the 32 */
1346 			if (bp->bp_path_cost > 65535)
1347 				bp->bp_path_cost = 65535;
1348 			break;
1349 
1350 		case BSTP_PROTO_RSTP:
1351 			bstp_timer_start(&bp->bp_migrate_delay_timer,
1352 			    bs->bs_migration_delay);
1353 			break;
1354 
1355 		default:
1356 			DPRINTF("Unsupported STP version %d\n", proto);
1357 			return;
1358 	}
1359 
1360 	bp->bp_protover = proto;
1361 	bp->bp_flags &= ~BSTP_PORT_CANMIGRATE;
1362 }
1363 
1364 static void
bstp_set_port_tc(struct bstp_port * bp,int state)1365 bstp_set_port_tc(struct bstp_port *bp, int state)
1366 {
1367 	struct bstp_state *bs = bp->bp_bs;
1368 
1369 	bp->bp_tcstate = state;
1370 
1371 	/* initialise the new state */
1372 	switch (bp->bp_tcstate) {
1373 		case BSTP_TCSTATE_ACTIVE:
1374 			DPRINTF("%s -> TC_ACTIVE\n", bp->bp_ifp->if_xname);
1375 			/* nothing to do */
1376 			break;
1377 
1378 		case BSTP_TCSTATE_INACTIVE:
1379 			bstp_timer_stop(&bp->bp_tc_timer);
1380 			/* flush routes on the parent bridge */
1381 			bp->bp_fdbflush = 1;
1382 			taskqueue_enqueue(taskqueue_swi, &bp->bp_rtagetask);
1383 			bp->bp_tc_ack = 0;
1384 			DPRINTF("%s -> TC_INACTIVE\n", bp->bp_ifp->if_xname);
1385 			break;
1386 
1387 		case BSTP_TCSTATE_LEARNING:
1388 			bp->bp_rcvdtc = 0;
1389 			bp->bp_rcvdtcn = 0;
1390 			bp->bp_rcvdtca = 0;
1391 			bp->bp_tc_prop = 0;
1392 			DPRINTF("%s -> TC_LEARNING\n", bp->bp_ifp->if_xname);
1393 			break;
1394 
1395 		case BSTP_TCSTATE_DETECTED:
1396 			bstp_set_timer_tc(bp);
1397 			bstp_set_other_tcprop(bp);
1398 			/* send out notification */
1399 			bp->bp_flags |= BSTP_PORT_NEWINFO;
1400 			bstp_transmit(bs, bp);
1401 			getmicrotime(&bs->bs_last_tc_time);
1402 			DPRINTF("%s -> TC_DETECTED\n", bp->bp_ifp->if_xname);
1403 			bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1404 			break;
1405 
1406 		case BSTP_TCSTATE_TCN:
1407 			bstp_set_timer_tc(bp);
1408 			DPRINTF("%s -> TC_TCN\n", bp->bp_ifp->if_xname);
1409 			/* fall through */
1410 		case BSTP_TCSTATE_TC:
1411 			bp->bp_rcvdtc = 0;
1412 			bp->bp_rcvdtcn = 0;
1413 			if (bp->bp_role == BSTP_ROLE_DESIGNATED)
1414 				bp->bp_tc_ack = 1;
1415 
1416 			bstp_set_other_tcprop(bp);
1417 			DPRINTF("%s -> TC_TC\n", bp->bp_ifp->if_xname);
1418 			bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1419 			break;
1420 
1421 		case BSTP_TCSTATE_PROPAG:
1422 			/* flush routes on the parent bridge */
1423 			bp->bp_fdbflush = 1;
1424 			taskqueue_enqueue(taskqueue_swi, &bp->bp_rtagetask);
1425 			bp->bp_tc_prop = 0;
1426 			bstp_set_timer_tc(bp);
1427 			DPRINTF("%s -> TC_PROPAG\n", bp->bp_ifp->if_xname);
1428 			bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1429 			break;
1430 
1431 		case BSTP_TCSTATE_ACK:
1432 			bstp_timer_stop(&bp->bp_tc_timer);
1433 			bp->bp_rcvdtca = 0;
1434 			DPRINTF("%s -> TC_ACK\n", bp->bp_ifp->if_xname);
1435 			bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1436 			break;
1437 	}
1438 }
1439 
1440 static void
bstp_set_timer_tc(struct bstp_port * bp)1441 bstp_set_timer_tc(struct bstp_port *bp)
1442 {
1443 	struct bstp_state *bs = bp->bp_bs;
1444 
1445 	if (bp->bp_tc_timer.active)
1446 		return;
1447 
1448 	switch (bp->bp_protover) {
1449 		case BSTP_PROTO_RSTP:
1450 			bstp_timer_start(&bp->bp_tc_timer,
1451 			    bp->bp_desg_htime + BSTP_TICK_VAL);
1452 			bp->bp_flags |= BSTP_PORT_NEWINFO;
1453 			break;
1454 
1455 		case BSTP_PROTO_STP:
1456 			bstp_timer_start(&bp->bp_tc_timer,
1457 			    bs->bs_root_max_age + bs->bs_root_fdelay);
1458 			break;
1459 	}
1460 }
1461 
1462 static void
bstp_set_timer_msgage(struct bstp_port * bp)1463 bstp_set_timer_msgage(struct bstp_port *bp)
1464 {
1465 	if (bp->bp_port_msg_age + BSTP_MESSAGE_AGE_INCR <=
1466 	    bp->bp_port_max_age) {
1467 		bstp_timer_start(&bp->bp_message_age_timer,
1468 		    bp->bp_port_htime * 3);
1469 	} else
1470 		/* expires immediately */
1471 		bstp_timer_start(&bp->bp_message_age_timer, 0);
1472 }
1473 
1474 static int
bstp_rerooted(struct bstp_state * bs,struct bstp_port * bp)1475 bstp_rerooted(struct bstp_state *bs, struct bstp_port *bp)
1476 {
1477 	struct bstp_port *bp2;
1478 	int rr_set = 0;
1479 
1480 	LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1481 		if (bp2 == bp)
1482 			continue;
1483 		if (bp2->bp_recent_root_timer.active) {
1484 			rr_set = 1;
1485 			break;
1486 		}
1487 	}
1488 	return (!rr_set);
1489 }
1490 
1491 int
bstp_set_htime(struct bstp_state * bs,int t)1492 bstp_set_htime(struct bstp_state *bs, int t)
1493 {
1494 	/* convert seconds to ticks */
1495 	t *=  BSTP_TICK_VAL;
1496 
1497 	/* value can only be changed in leagacy stp mode */
1498 	if (bs->bs_protover != BSTP_PROTO_STP)
1499 		return (EPERM);
1500 
1501 	if (t < BSTP_MIN_HELLO_TIME || t > BSTP_MAX_HELLO_TIME)
1502 		return (EINVAL);
1503 
1504 	BSTP_LOCK(bs);
1505 	bs->bs_bridge_htime = t;
1506 	bstp_reinit(bs);
1507 	BSTP_UNLOCK(bs);
1508 	return (0);
1509 }
1510 
1511 int
bstp_set_fdelay(struct bstp_state * bs,int t)1512 bstp_set_fdelay(struct bstp_state *bs, int t)
1513 {
1514 	/* convert seconds to ticks */
1515 	t *= BSTP_TICK_VAL;
1516 
1517 	if (t < BSTP_MIN_FORWARD_DELAY || t > BSTP_MAX_FORWARD_DELAY)
1518 		return (EINVAL);
1519 
1520 	BSTP_LOCK(bs);
1521 	bs->bs_bridge_fdelay = t;
1522 	bstp_reinit(bs);
1523 	BSTP_UNLOCK(bs);
1524 	return (0);
1525 }
1526 
1527 int
bstp_set_maxage(struct bstp_state * bs,int t)1528 bstp_set_maxage(struct bstp_state *bs, int t)
1529 {
1530 	/* convert seconds to ticks */
1531 	t *= BSTP_TICK_VAL;
1532 
1533 	if (t < BSTP_MIN_MAX_AGE || t > BSTP_MAX_MAX_AGE)
1534 		return (EINVAL);
1535 
1536 	BSTP_LOCK(bs);
1537 	bs->bs_bridge_max_age = t;
1538 	bstp_reinit(bs);
1539 	BSTP_UNLOCK(bs);
1540 	return (0);
1541 }
1542 
1543 int
bstp_set_holdcount(struct bstp_state * bs,int count)1544 bstp_set_holdcount(struct bstp_state *bs, int count)
1545 {
1546 	struct bstp_port *bp;
1547 
1548 	if (count < BSTP_MIN_HOLD_COUNT ||
1549 	    count > BSTP_MAX_HOLD_COUNT)
1550 		return (EINVAL);
1551 
1552 	BSTP_LOCK(bs);
1553 	bs->bs_txholdcount = count;
1554 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1555 		bp->bp_txcount = 0;
1556 	BSTP_UNLOCK(bs);
1557 	return (0);
1558 }
1559 
1560 int
bstp_set_protocol(struct bstp_state * bs,int proto)1561 bstp_set_protocol(struct bstp_state *bs, int proto)
1562 {
1563 	struct bstp_port *bp;
1564 
1565 	switch (proto) {
1566 		/* Supported protocol versions */
1567 		case BSTP_PROTO_STP:
1568 		case BSTP_PROTO_RSTP:
1569 			break;
1570 
1571 		default:
1572 			return (EINVAL);
1573 	}
1574 
1575 	BSTP_LOCK(bs);
1576 	bs->bs_protover = proto;
1577 	bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
1578 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1579 		/* reinit state */
1580 		bp->bp_infois = BSTP_INFO_DISABLED;
1581 		bp->bp_txcount = 0;
1582 		bstp_set_port_proto(bp, bs->bs_protover);
1583 		bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
1584 		bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
1585 		bstp_timer_stop(&bp->bp_recent_backup_timer);
1586 	}
1587 	bstp_reinit(bs);
1588 	BSTP_UNLOCK(bs);
1589 	return (0);
1590 }
1591 
1592 int
bstp_set_priority(struct bstp_state * bs,int pri)1593 bstp_set_priority(struct bstp_state *bs, int pri)
1594 {
1595 	if (pri < 0 || pri > BSTP_MAX_PRIORITY)
1596 		return (EINVAL);
1597 
1598 	/* Limit to steps of 4096 */
1599 	pri -= pri % 4096;
1600 
1601 	BSTP_LOCK(bs);
1602 	bs->bs_bridge_priority = pri;
1603 	bstp_reinit(bs);
1604 	BSTP_UNLOCK(bs);
1605 	return (0);
1606 }
1607 
1608 int
bstp_set_port_priority(struct bstp_port * bp,int pri)1609 bstp_set_port_priority(struct bstp_port *bp, int pri)
1610 {
1611 	struct bstp_state *bs = bp->bp_bs;
1612 
1613 	if (pri < 0 || pri > BSTP_MAX_PORT_PRIORITY)
1614 		return (EINVAL);
1615 
1616 	/* Limit to steps of 16 */
1617 	pri -= pri % 16;
1618 
1619 	BSTP_LOCK(bs);
1620 	bp->bp_priority = pri;
1621 	bstp_reinit(bs);
1622 	BSTP_UNLOCK(bs);
1623 	return (0);
1624 }
1625 
1626 int
bstp_set_path_cost(struct bstp_port * bp,uint32_t path_cost)1627 bstp_set_path_cost(struct bstp_port *bp, uint32_t path_cost)
1628 {
1629 	struct bstp_state *bs = bp->bp_bs;
1630 
1631 	if (path_cost > BSTP_MAX_PATH_COST)
1632 		return (EINVAL);
1633 
1634 	/* STP compat mode only uses 16 bits of the 32 */
1635 	if (bp->bp_protover == BSTP_PROTO_STP && path_cost > 65535)
1636 		path_cost = 65535;
1637 
1638 	BSTP_LOCK(bs);
1639 
1640 	if (path_cost == 0) {	/* use auto */
1641 		bp->bp_flags &= ~BSTP_PORT_ADMCOST;
1642 		bp->bp_path_cost = bstp_calc_path_cost(bp);
1643 	} else {
1644 		bp->bp_path_cost = path_cost;
1645 		bp->bp_flags |= BSTP_PORT_ADMCOST;
1646 	}
1647 	bstp_reinit(bs);
1648 	BSTP_UNLOCK(bs);
1649 	return (0);
1650 }
1651 
1652 int
bstp_set_edge(struct bstp_port * bp,int set)1653 bstp_set_edge(struct bstp_port *bp, int set)
1654 {
1655 	struct bstp_state *bs = bp->bp_bs;
1656 
1657 	BSTP_LOCK(bs);
1658 	if ((bp->bp_operedge = set) == 0)
1659 		bp->bp_flags &= ~BSTP_PORT_ADMEDGE;
1660 	else
1661 		bp->bp_flags |= BSTP_PORT_ADMEDGE;
1662 	BSTP_UNLOCK(bs);
1663 	return (0);
1664 }
1665 
1666 int
bstp_set_autoedge(struct bstp_port * bp,int set)1667 bstp_set_autoedge(struct bstp_port *bp, int set)
1668 {
1669 	struct bstp_state *bs = bp->bp_bs;
1670 
1671 	BSTP_LOCK(bs);
1672 	if (set) {
1673 		bp->bp_flags |= BSTP_PORT_AUTOEDGE;
1674 		/* we may be able to transition straight to edge */
1675 		if (bp->bp_edge_delay_timer.active == 0)
1676 			bstp_edge_delay_expiry(bs, bp);
1677 	} else
1678 		bp->bp_flags &= ~BSTP_PORT_AUTOEDGE;
1679 	BSTP_UNLOCK(bs);
1680 	return (0);
1681 }
1682 
1683 int
bstp_set_ptp(struct bstp_port * bp,int set)1684 bstp_set_ptp(struct bstp_port *bp, int set)
1685 {
1686 	struct bstp_state *bs = bp->bp_bs;
1687 
1688 	BSTP_LOCK(bs);
1689 	bp->bp_ptp_link = set;
1690 	BSTP_UNLOCK(bs);
1691 	return (0);
1692 }
1693 
1694 int
bstp_set_autoptp(struct bstp_port * bp,int set)1695 bstp_set_autoptp(struct bstp_port *bp, int set)
1696 {
1697 	struct bstp_state *bs = bp->bp_bs;
1698 
1699 	BSTP_LOCK(bs);
1700 	if (set) {
1701 		bp->bp_flags |= BSTP_PORT_AUTOPTP;
1702 		if (bp->bp_role != BSTP_ROLE_DISABLED)
1703 			taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
1704 	} else
1705 		bp->bp_flags &= ~BSTP_PORT_AUTOPTP;
1706 	BSTP_UNLOCK(bs);
1707 	return (0);
1708 }
1709 
1710 /*
1711  * Calculate the path cost according to the link speed.
1712  */
1713 static uint32_t
bstp_calc_path_cost(struct bstp_port * bp)1714 bstp_calc_path_cost(struct bstp_port *bp)
1715 {
1716 	struct ifnet *ifp = bp->bp_ifp;
1717 	uint32_t path_cost;
1718 
1719 	/* If the priority has been manually set then retain the value */
1720 	if (bp->bp_flags & BSTP_PORT_ADMCOST)
1721 		return bp->bp_path_cost;
1722 
1723 	if (ifp->if_link_state == LINK_STATE_DOWN) {
1724 		/* Recalc when the link comes up again */
1725 		bp->bp_flags |= BSTP_PORT_PNDCOST;
1726 		return (BSTP_DEFAULT_PATH_COST);
1727 	}
1728 
1729 	if (ifp->if_baudrate < 1000)
1730 		return (BSTP_DEFAULT_PATH_COST);
1731 
1732  	/* formula from section 17.14, IEEE Std 802.1D-2004 */
1733 	path_cost = 20000000000ULL / (ifp->if_baudrate / 1000);
1734 
1735 	if (path_cost > BSTP_MAX_PATH_COST)
1736 		path_cost = BSTP_MAX_PATH_COST;
1737 
1738 	/* STP compat mode only uses 16 bits of the 32 */
1739 	if (bp->bp_protover == BSTP_PROTO_STP && path_cost > 65535)
1740 		path_cost = 65535;
1741 
1742 	return (path_cost);
1743 }
1744 
1745 /*
1746  * Notify the bridge that a port state has changed, we need to do this from a
1747  * taskqueue to avoid a LOR.
1748  */
1749 static void
bstp_notify_state(void * arg,int pending)1750 bstp_notify_state(void *arg, int pending)
1751 {
1752 	struct bstp_port *bp = (struct bstp_port *)arg;
1753 	struct bstp_state *bs = bp->bp_bs;
1754 
1755 	if (bp->bp_active == 1 && bs->bs_state_cb != NULL)
1756 		(*bs->bs_state_cb)(bp->bp_ifp, bp->bp_state);
1757 }
1758 
1759 /*
1760  * Flush the routes on the bridge port, we need to do this from a
1761  * taskqueue to avoid a LOR.
1762  */
1763 static void
bstp_notify_rtage(void * arg,int pending)1764 bstp_notify_rtage(void *arg, int pending)
1765 {
1766 	struct bstp_port *bp = (struct bstp_port *)arg;
1767 	struct bstp_state *bs = bp->bp_bs;
1768 	int age = 0;
1769 
1770 	BSTP_LOCK(bs);
1771 	switch (bp->bp_protover) {
1772 		case BSTP_PROTO_STP:
1773 			/* convert to seconds */
1774 			age = bp->bp_desg_fdelay / BSTP_TICK_VAL;
1775 			break;
1776 
1777 		case BSTP_PROTO_RSTP:
1778 			age = 0;
1779 			break;
1780 	}
1781 	BSTP_UNLOCK(bs);
1782 
1783 	if (bp->bp_active == 1 && bs->bs_rtage_cb != NULL)
1784 		(*bs->bs_rtage_cb)(bp->bp_ifp, age);
1785 
1786 	/* flush is complete */
1787 	BSTP_LOCK(bs);
1788 	bp->bp_fdbflush = 0;
1789 	BSTP_UNLOCK(bs);
1790 }
1791 
1792 void
bstp_linkstate(struct bstp_port * bp)1793 bstp_linkstate(struct bstp_port *bp)
1794 {
1795 	struct bstp_state *bs = bp->bp_bs;
1796 
1797 	if (!bp->bp_active)
1798 		return;
1799 
1800 	bstp_ifupdstatus(bp, 0);
1801 	BSTP_LOCK(bs);
1802 	bstp_update_state(bs, bp);
1803 	BSTP_UNLOCK(bs);
1804 }
1805 
1806 static void
bstp_ifupdstatus(void * arg,int pending)1807 bstp_ifupdstatus(void *arg, int pending)
1808 {
1809 	struct bstp_port *bp = (struct bstp_port *)arg;
1810 	struct bstp_state *bs = bp->bp_bs;
1811 	struct ifnet *ifp = bp->bp_ifp;
1812 	struct ifmediareq ifmr;
1813 	int error, changed;
1814 
1815 	if (!bp->bp_active)
1816 		return;
1817 
1818 	bzero((char *)&ifmr, sizeof(ifmr));
1819 	error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
1820 
1821 	BSTP_LOCK(bs);
1822 	changed = 0;
1823 	if ((error == 0) && (ifp->if_flags & IFF_UP)) {
1824 		if (ifmr.ifm_status & IFM_ACTIVE) {
1825 			/* A full-duplex link is assumed to be point to point */
1826 			if (bp->bp_flags & BSTP_PORT_AUTOPTP) {
1827 				int fdx;
1828 
1829 				fdx = ifmr.ifm_active & IFM_FDX ? 1 : 0;
1830 				if (bp->bp_ptp_link ^ fdx) {
1831 					bp->bp_ptp_link = fdx;
1832 					changed = 1;
1833 				}
1834 			}
1835 
1836 			/* Calc the cost if the link was down previously */
1837 			if (bp->bp_flags & BSTP_PORT_PNDCOST) {
1838 				uint32_t cost;
1839 
1840 				cost = bstp_calc_path_cost(bp);
1841 				if (bp->bp_path_cost != cost) {
1842 					bp->bp_path_cost = cost;
1843 					changed = 1;
1844 				}
1845 				bp->bp_flags &= ~BSTP_PORT_PNDCOST;
1846 			}
1847 
1848 			if (bp->bp_role == BSTP_ROLE_DISABLED) {
1849 				bstp_enable_port(bs, bp);
1850 				changed = 1;
1851 			}
1852 		} else {
1853 			if (bp->bp_role != BSTP_ROLE_DISABLED) {
1854 				bstp_disable_port(bs, bp);
1855 				changed = 1;
1856 				if ((bp->bp_flags & BSTP_PORT_ADMEDGE) &&
1857 				    bp->bp_protover == BSTP_PROTO_RSTP)
1858 					bp->bp_operedge = 1;
1859 			}
1860 		}
1861 	} else if (bp->bp_infois != BSTP_INFO_DISABLED) {
1862 		bstp_disable_port(bs, bp);
1863 		changed = 1;
1864 	}
1865 	if (changed)
1866 		bstp_assign_roles(bs);
1867 	BSTP_UNLOCK(bs);
1868 }
1869 
1870 static void
bstp_enable_port(struct bstp_state * bs,struct bstp_port * bp)1871 bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp)
1872 {
1873 	bp->bp_infois = BSTP_INFO_AGED;
1874 }
1875 
1876 static void
bstp_disable_port(struct bstp_state * bs,struct bstp_port * bp)1877 bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp)
1878 {
1879 	bp->bp_infois = BSTP_INFO_DISABLED;
1880 }
1881 
1882 static void
bstp_tick(void * arg)1883 bstp_tick(void *arg)
1884 {
1885 	struct epoch_tracker et;
1886 	struct bstp_state *bs = arg;
1887 	struct bstp_port *bp;
1888 
1889 	BSTP_LOCK_ASSERT(bs);
1890 
1891 	if (bs->bs_running == 0)
1892 		return;
1893 
1894 	NET_EPOCH_ENTER(et);
1895 	CURVNET_SET(bs->bs_vnet);
1896 
1897 	/* poll link events on interfaces that do not support linkstate */
1898 	if (bstp_timer_dectest(&bs->bs_link_timer)) {
1899 		LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1900 			if (!(bp->bp_ifp->if_capabilities & IFCAP_LINKSTATE))
1901 				taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
1902 		}
1903 		bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
1904 	}
1905 
1906 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1907 		/* no events need to happen for these */
1908 		bstp_timer_dectest(&bp->bp_tc_timer);
1909 		bstp_timer_dectest(&bp->bp_recent_root_timer);
1910 		bstp_timer_dectest(&bp->bp_forward_delay_timer);
1911 		bstp_timer_dectest(&bp->bp_recent_backup_timer);
1912 
1913 		if (bstp_timer_dectest(&bp->bp_hello_timer))
1914 			bstp_hello_timer_expiry(bs, bp);
1915 
1916 		if (bstp_timer_dectest(&bp->bp_message_age_timer))
1917 			bstp_message_age_expiry(bs, bp);
1918 
1919 		if (bstp_timer_dectest(&bp->bp_migrate_delay_timer))
1920 			bstp_migrate_delay_expiry(bs, bp);
1921 
1922 		if (bstp_timer_dectest(&bp->bp_edge_delay_timer))
1923 			bstp_edge_delay_expiry(bs, bp);
1924 
1925 		/* update the various state machines for the port */
1926 		bstp_update_state(bs, bp);
1927 
1928 		if (bp->bp_txcount > 0)
1929 			bp->bp_txcount--;
1930 	}
1931 
1932 	CURVNET_RESTORE();
1933 	NET_EPOCH_EXIT(et);
1934 
1935 	callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
1936 }
1937 
1938 static void
bstp_timer_start(struct bstp_timer * t,uint16_t v)1939 bstp_timer_start(struct bstp_timer *t, uint16_t v)
1940 {
1941 	t->value = v;
1942 	t->active = 1;
1943 	t->latched = 0;
1944 }
1945 
1946 static void
bstp_timer_stop(struct bstp_timer * t)1947 bstp_timer_stop(struct bstp_timer *t)
1948 {
1949 	t->value = 0;
1950 	t->active = 0;
1951 	t->latched = 0;
1952 }
1953 
1954 static void
bstp_timer_latch(struct bstp_timer * t)1955 bstp_timer_latch(struct bstp_timer *t)
1956 {
1957 	t->latched = 1;
1958 	t->active = 1;
1959 }
1960 
1961 static int
bstp_timer_dectest(struct bstp_timer * t)1962 bstp_timer_dectest(struct bstp_timer *t)
1963 {
1964 	if (t->active == 0 || t->latched)
1965 		return (0);
1966 	t->value -= BSTP_TICK_VAL;
1967 	if (t->value <= 0) {
1968 		bstp_timer_stop(t);
1969 		return (1);
1970 	}
1971 	return (0);
1972 }
1973 
1974 static void
bstp_hello_timer_expiry(struct bstp_state * bs,struct bstp_port * bp)1975 bstp_hello_timer_expiry(struct bstp_state *bs, struct bstp_port *bp)
1976 {
1977 	if ((bp->bp_flags & BSTP_PORT_NEWINFO) ||
1978 	    bp->bp_role == BSTP_ROLE_DESIGNATED ||
1979 	    (bp->bp_role == BSTP_ROLE_ROOT &&
1980 	     bp->bp_tc_timer.active == 1)) {
1981 		bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
1982 		bp->bp_flags |= BSTP_PORT_NEWINFO;
1983 		bstp_transmit(bs, bp);
1984 	}
1985 }
1986 
1987 static void
bstp_message_age_expiry(struct bstp_state * bs,struct bstp_port * bp)1988 bstp_message_age_expiry(struct bstp_state *bs, struct bstp_port *bp)
1989 {
1990 	if (bp->bp_infois == BSTP_INFO_RECEIVED) {
1991 		bp->bp_infois = BSTP_INFO_AGED;
1992 		bstp_assign_roles(bs);
1993 		DPRINTF("aged info on %s\n", bp->bp_ifp->if_xname);
1994 	}
1995 }
1996 
1997 static void
bstp_migrate_delay_expiry(struct bstp_state * bs,struct bstp_port * bp)1998 bstp_migrate_delay_expiry(struct bstp_state *bs, struct bstp_port *bp)
1999 {
2000 	bp->bp_flags |= BSTP_PORT_CANMIGRATE;
2001 }
2002 
2003 static void
bstp_edge_delay_expiry(struct bstp_state * bs,struct bstp_port * bp)2004 bstp_edge_delay_expiry(struct bstp_state *bs, struct bstp_port *bp)
2005 {
2006 	if ((bp->bp_flags & BSTP_PORT_AUTOEDGE) &&
2007 	    bp->bp_protover == BSTP_PROTO_RSTP && bp->bp_proposing &&
2008 	    bp->bp_role == BSTP_ROLE_DESIGNATED) {
2009 		bp->bp_operedge = 1;
2010 		DPRINTF("%s -> edge port\n", bp->bp_ifp->if_xname);
2011 	}
2012 }
2013 
2014 static int
bstp_addr_cmp(const uint8_t * a,const uint8_t * b)2015 bstp_addr_cmp(const uint8_t *a, const uint8_t *b)
2016 {
2017 	int i, d;
2018 
2019 	for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
2020 		d = ((int)a[i]) - ((int)b[i]);
2021 	}
2022 
2023 	return (d);
2024 }
2025 
2026 /*
2027  * compare the bridge address component of the bridgeid
2028  */
2029 static int
bstp_same_bridgeid(uint64_t id1,uint64_t id2)2030 bstp_same_bridgeid(uint64_t id1, uint64_t id2)
2031 {
2032 	u_char addr1[ETHER_ADDR_LEN];
2033 	u_char addr2[ETHER_ADDR_LEN];
2034 
2035 	PV2ADDR(id1, addr1);
2036 	PV2ADDR(id2, addr2);
2037 
2038 	if (bstp_addr_cmp(addr1, addr2) == 0)
2039 		return (1);
2040 
2041 	return (0);
2042 }
2043 
2044 void
bstp_reinit(struct bstp_state * bs)2045 bstp_reinit(struct bstp_state *bs)
2046 {
2047 	struct epoch_tracker et;
2048 	struct bstp_port *bp;
2049 	struct ifnet *ifp, *mif;
2050 	u_char *e_addr;
2051 	void *bridgeptr;
2052 	static const u_char llzero[ETHER_ADDR_LEN];	/* 00:00:00:00:00:00 */
2053 
2054 	BSTP_LOCK_ASSERT(bs);
2055 
2056 	if (LIST_EMPTY(&bs->bs_bplist))
2057 		goto disablestp;
2058 
2059 	mif = NULL;
2060 	bridgeptr = LIST_FIRST(&bs->bs_bplist)->bp_ifp->if_bridge;
2061 	KASSERT(bridgeptr != NULL, ("Invalid bridge pointer"));
2062 	/*
2063 	 * Search through the Ethernet adapters and find the one with the
2064 	 * lowest value. Make sure the adapter which we take the MAC address
2065 	 * from is part of this bridge, so we can have more than one independent
2066 	 * bridges in the same STP domain.
2067 	 */
2068 	NET_EPOCH_ENTER(et);
2069 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2070 		if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN)
2071 			continue;	/* Not Ethernet */
2072 
2073 		if (ifp->if_bridge != bridgeptr)
2074 			continue;	/* Not part of our bridge */
2075 
2076 		if (bstp_addr_cmp(IF_LLADDR(ifp), llzero) == 0)
2077 			continue;	/* No mac address set */
2078 
2079 		if (mif == NULL) {
2080 			mif = ifp;
2081 			continue;
2082 		}
2083 		if (bstp_addr_cmp(IF_LLADDR(ifp), IF_LLADDR(mif)) < 0) {
2084 			mif = ifp;
2085 			continue;
2086 		}
2087 	}
2088 	NET_EPOCH_EXIT(et);
2089 	if (mif == NULL)
2090 		goto disablestp;
2091 
2092 	e_addr = IF_LLADDR(mif);
2093 	bs->bs_bridge_pv.pv_dbridge_id =
2094 	    (((uint64_t)bs->bs_bridge_priority) << 48) |
2095 	    (((uint64_t)e_addr[0]) << 40) |
2096 	    (((uint64_t)e_addr[1]) << 32) |
2097 	    (((uint64_t)e_addr[2]) << 24) |
2098 	    (((uint64_t)e_addr[3]) << 16) |
2099 	    (((uint64_t)e_addr[4]) << 8) |
2100 	    (((uint64_t)e_addr[5]));
2101 
2102 	bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id;
2103 	bs->bs_bridge_pv.pv_cost = 0;
2104 	bs->bs_bridge_pv.pv_dport_id = 0;
2105 	bs->bs_bridge_pv.pv_port_id = 0;
2106 
2107 	if (bs->bs_running && callout_pending(&bs->bs_bstpcallout) == 0)
2108 		callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
2109 
2110 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2111 		bp->bp_port_id = (bp->bp_priority << 8) |
2112 		    (bp->bp_ifp->if_index  & 0xfff);
2113 		taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
2114 	}
2115 
2116 	bstp_assign_roles(bs);
2117 	bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
2118 	return;
2119 
2120 disablestp:
2121 	/* Set the bridge and root id (lower bits) to zero */
2122 	bs->bs_bridge_pv.pv_dbridge_id =
2123 	    ((uint64_t)bs->bs_bridge_priority) << 48;
2124 	bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id;
2125 	bs->bs_root_pv = bs->bs_bridge_pv;
2126 	/* Disable any remaining ports, they will have no MAC address */
2127 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2128 		bp->bp_infois = BSTP_INFO_DISABLED;
2129 		bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2130 	}
2131 	callout_stop(&bs->bs_bstpcallout);
2132 }
2133 
2134 static int
bstp_modevent(module_t mod,int type,void * data)2135 bstp_modevent(module_t mod, int type, void *data)
2136 {
2137 	switch (type) {
2138 	case MOD_LOAD:
2139 		mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF);
2140 		LIST_INIT(&bstp_list);
2141 		break;
2142 	case MOD_UNLOAD:
2143 		mtx_destroy(&bstp_list_mtx);
2144 		break;
2145 	default:
2146 		return (EOPNOTSUPP);
2147 	}
2148 	return (0);
2149 }
2150 
2151 static moduledata_t bstp_mod = {
2152 	"bridgestp",
2153 	bstp_modevent,
2154 	0
2155 };
2156 
2157 DECLARE_MODULE(bridgestp, bstp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
2158 MODULE_VERSION(bridgestp, 1);
2159 
2160 void
bstp_attach(struct bstp_state * bs,struct bstp_cb_ops * cb)2161 bstp_attach(struct bstp_state *bs, struct bstp_cb_ops *cb)
2162 {
2163 	BSTP_LOCK_INIT(bs);
2164 	callout_init_mtx(&bs->bs_bstpcallout, &bs->bs_mtx, 0);
2165 	LIST_INIT(&bs->bs_bplist);
2166 
2167 	bs->bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
2168 	bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
2169 	bs->bs_bridge_fdelay = BSTP_DEFAULT_FORWARD_DELAY;
2170 	bs->bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
2171 	bs->bs_hold_time = BSTP_DEFAULT_HOLD_TIME;
2172 	bs->bs_migration_delay = BSTP_DEFAULT_MIGRATE_DELAY;
2173 	bs->bs_txholdcount = BSTP_DEFAULT_HOLD_COUNT;
2174 	bs->bs_protover = BSTP_PROTO_RSTP;
2175 	bs->bs_state_cb = cb->bcb_state;
2176 	bs->bs_rtage_cb = cb->bcb_rtage;
2177 	bs->bs_vnet = curvnet;
2178 
2179 	getmicrotime(&bs->bs_last_tc_time);
2180 
2181 	mtx_lock(&bstp_list_mtx);
2182 	LIST_INSERT_HEAD(&bstp_list, bs, bs_list);
2183 	mtx_unlock(&bstp_list_mtx);
2184 }
2185 
2186 void
bstp_detach(struct bstp_state * bs)2187 bstp_detach(struct bstp_state *bs)
2188 {
2189 	KASSERT(LIST_EMPTY(&bs->bs_bplist), ("bstp still active"));
2190 
2191 	mtx_lock(&bstp_list_mtx);
2192 	LIST_REMOVE(bs, bs_list);
2193 	mtx_unlock(&bstp_list_mtx);
2194 	callout_drain(&bs->bs_bstpcallout);
2195 	BSTP_LOCK_DESTROY(bs);
2196 }
2197 
2198 void
bstp_init(struct bstp_state * bs)2199 bstp_init(struct bstp_state *bs)
2200 {
2201 	BSTP_LOCK(bs);
2202 	callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
2203 	bs->bs_running = 1;
2204 	bstp_reinit(bs);
2205 	BSTP_UNLOCK(bs);
2206 }
2207 
2208 void
bstp_stop(struct bstp_state * bs)2209 bstp_stop(struct bstp_state *bs)
2210 {
2211 	struct bstp_port *bp;
2212 
2213 	BSTP_LOCK(bs);
2214 
2215 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
2216 		bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
2217 
2218 	bs->bs_running = 0;
2219 	callout_stop(&bs->bs_bstpcallout);
2220 	BSTP_UNLOCK(bs);
2221 }
2222 
2223 int
bstp_create(struct bstp_state * bs,struct bstp_port * bp,struct ifnet * ifp)2224 bstp_create(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp)
2225 {
2226 	bzero(bp, sizeof(struct bstp_port));
2227 
2228 	BSTP_LOCK(bs);
2229 	bp->bp_ifp = ifp;
2230 	bp->bp_bs = bs;
2231 	bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY;
2232 	TASK_INIT(&bp->bp_statetask, 0, bstp_notify_state, bp);
2233 	TASK_INIT(&bp->bp_rtagetask, 0, bstp_notify_rtage, bp);
2234 	TASK_INIT(&bp->bp_mediatask, 0, bstp_ifupdstatus, bp);
2235 
2236 	/* Init state */
2237 	bp->bp_infois = BSTP_INFO_DISABLED;
2238 	bp->bp_flags = BSTP_PORT_AUTOEDGE|BSTP_PORT_AUTOPTP;
2239 	bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
2240 	bstp_set_port_proto(bp, bs->bs_protover);
2241 	bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2242 	bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
2243 	bp->bp_path_cost = bstp_calc_path_cost(bp);
2244 	BSTP_UNLOCK(bs);
2245 	return (0);
2246 }
2247 
2248 int
bstp_enable(struct bstp_port * bp)2249 bstp_enable(struct bstp_port *bp)
2250 {
2251 	struct bstp_state *bs = bp->bp_bs;
2252 	struct ifnet *ifp = bp->bp_ifp;
2253 
2254 	KASSERT(bp->bp_active == 0, ("already a bstp member"));
2255 	NET_EPOCH_ASSERT(); /* Because bstp_update_roles() causes traffic. */
2256 
2257 	switch (ifp->if_type) {
2258 		case IFT_ETHER:	/* These can do spanning tree. */
2259 		case IFT_L2VLAN:
2260 			break;
2261 		default:
2262 			/* Nothing else can. */
2263 			return (EINVAL);
2264 	}
2265 
2266 	BSTP_LOCK(bs);
2267 	LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next);
2268 	bp->bp_active = 1;
2269 	bp->bp_flags |= BSTP_PORT_NEWINFO;
2270 	bstp_reinit(bs);
2271 	bstp_update_roles(bs, bp);
2272 	BSTP_UNLOCK(bs);
2273 	return (0);
2274 }
2275 
2276 void
bstp_disable(struct bstp_port * bp)2277 bstp_disable(struct bstp_port *bp)
2278 {
2279 	struct bstp_state *bs = bp->bp_bs;
2280 
2281 	KASSERT(bp->bp_active == 1, ("not a bstp member"));
2282 
2283 	BSTP_LOCK(bs);
2284 	bstp_disable_port(bs, bp);
2285 	LIST_REMOVE(bp, bp_next);
2286 	bp->bp_active = 0;
2287 	bstp_reinit(bs);
2288 	BSTP_UNLOCK(bs);
2289 }
2290 
2291 /*
2292  * The bstp_port structure is about to be freed by the parent bridge.
2293  */
2294 void
bstp_destroy(struct bstp_port * bp)2295 bstp_destroy(struct bstp_port *bp)
2296 {
2297 	KASSERT(bp->bp_active == 0, ("port is still attached"));
2298 	taskqueue_drain(taskqueue_swi, &bp->bp_statetask);
2299 	taskqueue_drain(taskqueue_swi, &bp->bp_rtagetask);
2300 	taskqueue_drain(taskqueue_swi, &bp->bp_mediatask);
2301 
2302 	if (bp->bp_bs->bs_root_port == bp)
2303 		bstp_assign_roles(bp->bp_bs);
2304 }
2305