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