1 /* $NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $ */
2
3 /*
4 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
5 *
6 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. The rights granted to you under the License
12 * may not be used to create, or enable the creation or redistribution of,
13 * unlawful or unlicensed copies of an Apple operating system, or to
14 * circumvent, violate, or enable the circumvention or violation of, any
15 * terms of an Apple operating system software license agreement.
16 *
17 * Please obtain a copy of the License at
18 * http://www.opensource.apple.com/apsl/ and read it before using this file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 */
30
31 /*
32 * Copyright (c) 2000 Jason L. Wright ([email protected])
33 * Copyright (c) 2006 Andrew Thompson ([email protected])
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
47 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
49 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
51 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
54 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 * POSSIBILITY OF SUCH DAMAGE.
56 *
57 * OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason Exp
58 */
59
60 /*
61 * Implementation of the spanning tree protocol as defined in
62 * ISO/IEC 802.1D-2004, June 9, 2004.
63 */
64
65 #include <sys/cdefs.h>
66 //__FBSDID("$FreeBSD$");
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/mbuf.h>
71 #include <sys/socket.h>
72 #include <sys/sockio.h>
73 #include <sys/kernel.h>
74 //#include <sys/module.h>
75 #include <sys/proc.h>
76 #include <sys/lock.h>
77 //#include <sys/mutex.h>
78 //#include <sys/taskqueue.h>
79
80 #include <net/if.h>
81 #include <net/if_dl.h>
82 #include <net/if_types.h>
83 #include <net/if_llc.h>
84 #include <net/if_media.h>
85
86 #include <net/kpi_interface.h>
87
88 #include <netinet/in.h>
89 #include <netinet/in_systm.h>
90 #include <netinet/in_var.h>
91 #include <netinet/if_ether.h>
92 #include <net/bridgestp.h>
93
94 #include <kern/thread.h>
95
96 static LCK_GRP_DECLARE(bstp_task_grp, "bstp_task");
97 #if BRIDGESTP_DEBUG
98 static LCK_ATTR_DECLARE(bstp_task_attr, LCK_ATTR_DEBUG, 0);
99 #else
100 static LCK_ATTR_DECLARE(bstp_task_attr, 0, 0);
101 #endif
102 static LCK_MTX_DECLARE_ATTR(bstp_task_mtx_data, &bstp_task_grp, &bstp_task_attr);
103 static lck_mtx_t *const bstp_task_mtx = &bstp_task_mtx_data;
104 static thread_t bstp_task_thread;
105 static TAILQ_HEAD(bstp_task_queue, bstp_task) bstp_task_queue =
106 TAILQ_HEAD_INITIALIZER(bstp_task_queue);
107 static struct bstp_task *bstp_task_queue_running = NULL;
108
109 static void bstp_task_enqueue(struct bstp_task *);
110 static void bstp_task_drain(struct bstp_task *);
111
112 #define BSTP_TASK_INIT(bt, func, context) do { \
113 (bt)->bt_count = 0; \
114 (bt)->bt_func = func; \
115 (bt)->bt_context = context; \
116 } while(0)
117
118
119
120 #define BSTP_LOCK_INIT(_bs) lck_mtx_init(&(_bs)->bs_mtx, &bstp_lock_grp, &bstp_lock_attr)
121 #define BSTP_LOCK_DESTROY(_bs) lck_mtx_destroy(&(_bs)->bs_mtx, &bstp_lock_grp)
122 #define BSTP_LOCK(_bs) lck_mtx_lock(&(_bs)->bs_mtx)
123 #define BSTP_UNLOCK(_bs) lck_mtx_unlock(&(_bs)->bs_mtx)
124 #define BSTP_LOCK_ASSERT(_bs) LCK_MTX_ASSERT(&(_bs)->bs_mtx, LCK_MTX_ASSERT_OWNED)
125
126
127 #ifdef BRIDGESTP_DEBUG
128 #define DPRINTF(fmt, arg...) printf("bstp: " fmt, ##arg)
129 #else
130 #define DPRINTF(fmt, arg...)
131 #endif
132
133 #define PV2ADDR(pv, eaddr) do { \
134 eaddr[0] = pv >> 40; \
135 eaddr[1] = pv >> 32; \
136 eaddr[2] = pv >> 24; \
137 eaddr[3] = pv >> 16; \
138 eaddr[4] = pv >> 8; \
139 eaddr[5] = pv >> 0; \
140 } while (0)
141
142 #define INFO_BETTER 1
143 #define INFO_SAME 0
144 #define INFO_WORSE -1
145
146 LIST_HEAD(, bstp_state) bstp_list = LIST_HEAD_INITIALIZER(bstp_list);
147 static LCK_GRP_DECLARE(bstp_lock_grp, "btsp");
148 #if BRIDGESTP_DEBUG
149 static LCK_ATTR_DECLARE(bstp_lock_attr, LCK_ATTR_DEBUG, 0);
150 #else
151 static LCK_ATTR_DECLARE(bstp_lock_attr, 0, 0);
152 #endif
153 static LCK_MTX_DECLARE_ATTR(&bstp_list_mtx_data, &bstp_lock_grp, &bstp_lock_attr);
154 static lck_mtx_t *const bstp_list_mtx = &bstp_list_mtx_data;
155
156 static void bstp_transmit(struct bstp_state *, struct bstp_port *);
157 static void bstp_transmit_bpdu(struct bstp_state *, struct bstp_port *);
158 static void bstp_transmit_tcn(struct bstp_state *, struct bstp_port *);
159 static void bstp_decode_bpdu(struct bstp_port *, struct bstp_cbpdu *,
160 struct bstp_config_unit *);
161 static void bstp_send_bpdu(struct bstp_state *, struct bstp_port *,
162 struct bstp_cbpdu *);
163 static void bstp_enqueue(struct ifnet *, struct mbuf *);
164 static int bstp_pdu_flags(struct bstp_port *);
165 static void bstp_received_stp(struct bstp_state *, struct bstp_port *,
166 struct mbuf **, struct bstp_tbpdu *);
167 static void bstp_received_rstp(struct bstp_state *, struct bstp_port *,
168 struct mbuf **, struct bstp_tbpdu *);
169 static void bstp_received_tcn(struct bstp_state *, struct bstp_port *,
170 struct bstp_tcn_unit *);
171 static void bstp_received_bpdu(struct bstp_state *, struct bstp_port *,
172 struct bstp_config_unit *);
173 static int bstp_pdu_rcvtype(struct bstp_port *, struct bstp_config_unit *);
174 static int bstp_pdu_bettersame(struct bstp_port *, int);
175 static int bstp_info_cmp(struct bstp_pri_vector *,
176 struct bstp_pri_vector *);
177 static int bstp_info_superior(struct bstp_pri_vector *,
178 struct bstp_pri_vector *);
179 static void bstp_assign_roles(struct bstp_state *);
180 static void bstp_update_roles(struct bstp_state *, struct bstp_port *);
181 static void bstp_update_state(struct bstp_state *, struct bstp_port *);
182 static void bstp_update_tc(struct bstp_port *);
183 static void bstp_update_info(struct bstp_port *);
184 static void bstp_set_other_tcprop(struct bstp_port *);
185 static void bstp_set_all_reroot(struct bstp_state *);
186 static void bstp_set_all_sync(struct bstp_state *);
187 static void bstp_set_port_state(struct bstp_port *, int);
188 static void bstp_set_port_role(struct bstp_port *, int);
189 static void bstp_set_port_proto(struct bstp_port *, int);
190 static void bstp_set_port_tc(struct bstp_port *, int);
191 static void bstp_set_timer_tc(struct bstp_port *);
192 static void bstp_set_timer_msgage(struct bstp_port *);
193 static int bstp_rerooted(struct bstp_state *, struct bstp_port *);
194 static uint32_t bstp_calc_path_cost(struct bstp_port *);
195 static void bstp_notify_state(void *, int);
196 static void bstp_notify_rtage(void *, int);
197 static void bstp_ifupdstatus(struct bstp_state *, struct bstp_port *);
198 static void bstp_enable_port(struct bstp_state *, struct bstp_port *);
199 static void bstp_disable_port(struct bstp_state *, struct bstp_port *);
200 static void bstp_tick(void *);
201 static void bstp_timer_start(struct bstp_timer *, uint16_t);
202 static void bstp_timer_stop(struct bstp_timer *);
203 static void bstp_timer_latch(struct bstp_timer *);
204 static int bstp_timer_expired(struct bstp_timer *);
205 static void bstp_hello_timer_expiry(struct bstp_state *,
206 struct bstp_port *);
207 static void bstp_message_age_expiry(struct bstp_state *,
208 struct bstp_port *);
209 static void bstp_migrate_delay_expiry(struct bstp_state *,
210 struct bstp_port *);
211 static void bstp_edge_delay_expiry(struct bstp_state *,
212 struct bstp_port *);
213 static int bstp_addr_cmp(const uint8_t *, const uint8_t *);
214 static int bstp_same_bridgeid(uint64_t, uint64_t);
215 static void bstp_reinit(struct bstp_state *);
216
217 static void
bstp_transmit(struct bstp_state * bs,struct bstp_port * bp)218 bstp_transmit(struct bstp_state *bs, struct bstp_port *bp)
219 {
220 if (bs->bs_running == 0) {
221 return;
222 }
223
224 /*
225 * a PDU can only be sent if we have tx quota left and the
226 * hello timer is running.
227 */
228 if (bp->bp_hello_timer.active == 0) {
229 /* Test if it needs to be reset */
230 bstp_hello_timer_expiry(bs, bp);
231 return;
232 }
233 if (bp->bp_txcount > bs->bs_txholdcount) {
234 /* Ran out of karma */
235 return;
236 }
237
238 if (bp->bp_protover == BSTP_PROTO_RSTP) {
239 bstp_transmit_bpdu(bs, bp);
240 bp->bp_tc_ack = 0;
241 } else { /* STP */
242 switch (bp->bp_role) {
243 case BSTP_ROLE_DESIGNATED:
244 bstp_transmit_bpdu(bs, bp);
245 bp->bp_tc_ack = 0;
246 break;
247
248 case BSTP_ROLE_ROOT:
249 bstp_transmit_tcn(bs, bp);
250 break;
251 }
252 }
253 bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
254 bp->bp_flags &= ~BSTP_PORT_NEWINFO;
255 }
256
257 static void
bstp_transmit_bpdu(struct bstp_state * bs,struct bstp_port * bp)258 bstp_transmit_bpdu(struct bstp_state *bs, struct bstp_port *bp)
259 {
260 struct bstp_cbpdu bpdu;
261
262 BSTP_LOCK_ASSERT(bs);
263
264 bpdu.cbu_rootpri = htons(bp->bp_desg_pv.pv_root_id >> 48);
265 PV2ADDR(bp->bp_desg_pv.pv_root_id, bpdu.cbu_rootaddr);
266
267 bpdu.cbu_rootpathcost = htonl(bp->bp_desg_pv.pv_cost);
268
269 bpdu.cbu_bridgepri = htons(bp->bp_desg_pv.pv_dbridge_id >> 48);
270 PV2ADDR(bp->bp_desg_pv.pv_dbridge_id, bpdu.cbu_bridgeaddr);
271
272 bpdu.cbu_portid = htons(bp->bp_port_id);
273 bpdu.cbu_messageage = htons(bp->bp_desg_msg_age);
274 bpdu.cbu_maxage = htons(bp->bp_desg_max_age);
275 bpdu.cbu_hellotime = htons(bp->bp_desg_htime);
276 bpdu.cbu_forwarddelay = htons(bp->bp_desg_fdelay);
277
278 bpdu.cbu_flags = bstp_pdu_flags(bp);
279
280 switch (bp->bp_protover) {
281 case BSTP_PROTO_STP:
282 bpdu.cbu_bpdutype = BSTP_MSGTYPE_CFG;
283 break;
284
285 case BSTP_PROTO_RSTP:
286 bpdu.cbu_bpdutype = BSTP_MSGTYPE_RSTP;
287 break;
288 }
289
290 bstp_send_bpdu(bs, bp, &bpdu);
291 }
292
293 static void
bstp_transmit_tcn(struct bstp_state * bs,struct bstp_port * bp)294 bstp_transmit_tcn(struct bstp_state *bs, struct bstp_port *bp)
295 {
296 struct bstp_tbpdu bpdu;
297 struct ifnet *ifp = bp->bp_ifp;
298 struct ether_header *eh;
299 struct mbuf *m;
300 int touched = bs ? 1 : 0;
301
302 touched++;
303
304 KASSERT(bp == bs->bs_root_port, ("%s: bad root port\n", __func__));
305
306 if ((ifp->if_flags & IFF_RUNNING) == 0) {
307 return;
308 }
309
310 MGETHDR(m, M_DONTWAIT, MT_DATA);
311 if (m == NULL) {
312 return;
313 }
314
315 m->m_pkthdr.rcvif = ifp;
316 m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
317 m->m_len = m->m_pkthdr.len;
318
319 eh = mtod(m, struct ether_header *);
320
321 memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
322 memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
323 eh->ether_type = htons(sizeof(bpdu));
324
325 bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
326 bpdu.tbu_ctl = LLC_UI;
327 bpdu.tbu_protoid = 0;
328 bpdu.tbu_protover = 0;
329 bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
330
331 memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
332
333 bp->bp_txcount++;
334 bstp_enqueue(ifp, m);
335 }
336
337 static void
bstp_decode_bpdu(struct bstp_port * bp,struct bstp_cbpdu * cpdu,struct bstp_config_unit * cu)338 bstp_decode_bpdu(struct bstp_port *bp, struct bstp_cbpdu *cpdu,
339 struct bstp_config_unit *cu)
340 {
341 int flags;
342
343 cu->cu_pv.pv_root_id =
344 (((uint64_t)ntohs(cpdu->cbu_rootpri)) << 48) |
345 (((uint64_t)cpdu->cbu_rootaddr[0]) << 40) |
346 (((uint64_t)cpdu->cbu_rootaddr[1]) << 32) |
347 (((uint64_t)cpdu->cbu_rootaddr[2]) << 24) |
348 (((uint64_t)cpdu->cbu_rootaddr[3]) << 16) |
349 (((uint64_t)cpdu->cbu_rootaddr[4]) << 8) |
350 (((uint64_t)cpdu->cbu_rootaddr[5]) << 0);
351
352 cu->cu_pv.pv_dbridge_id =
353 (((uint64_t)ntohs(cpdu->cbu_bridgepri)) << 48) |
354 (((uint64_t)cpdu->cbu_bridgeaddr[0]) << 40) |
355 (((uint64_t)cpdu->cbu_bridgeaddr[1]) << 32) |
356 (((uint64_t)cpdu->cbu_bridgeaddr[2]) << 24) |
357 (((uint64_t)cpdu->cbu_bridgeaddr[3]) << 16) |
358 (((uint64_t)cpdu->cbu_bridgeaddr[4]) << 8) |
359 (((uint64_t)cpdu->cbu_bridgeaddr[5]) << 0);
360
361 cu->cu_pv.pv_cost = ntohl(cpdu->cbu_rootpathcost);
362 cu->cu_message_age = ntohs(cpdu->cbu_messageage);
363 cu->cu_max_age = ntohs(cpdu->cbu_maxage);
364 cu->cu_hello_time = ntohs(cpdu->cbu_hellotime);
365 cu->cu_forward_delay = ntohs(cpdu->cbu_forwarddelay);
366 cu->cu_pv.pv_dport_id = ntohs(cpdu->cbu_portid);
367 cu->cu_pv.pv_port_id = bp->bp_port_id;
368 cu->cu_message_type = cpdu->cbu_bpdutype;
369
370 /* Strip off unused flags in STP mode */
371 flags = cpdu->cbu_flags;
372 switch (cpdu->cbu_protover) {
373 case BSTP_PROTO_STP:
374 flags &= BSTP_PDU_STPMASK;
375 /* A STP BPDU explicitly conveys a Designated Port */
376 cu->cu_role = BSTP_ROLE_DESIGNATED;
377 break;
378
379 case BSTP_PROTO_RSTP:
380 flags &= BSTP_PDU_RSTPMASK;
381 break;
382 }
383
384 cu->cu_topology_change_ack =
385 (flags & BSTP_PDU_F_TCA) ? 1 : 0;
386 cu->cu_proposal =
387 (flags & BSTP_PDU_F_P) ? 1 : 0;
388 cu->cu_agree =
389 (flags & BSTP_PDU_F_A) ? 1 : 0;
390 cu->cu_learning =
391 (flags & BSTP_PDU_F_L) ? 1 : 0;
392 cu->cu_forwarding =
393 (flags & BSTP_PDU_F_F) ? 1 : 0;
394 cu->cu_topology_change =
395 (flags & BSTP_PDU_F_TC) ? 1 : 0;
396
397 switch ((flags & BSTP_PDU_PRMASK) >> BSTP_PDU_PRSHIFT) {
398 case BSTP_PDU_F_ROOT:
399 cu->cu_role = BSTP_ROLE_ROOT;
400 break;
401 case BSTP_PDU_F_ALT:
402 cu->cu_role = BSTP_ROLE_ALTERNATE;
403 break;
404 case BSTP_PDU_F_DESG:
405 cu->cu_role = BSTP_ROLE_DESIGNATED;
406 break;
407 }
408 }
409
410 static void
bstp_send_bpdu(struct bstp_state * bs,struct bstp_port * bp,struct bstp_cbpdu * bpdu)411 bstp_send_bpdu(struct bstp_state *bs, struct bstp_port *bp,
412 struct bstp_cbpdu *bpdu)
413 {
414 struct ifnet *ifp;
415 struct mbuf *m;
416 struct ether_header *eh;
417
418 BSTP_LOCK_ASSERT(bs);
419
420 ifp = bp->bp_ifp;
421
422 if ((ifp->if_flags & IFF_RUNNING) == 0) {
423 return;
424 }
425
426 MGETHDR(m, M_DONTWAIT, MT_DATA);
427 if (m == NULL) {
428 return;
429 }
430
431 eh = mtod(m, struct ether_header *);
432
433 bpdu->cbu_ssap = bpdu->cbu_dsap = LLC_8021D_LSAP;
434 bpdu->cbu_ctl = LLC_UI;
435 bpdu->cbu_protoid = htons(BSTP_PROTO_ID);
436
437 memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
438 memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
439
440 switch (bpdu->cbu_bpdutype) {
441 case BSTP_MSGTYPE_CFG:
442 bpdu->cbu_protover = BSTP_PROTO_STP;
443 m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_STP_LEN;
444 eh->ether_type = htons(BSTP_BPDU_STP_LEN);
445 memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
446 BSTP_BPDU_STP_LEN);
447 break;
448
449 case BSTP_MSGTYPE_RSTP:
450 bpdu->cbu_protover = BSTP_PROTO_RSTP;
451 bpdu->cbu_versionlen = htons(0);
452 m->m_pkthdr.len = sizeof(*eh) + BSTP_BPDU_RSTP_LEN;
453 eh->ether_type = htons(BSTP_BPDU_RSTP_LEN);
454 memcpy(mtod(m, caddr_t) + sizeof(*eh), bpdu,
455 BSTP_BPDU_RSTP_LEN);
456 break;
457
458 default:
459 panic("not implemented");
460 }
461 m->m_pkthdr.rcvif = ifp;
462 m->m_len = m->m_pkthdr.len;
463
464 bp->bp_txcount++;
465 bstp_enqueue(ifp, m);
466 }
467
468 static void
bstp_enqueue(struct ifnet * dst_ifp,struct mbuf * m)469 bstp_enqueue(struct ifnet *dst_ifp, struct mbuf *m)
470 {
471 errno_t error = 0;
472 u_int32_t len = m->m_pkthdr.len;
473
474 m->m_flags |= M_PROTO1; //set to avoid loops
475
476 error = ifnet_output_raw(dst_ifp, 0, m);
477 if (error == 0) {
478 (void) ifnet_stat_increment_out(dst_ifp, 1, len, 0);
479 } else {
480 (void) ifnet_stat_increment_out(dst_ifp, 0, 0, 1);
481 }
482 }
483
484 static int
bstp_pdu_flags(struct bstp_port * bp)485 bstp_pdu_flags(struct bstp_port *bp)
486 {
487 int flags = 0;
488
489 if (bp->bp_proposing && bp->bp_state != BSTP_IFSTATE_FORWARDING) {
490 flags |= BSTP_PDU_F_P;
491 }
492
493 if (bp->bp_agree) {
494 flags |= BSTP_PDU_F_A;
495 }
496
497 if (bp->bp_tc_timer.active) {
498 flags |= BSTP_PDU_F_TC;
499 }
500
501 if (bp->bp_tc_ack) {
502 flags |= BSTP_PDU_F_TCA;
503 }
504
505 switch (bp->bp_state) {
506 case BSTP_IFSTATE_LEARNING:
507 flags |= BSTP_PDU_F_L;
508 break;
509
510 case BSTP_IFSTATE_FORWARDING:
511 flags |= (BSTP_PDU_F_L | BSTP_PDU_F_F);
512 break;
513 }
514
515 switch (bp->bp_role) {
516 case BSTP_ROLE_ROOT:
517 flags |=
518 (BSTP_PDU_F_ROOT << BSTP_PDU_PRSHIFT);
519 break;
520
521 case BSTP_ROLE_ALTERNATE:
522 case BSTP_ROLE_BACKUP: /* fall through */
523 flags |=
524 (BSTP_PDU_F_ALT << BSTP_PDU_PRSHIFT);
525 break;
526
527 case BSTP_ROLE_DESIGNATED:
528 flags |=
529 (BSTP_PDU_F_DESG << BSTP_PDU_PRSHIFT);
530 break;
531 }
532
533 /* Strip off unused flags in either mode */
534 switch (bp->bp_protover) {
535 case BSTP_PROTO_STP:
536 flags &= BSTP_PDU_STPMASK;
537 break;
538 case BSTP_PROTO_RSTP:
539 flags &= BSTP_PDU_RSTPMASK;
540 break;
541 }
542 return flags;
543 }
544
545 void
bstp_input(struct bstp_port * bp,struct mbuf * m)546 bstp_input(struct bstp_port *bp, struct mbuf *m)
547 {
548 struct bstp_state *bs = bp->bp_bs;
549 struct ether_header *eh;
550 struct bstp_tbpdu tpdu;
551 uint16_t len;
552
553 if (bp->bp_active == 0) {
554 m_freem(m);
555 return;
556 }
557
558 BSTP_LOCK(bs);
559
560 eh = mtod(m, struct ether_header *);
561
562 len = ntohs(eh->ether_type);
563 if (len < sizeof(tpdu)) {
564 goto out;
565 }
566
567 m_adj(m, ETHER_HDR_LEN);
568
569 if (m->m_pkthdr.len > len) {
570 m_adj(m, len - m->m_pkthdr.len);
571 }
572 if ((unsigned int)m->m_len < sizeof(tpdu) &&
573 (m = m_pullup(m, sizeof(tpdu))) == NULL) {
574 goto out;
575 }
576
577 memcpy(&tpdu, mtod(m, caddr_t), sizeof(tpdu));
578
579 /* basic packet checks */
580 if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
581 tpdu.tbu_ssap != LLC_8021D_LSAP ||
582 tpdu.tbu_ctl != LLC_UI) {
583 goto out;
584 }
585 if (tpdu.tbu_protoid != BSTP_PROTO_ID) {
586 goto out;
587 }
588
589 /*
590 * We can treat later versions of the PDU as the same as the maximum
591 * version we implement. All additional parameters/flags are ignored.
592 */
593 if (tpdu.tbu_protover > BSTP_PROTO_MAX) {
594 tpdu.tbu_protover = BSTP_PROTO_MAX;
595 }
596
597 if (tpdu.tbu_protover != bp->bp_protover) {
598 /*
599 * Wait for the migration delay timer to expire before changing
600 * protocol version to avoid flip-flops.
601 */
602 if (bp->bp_flags & BSTP_PORT_CANMIGRATE) {
603 bstp_set_port_proto(bp, tpdu.tbu_protover);
604 } else {
605 goto out;
606 }
607 }
608
609 /* Clear operedge upon receiving a PDU on the port */
610 bp->bp_operedge = 0;
611 bstp_timer_start(&bp->bp_edge_delay_timer,
612 BSTP_DEFAULT_MIGRATE_DELAY);
613
614 switch (tpdu.tbu_protover) {
615 case BSTP_PROTO_STP:
616 bstp_received_stp(bs, bp, &m, &tpdu);
617 break;
618
619 case BSTP_PROTO_RSTP:
620 bstp_received_rstp(bs, bp, &m, &tpdu);
621 break;
622 }
623 out:
624 BSTP_UNLOCK(bs);
625 if (m) {
626 m_freem(m);
627 }
628 return;
629 }
630
631 static void
bstp_received_stp(struct bstp_state * bs,struct bstp_port * bp,struct mbuf ** mp,struct bstp_tbpdu * tpdu)632 bstp_received_stp(struct bstp_state *bs, struct bstp_port *bp,
633 struct mbuf **mp, struct bstp_tbpdu *tpdu)
634 {
635 struct bstp_cbpdu cpdu;
636 struct bstp_config_unit *cu = &bp->bp_msg_cu;
637 struct bstp_tcn_unit tu;
638
639 switch (tpdu->tbu_bpdutype) {
640 case BSTP_MSGTYPE_TCN:
641 tu.tu_message_type = tpdu->tbu_bpdutype;
642 bstp_received_tcn(bs, bp, &tu);
643 break;
644 case BSTP_MSGTYPE_CFG:
645 if ((*mp)->m_len < BSTP_BPDU_STP_LEN &&
646 (*mp = m_pullup(*mp, BSTP_BPDU_STP_LEN)) == NULL) {
647 return;
648 }
649 memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_STP_LEN);
650
651 bstp_decode_bpdu(bp, &cpdu, cu);
652 bstp_received_bpdu(bs, bp, cu);
653 break;
654 }
655 }
656
657 static void
bstp_received_rstp(struct bstp_state * bs,struct bstp_port * bp,struct mbuf ** mp,struct bstp_tbpdu * tpdu)658 bstp_received_rstp(struct bstp_state *bs, struct bstp_port *bp,
659 struct mbuf **mp, struct bstp_tbpdu *tpdu)
660 {
661 struct bstp_cbpdu cpdu;
662 struct bstp_config_unit *cu = &bp->bp_msg_cu;
663
664 if (tpdu->tbu_bpdutype != BSTP_MSGTYPE_RSTP) {
665 return;
666 }
667
668 if ((*mp)->m_len < BSTP_BPDU_RSTP_LEN &&
669 (*mp = m_pullup(*mp, BSTP_BPDU_RSTP_LEN)) == NULL) {
670 return;
671 }
672 memcpy(&cpdu, mtod(*mp, caddr_t), BSTP_BPDU_RSTP_LEN);
673
674 bstp_decode_bpdu(bp, &cpdu, cu);
675 bstp_received_bpdu(bs, bp, cu);
676 }
677
678 static void
bstp_received_tcn(__unused struct bstp_state * bs,struct bstp_port * bp,__unused struct bstp_tcn_unit * tcn)679 bstp_received_tcn(__unused struct bstp_state *bs, struct bstp_port *bp,
680 __unused struct bstp_tcn_unit *tcn)
681 {
682 bp->bp_rcvdtcn = 1;
683 bstp_update_tc(bp);
684 }
685
686 static void
bstp_received_bpdu(struct bstp_state * bs,struct bstp_port * bp,struct bstp_config_unit * cu)687 bstp_received_bpdu(struct bstp_state *bs, struct bstp_port *bp,
688 struct bstp_config_unit *cu)
689 {
690 int type;
691
692 BSTP_LOCK_ASSERT(bs);
693
694 /* We need to have transitioned to INFO_MINE before proceeding */
695 switch (bp->bp_infois) {
696 case BSTP_INFO_DISABLED:
697 case BSTP_INFO_AGED:
698 return;
699 }
700
701 type = bstp_pdu_rcvtype(bp, cu);
702
703 switch (type) {
704 case BSTP_PDU_SUPERIOR:
705 bs->bs_allsynced = 0;
706 bp->bp_agreed = 0;
707 bp->bp_proposing = 0;
708
709 if (cu->cu_proposal && cu->cu_forwarding == 0) {
710 bp->bp_proposed = 1;
711 }
712 if (cu->cu_topology_change) {
713 bp->bp_rcvdtc = 1;
714 }
715 if (cu->cu_topology_change_ack) {
716 bp->bp_rcvdtca = 1;
717 }
718
719 if (bp->bp_agree &&
720 !bstp_pdu_bettersame(bp, BSTP_INFO_RECEIVED)) {
721 bp->bp_agree = 0;
722 }
723
724 /* copy the received priority and timers to the port */
725 bp->bp_port_pv = cu->cu_pv;
726 bp->bp_port_msg_age = cu->cu_message_age;
727 bp->bp_port_max_age = cu->cu_max_age;
728 bp->bp_port_fdelay = cu->cu_forward_delay;
729 bp->bp_port_htime =
730 (cu->cu_hello_time > BSTP_MIN_HELLO_TIME ?
731 cu->cu_hello_time : BSTP_MIN_HELLO_TIME);
732
733 /* set expiry for the new info */
734 bstp_set_timer_msgage(bp);
735
736 bp->bp_infois = BSTP_INFO_RECEIVED;
737 bstp_assign_roles(bs);
738 break;
739
740 case BSTP_PDU_REPEATED:
741 if (cu->cu_proposal && cu->cu_forwarding == 0) {
742 bp->bp_proposed = 1;
743 }
744 if (cu->cu_topology_change) {
745 bp->bp_rcvdtc = 1;
746 }
747 if (cu->cu_topology_change_ack) {
748 bp->bp_rcvdtca = 1;
749 }
750
751 /* rearm the age timer */
752 bstp_set_timer_msgage(bp);
753 break;
754
755 case BSTP_PDU_INFERIOR:
756 if (cu->cu_learning) {
757 bp->bp_agreed = 1;
758 bp->bp_proposing = 0;
759 }
760 break;
761
762 case BSTP_PDU_INFERIORALT:
763 /*
764 * only point to point links are allowed fast
765 * transitions to forwarding.
766 */
767 if (cu->cu_agree && bp->bp_ptp_link) {
768 bp->bp_agreed = 1;
769 bp->bp_proposing = 0;
770 } else {
771 bp->bp_agreed = 0;
772 }
773
774 if (cu->cu_topology_change) {
775 bp->bp_rcvdtc = 1;
776 }
777 if (cu->cu_topology_change_ack) {
778 bp->bp_rcvdtca = 1;
779 }
780 break;
781
782 case BSTP_PDU_OTHER:
783 return; /* do nothing */
784 }
785 /* update the state machines with the new data */
786 bstp_update_state(bs, bp);
787 }
788
789 static int
bstp_pdu_rcvtype(struct bstp_port * bp,struct bstp_config_unit * cu)790 bstp_pdu_rcvtype(struct bstp_port *bp, struct bstp_config_unit *cu)
791 {
792 int type;
793
794 /* default return type */
795 type = BSTP_PDU_OTHER;
796
797 switch (cu->cu_role) {
798 case BSTP_ROLE_DESIGNATED:
799 if (bstp_info_superior(&bp->bp_port_pv, &cu->cu_pv)) {
800 /* bpdu priority is superior */
801 type = BSTP_PDU_SUPERIOR;
802 } else if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) ==
803 INFO_SAME) {
804 if (bp->bp_port_msg_age != cu->cu_message_age ||
805 bp->bp_port_max_age != cu->cu_max_age ||
806 bp->bp_port_fdelay != cu->cu_forward_delay ||
807 bp->bp_port_htime != cu->cu_hello_time) {
808 /* bpdu priority is equal and timers differ */
809 type = BSTP_PDU_SUPERIOR;
810 } else {
811 /* bpdu is equal */
812 type = BSTP_PDU_REPEATED;
813 }
814 } else {
815 /* bpdu priority is worse */
816 type = BSTP_PDU_INFERIOR;
817 }
818
819 break;
820
821 case BSTP_ROLE_ROOT:
822 case BSTP_ROLE_ALTERNATE:
823 case BSTP_ROLE_BACKUP:
824 if (bstp_info_cmp(&bp->bp_port_pv, &cu->cu_pv) <= INFO_SAME) {
825 /*
826 * not a designated port and priority is the same or
827 * worse
828 */
829 type = BSTP_PDU_INFERIORALT;
830 }
831 break;
832 }
833
834 return type;
835 }
836
837 static int
bstp_pdu_bettersame(struct bstp_port * bp,int newinfo)838 bstp_pdu_bettersame(struct bstp_port *bp, int newinfo)
839 {
840 if (newinfo == BSTP_INFO_RECEIVED &&
841 bp->bp_infois == BSTP_INFO_RECEIVED &&
842 bstp_info_cmp(&bp->bp_port_pv, &bp->bp_msg_cu.cu_pv) >= INFO_SAME) {
843 return 1;
844 }
845
846 if (newinfo == BSTP_INFO_MINE &&
847 bp->bp_infois == BSTP_INFO_MINE &&
848 bstp_info_cmp(&bp->bp_port_pv, &bp->bp_desg_pv) >= INFO_SAME) {
849 return 1;
850 }
851
852 return 0;
853 }
854
855 static int
bstp_info_cmp(struct bstp_pri_vector * pv,struct bstp_pri_vector * cpv)856 bstp_info_cmp(struct bstp_pri_vector *pv,
857 struct bstp_pri_vector *cpv)
858 {
859 if (cpv->pv_root_id < pv->pv_root_id) {
860 return INFO_BETTER;
861 }
862 if (cpv->pv_root_id > pv->pv_root_id) {
863 return INFO_WORSE;
864 }
865
866 if (cpv->pv_cost < pv->pv_cost) {
867 return INFO_BETTER;
868 }
869 if (cpv->pv_cost > pv->pv_cost) {
870 return INFO_WORSE;
871 }
872
873 if (cpv->pv_dbridge_id < pv->pv_dbridge_id) {
874 return INFO_BETTER;
875 }
876 if (cpv->pv_dbridge_id > pv->pv_dbridge_id) {
877 return INFO_WORSE;
878 }
879
880 if (cpv->pv_dport_id < pv->pv_dport_id) {
881 return INFO_BETTER;
882 }
883 if (cpv->pv_dport_id > pv->pv_dport_id) {
884 return INFO_WORSE;
885 }
886
887 return INFO_SAME;
888 }
889
890 /*
891 * This message priority vector is superior to the port priority vector and
892 * will replace it if, and only if, the message priority vector is better than
893 * the port priority vector, or the message has been transmitted from the same
894 * designated bridge and designated port as the port priority vector.
895 */
896 static int
bstp_info_superior(struct bstp_pri_vector * pv,struct bstp_pri_vector * cpv)897 bstp_info_superior(struct bstp_pri_vector *pv,
898 struct bstp_pri_vector *cpv)
899 {
900 if (bstp_info_cmp(pv, cpv) == INFO_BETTER ||
901 (bstp_same_bridgeid(pv->pv_dbridge_id, cpv->pv_dbridge_id) &&
902 (cpv->pv_dport_id & 0xfff) == (pv->pv_dport_id & 0xfff))) {
903 return 1;
904 }
905 return 0;
906 }
907
908 static void
bstp_assign_roles(struct bstp_state * bs)909 bstp_assign_roles(struct bstp_state *bs)
910 {
911 struct bstp_port *bp, *rbp = NULL;
912 struct bstp_pri_vector pv;
913
914 /* default to our priority vector */
915 bs->bs_root_pv = bs->bs_bridge_pv;
916 bs->bs_root_msg_age = 0;
917 bs->bs_root_max_age = bs->bs_bridge_max_age;
918 bs->bs_root_fdelay = bs->bs_bridge_fdelay;
919 bs->bs_root_htime = bs->bs_bridge_htime;
920 bs->bs_root_port = NULL;
921
922 /* check if any recieved info supersedes us */
923 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
924 if (bp->bp_infois != BSTP_INFO_RECEIVED) {
925 continue;
926 }
927
928 pv = bp->bp_port_pv;
929 pv.pv_cost += bp->bp_path_cost;
930
931 /*
932 * The root priority vector is the best of the set comprising
933 * the bridge priority vector plus all root path priority
934 * vectors whose bridge address is not equal to us.
935 */
936 if (bstp_same_bridgeid(pv.pv_dbridge_id,
937 bs->bs_bridge_pv.pv_dbridge_id) == 0 &&
938 bstp_info_cmp(&bs->bs_root_pv, &pv) == INFO_BETTER) {
939 /* the port vector replaces the root */
940 bs->bs_root_pv = pv;
941 bs->bs_root_msg_age = bp->bp_port_msg_age +
942 BSTP_MESSAGE_AGE_INCR;
943 bs->bs_root_max_age = bp->bp_port_max_age;
944 bs->bs_root_fdelay = bp->bp_port_fdelay;
945 bs->bs_root_htime = bp->bp_port_htime;
946 rbp = bp;
947 }
948 }
949
950 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
951 /* calculate the port designated vector */
952 bp->bp_desg_pv.pv_root_id = bs->bs_root_pv.pv_root_id;
953 bp->bp_desg_pv.pv_cost = bs->bs_root_pv.pv_cost;
954 bp->bp_desg_pv.pv_dbridge_id = bs->bs_bridge_pv.pv_dbridge_id;
955 bp->bp_desg_pv.pv_dport_id = bp->bp_port_id;
956 bp->bp_desg_pv.pv_port_id = bp->bp_port_id;
957
958 /* calculate designated times */
959 bp->bp_desg_msg_age = bs->bs_root_msg_age;
960 bp->bp_desg_max_age = bs->bs_root_max_age;
961 bp->bp_desg_fdelay = bs->bs_root_fdelay;
962 bp->bp_desg_htime = bs->bs_bridge_htime;
963
964
965 switch (bp->bp_infois) {
966 case BSTP_INFO_DISABLED:
967 bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
968 break;
969
970 case BSTP_INFO_AGED:
971 bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
972 bstp_update_info(bp);
973 break;
974
975 case BSTP_INFO_MINE:
976 bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
977 /* update the port info if stale */
978 if (bstp_info_cmp(&bp->bp_port_pv,
979 &bp->bp_desg_pv) != INFO_SAME ||
980 (rbp != NULL &&
981 (bp->bp_port_msg_age != rbp->bp_port_msg_age ||
982 bp->bp_port_max_age != rbp->bp_port_max_age ||
983 bp->bp_port_fdelay != rbp->bp_port_fdelay ||
984 bp->bp_port_htime != rbp->bp_port_htime))) {
985 bstp_update_info(bp);
986 }
987 break;
988
989 case BSTP_INFO_RECEIVED:
990 if (bp == rbp) {
991 /*
992 * root priority is derived from this
993 * port, make it the root port.
994 */
995 bstp_set_port_role(bp, BSTP_ROLE_ROOT);
996 bs->bs_root_port = bp;
997 } else if (bstp_info_cmp(&bp->bp_port_pv,
998 &bp->bp_desg_pv) == INFO_BETTER) {
999 /*
1000 * the port priority is lower than the root
1001 * port.
1002 */
1003 bstp_set_port_role(bp, BSTP_ROLE_DESIGNATED);
1004 bstp_update_info(bp);
1005 } else {
1006 if (bstp_same_bridgeid(
1007 bp->bp_port_pv.pv_dbridge_id,
1008 bs->bs_bridge_pv.pv_dbridge_id)) {
1009 /*
1010 * the designated bridge refers to
1011 * another port on this bridge.
1012 */
1013 bstp_set_port_role(bp,
1014 BSTP_ROLE_BACKUP);
1015 } else {
1016 /*
1017 * the port is an inferior path to the
1018 * root bridge.
1019 */
1020 bstp_set_port_role(bp,
1021 BSTP_ROLE_ALTERNATE);
1022 }
1023 }
1024 break;
1025 }
1026 }
1027 }
1028
1029 static void
bstp_update_state(struct bstp_state * bs,struct bstp_port * bp)1030 bstp_update_state(struct bstp_state *bs, struct bstp_port *bp)
1031 {
1032 struct bstp_port *bp2;
1033 int synced;
1034
1035 BSTP_LOCK_ASSERT(bs);
1036
1037 /* check if all the ports have syncronised again */
1038 if (!bs->bs_allsynced) {
1039 synced = 1;
1040 LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1041 if (!(bp2->bp_synced ||
1042 bp2->bp_role == BSTP_ROLE_ROOT)) {
1043 synced = 0;
1044 break;
1045 }
1046 }
1047 bs->bs_allsynced = synced;
1048 }
1049
1050 bstp_update_roles(bs, bp);
1051 bstp_update_tc(bp);
1052 }
1053
1054 static void
bstp_update_roles(struct bstp_state * bs,struct bstp_port * bp)1055 bstp_update_roles(struct bstp_state *bs, struct bstp_port *bp)
1056 {
1057 switch (bp->bp_role) {
1058 case BSTP_ROLE_DISABLED:
1059 /* Clear any flags if set */
1060 if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
1061 bp->bp_sync = 0;
1062 bp->bp_synced = 1;
1063 bp->bp_reroot = 0;
1064 }
1065 break;
1066
1067 case BSTP_ROLE_ALTERNATE:
1068 case BSTP_ROLE_BACKUP:
1069 if ((bs->bs_allsynced && !bp->bp_agree) ||
1070 (bp->bp_proposed && bp->bp_agree)) {
1071 bp->bp_proposed = 0;
1072 bp->bp_agree = 1;
1073 bp->bp_flags |= BSTP_PORT_NEWINFO;
1074 DPRINTF("%s -> ALTERNATE_AGREED\n",
1075 bp->bp_ifp->if_xname);
1076 }
1077
1078 if (bp->bp_proposed && !bp->bp_agree) {
1079 bstp_set_all_sync(bs);
1080 bp->bp_proposed = 0;
1081 DPRINTF("%s -> ALTERNATE_PROPOSED\n",
1082 bp->bp_ifp->if_xname);
1083 }
1084
1085 /* Clear any flags if set */
1086 if (bp->bp_sync || !bp->bp_synced || bp->bp_reroot) {
1087 bp->bp_sync = 0;
1088 bp->bp_synced = 1;
1089 bp->bp_reroot = 0;
1090 DPRINTF("%s -> ALTERNATE_PORT\n", bp->bp_ifp->if_xname);
1091 }
1092 break;
1093
1094 case BSTP_ROLE_ROOT:
1095 if (bp->bp_state != BSTP_IFSTATE_FORWARDING && !bp->bp_reroot) {
1096 bstp_set_all_reroot(bs);
1097 DPRINTF("%s -> ROOT_REROOT\n", bp->bp_ifp->if_xname);
1098 }
1099
1100 if ((bs->bs_allsynced && !bp->bp_agree) ||
1101 (bp->bp_proposed && bp->bp_agree)) {
1102 bp->bp_proposed = 0;
1103 bp->bp_sync = 0;
1104 bp->bp_agree = 1;
1105 bp->bp_flags |= BSTP_PORT_NEWINFO;
1106 DPRINTF("%s -> ROOT_AGREED\n", bp->bp_ifp->if_xname);
1107 }
1108
1109 if (bp->bp_proposed && !bp->bp_agree) {
1110 bstp_set_all_sync(bs);
1111 bp->bp_proposed = 0;
1112 DPRINTF("%s -> ROOT_PROPOSED\n", bp->bp_ifp->if_xname);
1113 }
1114
1115 if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1116 (bp->bp_forward_delay_timer.active == 0 ||
1117 (bstp_rerooted(bs, bp) &&
1118 bp->bp_recent_backup_timer.active == 0 &&
1119 bp->bp_protover == BSTP_PROTO_RSTP))) {
1120 switch (bp->bp_state) {
1121 case BSTP_IFSTATE_DISCARDING:
1122 bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1123 break;
1124 case BSTP_IFSTATE_LEARNING:
1125 bstp_set_port_state(bp,
1126 BSTP_IFSTATE_FORWARDING);
1127 break;
1128 }
1129 }
1130
1131 if (bp->bp_state == BSTP_IFSTATE_FORWARDING && bp->bp_reroot) {
1132 bp->bp_reroot = 0;
1133 DPRINTF("%s -> ROOT_REROOTED\n", bp->bp_ifp->if_xname);
1134 }
1135 break;
1136
1137 case BSTP_ROLE_DESIGNATED:
1138 if (bp->bp_recent_root_timer.active == 0 && bp->bp_reroot) {
1139 bp->bp_reroot = 0;
1140 DPRINTF("%s -> DESIGNATED_RETIRED\n",
1141 bp->bp_ifp->if_xname);
1142 }
1143
1144 if ((bp->bp_state == BSTP_IFSTATE_DISCARDING &&
1145 !bp->bp_synced) || (bp->bp_agreed && !bp->bp_synced) ||
1146 (bp->bp_operedge && !bp->bp_synced) ||
1147 (bp->bp_sync && bp->bp_synced)) {
1148 bstp_timer_stop(&bp->bp_recent_root_timer);
1149 bp->bp_synced = 1;
1150 bp->bp_sync = 0;
1151 DPRINTF("%s -> DESIGNATED_SYNCED\n",
1152 bp->bp_ifp->if_xname);
1153 }
1154
1155 if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1156 !bp->bp_agreed && !bp->bp_proposing &&
1157 !bp->bp_operedge) {
1158 bp->bp_proposing = 1;
1159 bp->bp_flags |= BSTP_PORT_NEWINFO;
1160 bstp_timer_start(&bp->bp_edge_delay_timer,
1161 (bp->bp_ptp_link ? BSTP_DEFAULT_MIGRATE_DELAY :
1162 bp->bp_desg_max_age));
1163 DPRINTF("%s -> DESIGNATED_PROPOSE\n",
1164 bp->bp_ifp->if_xname);
1165 }
1166
1167 if (bp->bp_state != BSTP_IFSTATE_FORWARDING &&
1168 (bp->bp_forward_delay_timer.active == 0 || bp->bp_agreed ||
1169 bp->bp_operedge) &&
1170 (bp->bp_recent_root_timer.active == 0 || !bp->bp_reroot) &&
1171 !bp->bp_sync) {
1172 #ifdef BRIDGESTP_DEBUG
1173 if (bp->bp_agreed) {
1174 DPRINTF("%s -> AGREED\n", bp->bp_ifp->if_xname);
1175 }
1176 #endif /* BRIDGESTP_DEBUG */
1177 /*
1178 * If agreed|operedge then go straight to forwarding,
1179 * otherwise follow discard -> learn -> forward.
1180 */
1181 if (bp->bp_agreed || bp->bp_operedge ||
1182 bp->bp_state == BSTP_IFSTATE_LEARNING) {
1183 bstp_set_port_state(bp,
1184 BSTP_IFSTATE_FORWARDING);
1185 bp->bp_agreed = bp->bp_protover;
1186 } else if (bp->bp_state == BSTP_IFSTATE_DISCARDING) {
1187 bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
1188 }
1189 }
1190
1191 if (((bp->bp_sync && !bp->bp_synced) ||
1192 (bp->bp_reroot && bp->bp_recent_root_timer.active) ||
1193 (bp->bp_flags & BSTP_PORT_DISPUTED)) && !bp->bp_operedge &&
1194 bp->bp_state != BSTP_IFSTATE_DISCARDING) {
1195 bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1196 bp->bp_flags &= ~BSTP_PORT_DISPUTED;
1197 bstp_timer_start(&bp->bp_forward_delay_timer,
1198 bp->bp_protover == BSTP_PROTO_RSTP ?
1199 bp->bp_desg_htime : bp->bp_desg_fdelay);
1200 DPRINTF("%s -> DESIGNATED_DISCARD\n",
1201 bp->bp_ifp->if_xname);
1202 }
1203 break;
1204 }
1205
1206 if (bp->bp_flags & BSTP_PORT_NEWINFO) {
1207 bstp_transmit(bs, bp);
1208 }
1209 }
1210
1211 static void
bstp_update_tc(struct bstp_port * bp)1212 bstp_update_tc(struct bstp_port *bp)
1213 {
1214 switch (bp->bp_tcstate) {
1215 case BSTP_TCSTATE_ACTIVE:
1216 if ((bp->bp_role != BSTP_ROLE_DESIGNATED &&
1217 bp->bp_role != BSTP_ROLE_ROOT) || bp->bp_operedge) {
1218 bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1219 }
1220
1221 if (bp->bp_rcvdtcn) {
1222 bstp_set_port_tc(bp, BSTP_TCSTATE_TCN);
1223 }
1224 if (bp->bp_rcvdtc) {
1225 bstp_set_port_tc(bp, BSTP_TCSTATE_TC);
1226 }
1227
1228 if (bp->bp_tc_prop && !bp->bp_operedge) {
1229 bstp_set_port_tc(bp, BSTP_TCSTATE_PROPAG);
1230 }
1231
1232 if (bp->bp_rcvdtca) {
1233 bstp_set_port_tc(bp, BSTP_TCSTATE_ACK);
1234 }
1235 break;
1236
1237 case BSTP_TCSTATE_INACTIVE:
1238 if ((bp->bp_state == BSTP_IFSTATE_LEARNING ||
1239 bp->bp_state == BSTP_IFSTATE_FORWARDING) &&
1240 bp->bp_fdbflush == 0) {
1241 bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1242 }
1243 break;
1244
1245 case BSTP_TCSTATE_LEARNING:
1246 if (bp->bp_rcvdtc || bp->bp_rcvdtcn || bp->bp_rcvdtca ||
1247 bp->bp_tc_prop) {
1248 bstp_set_port_tc(bp, BSTP_TCSTATE_LEARNING);
1249 } else if (bp->bp_role != BSTP_ROLE_DESIGNATED &&
1250 bp->bp_role != BSTP_ROLE_ROOT &&
1251 bp->bp_state == BSTP_IFSTATE_DISCARDING) {
1252 bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
1253 }
1254
1255 if ((bp->bp_role == BSTP_ROLE_DESIGNATED ||
1256 bp->bp_role == BSTP_ROLE_ROOT) &&
1257 bp->bp_state == BSTP_IFSTATE_FORWARDING &&
1258 !bp->bp_operedge) {
1259 bstp_set_port_tc(bp, BSTP_TCSTATE_DETECTED);
1260 }
1261 break;
1262
1263 /* these are transient states and go straight back to ACTIVE */
1264 case BSTP_TCSTATE_DETECTED:
1265 case BSTP_TCSTATE_TCN:
1266 case BSTP_TCSTATE_TC:
1267 case BSTP_TCSTATE_PROPAG:
1268 case BSTP_TCSTATE_ACK:
1269 DPRINTF("Invalid TC state for %s\n",
1270 bp->bp_ifp->if_xname);
1271 break;
1272 }
1273 }
1274
1275 static void
bstp_update_info(struct bstp_port * bp)1276 bstp_update_info(struct bstp_port *bp)
1277 {
1278 struct bstp_state *bs = bp->bp_bs;
1279
1280 bp->bp_proposing = 0;
1281 bp->bp_proposed = 0;
1282
1283 if (bp->bp_agreed && !bstp_pdu_bettersame(bp, BSTP_INFO_MINE)) {
1284 bp->bp_agreed = 0;
1285 }
1286
1287 if (bp->bp_synced && !bp->bp_agreed) {
1288 bp->bp_synced = 0;
1289 bs->bs_allsynced = 0;
1290 }
1291
1292 /* copy the designated pv to the port */
1293 bp->bp_port_pv = bp->bp_desg_pv;
1294 bp->bp_port_msg_age = bp->bp_desg_msg_age;
1295 bp->bp_port_max_age = bp->bp_desg_max_age;
1296 bp->bp_port_fdelay = bp->bp_desg_fdelay;
1297 bp->bp_port_htime = bp->bp_desg_htime;
1298 bp->bp_infois = BSTP_INFO_MINE;
1299
1300 /* Set transmit flag but do not immediately send */
1301 bp->bp_flags |= BSTP_PORT_NEWINFO;
1302 }
1303
1304 /* set tcprop on every port other than the caller */
1305 static void
bstp_set_other_tcprop(struct bstp_port * bp)1306 bstp_set_other_tcprop(struct bstp_port *bp)
1307 {
1308 struct bstp_state *bs = bp->bp_bs;
1309 struct bstp_port *bp2;
1310
1311 BSTP_LOCK_ASSERT(bs);
1312
1313 LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1314 if (bp2 == bp) {
1315 continue;
1316 }
1317 bp2->bp_tc_prop = 1;
1318 }
1319 }
1320
1321 static void
bstp_set_all_reroot(struct bstp_state * bs)1322 bstp_set_all_reroot(struct bstp_state *bs)
1323 {
1324 struct bstp_port *bp;
1325
1326 BSTP_LOCK_ASSERT(bs);
1327
1328 LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1329 bp->bp_reroot = 1;
1330 }
1331
1332 static void
bstp_set_all_sync(struct bstp_state * bs)1333 bstp_set_all_sync(struct bstp_state *bs)
1334 {
1335 struct bstp_port *bp;
1336
1337 BSTP_LOCK_ASSERT(bs);
1338
1339 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1340 bp->bp_sync = 1;
1341 bp->bp_synced = 0; /* Not explicit in spec */
1342 }
1343
1344 bs->bs_allsynced = 0;
1345 }
1346
1347 static void
bstp_set_port_state(struct bstp_port * bp,int state)1348 bstp_set_port_state(struct bstp_port *bp, int state)
1349 {
1350 if (bp->bp_state == state) {
1351 return;
1352 }
1353
1354 bp->bp_state = state;
1355
1356 switch (bp->bp_state) {
1357 case BSTP_IFSTATE_DISCARDING:
1358 DPRINTF("state changed to DISCARDING on %s\n",
1359 bp->bp_ifp->if_xname);
1360 break;
1361
1362 case BSTP_IFSTATE_LEARNING:
1363 DPRINTF("state changed to LEARNING on %s\n",
1364 bp->bp_ifp->if_xname);
1365
1366 bstp_timer_start(&bp->bp_forward_delay_timer,
1367 bp->bp_protover == BSTP_PROTO_RSTP ?
1368 bp->bp_desg_htime : bp->bp_desg_fdelay);
1369 break;
1370
1371 case BSTP_IFSTATE_FORWARDING:
1372 DPRINTF("state changed to FORWARDING on %s\n",
1373 bp->bp_ifp->if_xname);
1374
1375 bstp_timer_stop(&bp->bp_forward_delay_timer);
1376 /* Record that we enabled forwarding */
1377 bp->bp_forward_transitions++;
1378 break;
1379 }
1380
1381 /* notify the parent bridge */
1382 bstp_task_enqueue(&bp->bp_statetask);
1383 }
1384
1385 static void
bstp_set_port_role(struct bstp_port * bp,int role)1386 bstp_set_port_role(struct bstp_port *bp, int role)
1387 {
1388 struct bstp_state *bs = bp->bp_bs;
1389
1390 if (bp->bp_role == role) {
1391 return;
1392 }
1393
1394 /* perform pre-change tasks */
1395 switch (bp->bp_role) {
1396 case BSTP_ROLE_DISABLED:
1397 bstp_timer_start(&bp->bp_forward_delay_timer,
1398 bp->bp_desg_max_age);
1399 break;
1400
1401 case BSTP_ROLE_BACKUP:
1402 bstp_timer_start(&bp->bp_recent_backup_timer,
1403 bp->bp_desg_htime * 2);
1404 /* fall through */
1405 case BSTP_ROLE_ALTERNATE:
1406 bstp_timer_start(&bp->bp_forward_delay_timer,
1407 bp->bp_desg_fdelay);
1408 bp->bp_sync = 0;
1409 bp->bp_synced = 1;
1410 bp->bp_reroot = 0;
1411 break;
1412
1413 case BSTP_ROLE_ROOT:
1414 bstp_timer_start(&bp->bp_recent_root_timer,
1415 BSTP_DEFAULT_FORWARD_DELAY);
1416 break;
1417 }
1418
1419 bp->bp_role = role;
1420 /* clear values not carried between roles */
1421 bp->bp_proposing = 0;
1422 bs->bs_allsynced = 0;
1423
1424 /* initialise the new role */
1425 switch (bp->bp_role) {
1426 case BSTP_ROLE_DISABLED:
1427 case BSTP_ROLE_ALTERNATE:
1428 case BSTP_ROLE_BACKUP:
1429 DPRINTF("%s role -> ALT/BACK/DISABLED\n",
1430 bp->bp_ifp->if_xname);
1431 bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1432 bstp_timer_stop(&bp->bp_recent_root_timer);
1433 bstp_timer_latch(&bp->bp_forward_delay_timer);
1434 bp->bp_sync = 0;
1435 bp->bp_synced = 1;
1436 bp->bp_reroot = 0;
1437 break;
1438
1439 case BSTP_ROLE_ROOT:
1440 DPRINTF("%s role -> ROOT\n",
1441 bp->bp_ifp->if_xname);
1442 bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
1443 bstp_timer_latch(&bp->bp_recent_root_timer);
1444 bp->bp_proposing = 0;
1445 break;
1446
1447 case BSTP_ROLE_DESIGNATED:
1448 DPRINTF("%s role -> DESIGNATED\n",
1449 bp->bp_ifp->if_xname);
1450 bstp_timer_start(&bp->bp_hello_timer,
1451 bp->bp_desg_htime);
1452 bp->bp_agree = 0;
1453 break;
1454 }
1455
1456 /* let the TC state know that the role changed */
1457 bstp_update_tc(bp);
1458 }
1459
1460 static void
bstp_set_port_proto(struct bstp_port * bp,int proto)1461 bstp_set_port_proto(struct bstp_port *bp, int proto)
1462 {
1463 struct bstp_state *bs = bp->bp_bs;
1464
1465 /* supported protocol versions */
1466 switch (proto) {
1467 case BSTP_PROTO_STP:
1468 /* we can downgrade protocols only */
1469 bstp_timer_stop(&bp->bp_migrate_delay_timer);
1470 /* clear unsupported features */
1471 bp->bp_operedge = 0;
1472 /* STP compat mode only uses 16 bits of the 32 */
1473 if (bp->bp_path_cost > 65535) {
1474 bp->bp_path_cost = 65535;
1475 }
1476 break;
1477
1478 case BSTP_PROTO_RSTP:
1479 bstp_timer_start(&bp->bp_migrate_delay_timer,
1480 bs->bs_migration_delay);
1481 break;
1482
1483 default:
1484 DPRINTF("Unsupported STP version %d\n", proto);
1485 return;
1486 }
1487
1488 bp->bp_protover = proto;
1489 bp->bp_flags &= ~BSTP_PORT_CANMIGRATE;
1490 }
1491
1492 static void
bstp_set_port_tc(struct bstp_port * bp,int state)1493 bstp_set_port_tc(struct bstp_port *bp, int state)
1494 {
1495 struct bstp_state *bs = bp->bp_bs;
1496
1497 bp->bp_tcstate = state;
1498
1499 /* initialise the new state */
1500 switch (bp->bp_tcstate) {
1501 case BSTP_TCSTATE_ACTIVE:
1502 DPRINTF("%s -> TC_ACTIVE\n", bp->bp_ifp->if_xname);
1503 /* nothing to do */
1504 break;
1505
1506 case BSTP_TCSTATE_INACTIVE:
1507 bstp_timer_stop(&bp->bp_tc_timer);
1508 /* flush routes on the parent bridge */
1509 bp->bp_fdbflush = 1;
1510 bstp_task_enqueue(&bp->bp_rtagetask);
1511 bp->bp_tc_ack = 0;
1512 DPRINTF("%s -> TC_INACTIVE\n", bp->bp_ifp->if_xname);
1513 break;
1514
1515 case BSTP_TCSTATE_LEARNING:
1516 bp->bp_rcvdtc = 0;
1517 bp->bp_rcvdtcn = 0;
1518 bp->bp_rcvdtca = 0;
1519 bp->bp_tc_prop = 0;
1520 DPRINTF("%s -> TC_LEARNING\n", bp->bp_ifp->if_xname);
1521 break;
1522
1523 case BSTP_TCSTATE_DETECTED:
1524 bstp_set_timer_tc(bp);
1525 bstp_set_other_tcprop(bp);
1526 /* send out notification */
1527 bp->bp_flags |= BSTP_PORT_NEWINFO;
1528 bstp_transmit(bs, bp);
1529 /* reviewed for getmicrotime usage */
1530 getmicrotime(&bs->bs_last_tc_time);
1531 DPRINTF("%s -> TC_DETECTED\n", bp->bp_ifp->if_xname);
1532 bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1533 break;
1534
1535 case BSTP_TCSTATE_TCN:
1536 bstp_set_timer_tc(bp);
1537 DPRINTF("%s -> TC_TCN\n", bp->bp_ifp->if_xname);
1538 /* fall through */
1539 case BSTP_TCSTATE_TC:
1540 bp->bp_rcvdtc = 0;
1541 bp->bp_rcvdtcn = 0;
1542 if (bp->bp_role == BSTP_ROLE_DESIGNATED) {
1543 bp->bp_tc_ack = 1;
1544 }
1545
1546 bstp_set_other_tcprop(bp);
1547 DPRINTF("%s -> TC_TC\n", bp->bp_ifp->if_xname);
1548 bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1549 break;
1550
1551 case BSTP_TCSTATE_PROPAG:
1552 /* flush routes on the parent bridge */
1553 bp->bp_fdbflush = 1;
1554 bstp_task_enqueue(&bp->bp_rtagetask);
1555 bp->bp_tc_prop = 0;
1556 bstp_set_timer_tc(bp);
1557 DPRINTF("%s -> TC_PROPAG\n", bp->bp_ifp->if_xname);
1558 bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1559 break;
1560
1561 case BSTP_TCSTATE_ACK:
1562 bstp_timer_stop(&bp->bp_tc_timer);
1563 bp->bp_rcvdtca = 0;
1564 DPRINTF("%s -> TC_ACK\n", bp->bp_ifp->if_xname);
1565 bp->bp_tcstate = BSTP_TCSTATE_ACTIVE; /* UCT */
1566 break;
1567 }
1568 }
1569
1570 static void
bstp_set_timer_tc(struct bstp_port * bp)1571 bstp_set_timer_tc(struct bstp_port *bp)
1572 {
1573 struct bstp_state *bs = bp->bp_bs;
1574
1575 if (bp->bp_tc_timer.active) {
1576 return;
1577 }
1578
1579 switch (bp->bp_protover) {
1580 case BSTP_PROTO_RSTP:
1581 bstp_timer_start(&bp->bp_tc_timer,
1582 bp->bp_desg_htime + BSTP_TICK_VAL);
1583 bp->bp_flags |= BSTP_PORT_NEWINFO;
1584 break;
1585
1586 case BSTP_PROTO_STP:
1587 bstp_timer_start(&bp->bp_tc_timer,
1588 bs->bs_root_max_age + bs->bs_root_fdelay);
1589 break;
1590 }
1591 }
1592
1593 static void
bstp_set_timer_msgage(struct bstp_port * bp)1594 bstp_set_timer_msgage(struct bstp_port *bp)
1595 {
1596 if (bp->bp_port_msg_age + BSTP_MESSAGE_AGE_INCR <=
1597 bp->bp_port_max_age) {
1598 bstp_timer_start(&bp->bp_message_age_timer,
1599 bp->bp_port_htime * 3);
1600 } else {
1601 /* expires immediately */
1602 bstp_timer_start(&bp->bp_message_age_timer, 0);
1603 }
1604 }
1605
1606 static int
bstp_rerooted(struct bstp_state * bs,struct bstp_port * bp)1607 bstp_rerooted(struct bstp_state *bs, struct bstp_port *bp)
1608 {
1609 struct bstp_port *bp2;
1610 int rr_set = 0;
1611
1612 LIST_FOREACH(bp2, &bs->bs_bplist, bp_next) {
1613 if (bp2 == bp) {
1614 continue;
1615 }
1616 if (bp2->bp_recent_root_timer.active) {
1617 rr_set = 1;
1618 break;
1619 }
1620 }
1621 return !rr_set;
1622 }
1623
1624 int
bstp_set_htime(struct bstp_state * bs,int t)1625 bstp_set_htime(struct bstp_state *bs, int t)
1626 {
1627 /* convert seconds to ticks */
1628 t *= BSTP_TICK_VAL;
1629
1630 /* value can only be changed in leagacy stp mode */
1631 if (bs->bs_protover != BSTP_PROTO_STP) {
1632 return EPERM;
1633 }
1634
1635 if (t < BSTP_MIN_HELLO_TIME || t > BSTP_MAX_HELLO_TIME) {
1636 return EINVAL;
1637 }
1638
1639 BSTP_LOCK(bs);
1640 bs->bs_bridge_htime = t;
1641 bstp_reinit(bs);
1642 BSTP_UNLOCK(bs);
1643 return 0;
1644 }
1645
1646 int
bstp_set_fdelay(struct bstp_state * bs,int t)1647 bstp_set_fdelay(struct bstp_state *bs, int t)
1648 {
1649 /* convert seconds to ticks */
1650 t *= BSTP_TICK_VAL;
1651
1652 if (t < BSTP_MIN_FORWARD_DELAY || t > BSTP_MAX_FORWARD_DELAY) {
1653 return EINVAL;
1654 }
1655
1656 BSTP_LOCK(bs);
1657 bs->bs_bridge_fdelay = t;
1658 bstp_reinit(bs);
1659 BSTP_UNLOCK(bs);
1660 return 0;
1661 }
1662
1663 int
bstp_set_maxage(struct bstp_state * bs,int t)1664 bstp_set_maxage(struct bstp_state *bs, int t)
1665 {
1666 /* convert seconds to ticks */
1667 t *= BSTP_TICK_VAL;
1668
1669 if (t < BSTP_MIN_MAX_AGE || t > BSTP_MAX_MAX_AGE) {
1670 return EINVAL;
1671 }
1672
1673 BSTP_LOCK(bs);
1674 bs->bs_bridge_max_age = t;
1675 bstp_reinit(bs);
1676 BSTP_UNLOCK(bs);
1677 return 0;
1678 }
1679
1680 int
bstp_set_holdcount(struct bstp_state * bs,int count)1681 bstp_set_holdcount(struct bstp_state *bs, int count)
1682 {
1683 struct bstp_port *bp;
1684
1685 if (count < BSTP_MIN_HOLD_COUNT ||
1686 count > BSTP_MAX_HOLD_COUNT) {
1687 return EINVAL;
1688 }
1689
1690 BSTP_LOCK(bs);
1691 bs->bs_txholdcount = count;
1692 LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
1693 bp->bp_txcount = 0;
1694 BSTP_UNLOCK(bs);
1695 return 0;
1696 }
1697
1698 int
bstp_set_protocol(struct bstp_state * bs,int proto)1699 bstp_set_protocol(struct bstp_state *bs, int proto)
1700 {
1701 struct bstp_port *bp;
1702
1703 switch (proto) {
1704 /* Supported protocol versions */
1705 case BSTP_PROTO_STP:
1706 case BSTP_PROTO_RSTP:
1707 break;
1708
1709 default:
1710 return EINVAL;
1711 }
1712
1713 BSTP_LOCK(bs);
1714 bs->bs_protover = proto;
1715 bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
1716 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1717 /* reinit state */
1718 bp->bp_infois = BSTP_INFO_DISABLED;
1719 bp->bp_txcount = 0;
1720 bstp_set_port_proto(bp, bs->bs_protover);
1721 bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
1722 bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
1723 bstp_timer_stop(&bp->bp_recent_backup_timer);
1724 }
1725 bstp_reinit(bs);
1726 BSTP_UNLOCK(bs);
1727 return 0;
1728 }
1729
1730 int
bstp_set_priority(struct bstp_state * bs,int pri)1731 bstp_set_priority(struct bstp_state *bs, int pri)
1732 {
1733 if (pri < 0 || pri > BSTP_MAX_PRIORITY) {
1734 return EINVAL;
1735 }
1736
1737 /* Limit to steps of 4096 */
1738 pri -= pri % 4096;
1739
1740 BSTP_LOCK(bs);
1741 bs->bs_bridge_priority = pri;
1742 bstp_reinit(bs);
1743 BSTP_UNLOCK(bs);
1744 return 0;
1745 }
1746
1747 int
bstp_set_port_priority(struct bstp_port * bp,int pri)1748 bstp_set_port_priority(struct bstp_port *bp, int pri)
1749 {
1750 struct bstp_state *bs = bp->bp_bs;
1751
1752 if (pri < 0 || pri > BSTP_MAX_PORT_PRIORITY) {
1753 return EINVAL;
1754 }
1755
1756 /* Limit to steps of 16 */
1757 pri -= pri % 16;
1758
1759 BSTP_LOCK(bs);
1760 bp->bp_priority = pri;
1761 bstp_reinit(bs);
1762 BSTP_UNLOCK(bs);
1763 return 0;
1764 }
1765
1766 int
bstp_set_path_cost(struct bstp_port * bp,uint32_t path_cost)1767 bstp_set_path_cost(struct bstp_port *bp, uint32_t path_cost)
1768 {
1769 struct bstp_state *bs = bp->bp_bs;
1770
1771 if (path_cost > BSTP_MAX_PATH_COST) {
1772 return EINVAL;
1773 }
1774
1775 /* STP compat mode only uses 16 bits of the 32 */
1776 if (bp->bp_protover == BSTP_PROTO_STP && path_cost > 65535) {
1777 path_cost = 65535;
1778 }
1779
1780 BSTP_LOCK(bs);
1781
1782 if (path_cost == 0) { /* use auto */
1783 bp->bp_flags &= ~BSTP_PORT_ADMCOST;
1784 bp->bp_path_cost = bstp_calc_path_cost(bp);
1785 } else {
1786 bp->bp_path_cost = path_cost;
1787 bp->bp_flags |= BSTP_PORT_ADMCOST;
1788 }
1789 bstp_reinit(bs);
1790 BSTP_UNLOCK(bs);
1791 return 0;
1792 }
1793
1794 int
bstp_set_edge(struct bstp_port * bp,int set)1795 bstp_set_edge(struct bstp_port *bp, int set)
1796 {
1797 struct bstp_state *bs = bp->bp_bs;
1798
1799 BSTP_LOCK(bs);
1800 if ((bp->bp_operedge = set) == 0) {
1801 bp->bp_flags &= ~BSTP_PORT_ADMEDGE;
1802 } else {
1803 bp->bp_flags |= BSTP_PORT_ADMEDGE;
1804 }
1805 BSTP_UNLOCK(bs);
1806 return 0;
1807 }
1808
1809 int
bstp_set_autoedge(struct bstp_port * bp,int set)1810 bstp_set_autoedge(struct bstp_port *bp, int set)
1811 {
1812 struct bstp_state *bs = bp->bp_bs;
1813
1814 BSTP_LOCK(bs);
1815 if (set) {
1816 bp->bp_flags |= BSTP_PORT_AUTOEDGE;
1817 /* we may be able to transition straight to edge */
1818 if (bp->bp_edge_delay_timer.active == 0) {
1819 bstp_edge_delay_expiry(bs, bp);
1820 }
1821 } else {
1822 bp->bp_flags &= ~BSTP_PORT_AUTOEDGE;
1823 }
1824 BSTP_UNLOCK(bs);
1825 return 0;
1826 }
1827
1828 int
bstp_set_ptp(struct bstp_port * bp,int set)1829 bstp_set_ptp(struct bstp_port *bp, int set)
1830 {
1831 struct bstp_state *bs = bp->bp_bs;
1832
1833 BSTP_LOCK(bs);
1834 bp->bp_ptp_link = set;
1835 BSTP_UNLOCK(bs);
1836 return 0;
1837 }
1838
1839 int
bstp_set_autoptp(struct bstp_port * bp,int set)1840 bstp_set_autoptp(struct bstp_port *bp, int set)
1841 {
1842 struct bstp_state *bs = bp->bp_bs;
1843
1844 BSTP_LOCK(bs);
1845 if (set) {
1846 bp->bp_flags |= BSTP_PORT_AUTOPTP;
1847 if (bp->bp_role != BSTP_ROLE_DISABLED) {
1848 bstp_ifupdstatus(bs, bp);
1849 }
1850 } else {
1851 bp->bp_flags &= ~BSTP_PORT_AUTOPTP;
1852 }
1853 BSTP_UNLOCK(bs);
1854 return 0;
1855 }
1856
1857 /*
1858 * Calculate the path cost according to the link speed.
1859 */
1860 static uint32_t
bstp_calc_path_cost(struct bstp_port * bp)1861 bstp_calc_path_cost(struct bstp_port *bp)
1862 {
1863 struct ifnet *ifp = bp->bp_ifp;
1864 uint32_t path_cost;
1865
1866 /* If the priority has been manually set then retain the value */
1867 if (bp->bp_flags & BSTP_PORT_ADMCOST) {
1868 return bp->bp_path_cost;
1869 }
1870
1871 if (bp->bp_if_link_state == LINK_STATE_DOWN) {
1872 /* Recalc when the link comes up again */
1873 bp->bp_flags |= BSTP_PORT_PNDCOST;
1874 return BSTP_DEFAULT_PATH_COST;
1875 }
1876
1877 if (ifp->if_baudrate < 1000) {
1878 return BSTP_DEFAULT_PATH_COST;
1879 }
1880
1881 /* formula from section 17.14, IEEE Std 802.1D-2004 */
1882 path_cost = 20000000000ULL / (ifp->if_baudrate / 1000);
1883
1884 if (path_cost > BSTP_MAX_PATH_COST) {
1885 path_cost = BSTP_MAX_PATH_COST;
1886 }
1887
1888 /* STP compat mode only uses 16 bits of the 32 */
1889 if (bp->bp_protover == BSTP_PROTO_STP && path_cost > 65535) {
1890 path_cost = 65535;
1891 }
1892
1893 return path_cost;
1894 }
1895
1896 /*
1897 * Notify the bridge that a port state has changed, we need to do this from a
1898 * taskqueue to avoid a LOR.
1899 */
1900 static void
bstp_notify_state(void * arg,__unused int pending)1901 bstp_notify_state(void *arg, __unused int pending)
1902 {
1903 struct bstp_port *bp = (struct bstp_port *)arg;
1904 struct bstp_state *bs = bp->bp_bs;
1905
1906 if (bp->bp_active == 1 && bs->bs_state_cb != NULL) {
1907 (*bs->bs_state_cb)(bp->bp_ifp, bp->bp_state);
1908 }
1909 }
1910
1911 /*
1912 * Flush the routes on the bridge port, we need to do this from a
1913 * taskqueue to avoid a LOR.
1914 */
1915 static void
bstp_notify_rtage(void * arg,__unused int pending)1916 bstp_notify_rtage(void *arg, __unused int pending)
1917 {
1918 struct bstp_port *bp = (struct bstp_port *)arg;
1919 struct bstp_state *bs = bp->bp_bs;
1920 int age = 0;
1921
1922 BSTP_LOCK(bs);
1923 switch (bp->bp_protover) {
1924 case BSTP_PROTO_STP:
1925 /* convert to seconds */
1926 age = bp->bp_desg_fdelay / BSTP_TICK_VAL;
1927 break;
1928
1929 case BSTP_PROTO_RSTP:
1930 age = 0;
1931 break;
1932 }
1933 BSTP_UNLOCK(bs);
1934
1935 if (bp->bp_active == 1 && bs->bs_rtage_cb != NULL) {
1936 (*bs->bs_rtage_cb)(bp->bp_ifp, age);
1937 }
1938
1939 /* flush is complete */
1940 BSTP_LOCK(bs);
1941 bp->bp_fdbflush = 0;
1942 BSTP_UNLOCK(bs);
1943 }
1944
1945 void
bstp_linkstate(struct ifnet * ifp,__unused int state)1946 bstp_linkstate(struct ifnet *ifp, __unused int state)
1947 {
1948 struct bstp_state *bs;
1949 struct bstp_port *bp;
1950
1951 /* search for the stp port */
1952 lck_mtx_lock(bstp_list_mtx);
1953 LIST_FOREACH(bs, &bstp_list, bs_list) {
1954 BSTP_LOCK(bs);
1955 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
1956 if (bp->bp_ifp == ifp) {
1957 bstp_ifupdstatus(bs, bp);
1958 bstp_update_state(bs, bp);
1959 /* it only exists once so return */
1960 BSTP_UNLOCK(bs);
1961 lck_mtx_unlock(bstp_list_mtx);
1962 return;
1963 }
1964 }
1965 BSTP_UNLOCK(bs);
1966 }
1967 lck_mtx_unlock(bstp_list_mtx);
1968 }
1969
1970 static void
bstp_ifupdstatus(struct bstp_state * bs,struct bstp_port * bp)1971 bstp_ifupdstatus(struct bstp_state *bs, struct bstp_port *bp)
1972 {
1973 struct ifnet *ifp = bp->bp_ifp;
1974 struct ifmediareq ifmr;
1975 int error = 0;
1976
1977 BSTP_LOCK_ASSERT(bs);
1978
1979 bzero((char *)&ifmr, sizeof(ifmr));
1980 error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
1981
1982 if ((error == 0) && (ifp->if_flags & IFF_UP)) {
1983 if (ifmr.ifm_status & IFM_ACTIVE) {
1984 /* A full-duplex link is assumed to be point to point */
1985 if (bp->bp_flags & BSTP_PORT_AUTOPTP) {
1986 bp->bp_ptp_link =
1987 ifmr.ifm_active & IFM_FDX ? 1 : 0;
1988 }
1989
1990 /* Calc the cost if the link was down previously */
1991 if (bp->bp_flags & BSTP_PORT_PNDCOST) {
1992 bp->bp_path_cost = bstp_calc_path_cost(bp);
1993 bp->bp_flags &= ~BSTP_PORT_PNDCOST;
1994 }
1995
1996 if (bp->bp_role == BSTP_ROLE_DISABLED) {
1997 bstp_enable_port(bs, bp);
1998 }
1999 } else {
2000 if (bp->bp_role != BSTP_ROLE_DISABLED) {
2001 bstp_disable_port(bs, bp);
2002 if ((bp->bp_flags & BSTP_PORT_ADMEDGE) &&
2003 bp->bp_protover == BSTP_PROTO_RSTP) {
2004 bp->bp_operedge = 1;
2005 }
2006 }
2007 }
2008 return;
2009 }
2010
2011 if (bp->bp_infois != BSTP_INFO_DISABLED) {
2012 bstp_disable_port(bs, bp);
2013 }
2014 }
2015
2016 static void
bstp_enable_port(struct bstp_state * bs,struct bstp_port * bp)2017 bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp)
2018 {
2019 bp->bp_infois = BSTP_INFO_AGED;
2020 bstp_assign_roles(bs);
2021 }
2022
2023 static void
bstp_disable_port(struct bstp_state * bs,struct bstp_port * bp)2024 bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp)
2025 {
2026 bp->bp_infois = BSTP_INFO_DISABLED;
2027 bstp_assign_roles(bs);
2028 }
2029
2030 static void
bstp_tick(void * arg)2031 bstp_tick(void *arg)
2032 {
2033 struct bstp_state *bs = arg;
2034 struct bstp_port *bp;
2035 struct timespec ts;
2036
2037 BSTP_LOCK(bs);
2038
2039 if (bs->bs_running == 0) {
2040 return;
2041 }
2042
2043 /* slow timer to catch missed link events */
2044 if (bstp_timer_expired(&bs->bs_link_timer)) {
2045 LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
2046 bstp_ifupdstatus(bs, bp);
2047 bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
2048 }
2049
2050 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2051 /* no events need to happen for these */
2052 bstp_timer_expired(&bp->bp_tc_timer);
2053 bstp_timer_expired(&bp->bp_recent_root_timer);
2054 bstp_timer_expired(&bp->bp_forward_delay_timer);
2055 bstp_timer_expired(&bp->bp_recent_backup_timer);
2056
2057 if (bstp_timer_expired(&bp->bp_hello_timer)) {
2058 bstp_hello_timer_expiry(bs, bp);
2059 }
2060
2061 if (bstp_timer_expired(&bp->bp_message_age_timer)) {
2062 bstp_message_age_expiry(bs, bp);
2063 }
2064
2065 if (bstp_timer_expired(&bp->bp_migrate_delay_timer)) {
2066 bstp_migrate_delay_expiry(bs, bp);
2067 }
2068
2069 if (bstp_timer_expired(&bp->bp_edge_delay_timer)) {
2070 bstp_edge_delay_expiry(bs, bp);
2071 }
2072
2073 /* update the various state machines for the port */
2074 bstp_update_state(bs, bp);
2075
2076 if (bp->bp_txcount > 0) {
2077 bp->bp_txcount--;
2078 }
2079 }
2080
2081 BSTP_UNLOCK(bs);
2082
2083 ts.tv_sec = 1;
2084 ts.tv_nsec = 0;
2085 bsd_timeout(bstp_tick, bs, &ts);
2086 }
2087
2088 static void
bstp_timer_start(struct bstp_timer * t,uint16_t v)2089 bstp_timer_start(struct bstp_timer *t, uint16_t v)
2090 {
2091 t->value = v;
2092 t->active = 1;
2093 t->latched = 0;
2094 }
2095
2096 static void
bstp_timer_stop(struct bstp_timer * t)2097 bstp_timer_stop(struct bstp_timer *t)
2098 {
2099 t->value = 0;
2100 t->active = 0;
2101 t->latched = 0;
2102 }
2103
2104 static void
bstp_timer_latch(struct bstp_timer * t)2105 bstp_timer_latch(struct bstp_timer *t)
2106 {
2107 t->latched = 1;
2108 t->active = 1;
2109 }
2110
2111 static int
bstp_timer_expired(struct bstp_timer * t)2112 bstp_timer_expired(struct bstp_timer *t)
2113 {
2114 if (t->active == 0 || t->latched) {
2115 return 0;
2116 }
2117 t->value -= BSTP_TICK_VAL;
2118 if (t->value <= 0) {
2119 bstp_timer_stop(t);
2120 return 1;
2121 }
2122 return 0;
2123 }
2124
2125 static void
bstp_hello_timer_expiry(struct bstp_state * bs,struct bstp_port * bp)2126 bstp_hello_timer_expiry(struct bstp_state *bs, struct bstp_port *bp)
2127 {
2128 if ((bp->bp_flags & BSTP_PORT_NEWINFO) ||
2129 bp->bp_role == BSTP_ROLE_DESIGNATED ||
2130 (bp->bp_role == BSTP_ROLE_ROOT &&
2131 bp->bp_tc_timer.active == 1)) {
2132 bstp_timer_start(&bp->bp_hello_timer, bp->bp_desg_htime);
2133 bp->bp_flags |= BSTP_PORT_NEWINFO;
2134 bstp_transmit(bs, bp);
2135 }
2136 }
2137
2138 static void
bstp_message_age_expiry(struct bstp_state * bs,struct bstp_port * bp)2139 bstp_message_age_expiry(struct bstp_state *bs, struct bstp_port *bp)
2140 {
2141 if (bp->bp_infois == BSTP_INFO_RECEIVED) {
2142 bp->bp_infois = BSTP_INFO_AGED;
2143 bstp_assign_roles(bs);
2144 DPRINTF("aged info on %s\n", bp->bp_ifp->if_xname);
2145 }
2146 }
2147
2148 static void
bstp_migrate_delay_expiry(__unused struct bstp_state * bs,struct bstp_port * bp)2149 bstp_migrate_delay_expiry(__unused struct bstp_state *bs, struct bstp_port *bp)
2150 {
2151 bp->bp_flags |= BSTP_PORT_CANMIGRATE;
2152 }
2153
2154 static void
bstp_edge_delay_expiry(__unused struct bstp_state * bs,struct bstp_port * bp)2155 bstp_edge_delay_expiry(__unused struct bstp_state *bs, struct bstp_port *bp)
2156 {
2157 if ((bp->bp_flags & BSTP_PORT_AUTOEDGE) &&
2158 bp->bp_protover == BSTP_PROTO_RSTP && bp->bp_proposing &&
2159 bp->bp_role == BSTP_ROLE_DESIGNATED) {
2160 bp->bp_operedge = 1;
2161 DPRINTF("%s -> edge port\n", bp->bp_ifp->if_xname);
2162 }
2163 }
2164
2165 static int
bstp_addr_cmp(const uint8_t * a,const uint8_t * b)2166 bstp_addr_cmp(const uint8_t *a, const uint8_t *b)
2167 {
2168 int i, d;
2169
2170 for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) {
2171 d = ((int)a[i]) - ((int)b[i]);
2172 }
2173
2174 return d;
2175 }
2176
2177 /*
2178 * compare the bridge address component of the bridgeid
2179 */
2180 static int
bstp_same_bridgeid(uint64_t id1,uint64_t id2)2181 bstp_same_bridgeid(uint64_t id1, uint64_t id2)
2182 {
2183 u_char addr1[ETHER_ADDR_LEN];
2184 u_char addr2[ETHER_ADDR_LEN];
2185
2186 PV2ADDR(id1, addr1);
2187 PV2ADDR(id2, addr2);
2188
2189 if (bstp_addr_cmp(addr1, addr2) == 0) {
2190 return 1;
2191 }
2192
2193 return 0;
2194 }
2195
2196 void
bstp_reinit(struct bstp_state * bs)2197 bstp_reinit(struct bstp_state *bs)
2198 {
2199 struct bstp_port *bp;
2200 struct ifnet *ifp, *mif;
2201 u_char *e_addr;
2202 static const u_char llzero[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */
2203
2204 BSTP_LOCK_ASSERT(bs);
2205
2206 mif = NULL;
2207 /*
2208 * Search through the Ethernet adapters and find the one with the
2209 * lowest value. The adapter which we take the MAC address from does
2210 * not need to be part of the bridge, it just needs to be a unique
2211 * value.
2212 */
2213 ifnet_head_lock_shared();
2214 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
2215 if (ifp->if_type != IFT_ETHER) {
2216 continue;
2217 }
2218
2219 if (bstp_addr_cmp(IF_LLADDR(ifp), llzero) == 0) {
2220 continue;
2221 }
2222
2223 if (mif == NULL) {
2224 mif = ifp;
2225 continue;
2226 }
2227 if (bstp_addr_cmp(IF_LLADDR(ifp), IF_LLADDR(mif)) < 0) {
2228 mif = ifp;
2229 continue;
2230 }
2231 }
2232 ifnet_head_done();
2233
2234 if (LIST_EMPTY(&bs->bs_bplist) || mif == NULL) {
2235 /* Set the bridge and root id (lower bits) to zero */
2236 bs->bs_bridge_pv.pv_dbridge_id =
2237 ((uint64_t)bs->bs_bridge_priority) << 48;
2238 bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id;
2239 bs->bs_root_pv = bs->bs_bridge_pv;
2240 /* Disable any remaining ports, they will have no MAC address */
2241 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2242 bp->bp_infois = BSTP_INFO_DISABLED;
2243 bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2244 }
2245 bsd_untimeout(bstp_tick, bs);
2246 return;
2247 }
2248
2249 e_addr = IF_LLADDR(mif);
2250 bs->bs_bridge_pv.pv_dbridge_id =
2251 (((uint64_t)bs->bs_bridge_priority) << 48) |
2252 (((uint64_t)e_addr[0]) << 40) |
2253 (((uint64_t)e_addr[1]) << 32) |
2254 (((uint64_t)e_addr[2]) << 24) |
2255 (((uint64_t)e_addr[3]) << 16) |
2256 (((uint64_t)e_addr[4]) << 8) |
2257 (((uint64_t)e_addr[5]));
2258
2259 bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id;
2260 bs->bs_bridge_pv.pv_cost = 0;
2261 bs->bs_bridge_pv.pv_dport_id = 0;
2262 bs->bs_bridge_pv.pv_port_id = 0;
2263
2264 if (bs->bs_running) {
2265 bsd_untimeout(bstp_tick, bs);
2266 }
2267
2268 LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
2269 bp->bp_port_id = (bp->bp_priority << 8) |
2270 (bp->bp_ifp->if_index & 0xfff);
2271 bstp_ifupdstatus(bs, bp);
2272 }
2273
2274 bstp_assign_roles(bs);
2275 bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
2276 }
2277
2278 void
bstp_attach(struct bstp_state * bs,struct bstp_cb_ops * cb)2279 bstp_attach(struct bstp_state *bs, struct bstp_cb_ops *cb)
2280 {
2281 BSTP_LOCK_INIT(bs);
2282 LIST_INIT(&bs->bs_bplist);
2283
2284 bs->bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
2285 bs->bs_bridge_htime = BSTP_DEFAULT_HELLO_TIME;
2286 bs->bs_bridge_fdelay = BSTP_DEFAULT_FORWARD_DELAY;
2287 bs->bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
2288 bs->bs_hold_time = BSTP_DEFAULT_HOLD_TIME;
2289 bs->bs_migration_delay = BSTP_DEFAULT_MIGRATE_DELAY;
2290 bs->bs_txholdcount = BSTP_DEFAULT_HOLD_COUNT;
2291 bs->bs_protover = BSTP_PROTO_RSTP;
2292 bs->bs_state_cb = cb->bcb_state;
2293 bs->bs_rtage_cb = cb->bcb_rtage;
2294
2295 /* reviewed for getmicrotime usage */
2296 getmicrotime(&bs->bs_last_tc_time);
2297
2298 lck_mtx_lock(bstp_list_mtx);
2299 LIST_INSERT_HEAD(&bstp_list, bs, bs_list);
2300 lck_mtx_unlock(bstp_list_mtx);
2301 }
2302
2303 void
bstp_detach(struct bstp_state * bs)2304 bstp_detach(struct bstp_state *bs)
2305 {
2306 KASSERT(LIST_EMPTY(&bs->bs_bplist), ("bstp still active"));
2307
2308 lck_mtx_lock(bstp_list_mtx);
2309 LIST_REMOVE(bs, bs_list);
2310 lck_mtx_unlock(bstp_list_mtx);
2311 bsd_untimeout(bstp_tick, bs);
2312 BSTP_LOCK_DESTROY(bs);
2313 }
2314
2315 void
bstp_init(struct bstp_state * bs)2316 bstp_init(struct bstp_state *bs)
2317 {
2318 struct timespec ts;
2319
2320 ts.tv_sec = 1;
2321 ts.tv_nsec = 0;
2322
2323 BSTP_LOCK(bs);
2324 bsd_timeout(bstp_tick, bs, &ts);
2325 bs->bs_running = 1;
2326 bstp_reinit(bs);
2327 BSTP_UNLOCK(bs);
2328 }
2329
2330 void
bstp_stop(struct bstp_state * bs)2331 bstp_stop(struct bstp_state *bs)
2332 {
2333 struct bstp_port *bp;
2334
2335 BSTP_LOCK(bs);
2336
2337 LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
2338 bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
2339
2340 bs->bs_running = 0;
2341 bsd_untimeout(bstp_tick, bs);
2342 BSTP_UNLOCK(bs);
2343 }
2344
2345 int
bstp_create(struct bstp_state * bs,struct bstp_port * bp,struct ifnet * ifp)2346 bstp_create(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp)
2347 {
2348 bzero(bp, sizeof(struct bstp_port));
2349
2350 BSTP_LOCK(bs);
2351 bp->bp_ifp = ifp;
2352 bp->bp_bs = bs;
2353 bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY;
2354 BSTP_TASK_INIT(&bp->bp_statetask, bstp_notify_state, bp);
2355 BSTP_TASK_INIT(&bp->bp_rtagetask, bstp_notify_rtage, bp);
2356
2357 /* Init state */
2358 bp->bp_infois = BSTP_INFO_DISABLED;
2359 bp->bp_flags = BSTP_PORT_AUTOEDGE | BSTP_PORT_AUTOPTP;
2360 bstp_set_port_state(bp, BSTP_IFSTATE_DISCARDING);
2361 bstp_set_port_proto(bp, bs->bs_protover);
2362 bstp_set_port_role(bp, BSTP_ROLE_DISABLED);
2363 bstp_set_port_tc(bp, BSTP_TCSTATE_INACTIVE);
2364 bp->bp_path_cost = bstp_calc_path_cost(bp);
2365 BSTP_UNLOCK(bs);
2366 return 0;
2367 }
2368
2369 int
bstp_enable(struct bstp_port * bp)2370 bstp_enable(struct bstp_port *bp)
2371 {
2372 struct bstp_state *bs = bp->bp_bs;
2373 struct ifnet *ifp = bp->bp_ifp;
2374
2375 KASSERT(bp->bp_active == 0, ("already a bstp member"));
2376
2377 switch (ifp->if_type) {
2378 case IFT_ETHER: /* These can do spanning tree. */
2379 break;
2380 default:
2381 /* Nothing else can. */
2382 return EINVAL;
2383 }
2384
2385 BSTP_LOCK(bs);
2386 LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next);
2387 bp->bp_active = 1;
2388 bp->bp_flags |= BSTP_PORT_NEWINFO;
2389 bstp_reinit(bs);
2390 bstp_update_roles(bs, bp);
2391 BSTP_UNLOCK(bs);
2392 return 0;
2393 }
2394
2395 void
bstp_disable(struct bstp_port * bp)2396 bstp_disable(struct bstp_port *bp)
2397 {
2398 struct bstp_state *bs = bp->bp_bs;
2399
2400 KASSERT(bp->bp_active == 1, ("not a bstp member"));
2401
2402 BSTP_LOCK(bs);
2403 bstp_disable_port(bs, bp);
2404 LIST_REMOVE(bp, bp_next);
2405 bp->bp_active = 0;
2406 bstp_reinit(bs);
2407 BSTP_UNLOCK(bs);
2408 }
2409
2410 /*
2411 * The bstp_port structure is about to be freed by the parent bridge.
2412 */
2413 void
bstp_destroy(struct bstp_port * bp)2414 bstp_destroy(struct bstp_port *bp)
2415 {
2416 KASSERT(bp->bp_active == 0, ("port is still attached"));
2417 bstp_task_drain(&bp->bp_statetask);
2418 bstp_task_drain(&bp->bp_rtagetask);
2419 }
2420
2421
2422 static void
bstp_task_thread_func(void * arg1 __unused,wait_result_t wr __unused)2423 bstp_task_thread_func(void *arg1 __unused, wait_result_t wr __unused)
2424 {
2425 struct bstp_task *bt, *tvar;
2426
2427 lck_mtx_lock(bstp_task_mtx);
2428
2429 do {
2430 while (TAILQ_EMPTY(&bstp_task_queue)) {
2431 wakeup(&bstp_task_queue_running);
2432 msleep(&bstp_task_queue, bstp_task_mtx, PZERO, "bstp_task_queue", NULL);
2433 }
2434
2435 TAILQ_FOREACH_SAFE(bt, &bstp_task_queue, bt_next, tvar) {
2436 int count = bt->bt_count;
2437
2438 bt->bt_count = 0;
2439
2440 bstp_task_queue_running = bt;
2441 lck_mtx_unlock(bstp_task_mtx);
2442
2443 (*bt->bt_func)(bt->bt_context, count);
2444
2445 lck_mtx_lock(bstp_task_mtx);
2446 bstp_task_queue_running = NULL;
2447
2448 if (bt->bt_count == 0) {
2449 TAILQ_REMOVE(&bstp_task_queue, bt, bt_next);
2450 }
2451 }
2452 } while (1);
2453
2454 /* UNREACHED */
2455 }
2456
2457 __private_extern__ void
bstp_sys_init(void)2458 bstp_sys_init(void)
2459 {
2460 kernel_thread_start(bstp_task_thread_func, NULL, &bstp_task_thread);
2461 }
2462
2463 static void
bstp_task_enqueue(struct bstp_task * bt)2464 bstp_task_enqueue(struct bstp_task *bt)
2465 {
2466 lck_mtx_lock(bstp_task_mtx);
2467
2468 if (bt->bt_count) {
2469 bt->bt_count++;
2470 lck_mtx_unlock(bstp_task_mtx);
2471 wakeup(&bstp_task_queue);
2472 return;
2473 }
2474
2475 bt->bt_count = 1;
2476 TAILQ_INSERT_TAIL(&bstp_task_queue, bt, bt_next);
2477
2478 lck_mtx_unlock(bstp_task_mtx);
2479
2480 wakeup(&bstp_task_queue);
2481 }
2482
2483 static void
bstp_task_drain(struct bstp_task * bt)2484 bstp_task_drain(struct bstp_task *bt)
2485 {
2486 lck_mtx_lock(bstp_task_mtx);
2487
2488 while (bt->bt_count != 0 || bstp_task_queue_running == bt) {
2489 wakeup(&bstp_task_queue);
2490 msleep(&bstp_task_queue_running, bstp_task_mtx, PZERO, "bstp_task_queue", NULL);
2491 }
2492 lck_mtx_unlock(bstp_task_mtx);
2493 }
2494