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