xref: /freebsd/sys/net/bridgestp.c (revision a4eb85b6acb49cb60c72c2cab0d0d3f00eaa6d46)
1 /*	$NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Jason L. Wright
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason 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/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/mbuf.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50 #include <sys/kernel.h>
51 #include <sys/callout.h>
52 #include <sys/module.h>
53 #include <sys/proc.h>
54 #include <sys/lock.h>
55 #include <sys/mutex.h>
56 
57 #include <net/if.h>
58 #include <net/if_dl.h>
59 #include <net/if_types.h>
60 #include <net/if_llc.h>
61 #include <net/if_media.h>
62 
63 #include <netinet/in.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/in_var.h>
66 #include <netinet/if_ether.h>
67 #include <net/bridgestp.h>
68 
69 const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
70 
71 LIST_HEAD(, bstp_state) bstp_list;
72 static struct mtx	bstp_list_mtx;
73 
74 static void	bstp_initialize_port(struct bstp_state *,
75 		    struct bstp_port *);
76 static void	bstp_ifupdstatus(struct bstp_state *, struct bstp_port *);
77 static void	bstp_enable_port(struct bstp_state *, struct bstp_port *);
78 static void	bstp_disable_port(struct bstp_state *,
79 		    struct bstp_port *);
80 #ifdef notused
81 static void	bstp_enable_change_detection(struct bstp_port *);
82 static void	bstp_disable_change_detection(struct bstp_port *);
83 #endif /* notused */
84 static int	bstp_root_bridge(struct bstp_state *bs);
85 static int	bstp_supersedes_port_info(struct bstp_state *,
86 		    struct bstp_port *, struct bstp_config_unit *);
87 static int	bstp_designated_port(struct bstp_state *,
88 		    struct bstp_port *);
89 static int	bstp_designated_for_some_port(struct bstp_state *);
90 static void	bstp_transmit_config(struct bstp_state *,
91 		    struct bstp_port *);
92 static void	bstp_transmit_tcn(struct bstp_state *);
93 static void	bstp_received_config_bpdu(struct bstp_state *,
94 		    struct bstp_port *, struct bstp_config_unit *);
95 static void	bstp_received_tcn_bpdu(struct bstp_state *,
96 		    struct bstp_port *, struct bstp_tcn_unit *);
97 static void	bstp_record_config_information(struct bstp_state *,
98 		    struct bstp_port *, struct bstp_config_unit *);
99 static void	bstp_record_config_timeout_values(struct bstp_state *,
100 		    struct bstp_config_unit *);
101 static void	bstp_config_bpdu_generation(struct bstp_state *);
102 static void	bstp_send_config_bpdu(struct bstp_state *,
103 		    struct bstp_port *, struct bstp_config_unit *);
104 static void	bstp_configuration_update(struct bstp_state *);
105 static void	bstp_root_selection(struct bstp_state *);
106 static void	bstp_designated_port_selection(struct bstp_state *);
107 static void	bstp_become_designated_port(struct bstp_state *,
108 		    struct bstp_port *);
109 static void	bstp_port_state_selection(struct bstp_state *);
110 static void	bstp_make_forwarding(struct bstp_state *,
111 		    struct bstp_port *);
112 static void	bstp_make_blocking(struct bstp_state *,
113 		    struct bstp_port *);
114 static void	bstp_set_port_state(struct bstp_port *, uint8_t);
115 #ifdef notused
116 static void	bstp_set_bridge_priority(struct bstp_state *, uint64_t);
117 static void	bstp_set_port_priority(struct bstp_state *,
118 		    struct bstp_port *, uint16_t);
119 static void	bstp_set_path_cost(struct bstp_state *,
120 		    struct bstp_port *, uint32_t);
121 #endif /* notused */
122 static void	bstp_topology_change_detection(struct bstp_state *);
123 static void	bstp_topology_change_acknowledged(struct bstp_state *);
124 static void	bstp_acknowledge_topology_change(struct bstp_state *,
125 		    struct bstp_port *);
126 
127 static void	bstp_enqueue(struct ifnet *, struct mbuf *);
128 static void	bstp_tick(void *);
129 static void	bstp_timer_start(struct bstp_timer *, uint16_t);
130 static void	bstp_timer_stop(struct bstp_timer *);
131 static int	bstp_timer_expired(struct bstp_timer *, uint16_t);
132 
133 static void	bstp_hold_timer_expiry(struct bstp_state *,
134 		    struct bstp_port *);
135 static void	bstp_message_age_timer_expiry(struct bstp_state *,
136 		    struct bstp_port *);
137 static void	bstp_forward_delay_timer_expiry(struct bstp_state *,
138 		    struct bstp_port *);
139 static void	bstp_topology_change_timer_expiry(struct bstp_state *);
140 static void	bstp_tcn_timer_expiry(struct bstp_state *);
141 static void	bstp_hello_timer_expiry(struct bstp_state *);
142 static int	bstp_addr_cmp(const uint8_t *, const uint8_t *);
143 
144 static void
145 bstp_transmit_config(struct bstp_state *bs, struct bstp_port *bp)
146 {
147 	BSTP_LOCK_ASSERT(bs);
148 
149 	if (bp->bp_hold_timer.active) {
150 		bp->bp_config_pending = 1;
151 		return;
152 	}
153 
154 	bp->bp_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
155 	bp->bp_config_bpdu.cu_rootid = bs->bs_designated_root;
156 	bp->bp_config_bpdu.cu_root_path_cost = bs->bs_root_path_cost;
157 	bp->bp_config_bpdu.cu_bridge_id = bs->bs_bridge_id;
158 	bp->bp_config_bpdu.cu_port_id = bp->bp_port_id;
159 
160 	if (bstp_root_bridge(bs))
161 		bp->bp_config_bpdu.cu_message_age = 0;
162 	else
163 		bp->bp_config_bpdu.cu_message_age =
164 		    bs->bs_root_port->bp_message_age_timer.value +
165 		    BSTP_MESSAGE_AGE_INCR;
166 
167 	bp->bp_config_bpdu.cu_max_age = bs->bs_max_age;
168 	bp->bp_config_bpdu.cu_hello_time = bs->bs_hello_time;
169 	bp->bp_config_bpdu.cu_forward_delay = bs->bs_forward_delay;
170 	bp->bp_config_bpdu.cu_topology_change_acknowledgment
171 	    = bp->bp_topology_change_acknowledge;
172 	bp->bp_config_bpdu.cu_topology_change = bs->bs_topology_change;
173 
174 	if (bp->bp_config_bpdu.cu_message_age < bs->bs_max_age) {
175 		bp->bp_topology_change_acknowledge = 0;
176 		bp->bp_config_pending = 0;
177 		bstp_send_config_bpdu(bs, bp, &bp->bp_config_bpdu);
178 		bstp_timer_start(&bp->bp_hold_timer, 0);
179 	}
180 }
181 
182 static void
183 bstp_send_config_bpdu(struct bstp_state *bs, struct bstp_port *bp,
184     struct bstp_config_unit *cu)
185 {
186 	struct ifnet *ifp;
187 	struct mbuf *m;
188 	struct ether_header *eh;
189 	struct bstp_cbpdu bpdu;
190 
191 	BSTP_LOCK_ASSERT(bs);
192 
193 	ifp = bp->bp_ifp;
194 
195 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
196 		return;
197 
198 	MGETHDR(m, M_DONTWAIT, MT_DATA);
199 	if (m == NULL)
200 		return;
201 
202 	eh = mtod(m, struct ether_header *);
203 
204 	m->m_pkthdr.rcvif = ifp;
205 	m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
206 	m->m_len = m->m_pkthdr.len;
207 
208 	bpdu.cbu_ssap = bpdu.cbu_dsap = LLC_8021D_LSAP;
209 	bpdu.cbu_ctl = LLC_UI;
210 	bpdu.cbu_protoid = htons(0);
211 	bpdu.cbu_protover = 0;
212 	bpdu.cbu_bpdutype = cu->cu_message_type;
213 	bpdu.cbu_flags = (cu->cu_topology_change ? BSTP_FLAG_TC : 0) |
214 	    (cu->cu_topology_change_acknowledgment ? BSTP_FLAG_TCA : 0);
215 
216 	bpdu.cbu_rootpri = htons(cu->cu_rootid >> 48);
217 	bpdu.cbu_rootaddr[0] = cu->cu_rootid >> 40;
218 	bpdu.cbu_rootaddr[1] = cu->cu_rootid >> 32;
219 	bpdu.cbu_rootaddr[2] = cu->cu_rootid >> 24;
220 	bpdu.cbu_rootaddr[3] = cu->cu_rootid >> 16;
221 	bpdu.cbu_rootaddr[4] = cu->cu_rootid >> 8;
222 	bpdu.cbu_rootaddr[5] = cu->cu_rootid >> 0;
223 
224 	bpdu.cbu_rootpathcost = htonl(cu->cu_root_path_cost);
225 
226 	bpdu.cbu_bridgepri = htons(cu->cu_bridge_id >> 48);
227 	bpdu.cbu_bridgeaddr[0] = cu->cu_bridge_id >> 40;
228 	bpdu.cbu_bridgeaddr[1] = cu->cu_bridge_id >> 32;
229 	bpdu.cbu_bridgeaddr[2] = cu->cu_bridge_id >> 24;
230 	bpdu.cbu_bridgeaddr[3] = cu->cu_bridge_id >> 16;
231 	bpdu.cbu_bridgeaddr[4] = cu->cu_bridge_id >> 8;
232 	bpdu.cbu_bridgeaddr[5] = cu->cu_bridge_id >> 0;
233 
234 	bpdu.cbu_portid = htons(cu->cu_port_id);
235 	bpdu.cbu_messageage = htons(cu->cu_message_age);
236 	bpdu.cbu_maxage = htons(cu->cu_max_age);
237 	bpdu.cbu_hellotime = htons(cu->cu_hello_time);
238 	bpdu.cbu_forwarddelay = htons(cu->cu_forward_delay);
239 
240 	memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
241 	memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
242 	eh->ether_type = htons(sizeof(bpdu));
243 
244 	memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
245 
246 	bstp_enqueue(ifp, m);
247 }
248 
249 static int
250 bstp_root_bridge(struct bstp_state *bs)
251 {
252 	return (bs->bs_designated_root == bs->bs_bridge_id);
253 }
254 
255 static int
256 bstp_supersedes_port_info(struct bstp_state *bs, struct bstp_port *bp,
257     struct bstp_config_unit *cu)
258 {
259 	if (cu->cu_rootid < bp->bp_designated_root)
260 		return (1);
261 	if (cu->cu_rootid > bp->bp_designated_root)
262 		return (0);
263 
264 	if (cu->cu_root_path_cost < bp->bp_designated_cost)
265 		return (1);
266 	if (cu->cu_root_path_cost > bp->bp_designated_cost)
267 		return (0);
268 
269 	if (cu->cu_bridge_id < bp->bp_designated_bridge)
270 		return (1);
271 	if (cu->cu_bridge_id > bp->bp_designated_bridge)
272 		return (0);
273 
274 	if (bs->bs_bridge_id != cu->cu_bridge_id)
275 		return (1);
276 	if (cu->cu_port_id <= bp->bp_designated_port)
277 		return (1);
278 	return (0);
279 }
280 
281 static void
282 bstp_record_config_information(struct bstp_state *bs,
283     struct bstp_port *bp, struct bstp_config_unit *cu)
284 {
285 	BSTP_LOCK_ASSERT(bs);
286 
287 	bp->bp_designated_root = cu->cu_rootid;
288 	bp->bp_designated_cost = cu->cu_root_path_cost;
289 	bp->bp_designated_bridge = cu->cu_bridge_id;
290 	bp->bp_designated_port = cu->cu_port_id;
291 	bstp_timer_start(&bp->bp_message_age_timer, cu->cu_message_age);
292 }
293 
294 static void
295 bstp_record_config_timeout_values(struct bstp_state *bs,
296     struct bstp_config_unit *config)
297 {
298 	BSTP_LOCK_ASSERT(bs);
299 
300 	bs->bs_max_age = config->cu_max_age;
301 	bs->bs_hello_time = config->cu_hello_time;
302 	bs->bs_forward_delay = config->cu_forward_delay;
303 	bs->bs_topology_change = config->cu_topology_change;
304 }
305 
306 static void
307 bstp_config_bpdu_generation(struct bstp_state *bs)
308 {
309 	struct bstp_port *bp;
310 
311 	BSTP_LOCK_ASSERT(bs);
312 
313 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
314 		if (bstp_designated_port(bs, bp) &&
315 		    (bp->bp_state != BSTP_IFSTATE_DISABLED))
316 			bstp_transmit_config(bs, bp);
317 	}
318 }
319 
320 static int
321 bstp_designated_port(struct bstp_state *bs, struct bstp_port *bp)
322 {
323 	return ((bp->bp_designated_bridge == bs->bs_bridge_id)
324 	    && (bp->bp_designated_port == bp->bp_port_id));
325 }
326 
327 static void
328 bstp_transmit_tcn(struct bstp_state *bs)
329 {
330 	struct bstp_tbpdu bpdu;
331 	struct bstp_port *bp = bs->bs_root_port;
332 	struct ifnet *ifp = bp->bp_ifp;
333 	struct ether_header *eh;
334 	struct mbuf *m;
335 
336 	BSTP_LOCK_ASSERT(bs);
337 
338 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
339 		return;
340 
341 	MGETHDR(m, M_DONTWAIT, MT_DATA);
342 	if (m == NULL)
343 		return;
344 
345 	m->m_pkthdr.rcvif = ifp;
346 	m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
347 	m->m_len = m->m_pkthdr.len;
348 
349 	eh = mtod(m, struct ether_header *);
350 
351 	memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
352 	memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
353 	eh->ether_type = htons(sizeof(bpdu));
354 
355 	bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
356 	bpdu.tbu_ctl = LLC_UI;
357 	bpdu.tbu_protoid = 0;
358 	bpdu.tbu_protover = 0;
359 	bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
360 
361 	memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
362 
363 	bstp_enqueue(ifp, m);
364 }
365 
366 static void
367 bstp_configuration_update(struct bstp_state *bs)
368 {
369 	BSTP_LOCK_ASSERT(bs);
370 
371 	bstp_root_selection(bs);
372 	bstp_designated_port_selection(bs);
373 }
374 
375 static void
376 bstp_root_selection(struct bstp_state *bs)
377 {
378 	struct bstp_port *root_port = NULL, *bp;
379 
380 	BSTP_LOCK_ASSERT(bs);
381 
382 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
383 		if (bstp_designated_port(bs, bp))
384 			continue;
385 		if (bp->bp_state == BSTP_IFSTATE_DISABLED)
386 			continue;
387 		if (bp->bp_designated_root >= bs->bs_bridge_id)
388 			continue;
389 		if (root_port == NULL)
390 			goto set_port;
391 
392 		if (bp->bp_designated_root < root_port->bp_designated_root)
393 			goto set_port;
394 		if (bp->bp_designated_root > root_port->bp_designated_root)
395 			continue;
396 
397 		if ((bp->bp_designated_cost + bp->bp_path_cost) <
398 		    (root_port->bp_designated_cost + root_port->bp_path_cost))
399 			goto set_port;
400 		if ((bp->bp_designated_cost + bp->bp_path_cost) >
401 		    (root_port->bp_designated_cost + root_port->bp_path_cost))
402 			continue;
403 
404 		if (bp->bp_designated_bridge <
405 		    root_port->bp_designated_bridge)
406 			goto set_port;
407 		if (bp->bp_designated_bridge >
408 		    root_port->bp_designated_bridge)
409 			continue;
410 
411 		if (bp->bp_designated_port < root_port->bp_designated_port)
412 			goto set_port;
413 		if (bp->bp_designated_port > root_port->bp_designated_port)
414 			continue;
415 
416 		if (bp->bp_port_id >= root_port->bp_port_id)
417 			continue;
418 set_port:
419 		root_port = bp;
420 	}
421 
422 	bs->bs_root_port = root_port;
423 	if (root_port == NULL) {
424 		bs->bs_designated_root = bs->bs_bridge_id;
425 		bs->bs_root_path_cost = 0;
426 	} else {
427 		bs->bs_designated_root = root_port->bp_designated_root;
428 		bs->bs_root_path_cost = root_port->bp_designated_cost +
429 		    root_port->bp_path_cost;
430 	}
431 }
432 
433 static void
434 bstp_designated_port_selection(struct bstp_state *bs)
435 {
436 	struct bstp_port *bp;
437 
438 	BSTP_LOCK_ASSERT(bs);
439 
440 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
441 		if (bstp_designated_port(bs, bp))
442 			goto designated;
443 		if (bp->bp_designated_root != bs->bs_designated_root)
444 			goto designated;
445 
446 		if (bs->bs_root_path_cost < bp->bp_designated_cost)
447 			goto designated;
448 		if (bs->bs_root_path_cost > bp->bp_designated_cost)
449 			continue;
450 
451 		if (bs->bs_bridge_id < bp->bp_designated_bridge)
452 			goto designated;
453 		if (bs->bs_bridge_id > bp->bp_designated_bridge)
454 			continue;
455 
456 		if (bp->bp_port_id > bp->bp_designated_port)
457 			continue;
458 designated:
459 		bstp_become_designated_port(bs, bp);
460 	}
461 }
462 
463 static void
464 bstp_become_designated_port(struct bstp_state *bs, struct bstp_port *bp)
465 {
466 	BSTP_LOCK_ASSERT(bs);
467 
468 	bp->bp_designated_root = bs->bs_designated_root;
469 	bp->bp_designated_cost = bs->bs_root_path_cost;
470 	bp->bp_designated_bridge = bs->bs_bridge_id;
471 	bp->bp_designated_port = bp->bp_port_id;
472 }
473 
474 static void
475 bstp_port_state_selection(struct bstp_state *bs)
476 {
477 	struct bstp_port *bp;
478 
479 	BSTP_LOCK_ASSERT(bs);
480 
481 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
482 		if (bp == bs->bs_root_port) {
483 			bp->bp_config_pending = 0;
484 			bp->bp_topology_change_acknowledge = 0;
485 			bstp_make_forwarding(bs, bp);
486 		} else if (bstp_designated_port(bs, bp)) {
487 			bstp_timer_stop(&bp->bp_message_age_timer);
488 			bstp_make_forwarding(bs, bp);
489 		} else {
490 			bp->bp_config_pending = 0;
491 			bp->bp_topology_change_acknowledge = 0;
492 			bstp_make_blocking(bs, bp);
493 		}
494 	}
495 }
496 
497 static void
498 bstp_make_forwarding(struct bstp_state *bs, struct bstp_port *bp)
499 {
500 	BSTP_LOCK_ASSERT(bs);
501 
502 	if (bp->bp_state == BSTP_IFSTATE_BLOCKING) {
503 		bstp_set_port_state(bp, BSTP_IFSTATE_LISTENING);
504 		bstp_timer_start(&bp->bp_forward_delay_timer, 0);
505 	}
506 }
507 
508 static void
509 bstp_make_blocking(struct bstp_state *bs, struct bstp_port *bp)
510 {
511 	BSTP_LOCK_ASSERT(bs);
512 
513 	if ((bp->bp_state != BSTP_IFSTATE_DISABLED) &&
514 	    (bp->bp_state != BSTP_IFSTATE_BLOCKING)) {
515 		if ((bp->bp_state == BSTP_IFSTATE_FORWARDING) ||
516 		    (bp->bp_state == BSTP_IFSTATE_LEARNING)) {
517 			if (bp->bp_change_detection_enabled) {
518 				bstp_topology_change_detection(bs);
519 			}
520 		}
521 		bstp_set_port_state(bp, BSTP_IFSTATE_BLOCKING);
522 		/* XXX bridge_rtdelete(bs, bp->bp_ifp, IFBF_FLUSHDYN); */
523 		bstp_timer_stop(&bp->bp_forward_delay_timer);
524 	}
525 }
526 
527 static void
528 bstp_set_port_state(struct bstp_port *bp, uint8_t state)
529 {
530 	bp->bp_state = state;
531 }
532 
533 static void
534 bstp_topology_change_detection(struct bstp_state *bs)
535 {
536 	BSTP_LOCK_ASSERT(bs);
537 
538 	if (bstp_root_bridge(bs)) {
539 		bs->bs_topology_change = 1;
540 		bstp_timer_start(&bs->bs_topology_change_timer, 0);
541 	} else if (!bs->bs_topology_change_detected) {
542 		bstp_transmit_tcn(bs);
543 		bstp_timer_start(&bs->bs_tcn_timer, 0);
544 	}
545 	bs->bs_topology_change_detected = 1;
546 }
547 
548 static void
549 bstp_topology_change_acknowledged(struct bstp_state *bs)
550 {
551 	BSTP_LOCK_ASSERT(bs);
552 
553 	bs->bs_topology_change_detected = 0;
554 	bstp_timer_stop(&bs->bs_tcn_timer);
555 }
556 
557 static void
558 bstp_acknowledge_topology_change(struct bstp_state *bs,
559     struct bstp_port *bp)
560 {
561 	BSTP_LOCK_ASSERT(bs);
562 
563 	bp->bp_topology_change_acknowledge = 1;
564 	bstp_transmit_config(bs, bp);
565 }
566 
567 struct mbuf *
568 bstp_input(struct bstp_port *bp, struct ifnet *ifp, struct mbuf *m)
569 {
570 	struct bstp_state *bs = bp->bp_bs;
571 	struct ether_header *eh;
572 	struct bstp_tbpdu tpdu;
573 	struct bstp_cbpdu cpdu;
574 	struct bstp_config_unit cu;
575 	struct bstp_tcn_unit tu;
576 	uint16_t len;
577 
578 	if (bp->bp_active == 0) {
579 		m_freem(m);
580 		return (NULL);
581 	}
582 
583 	BSTP_LOCK(bs);
584 
585 	eh = mtod(m, struct ether_header *);
586 
587 	len = ntohs(eh->ether_type);
588 	if (len < sizeof(tpdu))
589 		goto out;
590 
591 	m_adj(m, ETHER_HDR_LEN);
592 
593 	if (m->m_pkthdr.len > len)
594 		m_adj(m, len - m->m_pkthdr.len);
595 	if (m->m_len < sizeof(tpdu) &&
596 	    (m = m_pullup(m, sizeof(tpdu))) == NULL)
597 		goto out;
598 
599 	memcpy(&tpdu, mtod(m, caddr_t), sizeof(tpdu));
600 
601 	if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
602 	    tpdu.tbu_ssap != LLC_8021D_LSAP ||
603 	    tpdu.tbu_ctl != LLC_UI)
604 		goto out;
605 	if (tpdu.tbu_protoid != 0 || tpdu.tbu_protover != 0)
606 		goto out;
607 
608 	switch (tpdu.tbu_bpdutype) {
609 	case BSTP_MSGTYPE_TCN:
610 		tu.tu_message_type = tpdu.tbu_bpdutype;
611 		bstp_received_tcn_bpdu(bs, bp, &tu);
612 		break;
613 	case BSTP_MSGTYPE_CFG:
614 		if (m->m_len < sizeof(cpdu) &&
615 		    (m = m_pullup(m, sizeof(cpdu))) == NULL)
616 			goto out;
617 		memcpy(&cpdu, mtod(m, caddr_t), sizeof(cpdu));
618 
619 		cu.cu_rootid =
620 		    (((uint64_t)ntohs(cpdu.cbu_rootpri)) << 48) |
621 		    (((uint64_t)cpdu.cbu_rootaddr[0]) << 40) |
622 		    (((uint64_t)cpdu.cbu_rootaddr[1]) << 32) |
623 		    (((uint64_t)cpdu.cbu_rootaddr[2]) << 24) |
624 		    (((uint64_t)cpdu.cbu_rootaddr[3]) << 16) |
625 		    (((uint64_t)cpdu.cbu_rootaddr[4]) << 8) |
626 		    (((uint64_t)cpdu.cbu_rootaddr[5]) << 0);
627 
628 		cu.cu_bridge_id =
629 		    (((uint64_t)ntohs(cpdu.cbu_bridgepri)) << 48) |
630 		    (((uint64_t)cpdu.cbu_bridgeaddr[0]) << 40) |
631 		    (((uint64_t)cpdu.cbu_bridgeaddr[1]) << 32) |
632 		    (((uint64_t)cpdu.cbu_bridgeaddr[2]) << 24) |
633 		    (((uint64_t)cpdu.cbu_bridgeaddr[3]) << 16) |
634 		    (((uint64_t)cpdu.cbu_bridgeaddr[4]) << 8) |
635 		    (((uint64_t)cpdu.cbu_bridgeaddr[5]) << 0);
636 
637 		cu.cu_root_path_cost = ntohl(cpdu.cbu_rootpathcost);
638 		cu.cu_message_age = ntohs(cpdu.cbu_messageage);
639 		cu.cu_max_age = ntohs(cpdu.cbu_maxage);
640 		cu.cu_hello_time = ntohs(cpdu.cbu_hellotime);
641 		cu.cu_forward_delay = ntohs(cpdu.cbu_forwarddelay);
642 		cu.cu_port_id = ntohs(cpdu.cbu_portid);
643 		cu.cu_message_type = cpdu.cbu_bpdutype;
644 		cu.cu_topology_change_acknowledgment =
645 		    (cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0;
646 		cu.cu_topology_change =
647 		    (cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0;
648 		bstp_received_config_bpdu(bs, bp, &cu);
649 		break;
650 	default:
651 		goto out;
652 	}
653 
654 out:
655 	BSTP_UNLOCK(bs);
656 	if (m)
657 		m_freem(m);
658 	return (NULL);
659 }
660 
661 static void
662 bstp_received_config_bpdu(struct bstp_state *bs, struct bstp_port *bp,
663     struct bstp_config_unit *cu)
664 {
665 	int root;
666 
667 	BSTP_LOCK_ASSERT(bs);
668 
669 	root = bstp_root_bridge(bs);
670 
671 	if (bp->bp_state != BSTP_IFSTATE_DISABLED) {
672 		if (bstp_supersedes_port_info(bs, bp, cu)) {
673 			bstp_record_config_information(bs, bp, cu);
674 			bstp_configuration_update(bs);
675 			bstp_port_state_selection(bs);
676 
677 			if ((bstp_root_bridge(bs) == 0) && root) {
678 				bstp_timer_stop(&bs->bs_hello_timer);
679 
680 				if (bs->bs_topology_change_detected) {
681 					bstp_timer_stop(
682 					    &bs->bs_topology_change_timer);
683 					bstp_transmit_tcn(bs);
684 					bstp_timer_start(&bs->bs_tcn_timer, 0);
685 				}
686 			}
687 
688 			if (bp == bs->bs_root_port) {
689 				bstp_record_config_timeout_values(bs, cu);
690 				bstp_config_bpdu_generation(bs);
691 
692 				if (cu->cu_topology_change_acknowledgment)
693 					bstp_topology_change_acknowledged(bs);
694 			}
695 		} else if (bstp_designated_port(bs, bp))
696 			bstp_transmit_config(bs, bp);
697 	}
698 }
699 
700 static void
701 bstp_received_tcn_bpdu(struct bstp_state *bs, struct bstp_port *bp,
702     struct bstp_tcn_unit *tcn)
703 {
704 	if (bp->bp_state != BSTP_IFSTATE_DISABLED &&
705 	    bstp_designated_port(bs, bp)) {
706 		bstp_topology_change_detection(bs);
707 		bstp_acknowledge_topology_change(bs, bp);
708 	}
709 }
710 
711 static void
712 bstp_hello_timer_expiry(struct bstp_state *bs)
713 {
714 	bstp_config_bpdu_generation(bs);
715 	bstp_timer_start(&bs->bs_hello_timer, 0);
716 }
717 
718 static void
719 bstp_message_age_timer_expiry(struct bstp_state *bs,
720     struct bstp_port *bp)
721 {
722 	int root;
723 
724 	BSTP_LOCK_ASSERT(bs);
725 
726 	root = bstp_root_bridge(bs);
727 	bstp_become_designated_port(bs, bp);
728 	bstp_configuration_update(bs);
729 	bstp_port_state_selection(bs);
730 
731 	if ((bstp_root_bridge(bs)) && (root == 0)) {
732 		bs->bs_max_age = bs->bs_bridge_max_age;
733 		bs->bs_hello_time = bs->bs_bridge_hello_time;
734 		bs->bs_forward_delay = bs->bs_bridge_forward_delay;
735 
736 		bstp_topology_change_detection(bs);
737 		bstp_timer_stop(&bs->bs_tcn_timer);
738 		bstp_config_bpdu_generation(bs);
739 		bstp_timer_start(&bs->bs_hello_timer, 0);
740 	}
741 }
742 
743 static void
744 bstp_forward_delay_timer_expiry(struct bstp_state *bs,
745     struct bstp_port *bp)
746 {
747 	if (bp->bp_state == BSTP_IFSTATE_LISTENING) {
748 		bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
749 		bstp_timer_start(&bp->bp_forward_delay_timer, 0);
750 	} else if (bp->bp_state == BSTP_IFSTATE_LEARNING) {
751 		bstp_set_port_state(bp, BSTP_IFSTATE_FORWARDING);
752 		if (bstp_designated_for_some_port(bs) &&
753 		    bp->bp_change_detection_enabled)
754 			bstp_topology_change_detection(bs);
755 	}
756 }
757 
758 static int
759 bstp_designated_for_some_port(struct bstp_state *bs)
760 {
761 
762 	struct bstp_port *bp;
763 
764 	BSTP_LOCK_ASSERT(bs);
765 
766 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
767 		if (bp->bp_designated_bridge == bs->bs_bridge_id)
768 			return (1);
769 	}
770 	return (0);
771 }
772 
773 static void
774 bstp_tcn_timer_expiry(struct bstp_state *bs)
775 {
776 	BSTP_LOCK_ASSERT(bs);
777 
778 	bstp_transmit_tcn(bs);
779 	bstp_timer_start(&bs->bs_tcn_timer, 0);
780 }
781 
782 static void
783 bstp_topology_change_timer_expiry(struct bstp_state *bs)
784 {
785 	BSTP_LOCK_ASSERT(bs);
786 
787 	bs->bs_topology_change_detected = 0;
788 	bs->bs_topology_change = 0;
789 }
790 
791 static void
792 bstp_hold_timer_expiry(struct bstp_state *bs, struct bstp_port *bp)
793 {
794 	if (bp->bp_config_pending)
795 		bstp_transmit_config(bs, bp);
796 }
797 
798 static int
799 bstp_addr_cmp(const uint8_t *a, const uint8_t *b)
800 {
801 	int i, d;
802 
803 	for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
804 		d = ((int)a[i]) - ((int)b[i]);
805 	}
806 
807 	return (d);
808 }
809 
810 void
811 bstp_reinit(struct bstp_state *bs)
812 {
813 	struct bstp_port *bp, *mbp;
814 	u_char *e_addr;
815 
816 	BSTP_LOCK(bs);
817 
818 	mbp = NULL;
819 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
820 		bp->bp_port_id = (bp->bp_priority << 8) |
821 		    (bp->bp_ifp->if_index & 0xff);
822 
823 		if (mbp == NULL) {
824 			mbp = bp;
825 			continue;
826 		}
827 		if (bstp_addr_cmp(IF_LLADDR(bp->bp_ifp),
828 		    IF_LLADDR(mbp->bp_ifp)) < 0) {
829 			mbp = bp;
830 			continue;
831 		}
832 	}
833 	if (mbp == NULL) {
834 		BSTP_UNLOCK(bs);
835 		bstp_stop(bs);
836 		return;
837 	}
838 
839 	e_addr = IF_LLADDR(mbp->bp_ifp);
840 	bs->bs_bridge_id =
841 	    (((uint64_t)bs->bs_bridge_priority) << 48) |
842 	    (((uint64_t)e_addr[0]) << 40) |
843 	    (((uint64_t)e_addr[1]) << 32) |
844 	    (((uint64_t)e_addr[2]) << 24) |
845 	    (((uint64_t)e_addr[3]) << 16) |
846 	    (((uint64_t)e_addr[4]) << 8) |
847 	    (((uint64_t)e_addr[5]));
848 
849 	bs->bs_designated_root = bs->bs_bridge_id;
850 	bs->bs_root_path_cost = 0;
851 	bs->bs_root_port = NULL;
852 
853 	bs->bs_max_age = bs->bs_bridge_max_age;
854 	bs->bs_hello_time = bs->bs_bridge_hello_time;
855 	bs->bs_forward_delay = bs->bs_bridge_forward_delay;
856 	bs->bs_topology_change_detected = 0;
857 	bs->bs_topology_change = 0;
858 	bstp_timer_stop(&bs->bs_tcn_timer);
859 	bstp_timer_stop(&bs->bs_topology_change_timer);
860 
861 	if (callout_pending(&bs->bs_bstpcallout) == 0)
862 		callout_reset(&bs->bs_bstpcallout, hz,
863 		    bstp_tick, bs);
864 
865 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
866 		bstp_ifupdstatus(bs, bp);
867 
868 	bstp_port_state_selection(bs);
869 	bstp_config_bpdu_generation(bs);
870 	bstp_timer_start(&bs->bs_hello_timer, 0);
871 	bstp_timer_start(&bs->bs_link_timer, 0);
872 	BSTP_UNLOCK(bs);
873 }
874 
875 static int
876 bstp_modevent(module_t mod, int type, void *data)
877 {
878 
879 	switch (type) {
880 	case MOD_LOAD:
881 		mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF);
882 		LIST_INIT(&bstp_list);
883 		bstp_linkstate_p = bstp_linkstate;
884 		break;
885 	case MOD_UNLOAD:
886 		mtx_destroy(&bstp_list_mtx);
887 		break;
888 	default:
889 		return (EOPNOTSUPP);
890 	}
891 	return (0);
892 }
893 
894 static moduledata_t bstp_mod = {
895 	"bridgestp",
896 	bstp_modevent,
897 	0
898 };
899 
900 DECLARE_MODULE(bridgestp, bstp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
901 
902 void
903 bstp_attach(struct bstp_state *bs)
904 {
905 	BSTP_LOCK_INIT(bs);
906 	callout_init_mtx(&bs->bs_bstpcallout, &bs->bs_mtx, 0);
907 	LIST_INIT(&bs->bs_bplist);
908 
909 	bs->bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
910 	bs->bs_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
911 	bs->bs_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY;
912 	bs->bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
913 	bs->bs_hold_time = BSTP_DEFAULT_HOLD_TIME;
914 
915 	mtx_lock(&bstp_list_mtx);
916 	LIST_INSERT_HEAD(&bstp_list, bs, bs_list);
917 	mtx_unlock(&bstp_list_mtx);
918 }
919 
920 void
921 bstp_detach(struct bstp_state *bs)
922 {
923 	KASSERT(LIST_EMPTY(&bs->bs_bplist), ("bstp still active"));
924 
925 	mtx_lock(&bstp_list_mtx);
926 	LIST_REMOVE(bs, bs_list);
927 	mtx_unlock(&bstp_list_mtx);
928 	BSTP_LOCK_DESTROY(bs);
929 }
930 
931 void
932 bstp_init(struct bstp_state *bs)
933 {
934 	callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
935 	bstp_reinit(bs);
936 }
937 
938 void
939 bstp_stop(struct bstp_state *bs)
940 {
941 	struct bstp_port *bp;
942 
943 	BSTP_LOCK(bs);
944 
945 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
946 		bstp_set_port_state(bp, BSTP_IFSTATE_DISABLED);
947 		bstp_timer_stop(&bp->bp_hold_timer);
948 		bstp_timer_stop(&bp->bp_message_age_timer);
949 		bstp_timer_stop(&bp->bp_forward_delay_timer);
950 	}
951 
952 	callout_drain(&bs->bs_bstpcallout);
953 	callout_stop(&bs->bs_bstpcallout);
954 
955 	bstp_timer_stop(&bs->bs_topology_change_timer);
956 	bstp_timer_stop(&bs->bs_tcn_timer);
957 	bstp_timer_stop(&bs->bs_hello_timer);
958 
959 	BSTP_UNLOCK(bs);
960 }
961 
962 static void
963 bstp_initialize_port(struct bstp_state *bs, struct bstp_port *bp)
964 {
965 	BSTP_LOCK_ASSERT(bs);
966 
967 	bstp_become_designated_port(bs, bp);
968 	bstp_set_port_state(bp, BSTP_IFSTATE_BLOCKING);
969 	bp->bp_topology_change_acknowledge = 0;
970 	bp->bp_config_pending = 0;
971 	bp->bp_change_detection_enabled = 1;
972 	bstp_timer_stop(&bp->bp_message_age_timer);
973 	bstp_timer_stop(&bp->bp_forward_delay_timer);
974 	bstp_timer_stop(&bp->bp_hold_timer);
975 }
976 
977 static void
978 bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp)
979 {
980 	bstp_initialize_port(bs, bp);
981 	bstp_port_state_selection(bs);
982 }
983 
984 static void
985 bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp)
986 {
987 	int root;
988 
989 	BSTP_LOCK_ASSERT(bs);
990 
991 	root = bstp_root_bridge(bs);
992 	bstp_become_designated_port(bs, bp);
993 	bstp_set_port_state(bp, BSTP_IFSTATE_DISABLED);
994 	bp->bp_topology_change_acknowledge = 0;
995 	bp->bp_config_pending = 0;
996 	bstp_timer_stop(&bp->bp_message_age_timer);
997 	bstp_timer_stop(&bp->bp_forward_delay_timer);
998 	bstp_configuration_update(bs);
999 	bstp_port_state_selection(bs);
1000 	/* XXX bridge_rtdelete(bs, bp->bp_ifp, IFBF_FLUSHDYN); */
1001 
1002 	if (bstp_root_bridge(bs) && (root == 0)) {
1003 		bs->bs_max_age = bs->bs_bridge_max_age;
1004 		bs->bs_hello_time = bs->bs_bridge_hello_time;
1005 		bs->bs_forward_delay = bs->bs_bridge_forward_delay;
1006 
1007 		bstp_topology_change_detection(bs);
1008 		bstp_timer_stop(&bs->bs_tcn_timer);
1009 		bstp_config_bpdu_generation(bs);
1010 		bstp_timer_start(&bs->bs_hello_timer, 0);
1011 	}
1012 }
1013 
1014 #ifdef notused
1015 static void
1016 bstp_set_bridge_priority(struct bstp_state *bs, uint64_t new_bridge_id)
1017 {
1018 	struct bstp_port *bp;
1019 	int root;
1020 
1021 	BSTP_LOCK_ASSERT(bs);
1022 
1023 	root = bstp_root_bridge(bs);
1024 
1025 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1026 		if (bstp_designated_port(bs, bp))
1027 			bp->bp_designated_bridge = new_bridge_id;
1028 	}
1029 
1030 	bs->bs_bridge_id = new_bridge_id;
1031 
1032 	bstp_configuration_update(bs);
1033 	bstp_port_state_selection(bs);
1034 
1035 	if (bstp_root_bridge(bs) && (root == 0)) {
1036 		bs->bs_max_age = bs->bs_bridge_max_age;
1037 		bs->bs_hello_time = bs->bs_bridge_hello_time;
1038 		bs->bs_forward_delay = bs->bs_bridge_forward_delay;
1039 
1040 		bstp_topology_change_detection(bs);
1041 		bstp_timer_stop(&bs->bs_tcn_timer);
1042 		bstp_config_bpdu_generation(bs);
1043 		bstp_timer_start(&bs->bs_hello_timer, 0);
1044 	}
1045 }
1046 
1047 static void
1048 bstp_set_port_priority(struct bstp_state *bs, struct bstp_port *bp,
1049     uint16_t new_port_id)
1050 {
1051 	if (bstp_designated_port(bs, bp))
1052 		bp->bp_designated_port = new_port_id;
1053 
1054 	bp->bp_port_id = new_port_id;
1055 
1056 	if ((bs->bs_bridge_id == bp->bp_designated_bridge) &&
1057 	    (bp->bp_port_id < bp->bp_designated_port)) {
1058 		bstp_become_designated_port(bs, bp);
1059 		bstp_port_state_selection(bs);
1060 	}
1061 }
1062 
1063 static void
1064 bstp_set_path_cost(struct bstp_state *bs, struct bstp_port *bp,
1065     uint32_t path_cost)
1066 {
1067 	bp->bp_path_cost = path_cost;
1068 	bstp_configuration_update(bs);
1069 	bstp_port_state_selection(bs);
1070 }
1071 
1072 static void
1073 bstp_enable_change_detection(struct bstp_port *bp)
1074 {
1075 	bp->bp_change_detection_enabled = 1;
1076 }
1077 
1078 static void
1079 bstp_disable_change_detection(struct bstp_port *bp)
1080 {
1081 	bp->bp_change_detection_enabled = 0;
1082 }
1083 #endif /* notused */
1084 
1085 static void
1086 bstp_enqueue(struct ifnet *dst_ifp, struct mbuf *m)
1087 {
1088 	int err = 0;
1089 
1090 	IFQ_ENQUEUE(&dst_ifp->if_snd, m, err);
1091 
1092 	if ((dst_ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0)
1093 		(*dst_ifp->if_start)(dst_ifp);
1094 }
1095 
1096 void
1097 bstp_linkstate(struct ifnet *ifp, int state)
1098 {
1099 	struct bstp_state *bs;
1100 	struct bstp_port *bp;
1101 
1102 	/*
1103 	 * It would be nice if the ifnet had a pointer to the bstp_port so we
1104 	 * didnt need to search for it, but that may be an overkill. In reality
1105 	 * this is fast and doesnt get called often.
1106 	 */
1107 	mtx_lock(&bstp_list_mtx);
1108 	LIST_FOREACH(bs, &bstp_list, bs_list) {
1109 		BSTP_LOCK(bs);
1110 		LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1111 			if (bp->bp_ifp == ifp) {
1112 				bstp_ifupdstatus(bs, bp);
1113 				/* it only exists once so return */
1114 				BSTP_UNLOCK(bs);
1115 				mtx_unlock(&bstp_list_mtx);
1116 				return;
1117 			}
1118 		}
1119 		BSTP_UNLOCK(bs);
1120 	}
1121 	mtx_unlock(&bstp_list_mtx);
1122 }
1123 
1124 static void
1125 bstp_ifupdstatus(struct bstp_state *bs, struct bstp_port *bp)
1126 {
1127 	struct ifnet *ifp = bp->bp_ifp;
1128 	struct ifmediareq ifmr;
1129 	int error = 0;
1130 
1131 	BSTP_LOCK_ASSERT(bs);
1132 
1133 	bzero((char *)&ifmr, sizeof(ifmr));
1134 	error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
1135 
1136 	if ((error == 0) && (ifp->if_flags & IFF_UP)) {
1137 		if (ifmr.ifm_status & IFM_ACTIVE) {
1138 			if (bp->bp_state == BSTP_IFSTATE_DISABLED)
1139 				bstp_enable_port(bs, bp);
1140 
1141 		} else {
1142 			if (bp->bp_state != BSTP_IFSTATE_DISABLED)
1143 				bstp_disable_port(bs, bp);
1144 		}
1145 		return;
1146 	}
1147 
1148 	if (bp->bp_state != BSTP_IFSTATE_DISABLED)
1149 		bstp_disable_port(bs, bp);
1150 }
1151 
1152 static void
1153 bstp_tick(void *arg)
1154 {
1155 	struct bstp_state *bs = arg;
1156 	struct bstp_port *bp;
1157 
1158 	BSTP_LOCK_ASSERT(bs);
1159 
1160 	/* slow timer to catch missed link events */
1161 	if (bstp_timer_expired(&bs->bs_link_timer, BSTP_LINK_TIMER)) {
1162 		LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1163 			bstp_ifupdstatus(bs, bp);
1164 		}
1165 		bstp_timer_start(&bs->bs_link_timer, 0);
1166 	}
1167 
1168 	if (bstp_timer_expired(&bs->bs_hello_timer, bs->bs_hello_time))
1169 		bstp_hello_timer_expiry(bs);
1170 
1171 	if (bstp_timer_expired(&bs->bs_tcn_timer, bs->bs_bridge_hello_time))
1172 		bstp_tcn_timer_expiry(bs);
1173 
1174 	if (bstp_timer_expired(&bs->bs_topology_change_timer,
1175 	    bs->bs_topology_change_time))
1176 		bstp_topology_change_timer_expiry(bs);
1177 
1178 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1179 		if (bstp_timer_expired(&bp->bp_message_age_timer,
1180 		    bs->bs_max_age))
1181 			bstp_message_age_timer_expiry(bs, bp);
1182 	}
1183 
1184 	LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1185 		if (bstp_timer_expired(&bp->bp_forward_delay_timer,
1186 		    bs->bs_forward_delay))
1187 			bstp_forward_delay_timer_expiry(bs, bp);
1188 
1189 		if (bstp_timer_expired(&bp->bp_hold_timer,
1190 		    bs->bs_hold_time))
1191 			bstp_hold_timer_expiry(bs, bp);
1192 	}
1193 
1194 	callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
1195 }
1196 
1197 static void
1198 bstp_timer_start(struct bstp_timer *t, uint16_t v)
1199 {
1200 	t->value = v;
1201 	t->active = 1;
1202 }
1203 
1204 static void
1205 bstp_timer_stop(struct bstp_timer *t)
1206 {
1207 	t->value = 0;
1208 	t->active = 0;
1209 }
1210 
1211 static int
1212 bstp_timer_expired(struct bstp_timer *t, uint16_t v)
1213 {
1214 	if (t->active == 0)
1215 		return (0);
1216 	t->value += BSTP_TICK_VAL;
1217 	if (t->value >= v) {
1218 		bstp_timer_stop(t);
1219 		return (1);
1220 	}
1221 	return (0);
1222 
1223 }
1224 
1225 int
1226 bstp_add(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp)
1227 {
1228 	KASSERT(bp->bp_active == 0, ("already a bstp member"));
1229 
1230 	switch (ifp->if_type) {
1231 		case IFT_ETHER:	/* These can do spanning tree. */
1232 			break;
1233 		default:
1234 			/* Nothing else can. */
1235 			return (EINVAL);
1236 	}
1237 
1238 	BSTP_LOCK(bs);
1239 	bp->bp_ifp = ifp;
1240 	bp->bp_bs = bs;
1241 	bp->bp_active = 1;
1242 	bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY;
1243 	bp->bp_path_cost = BSTP_DEFAULT_PATH_COST;
1244 
1245 	LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next);
1246 	BSTP_UNLOCK(bs);
1247 	bstp_reinit(bs);
1248 
1249 	return (0);
1250 }
1251 
1252 void
1253 bstp_delete(struct bstp_port *bp)
1254 {
1255 	struct bstp_state *bs = bp->bp_bs;
1256 
1257 	KASSERT(bp->bp_active == 1, ("not a bstp member"));
1258 
1259 	BSTP_LOCK(bs);
1260 	LIST_REMOVE(bp, bp_next);
1261 	BSTP_UNLOCK(bs);
1262 	bp->bp_bs = NULL;
1263 	bp->bp_active = 0;
1264 
1265 	bstp_reinit(bs);
1266 }
1267