1 /* $OpenBSD: bridgestp.c,v 1.16 2003/11/16 20:30:07 avsm 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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * Implementation of the spanning tree protocol as defined in
31 * ISO/IEC Final DIS 15802-3 (IEEE P802.1D/D17), May 25, 1998.
32 * (In English: IEEE 802.1D, Draft 17, 1998)
33 */
34
35 #include "bridge.h"
36
37 #if NBRIDGE > 0
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43 #include <sys/ioctl.h>
44 #include <sys/device.h>
45 #include <sys/kernel.h>
46 #include <sys/timeout.h>
47
48 #include <net/if.h>
49 #include <net/if_types.h>
50 #include <net/if_llc.h>
51 #include <net/if_media.h>
52 #include <net/route.h>
53 #include <net/netisr.h>
54
55 #ifdef INET
56 #include <netinet/in.h>
57 #include <netinet/in_systm.h>
58 #include <netinet/in_var.h>
59 #include <netinet/ip.h>
60 #include <netinet/if_ether.h>
61 #endif
62
63 #if NBPFILTER > 0
64 #include <net/bpf.h>
65 #endif
66
67 #include <net/if_bridge.h>
68
69 /* BPDU message types */
70 #define BSTP_MSGTYPE_CFG 0x00 /* Configuration */
71 #define BSTP_MSGTYPE_TCN 0x80 /* Topology chg notification */
72
73 /* BPDU flags */
74 #define BSTP_FLAG_TC 0x01 /* Topology change */
75 #define BSTP_FLAG_TCA 0x80 /* Topology change ack */
76
77 #define BSTP_MESSAGE_AGE_INCR (1 * 256) /* in 256ths of a second */
78 #define BSTP_TICK_VAL (1 * 256) /* in 256ths of a second */
79
80 /*
81 * Because BPDU's do not make nicely aligned structures, two different
82 * declarations are used: bstp_?bpdu (wire representation, packed) and
83 * bstp_*_unit (internal, nicely aligned version).
84 */
85
86 /* configuration bridge protocol data unit */
87 struct bstp_cbpdu {
88 u_int8_t cbu_dsap; /* LLC: destination sap */
89 u_int8_t cbu_ssap; /* LLC: source sap */
90 u_int8_t cbu_ctl; /* LLC: control */
91 u_int16_t cbu_protoid; /* protocol id */
92 u_int8_t cbu_protover; /* protocol version */
93 u_int8_t cbu_bpdutype; /* message type */
94 u_int8_t cbu_flags; /* flags (below) */
95
96 /* root id */
97 u_int16_t cbu_rootpri; /* root priority */
98 u_int8_t cbu_rootaddr[6]; /* root address */
99
100 u_int32_t cbu_rootpathcost; /* root path cost */
101
102 /* bridge id */
103 u_int16_t cbu_bridgepri; /* bridge priority */
104 u_int8_t cbu_bridgeaddr[6]; /* bridge address */
105
106 u_int16_t cbu_portid; /* port id */
107 u_int16_t cbu_messageage; /* current message age */
108 u_int16_t cbu_maxage; /* maximum age */
109 u_int16_t cbu_hellotime; /* hello time */
110 u_int16_t cbu_forwarddelay; /* forwarding delay */
111 } __packed;
112
113 /* topology change notification bridge protocol data unit */
114 struct bstp_tbpdu {
115 u_int8_t tbu_dsap; /* LLC: destination sap */
116 u_int8_t tbu_ssap; /* LLC: source sap */
117 u_int8_t tbu_ctl; /* LLC: control */
118 u_int16_t tbu_protoid; /* protocol id */
119 u_int8_t tbu_protover; /* protocol version */
120 u_int8_t tbu_bpdutype; /* message type */
121 } __packed;
122
123 u_int8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
124
125 void bstp_initialization(struct bridge_softc *);
126 void bstp_stop(struct bridge_softc *);
127 void bstp_initialize_port(struct bridge_softc *, struct bridge_iflist *);
128 void bstp_ifupdstatus(struct bridge_softc *, struct bridge_iflist *);
129 void bstp_enable_port(struct bridge_softc *, struct bridge_iflist *);
130 void bstp_disable_port(struct bridge_softc *, struct bridge_iflist *);
131 void bstp_enable_change_detection(struct bridge_iflist *);
132 void bstp_disable_change_detection(struct bridge_iflist *);
133 int bstp_root_bridge(struct bridge_softc *sc);
134 int bstp_supersedes_port_info(struct bridge_softc *, struct bridge_iflist *,
135 struct bstp_config_unit *);
136 int bstp_designated_port(struct bridge_softc *, struct bridge_iflist *);
137 int bstp_designated_for_some_port(struct bridge_softc *);
138 void bstp_transmit_config(struct bridge_softc *, struct bridge_iflist *);
139 void bstp_transmit_tcn(struct bridge_softc *);
140 struct mbuf *bstp_input(struct bridge_softc *, struct ifnet *,
141 struct ether_header *, struct mbuf *);
142 void bstp_received_config_bpdu(struct bridge_softc *, struct bridge_iflist *,
143 struct bstp_config_unit *);
144 void bstp_received_tcn_bpdu(struct bridge_softc *, struct bridge_iflist *,
145 struct bstp_tcn_unit *);
146 void bstp_record_config_information(struct bridge_softc *,
147 struct bridge_iflist *, struct bstp_config_unit *);
148 void bstp_record_config_timeout_values(struct bridge_softc *,
149 struct bstp_config_unit *);
150 void bstp_config_bpdu_generation(struct bridge_softc *);
151 void bstp_send_config_bpdu(struct bridge_iflist *, struct bstp_config_unit *);
152 void bstp_configuration_update(struct bridge_softc *);
153 void bstp_root_selection(struct bridge_softc *);
154 void bstp_designated_port_selection(struct bridge_softc *);
155 void bstp_become_designated_port(struct bridge_softc *, struct bridge_iflist *);
156 void bstp_port_state_selection(struct bridge_softc *);
157 void bstp_make_forwarding(struct bridge_softc *, struct bridge_iflist *);
158 void bstp_make_blocking(struct bridge_softc *, struct bridge_iflist *);
159 void bstp_set_port_state(struct bridge_iflist *, u_int8_t);
160 void bstp_set_bridge_priority(struct bridge_softc *, u_int64_t);
161 void bstp_set_port_priority(struct bridge_softc *, struct bridge_iflist *,
162 u_int16_t);
163 void bstp_set_path_cost(struct bridge_softc *, struct bridge_iflist *,
164 u_int32_t);
165 void bstp_topology_change_detection(struct bridge_softc *);
166 void bstp_topology_change_acknowledged(struct bridge_softc *);
167 void bstp_acknowledge_topology_change(struct bridge_softc *,
168 struct bridge_iflist *);
169
170 void bstp_tick(void *);
171 void bstp_timer_start(struct bridge_timer *, u_int16_t);
172 void bstp_timer_stop(struct bridge_timer *);
173 int bstp_timer_expired(struct bridge_timer *, u_int16_t);
174
175 void bstp_hold_timer_expiry(struct bridge_softc *, struct bridge_iflist *);
176 void bstp_message_age_timer_expiry(struct bridge_softc *,
177 struct bridge_iflist *);
178 void bstp_forward_delay_timer_expiry(struct bridge_softc *,
179 struct bridge_iflist *);
180 void bstp_topology_change_timer_expiry(struct bridge_softc *);
181 void bstp_tcn_timer_expiry(struct bridge_softc *);
182 void bstp_hello_timer_expiry(struct bridge_softc *);
183
184 void
bstp_transmit_config(sc,bif)185 bstp_transmit_config(sc, bif)
186 struct bridge_softc *sc;
187 struct bridge_iflist *bif;
188 {
189 if (bif->bif_hold_timer.active) {
190 bif->bif_config_pending = 1;
191 return;
192 }
193
194 bif->bif_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
195 bif->bif_config_bpdu.cu_rootid = sc->sc_designated_root;
196 bif->bif_config_bpdu.cu_root_path_cost = sc->sc_root_path_cost;
197 bif->bif_config_bpdu.cu_bridge_id = sc->sc_bridge_id;
198 bif->bif_config_bpdu.cu_port_id = bif->bif_port_id;
199
200 if (bstp_root_bridge(sc))
201 bif->bif_config_bpdu.cu_message_age = 0;
202 else
203 bif->bif_config_bpdu.cu_message_age =
204 sc->sc_root_port->bif_message_age_timer.value +
205 BSTP_MESSAGE_AGE_INCR;
206
207 bif->bif_config_bpdu.cu_max_age = sc->sc_max_age;
208 bif->bif_config_bpdu.cu_hello_time = sc->sc_hello_time;
209 bif->bif_config_bpdu.cu_forward_delay = sc->sc_forward_delay;
210 bif->bif_config_bpdu.cu_topology_change_acknowledgment
211 = bif->bif_topology_change_acknowledge;
212 bif->bif_config_bpdu.cu_topology_change = sc->sc_topology_change;
213
214 if (bif->bif_config_bpdu.cu_message_age < sc->sc_max_age) {
215 bif->bif_topology_change_acknowledge = 0;
216 bif->bif_config_pending = 0;
217 bstp_send_config_bpdu(bif, &bif->bif_config_bpdu);
218 bstp_timer_start(&bif->bif_hold_timer, 0);
219 }
220 }
221
222 void
bstp_send_config_bpdu(bif,cu)223 bstp_send_config_bpdu(bif, cu)
224 struct bridge_iflist *bif;
225 struct bstp_config_unit *cu;
226 {
227 struct arpcom *arp;
228 struct ifnet *ifp;
229 struct mbuf *m;
230 struct ether_header eh;
231 struct bstp_cbpdu bpdu;
232 int s, error;
233
234 s = splimp();
235 ifp = bif->ifp;
236 arp = (struct arpcom *)ifp;
237
238 if ((ifp->if_flags & IFF_RUNNING) == 0) {
239 splx(s);
240 return;
241 }
242 #ifdef ALTQ
243 if (!ALTQ_IS_ENABLED(&ifp->if_snd))
244 #endif
245 if (IF_QFULL(&ifp->if_snd)) {
246 splx(s);
247 return;
248 }
249
250 MGETHDR(m, M_DONTWAIT, MT_DATA);
251 if (m == NULL) {
252 splx(s);
253 return;
254 }
255 m->m_pkthdr.rcvif = ifp;
256 m->m_pkthdr.len = sizeof(eh) + sizeof(bpdu);
257 m->m_len = m->m_pkthdr.len;
258
259 bpdu.cbu_ssap = bpdu.cbu_dsap = LLC_8021D_LSAP;
260 bpdu.cbu_ctl = LLC_UI;
261 bpdu.cbu_protoid = htons(0);
262 bpdu.cbu_protover = 0;
263 bpdu.cbu_bpdutype = cu->cu_message_type;
264 bpdu.cbu_flags = (cu->cu_topology_change ? BSTP_FLAG_TC : 0) |
265 (cu->cu_topology_change_acknowledgment ? BSTP_FLAG_TCA : 0);
266
267 bpdu.cbu_rootpri = htons(cu->cu_rootid >> 48);
268 bpdu.cbu_rootaddr[0] = cu->cu_rootid >> 40;
269 bpdu.cbu_rootaddr[1] = cu->cu_rootid >> 32;
270 bpdu.cbu_rootaddr[2] = cu->cu_rootid >> 24;
271 bpdu.cbu_rootaddr[3] = cu->cu_rootid >> 16;
272 bpdu.cbu_rootaddr[4] = cu->cu_rootid >> 8;
273 bpdu.cbu_rootaddr[5] = cu->cu_rootid >> 0;
274
275 bpdu.cbu_rootpathcost = htonl(cu->cu_root_path_cost);
276
277 bpdu.cbu_bridgepri = htons(cu->cu_rootid >> 48);
278 bpdu.cbu_bridgeaddr[0] = cu->cu_rootid >> 40;
279 bpdu.cbu_bridgeaddr[1] = cu->cu_rootid >> 32;
280 bpdu.cbu_bridgeaddr[2] = cu->cu_rootid >> 24;
281 bpdu.cbu_bridgeaddr[3] = cu->cu_rootid >> 16;
282 bpdu.cbu_bridgeaddr[4] = cu->cu_rootid >> 8;
283 bpdu.cbu_bridgeaddr[5] = cu->cu_rootid >> 0;
284
285 bpdu.cbu_portid = htons(cu->cu_port_id);
286 bpdu.cbu_messageage = htons(cu->cu_message_age);
287 bpdu.cbu_maxage = htons(cu->cu_max_age);
288 bpdu.cbu_hellotime = htons(cu->cu_hello_time);
289 bpdu.cbu_forwarddelay = htons(cu->cu_forward_delay);
290
291 bcopy(arp->ac_enaddr, eh.ether_shost, ETHER_ADDR_LEN);
292 bcopy(bstp_etheraddr, eh.ether_dhost, ETHER_ADDR_LEN);
293 eh.ether_type = htons(sizeof(bpdu));
294
295 bcopy(&eh, m->m_data, sizeof(eh));
296 bcopy(&bpdu, m->m_data + sizeof(eh), sizeof(bpdu));
297
298 IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
299 if (error == 0 && (ifp->if_flags & IFF_OACTIVE) == 0)
300 (*ifp->if_start)(ifp);
301 splx(s);
302 }
303
304 int
bstp_root_bridge(sc)305 bstp_root_bridge(sc)
306 struct bridge_softc *sc;
307 {
308 return (sc->sc_designated_root == sc->sc_bridge_id);
309 }
310
311 int
bstp_supersedes_port_info(sc,bif,cu)312 bstp_supersedes_port_info(sc, bif, cu)
313 struct bridge_softc *sc;
314 struct bridge_iflist *bif;
315 struct bstp_config_unit *cu;
316 {
317 if (cu->cu_rootid < bif->bif_designated_root)
318 return (1);
319 if (cu->cu_rootid > bif->bif_designated_root)
320 return (0);
321
322 if (cu->cu_root_path_cost < bif->bif_designated_cost)
323 return (1);
324 if (cu->cu_root_path_cost > bif->bif_designated_cost)
325 return (0);
326
327 if (cu->cu_bridge_id < bif->bif_designated_bridge)
328 return (1);
329 if (cu->cu_bridge_id > bif->bif_designated_bridge)
330 return (0);
331
332 if (sc->sc_bridge_id != cu->cu_bridge_id)
333 return (1);
334 if (cu->cu_port_id <= bif->bif_designated_port)
335 return (1);
336 return (0);
337 }
338
339 void
bstp_record_config_information(sc,bif,cu)340 bstp_record_config_information(sc, bif, cu)
341 struct bridge_softc *sc;
342 struct bridge_iflist *bif;
343 struct bstp_config_unit *cu;
344 {
345 bif->bif_designated_root = cu->cu_rootid;
346 bif->bif_designated_cost = cu->cu_root_path_cost;
347 bif->bif_designated_bridge = cu->cu_bridge_id;
348 bif->bif_designated_port = cu->cu_port_id;
349 bstp_timer_start(&bif->bif_message_age_timer, cu->cu_message_age);
350 }
351
352 void
bstp_record_config_timeout_values(sc,config)353 bstp_record_config_timeout_values(sc, config)
354 struct bridge_softc *sc;
355 struct bstp_config_unit *config;
356 {
357 sc->sc_max_age = config->cu_max_age;
358 sc->sc_hello_time = config->cu_hello_time;
359 sc->sc_forward_delay = config->cu_forward_delay;
360 sc->sc_topology_change = config->cu_topology_change;
361 }
362
363 void
bstp_config_bpdu_generation(sc)364 bstp_config_bpdu_generation(sc)
365 struct bridge_softc *sc;
366 {
367 struct bridge_iflist *bif;
368
369 LIST_FOREACH(bif, &sc->sc_iflist, next) {
370 if (!(bif->bif_flags & IFBIF_STP))
371 continue;
372 if (bstp_designated_port(sc, bif) &&
373 (bif->bif_state != BSTP_IFSTATE_DISABLED))
374 bstp_transmit_config(sc, bif);
375 }
376 }
377
378 int
bstp_designated_port(sc,bif)379 bstp_designated_port(sc, bif)
380 struct bridge_softc *sc;
381 struct bridge_iflist *bif;
382 {
383 return ((bif->bif_designated_bridge == sc->sc_bridge_id)
384 && (bif->bif_designated_port == bif->bif_port_id));
385 }
386
387 void
bstp_transmit_tcn(sc)388 bstp_transmit_tcn(sc)
389 struct bridge_softc *sc;
390 {
391 struct bstp_tbpdu bpdu;
392 struct bridge_iflist *bif = sc->sc_root_port;
393 struct ifnet *ifp = bif->ifp;
394 struct arpcom *arp = (struct arpcom *)ifp;
395 struct ether_header *eh;
396 struct mbuf *m;
397 int s, error;
398
399 if ((ifp->if_flags & IFF_RUNNING) == 0)
400 return;
401
402 MGETHDR(m, M_DONTWAIT, MT_DATA);
403 if (m == NULL)
404 return;
405 m->m_pkthdr.rcvif = ifp;
406 m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
407 m->m_len = m->m_pkthdr.len;
408
409 eh = mtod(m, struct ether_header *);
410 bcopy(arp->ac_enaddr, eh->ether_shost, ETHER_ADDR_LEN);
411 bcopy(bstp_etheraddr, eh->ether_dhost, ETHER_ADDR_LEN);
412 eh->ether_type = htons(sizeof(bpdu));
413
414 bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
415 bpdu.tbu_ctl = LLC_UI;
416 bpdu.tbu_protoid = 0;
417 bpdu.tbu_protover = 0;
418 bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
419 bcopy(&bpdu, m->m_data + sizeof(*eh), sizeof(bpdu));
420
421 s = splimp();
422 IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
423 if (error == 0 && (ifp->if_flags & IFF_OACTIVE) == 0)
424 (*ifp->if_start)(ifp);
425 m = NULL;
426
427 splx(s);
428 if (m != NULL)
429 m_freem(m);
430 }
431
432 void
bstp_configuration_update(sc)433 bstp_configuration_update(sc)
434 struct bridge_softc *sc;
435 {
436 bstp_root_selection(sc);
437 bstp_designated_port_selection(sc);
438 }
439
440 void
bstp_root_selection(sc)441 bstp_root_selection(sc)
442 struct bridge_softc *sc;
443 {
444 struct bridge_iflist *root_port = NULL, *bif;
445
446 LIST_FOREACH(bif, &sc->sc_iflist, next) {
447 if (!(bif->bif_flags & IFBIF_STP))
448 continue;
449 if (bstp_designated_port(sc, bif))
450 continue;
451 if (bif->bif_state == BSTP_IFSTATE_DISABLED)
452 continue;
453 if (bif->bif_designated_root >= sc->sc_bridge_id)
454 continue;
455 if (root_port == NULL)
456 goto set_port;
457
458 if (bif->bif_designated_root < root_port->bif_designated_root)
459 goto set_port;
460 if (bif->bif_designated_root > root_port->bif_designated_root)
461 continue;
462
463 if ((bif->bif_designated_cost + bif->bif_path_cost) <
464 (root_port->bif_designated_cost + root_port->bif_path_cost))
465 goto set_port;
466 if ((bif->bif_designated_cost + bif->bif_path_cost) >
467 (root_port->bif_designated_cost + root_port->bif_path_cost))
468 continue;
469
470 if (bif->bif_designated_bridge < root_port->bif_designated_bridge)
471 goto set_port;
472 if (bif->bif_designated_bridge > root_port->bif_designated_bridge)
473 continue;
474
475 if (bif->bif_designated_port < root_port->bif_designated_port)
476 goto set_port;
477 if (bif->bif_designated_port > root_port->bif_designated_port)
478 continue;
479
480 if (bif->bif_port_id >= root_port->bif_port_id)
481 continue;
482 set_port:
483 root_port = bif;
484 }
485
486 sc->sc_root_port = root_port;
487 if (root_port == NULL) {
488 sc->sc_designated_root = sc->sc_bridge_id;
489 sc->sc_root_path_cost = 0;
490 } else {
491 sc->sc_designated_root = root_port->bif_designated_root;
492 sc->sc_root_path_cost = root_port->bif_designated_cost +
493 root_port->bif_path_cost;
494 }
495 }
496
497 void
bstp_designated_port_selection(sc)498 bstp_designated_port_selection(sc)
499 struct bridge_softc *sc;
500 {
501 struct bridge_iflist *bif;
502
503 LIST_FOREACH(bif, &sc->sc_iflist, next) {
504 if (!(bif->bif_flags & IFBIF_STP))
505 continue;
506 if (bstp_designated_port(sc, bif))
507 goto designated;
508 if (bif->bif_designated_root != sc->sc_designated_root)
509 goto designated;
510
511 if (sc->sc_root_path_cost < bif->bif_designated_cost)
512 goto designated;
513 if (sc->sc_root_path_cost > bif->bif_designated_cost)
514 continue;
515
516 if (sc->sc_bridge_id < bif->bif_designated_bridge)
517 goto designated;
518 if (sc->sc_bridge_id > bif->bif_designated_bridge)
519 continue;
520
521 if (bif->bif_port_id > bif->bif_designated_port)
522 continue;
523 designated:
524 bstp_become_designated_port(sc, bif);
525 }
526 }
527
528 void
bstp_become_designated_port(sc,bif)529 bstp_become_designated_port(sc, bif)
530 struct bridge_softc *sc;
531 struct bridge_iflist *bif;
532 {
533 bif->bif_designated_root = sc->sc_designated_root;
534 bif->bif_designated_cost = sc->sc_root_path_cost;
535 bif->bif_designated_bridge = sc->sc_bridge_id;
536 bif->bif_designated_port = bif->bif_port_id;
537 }
538
539 void
bstp_port_state_selection(sc)540 bstp_port_state_selection(sc)
541 struct bridge_softc *sc;
542 {
543 struct bridge_iflist *bif;
544
545 LIST_FOREACH(bif, &sc->sc_iflist, next) {
546 if (!(bif->bif_flags & IFBIF_STP))
547 continue;
548 if (bif == sc->sc_root_port) {
549 bif->bif_config_pending = 0;
550 bif->bif_topology_change_acknowledge = 0;
551 bstp_make_forwarding(sc, bif);
552 } else if (bstp_designated_port(sc, bif)) {
553 bstp_timer_stop(&bif->bif_message_age_timer);
554 bstp_make_forwarding(sc, bif);
555 } else {
556 bif->bif_config_pending = 0;
557 bif->bif_topology_change_acknowledge = 0;
558 bstp_make_blocking(sc, bif);
559 }
560 }
561 }
562
563 void
bstp_make_forwarding(sc,bif)564 bstp_make_forwarding(sc, bif)
565 struct bridge_softc *sc;
566 struct bridge_iflist *bif;
567 {
568 if (bif->bif_state == BSTP_IFSTATE_BLOCKING) {
569 bstp_set_port_state(bif, BSTP_IFSTATE_LISTENING);
570 bstp_timer_start(&bif->bif_forward_delay_timer, 0);
571 }
572 }
573
574 void
bstp_make_blocking(sc,bif)575 bstp_make_blocking(sc, bif)
576 struct bridge_softc *sc;
577 struct bridge_iflist *bif;
578 {
579 if ((bif->bif_state != BSTP_IFSTATE_DISABLED) &&
580 (bif->bif_state != BSTP_IFSTATE_BLOCKING)) {
581 if ((bif->bif_state == BSTP_IFSTATE_FORWARDING) ||
582 (bif->bif_state == BSTP_IFSTATE_LEARNING)) {
583 if (bif->bif_change_detection_enabled) {
584 bstp_topology_change_detection(sc);
585 }
586 bridge_rtdelete(sc, bif->ifp, 1);
587 }
588 bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
589 bstp_timer_stop(&bif->bif_forward_delay_timer);
590 }
591 }
592
593 void
bstp_set_port_state(bif,state)594 bstp_set_port_state(bif, state)
595 struct bridge_iflist *bif;
596 u_int8_t state;
597 {
598 bif->bif_state = state;
599 }
600
601 void
bstp_topology_change_detection(sc)602 bstp_topology_change_detection(sc)
603 struct bridge_softc *sc;
604 {
605 if (bstp_root_bridge(sc)) {
606 sc->sc_topology_change = 1;
607 bstp_timer_start(&sc->sc_topology_change_timer, 0);
608 } else if (!sc->sc_topology_change_detected) {
609 bstp_transmit_tcn(sc);
610 bstp_timer_start(&sc->sc_tcn_timer, 0);
611 }
612 sc->sc_topology_change_detected = 1;
613 }
614
615 void
bstp_topology_change_acknowledged(sc)616 bstp_topology_change_acknowledged(sc)
617 struct bridge_softc *sc;
618 {
619 sc->sc_topology_change_detected = 0;
620 bstp_timer_stop(&sc->sc_tcn_timer);
621 }
622
623 void
bstp_acknowledge_topology_change(sc,bif)624 bstp_acknowledge_topology_change(sc, bif)
625 struct bridge_softc *sc;
626 struct bridge_iflist *bif;
627 {
628 bif->bif_topology_change_acknowledge = 1;
629 bstp_transmit_config(sc, bif);
630 }
631
632 struct mbuf *
bstp_input(sc,ifp,eh,m)633 bstp_input(sc, ifp, eh, m)
634 struct bridge_softc *sc;
635 struct ifnet *ifp;
636 struct ether_header *eh;
637 struct mbuf *m;
638 {
639 struct bridge_iflist *bif = NULL;
640 struct bstp_tbpdu tpdu;
641 struct bstp_cbpdu cpdu;
642 struct bstp_config_unit cu;
643 struct bstp_tcn_unit tu;
644 u_int16_t len;
645
646 LIST_FOREACH(bif, &sc->sc_iflist, next) {
647 if (!(bif->bif_flags & IFBIF_STP))
648 continue;
649 if (bif->ifp == ifp)
650 break;
651 }
652 if (bif == NULL)
653 goto out;
654
655 len = ntohs(eh->ether_type);
656 if (len < sizeof(tpdu))
657 goto out;
658 if (m->m_pkthdr.len > len)
659 m_adj(m, len - m->m_pkthdr.len);
660 if ((m = m_pullup(m, sizeof(tpdu))) == NULL)
661 goto out;
662 bcopy(mtod(m, struct tpdu *), &tpdu, sizeof(tpdu));
663
664 if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
665 tpdu.tbu_ssap != LLC_8021D_LSAP ||
666 tpdu.tbu_ctl != LLC_UI)
667 goto out;
668 if (tpdu.tbu_protoid != 0 || tpdu.tbu_protover != 0)
669 goto out;
670
671 switch (tpdu.tbu_bpdutype) {
672 case BSTP_MSGTYPE_TCN:
673 tu.tu_message_type = tpdu.tbu_bpdutype;
674 bstp_received_tcn_bpdu(sc, bif, &tu);
675 break;
676 case BSTP_MSGTYPE_CFG:
677 if ((m = m_pullup(m, sizeof(cpdu))) == NULL)
678 goto out;
679 bcopy(mtod(m, struct bstp_cpdu *), &cpdu, sizeof(cpdu));
680
681 cu.cu_rootid =
682 (((u_int64_t)ntohs(cpdu.cbu_rootpri)) << 48) |
683 (((u_int64_t)cpdu.cbu_rootaddr[0]) << 40) |
684 (((u_int64_t)cpdu.cbu_rootaddr[1]) << 32) |
685 (((u_int64_t)cpdu.cbu_rootaddr[2]) << 24) |
686 (((u_int64_t)cpdu.cbu_rootaddr[3]) << 16) |
687 (((u_int64_t)cpdu.cbu_rootaddr[4]) << 8) |
688 (((u_int64_t)cpdu.cbu_rootaddr[5]) << 0);
689
690 cu.cu_bridge_id =
691 (((u_int64_t)ntohs(cpdu.cbu_bridgepri)) << 48) |
692 (((u_int64_t)cpdu.cbu_bridgeaddr[0]) << 40) |
693 (((u_int64_t)cpdu.cbu_bridgeaddr[1]) << 32) |
694 (((u_int64_t)cpdu.cbu_bridgeaddr[2]) << 24) |
695 (((u_int64_t)cpdu.cbu_bridgeaddr[3]) << 16) |
696 (((u_int64_t)cpdu.cbu_bridgeaddr[4]) << 8) |
697 (((u_int64_t)cpdu.cbu_bridgeaddr[5]) << 0);
698
699 cu.cu_root_path_cost = ntohl(cpdu.cbu_rootpathcost);
700 cu.cu_message_age = ntohs(cpdu.cbu_messageage);
701 cu.cu_max_age = ntohs(cpdu.cbu_maxage);
702 cu.cu_hello_time = ntohs(cpdu.cbu_hellotime);
703 cu.cu_forward_delay = ntohs(cpdu.cbu_forwarddelay);
704 cu.cu_port_id = ntohs(cpdu.cbu_portid);
705 cu.cu_message_type = cpdu.cbu_bpdutype;
706 cu.cu_topology_change_acknowledgment =
707 (cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0;
708 cu.cu_topology_change =
709 (cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0;
710 bstp_received_config_bpdu(sc, bif, &cu);
711 break;
712 default:
713 goto out;
714 }
715
716 out:
717 if (m)
718 m_freem(m);
719 return (NULL);
720 }
721
722 void
bstp_received_config_bpdu(sc,bif,cu)723 bstp_received_config_bpdu(sc, bif, cu)
724 struct bridge_softc *sc;
725 struct bridge_iflist *bif;
726 struct bstp_config_unit *cu;
727 {
728 int root;
729
730 root = bstp_root_bridge(sc);
731
732 if (bif->bif_state != BSTP_IFSTATE_DISABLED) {
733 if (bstp_supersedes_port_info(sc, bif, cu)) {
734 bstp_record_config_information(sc, bif, cu);
735 bstp_configuration_update(sc);
736 bstp_port_state_selection(sc);
737
738 if ((!bstp_root_bridge(sc)) && root) {
739 bstp_timer_stop(&sc->sc_hello_timer);
740
741 if (sc->sc_topology_change_detected) {
742 bstp_timer_stop(&sc->sc_topology_change_timer);
743 bstp_transmit_tcn(sc);
744 bstp_timer_start(&sc->sc_tcn_timer, 0);
745 }
746 }
747
748 if (bif == sc->sc_root_port) {
749 bstp_record_config_timeout_values(sc, cu);
750 bstp_config_bpdu_generation(sc);
751
752 if (cu->cu_topology_change_acknowledgment)
753 bstp_topology_change_acknowledged(sc);
754 }
755 } else if (bstp_designated_port(sc, bif))
756 bstp_transmit_config(sc, bif);
757 }
758 }
759
760 void
bstp_received_tcn_bpdu(sc,bif,tcn)761 bstp_received_tcn_bpdu(sc, bif, tcn)
762 struct bridge_softc *sc;
763 struct bridge_iflist *bif;
764 struct bstp_tcn_unit *tcn;
765 {
766 if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
767 bstp_designated_port(sc, bif)) {
768 bstp_topology_change_detection(sc);
769 bstp_acknowledge_topology_change(sc, bif);
770 }
771 }
772
773 void
bstp_hello_timer_expiry(sc)774 bstp_hello_timer_expiry(sc)
775 struct bridge_softc *sc;
776 {
777 bstp_config_bpdu_generation(sc);
778 bstp_timer_start(&sc->sc_hello_timer, 0);
779 }
780
781 void
bstp_message_age_timer_expiry(sc,bif)782 bstp_message_age_timer_expiry(sc, bif)
783 struct bridge_softc *sc;
784 struct bridge_iflist *bif;
785 {
786 int root;
787
788 root = bstp_root_bridge(sc);
789 bstp_become_designated_port(sc, bif);
790 bstp_configuration_update(sc);
791 bstp_port_state_selection(sc);
792
793 if ((bstp_root_bridge(sc)) && (!root)) {
794 sc->sc_max_age = sc->sc_bridge_max_age;
795 sc->sc_hello_time = sc->sc_bridge_hello_time;
796 sc->sc_forward_delay = sc->sc_bridge_forward_delay;
797
798 bstp_topology_change_detection(sc);
799 bstp_timer_stop(&sc->sc_tcn_timer);
800 bstp_config_bpdu_generation(sc);
801 bstp_timer_start(&sc->sc_hello_timer, 0);
802 }
803 }
804
805 void
bstp_forward_delay_timer_expiry(sc,bif)806 bstp_forward_delay_timer_expiry(sc, bif)
807 struct bridge_softc *sc;
808 struct bridge_iflist *bif;
809 {
810 if (bif->bif_state == BSTP_IFSTATE_LISTENING) {
811 bstp_set_port_state(bif, BSTP_IFSTATE_LEARNING);
812 bstp_timer_start(&bif->bif_forward_delay_timer, 0);
813 } else if (bif->bif_state == BSTP_IFSTATE_LEARNING) {
814 bstp_set_port_state(bif, BSTP_IFSTATE_FORWARDING);
815 if (bstp_designated_for_some_port(sc) &&
816 bif->bif_change_detection_enabled)
817 bstp_topology_change_detection(sc);
818 }
819 }
820
821 int
bstp_designated_for_some_port(sc)822 bstp_designated_for_some_port(sc)
823 struct bridge_softc *sc;
824 {
825
826 struct bridge_iflist *bif;
827
828 LIST_FOREACH(bif, &sc->sc_iflist, next) {
829 if (!(bif->bif_flags & IFBIF_STP))
830 continue;
831 if (bif->bif_designated_bridge == sc->sc_bridge_id)
832 return (1);
833 }
834 return (0);
835 }
836
837 void
bstp_tcn_timer_expiry(sc)838 bstp_tcn_timer_expiry(sc)
839 struct bridge_softc *sc;
840 {
841 bstp_transmit_tcn(sc);
842 bstp_timer_start(&sc->sc_tcn_timer, 0);
843 }
844
845 void
bstp_topology_change_timer_expiry(sc)846 bstp_topology_change_timer_expiry(sc)
847 struct bridge_softc *sc;
848 {
849 sc->sc_topology_change_detected = 0;
850 sc->sc_topology_change = 0;
851 }
852
853 void
bstp_hold_timer_expiry(sc,bif)854 bstp_hold_timer_expiry(sc, bif)
855 struct bridge_softc *sc;
856 struct bridge_iflist *bif;
857 {
858 if (bif->bif_config_pending)
859 bstp_transmit_config(sc, bif);
860 }
861
862 void
bstp_initialization(sc)863 bstp_initialization(sc)
864 struct bridge_softc *sc;
865 {
866 struct bridge_iflist *bif, *mif;
867 struct arpcom *ac, *mac;
868
869 mif = NULL; mac = NULL;
870 LIST_FOREACH(bif, &sc->sc_iflist, next) {
871 if (!(bif->bif_flags & IFBIF_STP))
872 continue;
873 if (bif->ifp->if_type != IFT_ETHER)
874 continue;
875 bif->bif_port_id = (bif->bif_priority << 8) |
876 (bif->ifp->if_index & 0xff);
877
878 if (mif == NULL) {
879 mif = bif;
880 mac = (struct arpcom *)bif->ifp;
881 continue;
882 }
883 ac = (struct arpcom *)bif->ifp;
884 if (memcmp(ac->ac_enaddr, mac->ac_enaddr, ETHER_ADDR_LEN) < 0) {
885 mif = bif;
886 mac = (struct arpcom *)bif->ifp;
887 continue;
888 }
889 }
890 if (mif == NULL) {
891 bstp_stop(sc);
892 return;
893 }
894
895 sc->sc_bridge_id =
896 (((u_int64_t)sc->sc_bridge_priority) << 48) |
897 (((u_int64_t)mac->ac_enaddr[0]) << 40) |
898 (((u_int64_t)mac->ac_enaddr[1]) << 32) |
899 (mac->ac_enaddr[2] << 24) | (mac->ac_enaddr[3] << 16) |
900 (mac->ac_enaddr[4] << 8) | (mac->ac_enaddr[5]);
901
902 sc->sc_designated_root = sc->sc_bridge_id;
903 sc->sc_root_path_cost = 0;
904 sc->sc_root_port = NULL;
905
906 sc->sc_max_age = sc->sc_bridge_max_age;
907 sc->sc_hello_time = sc->sc_bridge_hello_time;
908 sc->sc_forward_delay = sc->sc_bridge_forward_delay;
909 sc->sc_topology_change_detected = 0;
910 sc->sc_topology_change = 0;
911 bstp_timer_stop(&sc->sc_tcn_timer);
912 bstp_timer_stop(&sc->sc_topology_change_timer);
913
914 if (!timeout_initialized(&sc->sc_bstptimeout))
915 timeout_set(&sc->sc_bstptimeout, bstp_tick, sc);
916 if (!timeout_pending(&sc->sc_bstptimeout))
917 timeout_add(&sc->sc_bstptimeout, hz);
918
919 LIST_FOREACH(bif, &sc->sc_iflist, next) {
920 if (bif->bif_flags & IFBIF_STP)
921 bstp_enable_port(sc, bif);
922 else
923 bstp_disable_port(sc, bif);
924 }
925
926 bstp_port_state_selection(sc);
927 bstp_config_bpdu_generation(sc);
928 bstp_timer_start(&sc->sc_hello_timer, 0);
929 }
930
931 void
bstp_stop(sc)932 bstp_stop(sc)
933 struct bridge_softc *sc;
934 {
935
936 struct bridge_iflist *bif;
937
938 LIST_FOREACH(bif, &sc->sc_iflist, next) {
939 bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
940 bstp_timer_stop(&bif->bif_hold_timer);
941 bstp_timer_stop(&bif->bif_message_age_timer);
942 bstp_timer_stop(&bif->bif_forward_delay_timer);
943 }
944
945 if (timeout_initialized(&sc->sc_bstptimeout) &&
946 timeout_pending(&sc->sc_bstptimeout))
947 timeout_del(&sc->sc_bstptimeout);
948
949 bstp_timer_stop(&sc->sc_topology_change_timer);
950 bstp_timer_stop(&sc->sc_tcn_timer);
951 bstp_timer_stop(&sc->sc_hello_timer);
952
953 }
954
955 void
bstp_initialize_port(sc,bif)956 bstp_initialize_port(sc, bif)
957 struct bridge_softc *sc;
958 struct bridge_iflist *bif;
959 {
960 bstp_become_designated_port(sc, bif);
961 bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
962 bif->bif_topology_change_acknowledge = 0;
963 bif->bif_config_pending = 0;
964 bstp_enable_change_detection(bif);
965 bstp_timer_stop(&bif->bif_message_age_timer);
966 bstp_timer_stop(&bif->bif_forward_delay_timer);
967 bstp_timer_stop(&bif->bif_hold_timer);
968 }
969
970 void
bstp_enable_port(sc,bif)971 bstp_enable_port(sc, bif)
972 struct bridge_softc *sc;
973 struct bridge_iflist *bif;
974 {
975 bstp_initialize_port(sc, bif);
976 bstp_port_state_selection(sc);
977 }
978
979 void
bstp_disable_port(sc,bif)980 bstp_disable_port(sc, bif)
981 struct bridge_softc *sc;
982 struct bridge_iflist *bif;
983 {
984 int root;
985
986 root = bstp_root_bridge(sc);
987 bstp_become_designated_port(sc, bif);
988 bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
989 bif->bif_topology_change_acknowledge = 0;
990 bif->bif_config_pending = 0;
991 bstp_timer_stop(&bif->bif_message_age_timer);
992 bstp_timer_stop(&bif->bif_forward_delay_timer);
993 bstp_configuration_update(sc);
994 bstp_port_state_selection(sc);
995 bridge_rtdelete(sc, bif->ifp, 1);
996
997 if (bstp_root_bridge(sc) && (!root)) {
998 sc->sc_max_age = sc->sc_bridge_max_age;
999 sc->sc_hello_time = sc->sc_bridge_hello_time;
1000 sc->sc_forward_delay = sc->sc_bridge_forward_delay;
1001
1002 bstp_topology_change_detection(sc);
1003 bstp_timer_stop(&sc->sc_tcn_timer);
1004 bstp_config_bpdu_generation(sc);
1005 bstp_timer_start(&sc->sc_hello_timer, 0);
1006 }
1007 }
1008
1009 void
bstp_set_bridge_priority(sc,new_bridge_id)1010 bstp_set_bridge_priority(sc, new_bridge_id)
1011 struct bridge_softc *sc;
1012 u_int64_t new_bridge_id;
1013 {
1014 int root;
1015 struct bridge_iflist *bif;
1016
1017 root = bstp_root_bridge(sc);
1018
1019 LIST_FOREACH(bif, &sc->sc_iflist, next) {
1020 if (!(bif->bif_flags & IFBIF_STP))
1021 continue;
1022 if (bstp_designated_port(sc, bif))
1023 bif->bif_designated_bridge = new_bridge_id;
1024 }
1025
1026 sc->sc_bridge_id = new_bridge_id;
1027
1028 bstp_configuration_update(sc);
1029 bstp_port_state_selection(sc);
1030
1031 if (bstp_root_bridge(sc) && (!root)) {
1032 sc->sc_max_age = sc->sc_bridge_max_age;
1033 sc->sc_hello_time = sc->sc_bridge_hello_time;
1034 sc->sc_forward_delay = sc->sc_bridge_forward_delay;
1035
1036 bstp_topology_change_detection(sc);
1037 bstp_timer_stop(&sc->sc_tcn_timer);
1038 bstp_config_bpdu_generation(sc);
1039 bstp_timer_start(&sc->sc_hello_timer, 0);
1040 }
1041 }
1042
1043 void
bstp_set_port_priority(sc,bif,new_port_id)1044 bstp_set_port_priority(sc, bif, new_port_id)
1045 struct bridge_softc *sc;
1046 struct bridge_iflist *bif;
1047 u_int16_t new_port_id;
1048 {
1049 if (bstp_designated_port(sc, bif))
1050 bif->bif_designated_port = new_port_id;
1051
1052 bif->bif_port_id = new_port_id;
1053
1054 if ((sc->sc_bridge_id == bif->bif_designated_bridge) &&
1055 (bif->bif_port_id < bif->bif_designated_port)) {
1056 bstp_become_designated_port(sc, bif);
1057 bstp_port_state_selection(sc);
1058 }
1059 }
1060
1061 void
bstp_set_path_cost(sc,bif,path_cost)1062 bstp_set_path_cost(sc, bif, path_cost)
1063 struct bridge_softc *sc;
1064 struct bridge_iflist *bif;
1065 u_int32_t path_cost;
1066 {
1067 bif->bif_path_cost = path_cost;
1068 bstp_configuration_update(sc);
1069 bstp_port_state_selection(sc);
1070 }
1071
1072 void
bstp_enable_change_detection(bif)1073 bstp_enable_change_detection(bif)
1074 struct bridge_iflist *bif;
1075 {
1076 bif->bif_change_detection_enabled = 1;
1077 }
1078
1079 void
bstp_disable_change_detection(bif)1080 bstp_disable_change_detection(bif)
1081 struct bridge_iflist *bif;
1082 {
1083 bif->bif_change_detection_enabled = 0;
1084 }
1085
1086 void
bstp_ifupdstatus(sc,bif)1087 bstp_ifupdstatus(sc, bif)
1088 struct bridge_softc *sc;
1089 struct bridge_iflist *bif;
1090 {
1091 struct ifnet *ifp = bif->ifp;
1092 struct ifmediareq ifmr;
1093 int err;
1094
1095 if (ifp->if_flags & IFF_UP) {
1096 ifmr.ifm_count = 0;
1097 err = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
1098 if (err) {
1099 if (bif->bif_state == BSTP_IFSTATE_DISABLED)
1100 bstp_enable_port(sc, bif);
1101 return;
1102 }
1103
1104 if (!(ifmr.ifm_status & IFM_AVALID)) {
1105 if (bif->bif_state == BSTP_IFSTATE_DISABLED)
1106 bstp_enable_port(sc, bif);
1107 return;
1108 }
1109
1110 if (ifmr.ifm_status & IFM_ACTIVE) {
1111 if (bif->bif_state == BSTP_IFSTATE_DISABLED)
1112 bstp_enable_port(sc, bif);
1113 return;
1114 }
1115
1116 if (bif->bif_state != BSTP_IFSTATE_DISABLED)
1117 bstp_disable_port(sc, bif);
1118
1119 return;
1120 }
1121
1122 if (bif->bif_state != BSTP_IFSTATE_DISABLED)
1123 bstp_disable_port(sc, bif);
1124 }
1125
1126 void
bstp_tick(vsc)1127 bstp_tick(vsc)
1128 void *vsc;
1129 {
1130 struct bridge_softc *sc = vsc;
1131 struct bridge_iflist *bif;
1132 int s;
1133
1134 s = splnet();
1135
1136 LIST_FOREACH(bif, &sc->sc_iflist, next) {
1137 if (!(bif->bif_flags & IFBIF_STP))
1138 continue;
1139 bstp_ifupdstatus(sc, bif);
1140 }
1141
1142 if (bstp_timer_expired(&sc->sc_hello_timer, sc->sc_hello_time))
1143 bstp_hello_timer_expiry(sc);
1144
1145 if (bstp_timer_expired(&sc->sc_tcn_timer, sc->sc_bridge_hello_time))
1146 bstp_tcn_timer_expiry(sc);
1147
1148 if (bstp_timer_expired(&sc->sc_topology_change_timer,
1149 sc->sc_topology_change_time))
1150 bstp_topology_change_timer_expiry(sc);
1151
1152 LIST_FOREACH(bif, &sc->sc_iflist, next) {
1153 if (!(bif->bif_flags & IFBIF_STP))
1154 continue;
1155 if (bstp_timer_expired(&bif->bif_message_age_timer,
1156 sc->sc_max_age))
1157 bstp_message_age_timer_expiry(sc, bif);
1158 }
1159
1160 LIST_FOREACH(bif, &sc->sc_iflist, next) {
1161 if (!(bif->bif_flags & IFBIF_STP))
1162 continue;
1163 if (bstp_timer_expired(&bif->bif_forward_delay_timer,
1164 sc->sc_forward_delay))
1165 bstp_forward_delay_timer_expiry(sc, bif);
1166
1167 if (bstp_timer_expired(&bif->bif_hold_timer,
1168 sc->sc_hold_time))
1169 bstp_hold_timer_expiry(sc, bif);
1170 }
1171
1172 if (sc->sc_if.if_flags & IFF_RUNNING)
1173 timeout_add(&sc->sc_bstptimeout, hz);
1174
1175 splx(s);
1176 }
1177
1178 void
bstp_timer_start(t,v)1179 bstp_timer_start(t, v)
1180 struct bridge_timer *t;
1181 u_int16_t v;
1182 {
1183 t->value = v;
1184 t->active = 1;
1185 }
1186
1187 void
bstp_timer_stop(t)1188 bstp_timer_stop(t)
1189 struct bridge_timer *t;
1190 {
1191 t->value = 0;
1192 t->active = 0;
1193 }
1194
1195 int
bstp_timer_expired(t,v)1196 bstp_timer_expired(t, v)
1197 struct bridge_timer *t;
1198 u_int16_t v;
1199 {
1200 if (!t->active)
1201 return (0);
1202 t->value += BSTP_TICK_VAL;
1203 if (t->value >= v) {
1204 bstp_timer_stop(t);
1205 return (1);
1206 }
1207 return (0);
1208
1209 }
1210
1211 int
bstp_ioctl(ifp,cmd,data)1212 bstp_ioctl(ifp, cmd, data)
1213 struct ifnet *ifp;
1214 u_long cmd;
1215 caddr_t data;
1216 {
1217 struct bridge_softc *sc = (struct bridge_softc *)ifp;
1218 struct ifbrparam *bp = (struct ifbrparam *)data;
1219 int r = 0, err = 0;
1220
1221 switch (cmd) {
1222 case SIOCBRDGGPRI:
1223 bp->ifbrp_prio = sc->sc_bridge_priority;
1224 break;
1225 case SIOCBRDGGMA:
1226 bp->ifbrp_maxage = sc->sc_bridge_max_age >> 8;
1227 break;
1228 case SIOCBRDGGHT:
1229 bp->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8;
1230 break;
1231 case SIOCBRDGGFD:
1232 bp->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8;
1233 break;
1234 case SIOCBRDGSPRI:
1235 sc->sc_bridge_priority = bp->ifbrp_prio;
1236 r = 1;
1237 break;
1238 case SIOCBRDGSMA:
1239 if (bp->ifbrp_maxage == 0) {
1240 err = EINVAL;
1241 break;
1242 }
1243 sc->sc_bridge_max_age = bp->ifbrp_maxage << 8;
1244 r = 1;
1245 break;
1246 case SIOCBRDGSHT:
1247 if (bp->ifbrp_hellotime == 0) {
1248 err = EINVAL;
1249 break;
1250 }
1251 sc->sc_bridge_hello_time = bp->ifbrp_hellotime << 8;
1252 r = 1;
1253 break;
1254 case SIOCBRDGSFD:
1255 if (bp->ifbrp_fwddelay == 0) {
1256 err = EINVAL;
1257 break;
1258 }
1259 sc->sc_bridge_forward_delay = bp->ifbrp_fwddelay << 8;
1260 r = 1;
1261 break;
1262 case SIOCBRDGADD:
1263 case SIOCBRDGDEL:
1264 case SIOCBRDGSIFFLGS:
1265 case SIOCBRDGSIFPRIO:
1266 case SIOCBRDGSIFCOST:
1267 r = 1;
1268 break;
1269 default:
1270 break;
1271 }
1272
1273 if (r)
1274 bstp_initialization(sc);
1275
1276 return (err);
1277 }
1278
1279 #endif /* NBRIDGE */
1280