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