xref: /dragonfly/sys/net/bridge/bridgestp.c (revision a68e0df0)
1 /*
2  * Copyright (c) 2000 Jason L. Wright (jason@thought.net)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Jason L. Wright
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
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  * $NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $
33  * $FreeBSD: src/sys/net/bridgestp.c,v 1.7 2005/10/11 02:58:32 thompsa Exp $
34  */
35 
36 /*
37  * Implementation of the spanning tree protocol as defined in
38  * ISO/IEC Final DIS 15802-3 (IEEE P802.1D/D17), May 25, 1998.
39  * (In English: IEEE 802.1D, Draft 17, 1998)
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/mbuf.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #include <sys/kernel.h>
48 #include <sys/callout.h>
49 #include <sys/proc.h>
50 #include <sys/lock.h>
51 #include <sys/thread.h>
52 #include <sys/thread2.h>
53 #include <sys/msgport2.h>
54 
55 #include <net/if.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 
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/in_var.h>
64 #include <netinet/if_ether.h>
65 #include <net/bridge/if_bridgevar.h>
66 
67 /* BPDU message types */
68 #define	BSTP_MSGTYPE_CFG	0x00		/* Configuration */
69 #define	BSTP_MSGTYPE_TCN	0x80		/* Topology chg notification */
70 
71 /* BPDU flags */
72 #define	BSTP_FLAG_TC		0x01		/* Topology change */
73 #define	BSTP_FLAG_TCA		0x80		/* Topology change ack */
74 
75 #define	BSTP_MESSAGE_AGE_INCR	(1 * 256)	/* in 256ths of a second */
76 #define	BSTP_TICK_VAL		(1 * 256)	/* in 256ths of a second */
77 
78 /*
79  * Because BPDU's do not make nicely aligned structures, two different
80  * declarations are used: bstp_?bpdu (wire representation, packed) and
81  * bstp_*_unit (internal, nicely aligned version).
82  */
83 
84 /* configuration bridge protocol data unit */
85 struct bstp_cbpdu {
86 	uint8_t		cbu_dsap;		/* LLC: destination sap */
87 	uint8_t		cbu_ssap;		/* LLC: source sap */
88 	uint8_t		cbu_ctl;		/* LLC: control */
89 	uint16_t	cbu_protoid;		/* protocol id */
90 	uint8_t		cbu_protover;		/* protocol version */
91 	uint8_t		cbu_bpdutype;		/* message type */
92 	uint8_t		cbu_flags;		/* flags (below) */
93 
94 	/* root id */
95 	uint16_t	cbu_rootpri;		/* root priority */
96 	uint8_t	cbu_rootaddr[6];	/* root address */
97 
98 	uint32_t	cbu_rootpathcost;	/* root path cost */
99 
100 	/* bridge id */
101 	uint16_t	cbu_bridgepri;		/* bridge priority */
102 	uint8_t		cbu_bridgeaddr[6];	/* bridge address */
103 
104 	uint16_t	cbu_portid;		/* port id */
105 	uint16_t	cbu_messageage;		/* current message age */
106 	uint16_t	cbu_maxage;		/* maximum age */
107 	uint16_t	cbu_hellotime;		/* hello time */
108 	uint16_t	cbu_forwarddelay;	/* forwarding delay */
109 } __attribute__((__packed__));
110 
111 /* topology change notification bridge protocol data unit */
112 struct bstp_tbpdu {
113 	uint8_t		tbu_dsap;		/* LLC: destination sap */
114 	uint8_t		tbu_ssap;		/* LLC: source sap */
115 	uint8_t		tbu_ctl;		/* LLC: control */
116 	uint16_t	tbu_protoid;		/* protocol id */
117 	uint8_t		tbu_protover;		/* protocol version */
118 	uint8_t		tbu_bpdutype;		/* message type */
119 } __attribute__((__packed__));
120 
121 const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
122 
123 static void	bstp_initialize_port(struct bridge_softc *,
124 		    struct bridge_iflist *);
125 static void	bstp_ifupdstatus(struct bridge_softc *, struct bridge_iflist *);
126 static void	bstp_enable_port(struct bridge_softc *, struct bridge_iflist *);
127 static void	bstp_disable_port(struct bridge_softc *,
128 		    struct bridge_iflist *);
129 #ifdef notused
130 static void	bstp_enable_change_detection(struct bridge_iflist *);
131 static void	bstp_disable_change_detection(struct bridge_iflist *);
132 #endif /* notused */
133 static int	bstp_root_bridge(struct bridge_softc *sc);
134 static int	bstp_supersedes_port_info(struct bridge_softc *,
135 		    struct bridge_iflist *, struct bstp_config_unit *);
136 static int	bstp_designated_port(struct bridge_softc *,
137 		    struct bridge_iflist *);
138 static int	bstp_designated_for_some_port(struct bridge_softc *);
139 static void	bstp_transmit_config(struct bridge_softc *,
140 		    struct bridge_iflist *);
141 static void	bstp_transmit_tcn(struct bridge_softc *);
142 static void	bstp_received_config_bpdu(struct bridge_softc *,
143 		    struct bridge_iflist *, struct bstp_config_unit *);
144 static void	bstp_received_tcn_bpdu(struct bridge_softc *,
145 		    struct bridge_iflist *, struct bstp_tcn_unit *);
146 static void	bstp_record_config_information(struct bridge_softc *,
147 		    struct bridge_iflist *, struct bstp_config_unit *);
148 static void	bstp_record_config_timeout_values(struct bridge_softc *,
149 		    struct bstp_config_unit *);
150 static void	bstp_config_bpdu_generation(struct bridge_softc *);
151 static void	bstp_send_config_bpdu(struct bridge_softc *,
152 		    struct bridge_iflist *, struct bstp_config_unit *);
153 static void	bstp_configuration_update(struct bridge_softc *);
154 static void	bstp_root_selection(struct bridge_softc *);
155 static void	bstp_designated_port_selection(struct bridge_softc *);
156 static void	bstp_become_designated_port(struct bridge_softc *,
157 		    struct bridge_iflist *);
158 static void	bstp_port_state_selection(struct bridge_softc *);
159 static void	bstp_make_forwarding(struct bridge_softc *,
160 		    struct bridge_iflist *);
161 static void	bstp_make_blocking(struct bridge_softc *,
162 		    struct bridge_iflist *);
163 static void	bstp_set_port_state(struct bridge_iflist *, uint8_t);
164 #ifdef notused
165 static void	bstp_set_bridge_priority(struct bridge_softc *, uint64_t);
166 static void	bstp_set_port_priority(struct bridge_softc *,
167 		    struct bridge_iflist *, uint16_t);
168 static void	bstp_set_path_cost(struct bridge_softc *,
169 		    struct bridge_iflist *, uint32_t);
170 #endif /* notused */
171 static void	bstp_topology_change_detection(struct bridge_softc *);
172 static void	bstp_topology_change_acknowledged(struct bridge_softc *);
173 static void	bstp_acknowledge_topology_change(struct bridge_softc *,
174 		    struct bridge_iflist *);
175 
176 static void	bstp_tick(void *);
177 static void	bstp_timer_start(struct bridge_timer *, uint16_t);
178 static void	bstp_timer_stop(struct bridge_timer *);
179 static int	bstp_timer_expired(struct bridge_timer *, uint16_t);
180 
181 static void	bstp_hold_timer_expiry(struct bridge_softc *,
182 		    struct bridge_iflist *);
183 static void	bstp_message_age_timer_expiry(struct bridge_softc *,
184 		    struct bridge_iflist *);
185 static void	bstp_forward_delay_timer_expiry(struct bridge_softc *,
186 		    struct bridge_iflist *);
187 static void	bstp_topology_change_timer_expiry(struct bridge_softc *);
188 static void	bstp_tcn_timer_expiry(struct bridge_softc *);
189 static void	bstp_hello_timer_expiry(struct bridge_softc *);
190 static int	bstp_addr_cmp(const uint8_t *, const uint8_t *);
191 
192 static void
193 bstp_transmit_config(struct bridge_softc *sc, struct bridge_iflist *bif)
194 {
195 	if (bif->bif_hold_timer.active) {
196 		bif->bif_config_pending = 1;
197 		return;
198 	}
199 
200 	bif->bif_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
201 	bif->bif_config_bpdu.cu_rootid = sc->sc_designated_root;
202 	bif->bif_config_bpdu.cu_root_path_cost = sc->sc_root_path_cost;
203 	bif->bif_config_bpdu.cu_bridge_id = sc->sc_bridge_id;
204 	bif->bif_config_bpdu.cu_port_id = bif->bif_port_id;
205 
206 	if (bstp_root_bridge(sc)) {
207 		bif->bif_config_bpdu.cu_message_age = 0;
208 	} else {
209 		bif->bif_config_bpdu.cu_message_age =
210 		    sc->sc_root_port->bifi_message_age_timer.value +
211 		    BSTP_MESSAGE_AGE_INCR;
212 	}
213 
214 	bif->bif_config_bpdu.cu_max_age = sc->sc_max_age;
215 	bif->bif_config_bpdu.cu_hello_time = sc->sc_hello_time;
216 	bif->bif_config_bpdu.cu_forward_delay = sc->sc_forward_delay;
217 	bif->bif_config_bpdu.cu_topology_change_acknowledgment
218 	    = bif->bif_topology_change_acknowledge;
219 	bif->bif_config_bpdu.cu_topology_change = sc->sc_topology_change;
220 
221 	if (bif->bif_config_bpdu.cu_message_age < sc->sc_max_age) {
222 		bif->bif_topology_change_acknowledge = 0;
223 		bif->bif_config_pending = 0;
224 		bstp_send_config_bpdu(sc, bif, &bif->bif_config_bpdu);
225 		bstp_timer_start(&bif->bif_hold_timer, 0);
226 	}
227 }
228 
229 static void
230 bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
231     struct bstp_config_unit *cu)
232 {
233 	struct ifnet *ifp;
234 	struct mbuf *m;
235 	struct ether_header *eh;
236 	struct bstp_cbpdu bpdu;
237 
238 	ifp = bif->bif_ifp;
239 
240 	if ((ifp->if_flags & IFF_RUNNING) == 0)
241 		return;
242 
243 	MGETHDR(m, MB_DONTWAIT, MT_DATA);
244 	if (m == NULL)
245 		return;
246 
247 	eh = mtod(m, struct ether_header *);
248 
249 	m->m_pkthdr.rcvif = ifp;
250 	m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
251 	m->m_len = m->m_pkthdr.len;
252 
253 	bpdu.cbu_ssap = bpdu.cbu_dsap = LLC_8021D_LSAP;
254 	bpdu.cbu_ctl = LLC_UI;
255 	bpdu.cbu_protoid = htons(0);
256 	bpdu.cbu_protover = 0;
257 	bpdu.cbu_bpdutype = cu->cu_message_type;
258 	bpdu.cbu_flags = (cu->cu_topology_change ? BSTP_FLAG_TC : 0) |
259 	    (cu->cu_topology_change_acknowledgment ? BSTP_FLAG_TCA : 0);
260 
261 	bpdu.cbu_rootpri = htons(cu->cu_rootid >> 48);
262 	bpdu.cbu_rootaddr[0] = cu->cu_rootid >> 40;
263 	bpdu.cbu_rootaddr[1] = cu->cu_rootid >> 32;
264 	bpdu.cbu_rootaddr[2] = cu->cu_rootid >> 24;
265 	bpdu.cbu_rootaddr[3] = cu->cu_rootid >> 16;
266 	bpdu.cbu_rootaddr[4] = cu->cu_rootid >> 8;
267 	bpdu.cbu_rootaddr[5] = cu->cu_rootid >> 0;
268 
269 	bpdu.cbu_rootpathcost = htonl(cu->cu_root_path_cost);
270 
271 	bpdu.cbu_bridgepri = htons(cu->cu_bridge_id >> 48);
272 	bpdu.cbu_bridgeaddr[0] = cu->cu_bridge_id >> 40;
273 	bpdu.cbu_bridgeaddr[1] = cu->cu_bridge_id >> 32;
274 	bpdu.cbu_bridgeaddr[2] = cu->cu_bridge_id >> 24;
275 	bpdu.cbu_bridgeaddr[3] = cu->cu_bridge_id >> 16;
276 	bpdu.cbu_bridgeaddr[4] = cu->cu_bridge_id >> 8;
277 	bpdu.cbu_bridgeaddr[5] = cu->cu_bridge_id >> 0;
278 
279 	bpdu.cbu_portid = htons(cu->cu_port_id);
280 	bpdu.cbu_messageage = htons(cu->cu_message_age);
281 	bpdu.cbu_maxage = htons(cu->cu_max_age);
282 	bpdu.cbu_hellotime = htons(cu->cu_hello_time);
283 	bpdu.cbu_forwarddelay = htons(cu->cu_forward_delay);
284 
285 	memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
286 	memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
287 	eh->ether_type = htons(sizeof(bpdu));
288 
289 	memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
290 
291 	bridge_enqueue(ifp, m);
292 }
293 
294 static int
295 bstp_root_bridge(struct bridge_softc *sc)
296 {
297 	return (sc->sc_designated_root == sc->sc_bridge_id);
298 }
299 
300 static int
301 bstp_supersedes_port_info(struct bridge_softc *sc, struct bridge_iflist *bif,
302     struct bstp_config_unit *cu)
303 {
304 	if (cu->cu_rootid < bif->bif_designated_root)
305 		return (1);
306 	if (cu->cu_rootid > bif->bif_designated_root)
307 		return (0);
308 
309 	if (cu->cu_root_path_cost < bif->bif_designated_cost)
310 		return (1);
311 	if (cu->cu_root_path_cost > bif->bif_designated_cost)
312 		return (0);
313 
314 	if (cu->cu_bridge_id < bif->bif_designated_bridge)
315 		return (1);
316 	if (cu->cu_bridge_id > bif->bif_designated_bridge)
317 		return (0);
318 
319 	if (sc->sc_bridge_id != cu->cu_bridge_id)
320 		return (1);
321 	if (cu->cu_port_id <= bif->bif_designated_port)
322 		return (1);
323 	return (0);
324 }
325 
326 static void
327 bstp_record_config_information(struct bridge_softc *sc,
328     struct bridge_iflist *bif, struct bstp_config_unit *cu)
329 {
330 	bif->bif_designated_root = cu->cu_rootid;
331 	bif->bif_designated_cost = cu->cu_root_path_cost;
332 	bif->bif_designated_bridge = cu->cu_bridge_id;
333 	bif->bif_designated_port = cu->cu_port_id;
334 	bstp_timer_start(&bif->bif_message_age_timer, cu->cu_message_age);
335 }
336 
337 static void
338 bstp_record_config_timeout_values(struct bridge_softc *sc,
339     struct bstp_config_unit *config)
340 {
341 	sc->sc_max_age = config->cu_max_age;
342 	sc->sc_hello_time = config->cu_hello_time;
343 	sc->sc_forward_delay = config->cu_forward_delay;
344 	sc->sc_topology_change = config->cu_topology_change;
345 }
346 
347 static void
348 bstp_config_bpdu_generation(struct bridge_softc *sc)
349 {
350 	struct bridge_iflist *bif, *nbif;
351 
352 	LIST_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
353 		if ((bif->bif_flags & IFBIF_STP) == 0)
354 			continue;
355 		if (bstp_designated_port(sc, bif) &&
356 		    (bif->bif_state != BSTP_IFSTATE_DISABLED))
357 			bstp_transmit_config(sc, bif);
358 
359 		if (nbif != NULL && !nbif->bif_onlist) {
360 			KKASSERT(bif->bif_onlist);
361 			nbif = LIST_NEXT(bif, bif_next);
362 		}
363 	}
364 }
365 
366 static int
367 bstp_designated_port(struct bridge_softc *sc, struct bridge_iflist *bif)
368 {
369 	return ((bif->bif_designated_bridge == sc->sc_bridge_id)
370 	    && (bif->bif_designated_port == bif->bif_port_id));
371 }
372 
373 static void
374 bstp_transmit_tcn(struct bridge_softc *sc)
375 {
376 	struct bstp_tbpdu bpdu;
377 	struct ifnet *ifp = sc->sc_root_port->bifi_ifp;
378 	struct ether_header *eh;
379 	struct mbuf *m;
380 
381 	if ((ifp->if_flags & IFF_RUNNING) == 0)
382 		return;
383 
384 	MGETHDR(m, MB_DONTWAIT, MT_DATA);
385 	if (m == NULL)
386 		return;
387 
388 	m->m_pkthdr.rcvif = ifp;
389 	m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
390 	m->m_len = m->m_pkthdr.len;
391 
392 	eh = mtod(m, struct ether_header *);
393 
394 	memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
395 	memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
396 	eh->ether_type = htons(sizeof(bpdu));
397 
398 	bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
399 	bpdu.tbu_ctl = LLC_UI;
400 	bpdu.tbu_protoid = 0;
401 	bpdu.tbu_protover = 0;
402 	bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
403 
404 	memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
405 
406 	bridge_enqueue(ifp, m);
407 }
408 
409 static void
410 bstp_configuration_update(struct bridge_softc *sc)
411 {
412 	bstp_root_selection(sc);
413 	bstp_designated_port_selection(sc);
414 }
415 
416 static void
417 bstp_root_selection(struct bridge_softc *sc)
418 {
419 	struct bridge_iflist *root_port = NULL, *bif;
420 
421 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
422 		if ((bif->bif_flags & IFBIF_STP) == 0)
423 			continue;
424 		if (bstp_designated_port(sc, bif))
425 			continue;
426 		if (bif->bif_state == BSTP_IFSTATE_DISABLED)
427 			continue;
428 		if (bif->bif_designated_root >= sc->sc_bridge_id)
429 			continue;
430 		if (root_port == NULL)
431 			goto set_port;
432 
433 		if (bif->bif_designated_root < root_port->bif_designated_root)
434 			goto set_port;
435 		if (bif->bif_designated_root > root_port->bif_designated_root)
436 			continue;
437 
438 		if ((bif->bif_designated_cost + bif->bif_path_cost) <
439 		    (root_port->bif_designated_cost + root_port->bif_path_cost))
440 			goto set_port;
441 		if ((bif->bif_designated_cost + bif->bif_path_cost) >
442 		    (root_port->bif_designated_cost + root_port->bif_path_cost))
443 			continue;
444 
445 		if (bif->bif_designated_bridge <
446 		    root_port->bif_designated_bridge)
447 			goto set_port;
448 		if (bif->bif_designated_bridge >
449 		    root_port->bif_designated_bridge)
450 			continue;
451 
452 		if (bif->bif_designated_port < root_port->bif_designated_port)
453 			goto set_port;
454 		if (bif->bif_designated_port > root_port->bif_designated_port)
455 			continue;
456 
457 		if (bif->bif_port_id >= root_port->bif_port_id)
458 			continue;
459 set_port:
460 		root_port = bif;
461 	}
462 
463 	if (root_port == NULL) {
464 		sc->sc_root_port = NULL;
465 		sc->sc_designated_root = sc->sc_bridge_id;
466 		sc->sc_root_path_cost = 0;
467 	} else {
468 		sc->sc_root_port = root_port->bif_info;
469 		sc->sc_designated_root = root_port->bif_designated_root;
470 		sc->sc_root_path_cost = root_port->bif_designated_cost +
471 		    root_port->bif_path_cost;
472 	}
473 }
474 
475 static void
476 bstp_designated_port_selection(struct bridge_softc *sc)
477 {
478 	struct bridge_iflist *bif;
479 
480 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
481 		if ((bif->bif_flags & IFBIF_STP) == 0)
482 			continue;
483 		if (bstp_designated_port(sc, bif))
484 			goto designated;
485 		if (bif->bif_designated_root != sc->sc_designated_root)
486 			goto designated;
487 
488 		if (sc->sc_root_path_cost < bif->bif_designated_cost)
489 			goto designated;
490 		if (sc->sc_root_path_cost > bif->bif_designated_cost)
491 			continue;
492 
493 		if (sc->sc_bridge_id < bif->bif_designated_bridge)
494 			goto designated;
495 		if (sc->sc_bridge_id > bif->bif_designated_bridge)
496 			continue;
497 
498 		if (bif->bif_port_id > bif->bif_designated_port)
499 			continue;
500 designated:
501 		bstp_become_designated_port(sc, bif);
502 	}
503 }
504 
505 static void
506 bstp_become_designated_port(struct bridge_softc *sc, struct bridge_iflist *bif)
507 {
508 	bif->bif_designated_root = sc->sc_designated_root;
509 	bif->bif_designated_cost = sc->sc_root_path_cost;
510 	bif->bif_designated_bridge = sc->sc_bridge_id;
511 	bif->bif_designated_port = bif->bif_port_id;
512 }
513 
514 static void
515 bstp_port_state_selection(struct bridge_softc *sc)
516 {
517 	struct bridge_iflist *bif, *nbif;
518 
519 	LIST_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
520 		if ((bif->bif_flags & IFBIF_STP) == 0)
521 			continue;
522 		if (bif->bif_info == sc->sc_root_port) {
523 			bif->bif_config_pending = 0;
524 			bif->bif_topology_change_acknowledge = 0;
525 			bstp_make_forwarding(sc, bif);
526 		} else if (bstp_designated_port(sc, bif)) {
527 			bstp_timer_stop(&bif->bif_message_age_timer);
528 			bstp_make_forwarding(sc, bif);
529 		} else {
530 			bif->bif_config_pending = 0;
531 			bif->bif_topology_change_acknowledge = 0;
532 			bstp_make_blocking(sc, bif);
533 		}
534 
535 		if (nbif != NULL && !nbif->bif_onlist) {
536 			KKASSERT(bif->bif_onlist);
537 			nbif = LIST_NEXT(bif, bif_next);
538 		}
539 	}
540 }
541 
542 static void
543 bstp_make_forwarding(struct bridge_softc *sc, struct bridge_iflist *bif)
544 {
545 	if (bif->bif_state == BSTP_IFSTATE_BLOCKING) {
546 		bstp_set_port_state(bif, BSTP_IFSTATE_LISTENING);
547 		bstp_timer_start(&bif->bif_forward_delay_timer, 0);
548 	}
549 }
550 
551 static void
552 bstp_make_blocking(struct bridge_softc *sc, struct bridge_iflist *bif)
553 {
554 	if ((bif->bif_state != BSTP_IFSTATE_DISABLED) &&
555 	    (bif->bif_state != BSTP_IFSTATE_BLOCKING)) {
556 		if ((bif->bif_state == BSTP_IFSTATE_FORWARDING) ||
557 		    (bif->bif_state == BSTP_IFSTATE_LEARNING)) {
558 			if (bif->bif_change_detection_enabled) {
559 				bstp_topology_change_detection(sc);
560 			}
561 		}
562 		bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
563 		bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
564 		bstp_timer_stop(&bif->bif_forward_delay_timer);
565 	}
566 }
567 
568 static void
569 bstp_set_port_state(struct bridge_iflist *bif, uint8_t state)
570 {
571 	bif->bif_state = state;
572 }
573 
574 static void
575 bstp_topology_change_detection(struct bridge_softc *sc)
576 {
577 	if (bstp_root_bridge(sc)) {
578 		sc->sc_topology_change = 1;
579 		bstp_timer_start(&sc->sc_topology_change_timer, 0);
580 	} else if (!sc->sc_topology_change_detected) {
581 		bstp_transmit_tcn(sc);
582 		bstp_timer_start(&sc->sc_tcn_timer, 0);
583 	}
584 	sc->sc_topology_change_detected = 1;
585 }
586 
587 static void
588 bstp_topology_change_acknowledged(struct bridge_softc *sc)
589 {
590 	sc->sc_topology_change_detected = 0;
591 	bstp_timer_stop(&sc->sc_tcn_timer);
592 }
593 
594 static void
595 bstp_acknowledge_topology_change(struct bridge_softc *sc,
596     struct bridge_iflist *bif)
597 {
598 	bif->bif_topology_change_acknowledge = 1;
599 	bstp_transmit_config(sc, bif);
600 }
601 
602 void
603 bstp_input(struct bridge_softc *sc, struct bridge_iflist *bif, struct mbuf *m)
604 {
605 	struct ether_header *eh;
606 	struct bstp_tbpdu tpdu;
607 	struct bstp_cbpdu cpdu;
608 	struct bstp_config_unit cu;
609 	struct bstp_tcn_unit tu;
610 	uint16_t len;
611 
612 	if ((bif->bif_flags & IFBIF_STP) == 0)
613 		goto out;
614 
615 	eh = mtod(m, struct ether_header *);
616 
617 	len = ntohs(eh->ether_type);
618 	if (len < sizeof(tpdu))
619 		goto out;
620 
621 	m_adj(m, ETHER_HDR_LEN);
622 
623 	if (m->m_pkthdr.len > len)
624 		m_adj(m, len - m->m_pkthdr.len);
625 	if (m->m_len < sizeof(tpdu) &&
626 	    (m = m_pullup(m, sizeof(tpdu))) == NULL)
627 		goto out;
628 
629 	memcpy(&tpdu, mtod(m, caddr_t), sizeof(tpdu));
630 
631 	if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
632 	    tpdu.tbu_ssap != LLC_8021D_LSAP ||
633 	    tpdu.tbu_ctl != LLC_UI)
634 		goto out;
635 	if (tpdu.tbu_protoid != 0 || tpdu.tbu_protover != 0)
636 		goto out;
637 
638 	switch (tpdu.tbu_bpdutype) {
639 	case BSTP_MSGTYPE_TCN:
640 		tu.tu_message_type = tpdu.tbu_bpdutype;
641 		bstp_received_tcn_bpdu(sc, bif, &tu);
642 		break;
643 	case BSTP_MSGTYPE_CFG:
644 		if (m->m_len < sizeof(cpdu) &&
645 		    (m = m_pullup(m, sizeof(cpdu))) == NULL)
646 			goto out;
647 		memcpy(&cpdu, mtod(m, caddr_t), sizeof(cpdu));
648 
649 		cu.cu_rootid =
650 		    (((uint64_t)ntohs(cpdu.cbu_rootpri)) << 48) |
651 		    (((uint64_t)cpdu.cbu_rootaddr[0]) << 40) |
652 		    (((uint64_t)cpdu.cbu_rootaddr[1]) << 32) |
653 		    (((uint64_t)cpdu.cbu_rootaddr[2]) << 24) |
654 		    (((uint64_t)cpdu.cbu_rootaddr[3]) << 16) |
655 		    (((uint64_t)cpdu.cbu_rootaddr[4]) << 8) |
656 		    (((uint64_t)cpdu.cbu_rootaddr[5]) << 0);
657 
658 		cu.cu_bridge_id =
659 		    (((uint64_t)ntohs(cpdu.cbu_bridgepri)) << 48) |
660 		    (((uint64_t)cpdu.cbu_bridgeaddr[0]) << 40) |
661 		    (((uint64_t)cpdu.cbu_bridgeaddr[1]) << 32) |
662 		    (((uint64_t)cpdu.cbu_bridgeaddr[2]) << 24) |
663 		    (((uint64_t)cpdu.cbu_bridgeaddr[3]) << 16) |
664 		    (((uint64_t)cpdu.cbu_bridgeaddr[4]) << 8) |
665 		    (((uint64_t)cpdu.cbu_bridgeaddr[5]) << 0);
666 
667 		cu.cu_root_path_cost = ntohl(cpdu.cbu_rootpathcost);
668 		cu.cu_message_age = ntohs(cpdu.cbu_messageage);
669 		cu.cu_max_age = ntohs(cpdu.cbu_maxage);
670 		cu.cu_hello_time = ntohs(cpdu.cbu_hellotime);
671 		cu.cu_forward_delay = ntohs(cpdu.cbu_forwarddelay);
672 		cu.cu_port_id = ntohs(cpdu.cbu_portid);
673 		cu.cu_message_type = cpdu.cbu_bpdutype;
674 		cu.cu_topology_change_acknowledgment =
675 		    (cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0;
676 		cu.cu_topology_change =
677 		    (cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0;
678 		bstp_received_config_bpdu(sc, bif, &cu);
679 		break;
680 	default:
681 		goto out;
682 	}
683 out:
684 	if (m)
685 		m_freem(m);
686 }
687 
688 static void
689 bstp_received_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
690     struct bstp_config_unit *cu)
691 {
692 	int root;
693 
694 	root = bstp_root_bridge(sc);
695 
696 	if (bif->bif_state != BSTP_IFSTATE_DISABLED) {
697 		if (bstp_supersedes_port_info(sc, bif, cu)) {
698 			bstp_record_config_information(sc, bif, cu);
699 			bstp_configuration_update(sc);
700 			bstp_port_state_selection(sc);
701 
702 			if ((bstp_root_bridge(sc) == 0) && root) {
703 				bstp_timer_stop(&sc->sc_hello_timer);
704 
705 				if (sc->sc_topology_change_detected) {
706 					bstp_timer_stop(
707 					    &sc->sc_topology_change_timer);
708 					bstp_transmit_tcn(sc);
709 					bstp_timer_start(&sc->sc_tcn_timer, 0);
710 				}
711 			}
712 
713 			if (bif->bif_info == sc->sc_root_port) {
714 				bstp_record_config_timeout_values(sc, cu);
715 				bstp_config_bpdu_generation(sc);
716 
717 				if (cu->cu_topology_change_acknowledgment)
718 					bstp_topology_change_acknowledged(sc);
719 			}
720 		} else if (bstp_designated_port(sc, bif))
721 			bstp_transmit_config(sc, bif);
722 	}
723 }
724 
725 static void
726 bstp_received_tcn_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
727     struct bstp_tcn_unit *tcn)
728 {
729 	if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
730 	    bstp_designated_port(sc, bif)) {
731 		bstp_topology_change_detection(sc);
732 		bstp_acknowledge_topology_change(sc, bif);
733 	}
734 }
735 
736 static void
737 bstp_hello_timer_expiry(struct bridge_softc *sc)
738 {
739 	bstp_config_bpdu_generation(sc);
740 	bstp_timer_start(&sc->sc_hello_timer, 0);
741 }
742 
743 static void
744 bstp_message_age_timer_expiry(struct bridge_softc *sc,
745     struct bridge_iflist *bif)
746 {
747 	int root;
748 
749 	root = bstp_root_bridge(sc);
750 	bstp_become_designated_port(sc, bif);
751 	bstp_configuration_update(sc);
752 	bstp_port_state_selection(sc);
753 
754 	if ((bstp_root_bridge(sc)) && (root == 0)) {
755 		sc->sc_max_age = sc->sc_bridge_max_age;
756 		sc->sc_hello_time = sc->sc_bridge_hello_time;
757 		sc->sc_forward_delay = sc->sc_bridge_forward_delay;
758 
759 		bstp_topology_change_detection(sc);
760 		bstp_timer_stop(&sc->sc_tcn_timer);
761 		bstp_config_bpdu_generation(sc);
762 		bstp_timer_start(&sc->sc_hello_timer, 0);
763 	}
764 }
765 
766 static void
767 bstp_forward_delay_timer_expiry(struct bridge_softc *sc,
768     struct bridge_iflist *bif)
769 {
770 	if (bif->bif_state == BSTP_IFSTATE_LISTENING) {
771 		bstp_set_port_state(bif, BSTP_IFSTATE_LEARNING);
772 		bstp_timer_start(&bif->bif_forward_delay_timer, 0);
773 	} else if (bif->bif_state == BSTP_IFSTATE_LEARNING) {
774 		bstp_set_port_state(bif, BSTP_IFSTATE_FORWARDING);
775 		if (bstp_designated_for_some_port(sc) &&
776 		    bif->bif_change_detection_enabled)
777 			bstp_topology_change_detection(sc);
778 	}
779 }
780 
781 static int
782 bstp_designated_for_some_port(struct bridge_softc *sc)
783 {
784 
785 	struct bridge_iflist *bif;
786 
787 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
788 		if ((bif->bif_flags & IFBIF_STP) == 0)
789 			continue;
790 		if (bif->bif_designated_bridge == sc->sc_bridge_id)
791 			return (1);
792 	}
793 	return (0);
794 }
795 
796 static void
797 bstp_tcn_timer_expiry(struct bridge_softc *sc)
798 {
799 	bstp_transmit_tcn(sc);
800 	bstp_timer_start(&sc->sc_tcn_timer, 0);
801 }
802 
803 static void
804 bstp_topology_change_timer_expiry(struct bridge_softc *sc)
805 {
806 	sc->sc_topology_change_detected = 0;
807 	sc->sc_topology_change = 0;
808 }
809 
810 static void
811 bstp_hold_timer_expiry(struct bridge_softc *sc, struct bridge_iflist *bif)
812 {
813 	if (bif->bif_config_pending)
814 		bstp_transmit_config(sc, bif);
815 }
816 
817 static int
818 bstp_addr_cmp(const uint8_t *a, const uint8_t *b)
819 {
820 	int i, d;
821 
822 	for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
823 		d = ((int)a[i]) - ((int)b[i]);
824 	}
825 
826 	return (d);
827 }
828 
829 void
830 bstp_initialization(struct bridge_softc *sc)
831 {
832 	struct bridge_iflist *bif, *mif, *nbif;
833 	u_char *e_addr;
834 
835 	KKASSERT(&curthread->td_msgport == BRIDGE_CFGPORT);
836 
837 	mif = NULL;
838 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
839 		if ((bif->bif_flags & IFBIF_STP) == 0)
840 			continue;
841 		if (bif->bif_ifp->if_type != IFT_ETHER)
842 			continue;
843 		bif->bif_port_id = (bif->bif_priority << 8) |
844 		    (bif->bif_ifp->if_index & 0xff);
845 
846 		if (mif == NULL) {
847 			mif = bif;
848 			continue;
849 		}
850 		if (bstp_addr_cmp(IF_LLADDR(bif->bif_ifp),
851 		    IF_LLADDR(mif->bif_ifp)) < 0) {
852 			mif = bif;
853 			continue;
854 		}
855 	}
856 	if (mif == NULL) {
857 		bstp_stop(sc);
858 		return;
859 	}
860 
861 	e_addr = IF_LLADDR(mif->bif_ifp);
862 	sc->sc_bridge_id =
863 	    (((uint64_t)sc->sc_bridge_priority) << 48) |
864 	    (((uint64_t)e_addr[0]) << 40) |
865 	    (((uint64_t)e_addr[1]) << 32) |
866 	    (((uint64_t)e_addr[2]) << 24) |
867 	    (((uint64_t)e_addr[3]) << 16) |
868 	    (((uint64_t)e_addr[4]) << 8) |
869 	    (((uint64_t)e_addr[5]));
870 
871 	sc->sc_designated_root = sc->sc_bridge_id;
872 	sc->sc_root_path_cost = 0;
873 	sc->sc_root_port = NULL;
874 
875 	sc->sc_max_age = sc->sc_bridge_max_age;
876 	sc->sc_hello_time = sc->sc_bridge_hello_time;
877 	sc->sc_forward_delay = sc->sc_bridge_forward_delay;
878 	sc->sc_topology_change_detected = 0;
879 	sc->sc_topology_change = 0;
880 	bstp_timer_stop(&sc->sc_tcn_timer);
881 	bstp_timer_stop(&sc->sc_topology_change_timer);
882 
883 	if (callout_pending(&sc->sc_bstpcallout) == 0)
884 		callout_reset(&sc->sc_bstpcallout, hz,
885 		    bstp_tick, sc);
886 
887 	LIST_FOREACH_MUTABLE(bif, &sc->sc_iflists[mycpuid], bif_next, nbif) {
888 		if (bif->bif_flags & IFBIF_STP)
889 			bstp_ifupdstatus(sc, bif);
890 		else
891 			bstp_disable_port(sc, bif);
892 
893 		if (nbif != NULL && !nbif->bif_onlist) {
894 			KKASSERT(bif->bif_onlist);
895 			nbif = LIST_NEXT(bif, bif_next);
896 		}
897 	}
898 
899 	bstp_port_state_selection(sc);
900 	bstp_config_bpdu_generation(sc);
901 	bstp_timer_start(&sc->sc_hello_timer, 0);
902 }
903 
904 void
905 bstp_stop(struct bridge_softc *sc)
906 {
907 	struct bridge_iflist *bif;
908 	struct lwkt_msg *lmsg;
909 
910 	KKASSERT(&curthread->td_msgport == BRIDGE_CFGPORT);
911 
912 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
913 		bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
914 		bstp_timer_stop(&bif->bif_hold_timer);
915 		bstp_timer_stop(&bif->bif_message_age_timer);
916 		bstp_timer_stop(&bif->bif_forward_delay_timer);
917 	}
918 
919 	callout_stop(&sc->sc_bstpcallout);
920 
921 	bstp_timer_stop(&sc->sc_topology_change_timer);
922 	bstp_timer_stop(&sc->sc_tcn_timer);
923 	bstp_timer_stop(&sc->sc_hello_timer);
924 
925 	crit_enter();
926 	lmsg = &sc->sc_bstptimemsg.nm_lmsg;
927 	if ((lmsg->ms_flags & MSGF_DONE) == 0) {
928 		/* Pending to be processed; drop it */
929 		lwkt_dropmsg(lmsg);
930 	}
931 	crit_exit();
932 }
933 
934 static void
935 bstp_initialize_port(struct bridge_softc *sc, struct bridge_iflist *bif)
936 {
937 	bstp_become_designated_port(sc, bif);
938 	bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
939 	bif->bif_topology_change_acknowledge = 0;
940 	bif->bif_config_pending = 0;
941 	bif->bif_change_detection_enabled = 1;
942 	bstp_timer_stop(&bif->bif_message_age_timer);
943 	bstp_timer_stop(&bif->bif_forward_delay_timer);
944 	bstp_timer_stop(&bif->bif_hold_timer);
945 }
946 
947 static void
948 bstp_enable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
949 {
950 	bstp_initialize_port(sc, bif);
951 	bstp_port_state_selection(sc);
952 }
953 
954 static void
955 bstp_disable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
956 {
957 	int root;
958 
959 	root = bstp_root_bridge(sc);
960 	bstp_become_designated_port(sc, bif);
961 	bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
962 	bif->bif_topology_change_acknowledge = 0;
963 	bif->bif_config_pending = 0;
964 	bstp_timer_stop(&bif->bif_message_age_timer);
965 	bstp_timer_stop(&bif->bif_forward_delay_timer);
966 	bstp_configuration_update(sc);
967 	bstp_port_state_selection(sc);
968 	bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
969 
970 	if (bstp_root_bridge(sc) && (root == 0)) {
971 		sc->sc_max_age = sc->sc_bridge_max_age;
972 		sc->sc_hello_time = sc->sc_bridge_hello_time;
973 		sc->sc_forward_delay = sc->sc_bridge_forward_delay;
974 
975 		bstp_topology_change_detection(sc);
976 		bstp_timer_stop(&sc->sc_tcn_timer);
977 		bstp_config_bpdu_generation(sc);
978 		bstp_timer_start(&sc->sc_hello_timer, 0);
979 	}
980 }
981 
982 #ifdef notused
983 static void
984 bstp_set_bridge_priority(struct bridge_softc *sc, uint64_t new_bridge_id)
985 {
986 	struct bridge_iflist *bif;
987 	int root;
988 
989 	root = bstp_root_bridge(sc);
990 
991 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
992 		if ((bif->bif_flags & IFBIF_STP) == 0)
993 			continue;
994 		if (bstp_designated_port(sc, bif))
995 			bif->bif_designated_bridge = new_bridge_id;
996 	}
997 
998 	sc->sc_bridge_id = new_bridge_id;
999 
1000 	bstp_configuration_update(sc);
1001 	bstp_port_state_selection(sc);
1002 
1003 	if (bstp_root_bridge(sc) && (root == 0)) {
1004 		sc->sc_max_age = sc->sc_bridge_max_age;
1005 		sc->sc_hello_time = sc->sc_bridge_hello_time;
1006 		sc->sc_forward_delay = sc->sc_bridge_forward_delay;
1007 
1008 		bstp_topology_change_detection(sc);
1009 		bstp_timer_stop(&sc->sc_tcn_timer);
1010 		bstp_config_bpdu_generation(sc);
1011 		bstp_timer_start(&sc->sc_hello_timer, 0);
1012 	}
1013 }
1014 
1015 static void
1016 bstp_set_port_priority(struct bridge_softc *sc, struct bridge_iflist *bif,
1017     uint16_t new_port_id)
1018 {
1019 	if (bstp_designated_port(sc, bif))
1020 		bif->bif_designated_port = new_port_id;
1021 
1022 	bif->bif_port_id = new_port_id;
1023 
1024 	if ((sc->sc_bridge_id == bif->bif_designated_bridge) &&
1025 	    (bif->bif_port_id < bif->bif_designated_port)) {
1026 		bstp_become_designated_port(sc, bif);
1027 		bstp_port_state_selection(sc);
1028 	}
1029 }
1030 
1031 static void
1032 bstp_set_path_cost(struct bridge_softc *sc, struct bridge_iflist *bif,
1033     uint32_t path_cost)
1034 {
1035 	bif->bif_path_cost = path_cost;
1036 	bstp_configuration_update(sc);
1037 	bstp_port_state_selection(sc);
1038 }
1039 
1040 static void
1041 bstp_enable_change_detection(struct bridge_iflist *bif)
1042 {
1043 	bif->bif_change_detection_enabled = 1;
1044 }
1045 
1046 static void
1047 bstp_disable_change_detection(struct bridge_iflist *bif)
1048 {
1049 	bif->bif_change_detection_enabled = 0;
1050 }
1051 #endif /* notused */
1052 
1053 void
1054 bstp_linkstate(struct ifnet *ifp, int state)
1055 {
1056 	struct bridge_softc *sc;
1057 	struct bridge_iflist *bif;
1058 
1059 	sc = ifp->if_bridge;
1060 	ifnet_serialize_all(sc->sc_ifp);
1061 
1062 	/*
1063 	 * bstp_ifupdstatus() may block, but it is the last
1064 	 * operation of the member iface iteration, so we
1065 	 * don't need to use LIST_FOREACH_MUTABLE()+bif_onlist
1066 	 * check here.
1067 	 */
1068 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
1069 		if ((bif->bif_flags & IFBIF_STP) == 0)
1070 			continue;
1071 
1072 		if (bif->bif_ifp == ifp) {
1073 			bstp_ifupdstatus(sc, bif);
1074 			break;
1075 		}
1076 	}
1077 	ifnet_deserialize_all(sc->sc_ifp);
1078 }
1079 
1080 static void
1081 bstp_ifupdstatus(struct bridge_softc *sc, struct bridge_iflist *bif)
1082 {
1083 	struct ifnet *ifp = bif->bif_ifp;
1084 	struct ifmediareq ifmr;
1085 	int error = 0;
1086 
1087 	bzero((char *)&ifmr, sizeof(ifmr));
1088 	ifnet_serialize_all(ifp);
1089 	error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr, NULL);
1090 	ifnet_deserialize_all(ifp);
1091 
1092 	if ((error == 0) && (ifp->if_flags & IFF_UP)) {
1093 	 	if (ifmr.ifm_status & IFM_ACTIVE) {
1094 			if (bif->bif_state == BSTP_IFSTATE_DISABLED)
1095 				bstp_enable_port(sc, bif);
1096 
1097 		} else {
1098 			if (bif->bif_state != BSTP_IFSTATE_DISABLED)
1099 				bstp_disable_port(sc, bif);
1100 		}
1101 		return;
1102 	}
1103 
1104 	if (bif->bif_state != BSTP_IFSTATE_DISABLED)
1105 		bstp_disable_port(sc, bif);
1106 }
1107 
1108 static void
1109 bstp_tick(void *arg)
1110 {
1111 	struct bridge_softc *sc = arg;
1112 	struct lwkt_msg *lmsg;
1113 
1114 	KKASSERT(mycpuid == BRIDGE_CFGCPU);
1115 
1116 	crit_enter();
1117 
1118 	if (callout_pending(&sc->sc_bstpcallout) ||
1119 	    !callout_active(&sc->sc_bstpcallout)) {
1120 		crit_exit();
1121 		return;
1122 	}
1123 	callout_deactivate(&sc->sc_bstpcallout);
1124 
1125 	lmsg = &sc->sc_bstptimemsg.nm_lmsg;
1126 	KKASSERT(lmsg->ms_flags & MSGF_DONE);
1127 	lwkt_sendmsg(BRIDGE_CFGPORT, lmsg);
1128 
1129 	crit_exit();
1130 }
1131 
1132 void
1133 bstp_tick_handler(struct netmsg *nmsg)
1134 {
1135 	struct bridge_softc *sc = nmsg->nm_lmsg.u.ms_resultp;
1136 	struct bridge_iflist *bif;
1137 
1138 	KKASSERT(&curthread->td_msgport == BRIDGE_CFGPORT);
1139 	crit_enter();
1140 	/* Reply ASAP */
1141 	lwkt_replymsg(&nmsg->nm_lmsg, 0);
1142 	crit_exit();
1143 
1144 	ifnet_serialize_all(sc->sc_ifp);
1145 
1146 	/*
1147 	 * NOTE:
1148 	 * We don't need to worry that member iface is ripped
1149 	 * from the per-cpu list during the blocking operation
1150 	 * in the loop body, since deletion is serialized by
1151 	 * BRIDGE_CFGPORT
1152 	 */
1153 
1154 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
1155 		if ((bif->bif_flags & IFBIF_STP) == 0)
1156 			continue;
1157 		/*
1158 		 * XXX This can cause a lag in "link does away"
1159 		 * XXX and "spanning tree gets updated".  We need
1160 		 * XXX come sort of callback from the link state
1161 		 * XXX update code to kick spanning tree.
1162 		 * XXX --thorpej@NetBSD.org
1163 		 */
1164 		bstp_ifupdstatus(sc, bif);
1165 	}
1166 
1167 	if (bstp_timer_expired(&sc->sc_hello_timer, sc->sc_hello_time))
1168 		bstp_hello_timer_expiry(sc);
1169 
1170 	if (bstp_timer_expired(&sc->sc_tcn_timer, sc->sc_bridge_hello_time))
1171 		bstp_tcn_timer_expiry(sc);
1172 
1173 	if (bstp_timer_expired(&sc->sc_topology_change_timer,
1174 	    sc->sc_topology_change_time))
1175 		bstp_topology_change_timer_expiry(sc);
1176 
1177 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
1178 		if ((bif->bif_flags & IFBIF_STP) == 0)
1179 			continue;
1180 		if (bstp_timer_expired(&bif->bif_message_age_timer,
1181 		    sc->sc_max_age))
1182 			bstp_message_age_timer_expiry(sc, bif);
1183 	}
1184 
1185 	LIST_FOREACH(bif, &sc->sc_iflists[mycpuid], bif_next) {
1186 		if ((bif->bif_flags & IFBIF_STP) == 0)
1187 			continue;
1188 		if (bstp_timer_expired(&bif->bif_forward_delay_timer,
1189 		    sc->sc_forward_delay))
1190 			bstp_forward_delay_timer_expiry(sc, bif);
1191 
1192 		if (bstp_timer_expired(&bif->bif_hold_timer,
1193 		    sc->sc_hold_time))
1194 			bstp_hold_timer_expiry(sc, bif);
1195 	}
1196 
1197 	if (sc->sc_ifp->if_flags & IFF_RUNNING)
1198 		callout_reset(&sc->sc_bstpcallout, hz, bstp_tick, sc);
1199 
1200 	ifnet_deserialize_all(sc->sc_ifp);
1201 }
1202 
1203 static void
1204 bstp_timer_start(struct bridge_timer *t, uint16_t v)
1205 {
1206 	t->value = v;
1207 	t->active = 1;
1208 }
1209 
1210 static void
1211 bstp_timer_stop(struct bridge_timer *t)
1212 {
1213 	t->value = 0;
1214 	t->active = 0;
1215 }
1216 
1217 static int
1218 bstp_timer_expired(struct bridge_timer *t, uint16_t v)
1219 {
1220 	if (t->active == 0)
1221 		return (0);
1222 	t->value += BSTP_TICK_VAL;
1223 	if (t->value >= v) {
1224 		bstp_timer_stop(t);
1225 		return (1);
1226 	}
1227 	return (0);
1228 
1229 }
1230