1 /* $NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $ */
4 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
6 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
17 * Please obtain a copy of the License at
18 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
28 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Copyright (c) 2000 Jason L. Wright (jason@thought.net)
33 * Copyright (c) 2006 Andrew Thompson (thompsa@FreeBSD.org)
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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.
57 * OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason Exp
61 * Implementation of the spanning tree protocol as defined in
62 * ISO/IEC 802.1D-2004, June 9, 2004.
65 #include <sys/cdefs.h>
66 //__FBSDID("$FreeBSD$");
68 #include <sys/param.h>
69 #include <sys/systm.h>
71 #include <sys/socket.h>
72 #include <sys/sockio.h>
73 #include <sys/kernel.h>
74 //#include <sys/module.h>
77 //#include <sys/mutex.h>
78 //#include <sys/taskqueue.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>
86 #include <net/kpi_interface.h>
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>
94 #include <kern/thread.h>
96 decl_lck_mtx_data(static, bstp_task_mtx_data
);
97 static lck_mtx_t
*bstp_task_mtx
= &bstp_task_mtx_data
;
98 static lck_grp_t
*bstp_task_grp
= NULL
;
99 static lck_attr_t
*bstp_task_attr
= NULL
;
100 static thread_t bstp_task_thread
;
101 static TAILQ_HEAD(bstp_task_queue
, bstp_task
)
102 bstp_task_queue
= TAILQ_HEAD_INITIALIZER(bstp_task_queue
);
103 static struct bstp_task
*bstp_task_queue_running
= NULL
;
105 static void bstp_create_task_thread(void);
106 static void bstp_task_thread_func(void);
108 static void bstp_task_enqueue(struct bstp_task
*);
109 static void bstp_task_drain(struct bstp_task
*);
111 #define BSTP_TASK_INIT(bt, func, context) do { \
112 (bt)->bt_count = 0; \
113 (bt)->bt_func = func; \
114 (bt)->bt_context = context; \
119 #define BSTP_LOCK_INIT(_bs) (_bs)->bs_mtx = lck_mtx_alloc_init(bstp_lock_grp, bstp_lock_attr)
120 #define BSTP_LOCK_DESTROY(_bs) lck_mtx_free((_bs)->bs_mtx, bstp_lock_grp)
121 #define BSTP_LOCK(_bs) lck_mtx_lock((_bs)->bs_mtx)
122 #define BSTP_UNLOCK(_bs) lck_mtx_unlock((_bs)->bs_mtx)
123 #define BSTP_LOCK_ASSERT(_bs) LCK_MTX_ASSERT((_bs)->bs_mtx, LCK_MTX_ASSERT_OWNED)
126 #ifdef BRIDGESTP_DEBUG
127 #define DPRINTF(fmt, arg...) printf("bstp: " fmt, ##arg)
129 #define DPRINTF(fmt, arg...)
132 #define PV2ADDR(pv, eaddr) do { \
133 eaddr[0] = pv >> 40; \
134 eaddr[1] = pv >> 32; \
135 eaddr[2] = pv >> 24; \
136 eaddr[3] = pv >> 16; \
137 eaddr[4] = pv >> 8; \
138 eaddr[5] = pv >> 0; \
141 #define INFO_BETTER 1
143 #define INFO_WORSE -1
145 LIST_HEAD(, bstp_state
) bstp_list
;
146 decl_lck_mtx_data(static, bstp_list_mtx_data
);
147 static lck_mtx_t
*bstp_list_mtx
= &bstp_list_mtx_data
;
148 static lck_grp_t
*bstp_lock_grp
= NULL
;
149 static lck_attr_t
*bstp_lock_attr
= NULL
;
151 static void bstp_transmit(struct bstp_state
*, struct bstp_port
*);
152 static void bstp_transmit_bpdu(struct bstp_state
*, struct bstp_port
*);
153 static void bstp_transmit_tcn(struct bstp_state
*, struct bstp_port
*);
154 static void bstp_decode_bpdu(struct bstp_port
*, struct bstp_cbpdu
*,
155 struct bstp_config_unit
*);
156 static void bstp_send_bpdu(struct bstp_state
*, struct bstp_port
*,
157 struct bstp_cbpdu
*);
158 static void bstp_enqueue(struct ifnet
*, struct mbuf
*);
159 static int bstp_pdu_flags(struct bstp_port
*);
160 static void bstp_received_stp(struct bstp_state
*, struct bstp_port
*,
161 struct mbuf
**, struct bstp_tbpdu
*);
162 static void bstp_received_rstp(struct bstp_state
*, struct bstp_port
*,
163 struct mbuf
**, struct bstp_tbpdu
*);
164 static void bstp_received_tcn(struct bstp_state
*, struct bstp_port
*,
165 struct bstp_tcn_unit
*);
166 static void bstp_received_bpdu(struct bstp_state
*, struct bstp_port
*,
167 struct bstp_config_unit
*);
168 static int bstp_pdu_rcvtype(struct bstp_port
*, struct bstp_config_unit
*);
169 static int bstp_pdu_bettersame(struct bstp_port
*, int);
170 static int bstp_info_cmp(struct bstp_pri_vector
*,
171 struct bstp_pri_vector
*);
172 static int bstp_info_superior(struct bstp_pri_vector
*,
173 struct bstp_pri_vector
*);
174 static void bstp_assign_roles(struct bstp_state
*);
175 static void bstp_update_roles(struct bstp_state
*, struct bstp_port
*);
176 static void bstp_update_state(struct bstp_state
*, struct bstp_port
*);
177 static void bstp_update_tc(struct bstp_port
*);
178 static void bstp_update_info(struct bstp_port
*);
179 static void bstp_set_other_tcprop(struct bstp_port
*);
180 static void bstp_set_all_reroot(struct bstp_state
*);
181 static void bstp_set_all_sync(struct bstp_state
*);
182 static void bstp_set_port_state(struct bstp_port
*, int);
183 static void bstp_set_port_role(struct bstp_port
*, int);
184 static void bstp_set_port_proto(struct bstp_port
*, int);
185 static void bstp_set_port_tc(struct bstp_port
*, int);
186 static void bstp_set_timer_tc(struct bstp_port
*);
187 static void bstp_set_timer_msgage(struct bstp_port
*);
188 static int bstp_rerooted(struct bstp_state
*, struct bstp_port
*);
189 static uint32_t bstp_calc_path_cost(struct bstp_port
*);
190 static void bstp_notify_state(void *, int);
191 static void bstp_notify_rtage(void *, int);
192 static void bstp_ifupdstatus(struct bstp_state
*, struct bstp_port
*);
193 static void bstp_enable_port(struct bstp_state
*, struct bstp_port
*);
194 static void bstp_disable_port(struct bstp_state
*, struct bstp_port
*);
195 static void bstp_tick(void *);
196 static void bstp_timer_start(struct bstp_timer
*, uint16_t);
197 static void bstp_timer_stop(struct bstp_timer
*);
198 static void bstp_timer_latch(struct bstp_timer
*);
199 static int bstp_timer_expired(struct bstp_timer
*);
200 static void bstp_hello_timer_expiry(struct bstp_state
*,
202 static void bstp_message_age_expiry(struct bstp_state
*,
204 static void bstp_migrate_delay_expiry(struct bstp_state
*,
206 static void bstp_edge_delay_expiry(struct bstp_state
*,
208 static int bstp_addr_cmp(const uint8_t *, const uint8_t *);
209 static int bstp_same_bridgeid(uint64_t, uint64_t);
210 static void bstp_reinit(struct bstp_state
*);
213 bstp_transmit(struct bstp_state
*bs
, struct bstp_port
*bp
)
215 if (bs
->bs_running
== 0) {
220 * a PDU can only be sent if we have tx quota left and the
221 * hello timer is running.
223 if (bp
->bp_hello_timer
.active
== 0) {
224 /* Test if it needs to be reset */
225 bstp_hello_timer_expiry(bs
, bp
);
228 if (bp
->bp_txcount
> bs
->bs_txholdcount
) {
229 /* Ran out of karma */
233 if (bp
->bp_protover
== BSTP_PROTO_RSTP
) {
234 bstp_transmit_bpdu(bs
, bp
);
237 switch (bp
->bp_role
) {
238 case BSTP_ROLE_DESIGNATED
:
239 bstp_transmit_bpdu(bs
, bp
);
244 bstp_transmit_tcn(bs
, bp
);
248 bstp_timer_start(&bp
->bp_hello_timer
, bp
->bp_desg_htime
);
249 bp
->bp_flags
&= ~BSTP_PORT_NEWINFO
;
253 bstp_transmit_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
)
255 struct bstp_cbpdu bpdu
;
257 BSTP_LOCK_ASSERT(bs
);
259 bpdu
.cbu_rootpri
= htons(bp
->bp_desg_pv
.pv_root_id
>> 48);
260 PV2ADDR(bp
->bp_desg_pv
.pv_root_id
, bpdu
.cbu_rootaddr
);
262 bpdu
.cbu_rootpathcost
= htonl(bp
->bp_desg_pv
.pv_cost
);
264 bpdu
.cbu_bridgepri
= htons(bp
->bp_desg_pv
.pv_dbridge_id
>> 48);
265 PV2ADDR(bp
->bp_desg_pv
.pv_dbridge_id
, bpdu
.cbu_bridgeaddr
);
267 bpdu
.cbu_portid
= htons(bp
->bp_port_id
);
268 bpdu
.cbu_messageage
= htons(bp
->bp_desg_msg_age
);
269 bpdu
.cbu_maxage
= htons(bp
->bp_desg_max_age
);
270 bpdu
.cbu_hellotime
= htons(bp
->bp_desg_htime
);
271 bpdu
.cbu_forwarddelay
= htons(bp
->bp_desg_fdelay
);
273 bpdu
.cbu_flags
= bstp_pdu_flags(bp
);
275 switch (bp
->bp_protover
) {
277 bpdu
.cbu_bpdutype
= BSTP_MSGTYPE_CFG
;
280 case BSTP_PROTO_RSTP
:
281 bpdu
.cbu_bpdutype
= BSTP_MSGTYPE_RSTP
;
285 bstp_send_bpdu(bs
, bp
, &bpdu
);
289 bstp_transmit_tcn(struct bstp_state
*bs
, struct bstp_port
*bp
)
291 struct bstp_tbpdu bpdu
;
292 struct ifnet
*ifp
= bp
->bp_ifp
;
293 struct ether_header
*eh
;
295 int touched
= bs
? 1 : 0;
299 KASSERT(bp
== bs
->bs_root_port
, ("%s: bad root port\n", __func__
));
301 if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
305 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
310 m
->m_pkthdr
.rcvif
= ifp
;
311 m
->m_pkthdr
.len
= sizeof(*eh
) + sizeof(bpdu
);
312 m
->m_len
= m
->m_pkthdr
.len
;
314 eh
= mtod(m
, struct ether_header
*);
316 memcpy(eh
->ether_shost
, IF_LLADDR(ifp
), ETHER_ADDR_LEN
);
317 memcpy(eh
->ether_dhost
, bstp_etheraddr
, ETHER_ADDR_LEN
);
318 eh
->ether_type
= htons(sizeof(bpdu
));
320 bpdu
.tbu_ssap
= bpdu
.tbu_dsap
= LLC_8021D_LSAP
;
321 bpdu
.tbu_ctl
= LLC_UI
;
322 bpdu
.tbu_protoid
= 0;
323 bpdu
.tbu_protover
= 0;
324 bpdu
.tbu_bpdutype
= BSTP_MSGTYPE_TCN
;
326 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), &bpdu
, sizeof(bpdu
));
329 bstp_enqueue(ifp
, m
);
333 bstp_decode_bpdu(struct bstp_port
*bp
, struct bstp_cbpdu
*cpdu
,
334 struct bstp_config_unit
*cu
)
338 cu
->cu_pv
.pv_root_id
=
339 (((uint64_t)ntohs(cpdu
->cbu_rootpri
)) << 48) |
340 (((uint64_t)cpdu
->cbu_rootaddr
[0]) << 40) |
341 (((uint64_t)cpdu
->cbu_rootaddr
[1]) << 32) |
342 (((uint64_t)cpdu
->cbu_rootaddr
[2]) << 24) |
343 (((uint64_t)cpdu
->cbu_rootaddr
[3]) << 16) |
344 (((uint64_t)cpdu
->cbu_rootaddr
[4]) << 8) |
345 (((uint64_t)cpdu
->cbu_rootaddr
[5]) << 0);
347 cu
->cu_pv
.pv_dbridge_id
=
348 (((uint64_t)ntohs(cpdu
->cbu_bridgepri
)) << 48) |
349 (((uint64_t)cpdu
->cbu_bridgeaddr
[0]) << 40) |
350 (((uint64_t)cpdu
->cbu_bridgeaddr
[1]) << 32) |
351 (((uint64_t)cpdu
->cbu_bridgeaddr
[2]) << 24) |
352 (((uint64_t)cpdu
->cbu_bridgeaddr
[3]) << 16) |
353 (((uint64_t)cpdu
->cbu_bridgeaddr
[4]) << 8) |
354 (((uint64_t)cpdu
->cbu_bridgeaddr
[5]) << 0);
356 cu
->cu_pv
.pv_cost
= ntohl(cpdu
->cbu_rootpathcost
);
357 cu
->cu_message_age
= ntohs(cpdu
->cbu_messageage
);
358 cu
->cu_max_age
= ntohs(cpdu
->cbu_maxage
);
359 cu
->cu_hello_time
= ntohs(cpdu
->cbu_hellotime
);
360 cu
->cu_forward_delay
= ntohs(cpdu
->cbu_forwarddelay
);
361 cu
->cu_pv
.pv_dport_id
= ntohs(cpdu
->cbu_portid
);
362 cu
->cu_pv
.pv_port_id
= bp
->bp_port_id
;
363 cu
->cu_message_type
= cpdu
->cbu_bpdutype
;
365 /* Strip off unused flags in STP mode */
366 flags
= cpdu
->cbu_flags
;
367 switch (cpdu
->cbu_protover
) {
369 flags
&= BSTP_PDU_STPMASK
;
370 /* A STP BPDU explicitly conveys a Designated Port */
371 cu
->cu_role
= BSTP_ROLE_DESIGNATED
;
374 case BSTP_PROTO_RSTP
:
375 flags
&= BSTP_PDU_RSTPMASK
;
379 cu
->cu_topology_change_ack
=
380 (flags
& BSTP_PDU_F_TCA
) ? 1 : 0;
382 (flags
& BSTP_PDU_F_P
) ? 1 : 0;
384 (flags
& BSTP_PDU_F_A
) ? 1 : 0;
386 (flags
& BSTP_PDU_F_L
) ? 1 : 0;
388 (flags
& BSTP_PDU_F_F
) ? 1 : 0;
389 cu
->cu_topology_change
=
390 (flags
& BSTP_PDU_F_TC
) ? 1 : 0;
392 switch ((flags
& BSTP_PDU_PRMASK
) >> BSTP_PDU_PRSHIFT
) {
393 case BSTP_PDU_F_ROOT
:
394 cu
->cu_role
= BSTP_ROLE_ROOT
;
397 cu
->cu_role
= BSTP_ROLE_ALTERNATE
;
399 case BSTP_PDU_F_DESG
:
400 cu
->cu_role
= BSTP_ROLE_DESIGNATED
;
406 bstp_send_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
,
407 struct bstp_cbpdu
*bpdu
)
411 struct ether_header
*eh
;
413 BSTP_LOCK_ASSERT(bs
);
417 if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
421 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
426 eh
= mtod(m
, struct ether_header
*);
428 bpdu
->cbu_ssap
= bpdu
->cbu_dsap
= LLC_8021D_LSAP
;
429 bpdu
->cbu_ctl
= LLC_UI
;
430 bpdu
->cbu_protoid
= htons(BSTP_PROTO_ID
);
432 memcpy(eh
->ether_shost
, IF_LLADDR(ifp
), ETHER_ADDR_LEN
);
433 memcpy(eh
->ether_dhost
, bstp_etheraddr
, ETHER_ADDR_LEN
);
435 switch (bpdu
->cbu_bpdutype
) {
436 case BSTP_MSGTYPE_CFG
:
437 bpdu
->cbu_protover
= BSTP_PROTO_STP
;
438 m
->m_pkthdr
.len
= sizeof(*eh
) + BSTP_BPDU_STP_LEN
;
439 eh
->ether_type
= htons(BSTP_BPDU_STP_LEN
);
440 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), bpdu
,
444 case BSTP_MSGTYPE_RSTP
:
445 bpdu
->cbu_protover
= BSTP_PROTO_RSTP
;
446 bpdu
->cbu_versionlen
= htons(0);
447 m
->m_pkthdr
.len
= sizeof(*eh
) + BSTP_BPDU_RSTP_LEN
;
448 eh
->ether_type
= htons(BSTP_BPDU_RSTP_LEN
);
449 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), bpdu
,
454 panic("not implemented");
456 m
->m_pkthdr
.rcvif
= ifp
;
457 m
->m_len
= m
->m_pkthdr
.len
;
460 bstp_enqueue(ifp
, m
);
464 bstp_enqueue(struct ifnet
*dst_ifp
, struct mbuf
*m
)
467 u_int32_t len
= m
->m_pkthdr
.len
;
469 m
->m_flags
|= M_PROTO1
; //set to avoid loops
471 error
= ifnet_output_raw(dst_ifp
, 0, m
);
473 (void) ifnet_stat_increment_out(dst_ifp
, 1, len
, 0);
475 (void) ifnet_stat_increment_out(dst_ifp
, 0, 0, 1);
480 bstp_pdu_flags(struct bstp_port
*bp
)
484 if (bp
->bp_proposing
&& bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
) {
485 flags
|= BSTP_PDU_F_P
;
489 flags
|= BSTP_PDU_F_A
;
492 if (bp
->bp_tc_timer
.active
) {
493 flags
|= BSTP_PDU_F_TC
;
497 flags
|= BSTP_PDU_F_TCA
;
500 switch (bp
->bp_state
) {
501 case BSTP_IFSTATE_LEARNING
:
502 flags
|= BSTP_PDU_F_L
;
505 case BSTP_IFSTATE_FORWARDING
:
506 flags
|= (BSTP_PDU_F_L
| BSTP_PDU_F_F
);
510 switch (bp
->bp_role
) {
513 (BSTP_PDU_F_ROOT
<< BSTP_PDU_PRSHIFT
);
516 case BSTP_ROLE_ALTERNATE
:
517 case BSTP_ROLE_BACKUP
: /* fall through */
519 (BSTP_PDU_F_ALT
<< BSTP_PDU_PRSHIFT
);
522 case BSTP_ROLE_DESIGNATED
:
524 (BSTP_PDU_F_DESG
<< BSTP_PDU_PRSHIFT
);
528 /* Strip off unused flags in either mode */
529 switch (bp
->bp_protover
) {
531 flags
&= BSTP_PDU_STPMASK
;
533 case BSTP_PROTO_RSTP
:
534 flags
&= BSTP_PDU_RSTPMASK
;
541 bstp_input(struct bstp_port
*bp
, __unused
struct ifnet
*ifp
, struct mbuf
*m
)
543 struct bstp_state
*bs
= bp
->bp_bs
;
544 struct ether_header
*eh
;
545 struct bstp_tbpdu tpdu
;
548 if (bp
->bp_active
== 0) {
555 eh
= mtod(m
, struct ether_header
*);
557 len
= ntohs(eh
->ether_type
);
558 if (len
< sizeof(tpdu
)) {
562 m_adj(m
, ETHER_HDR_LEN
);
564 if (m
->m_pkthdr
.len
> len
) {
565 m_adj(m
, len
- m
->m_pkthdr
.len
);
567 if ((unsigned int)m
->m_len
< sizeof(tpdu
) &&
568 (m
= m_pullup(m
, sizeof(tpdu
))) == NULL
) {
572 memcpy(&tpdu
, mtod(m
, caddr_t
), sizeof(tpdu
));
574 /* basic packet checks */
575 if (tpdu
.tbu_dsap
!= LLC_8021D_LSAP
||
576 tpdu
.tbu_ssap
!= LLC_8021D_LSAP
||
577 tpdu
.tbu_ctl
!= LLC_UI
) {
580 if (tpdu
.tbu_protoid
!= BSTP_PROTO_ID
) {
585 * We can treat later versions of the PDU as the same as the maximum
586 * version we implement. All additional parameters/flags are ignored.
588 if (tpdu
.tbu_protover
> BSTP_PROTO_MAX
) {
589 tpdu
.tbu_protover
= BSTP_PROTO_MAX
;
592 if (tpdu
.tbu_protover
!= bp
->bp_protover
) {
594 * Wait for the migration delay timer to expire before changing
595 * protocol version to avoid flip-flops.
597 if (bp
->bp_flags
& BSTP_PORT_CANMIGRATE
) {
598 bstp_set_port_proto(bp
, tpdu
.tbu_protover
);
604 /* Clear operedge upon receiving a PDU on the port */
606 bstp_timer_start(&bp
->bp_edge_delay_timer
,
607 BSTP_DEFAULT_MIGRATE_DELAY
);
609 switch (tpdu
.tbu_protover
) {
611 bstp_received_stp(bs
, bp
, &m
, &tpdu
);
614 case BSTP_PROTO_RSTP
:
615 bstp_received_rstp(bs
, bp
, &m
, &tpdu
);
627 bstp_received_stp(struct bstp_state
*bs
, struct bstp_port
*bp
,
628 struct mbuf
**mp
, struct bstp_tbpdu
*tpdu
)
630 struct bstp_cbpdu cpdu
;
631 struct bstp_config_unit
*cu
= &bp
->bp_msg_cu
;
632 struct bstp_tcn_unit tu
;
634 switch (tpdu
->tbu_bpdutype
) {
635 case BSTP_MSGTYPE_TCN
:
636 tu
.tu_message_type
= tpdu
->tbu_bpdutype
;
637 bstp_received_tcn(bs
, bp
, &tu
);
639 case BSTP_MSGTYPE_CFG
:
640 if ((*mp
)->m_len
< BSTP_BPDU_STP_LEN
&&
641 (*mp
= m_pullup(*mp
, BSTP_BPDU_STP_LEN
)) == NULL
) {
644 memcpy(&cpdu
, mtod(*mp
, caddr_t
), BSTP_BPDU_STP_LEN
);
646 bstp_decode_bpdu(bp
, &cpdu
, cu
);
647 bstp_received_bpdu(bs
, bp
, cu
);
653 bstp_received_rstp(struct bstp_state
*bs
, struct bstp_port
*bp
,
654 struct mbuf
**mp
, struct bstp_tbpdu
*tpdu
)
656 struct bstp_cbpdu cpdu
;
657 struct bstp_config_unit
*cu
= &bp
->bp_msg_cu
;
659 if (tpdu
->tbu_bpdutype
!= BSTP_MSGTYPE_RSTP
) {
663 if ((*mp
)->m_len
< BSTP_BPDU_RSTP_LEN
&&
664 (*mp
= m_pullup(*mp
, BSTP_BPDU_RSTP_LEN
)) == NULL
) {
667 memcpy(&cpdu
, mtod(*mp
, caddr_t
), BSTP_BPDU_RSTP_LEN
);
669 bstp_decode_bpdu(bp
, &cpdu
, cu
);
670 bstp_received_bpdu(bs
, bp
, cu
);
674 bstp_received_tcn(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
,
675 __unused
struct bstp_tcn_unit
*tcn
)
682 bstp_received_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
,
683 struct bstp_config_unit
*cu
)
687 BSTP_LOCK_ASSERT(bs
);
689 /* We need to have transitioned to INFO_MINE before proceeding */
690 switch (bp
->bp_infois
) {
691 case BSTP_INFO_DISABLED
:
696 type
= bstp_pdu_rcvtype(bp
, cu
);
699 case BSTP_PDU_SUPERIOR
:
700 bs
->bs_allsynced
= 0;
702 bp
->bp_proposing
= 0;
704 if (cu
->cu_proposal
&& cu
->cu_forwarding
== 0) {
707 if (cu
->cu_topology_change
) {
710 if (cu
->cu_topology_change_ack
) {
715 !bstp_pdu_bettersame(bp
, BSTP_INFO_RECEIVED
)) {
719 /* copy the received priority and timers to the port */
720 bp
->bp_port_pv
= cu
->cu_pv
;
721 bp
->bp_port_msg_age
= cu
->cu_message_age
;
722 bp
->bp_port_max_age
= cu
->cu_max_age
;
723 bp
->bp_port_fdelay
= cu
->cu_forward_delay
;
725 (cu
->cu_hello_time
> BSTP_MIN_HELLO_TIME
?
726 cu
->cu_hello_time
: BSTP_MIN_HELLO_TIME
);
728 /* set expiry for the new info */
729 bstp_set_timer_msgage(bp
);
731 bp
->bp_infois
= BSTP_INFO_RECEIVED
;
732 bstp_assign_roles(bs
);
735 case BSTP_PDU_REPEATED
:
736 if (cu
->cu_proposal
&& cu
->cu_forwarding
== 0) {
739 if (cu
->cu_topology_change
) {
742 if (cu
->cu_topology_change_ack
) {
746 /* rearm the age timer */
747 bstp_set_timer_msgage(bp
);
750 case BSTP_PDU_INFERIOR
:
751 if (cu
->cu_learning
) {
753 bp
->bp_proposing
= 0;
757 case BSTP_PDU_INFERIORALT
:
759 * only point to point links are allowed fast
760 * transitions to forwarding.
762 if (cu
->cu_agree
&& bp
->bp_ptp_link
) {
764 bp
->bp_proposing
= 0;
769 if (cu
->cu_topology_change
) {
772 if (cu
->cu_topology_change_ack
) {
778 return; /* do nothing */
780 /* update the state machines with the new data */
781 bstp_update_state(bs
, bp
);
785 bstp_pdu_rcvtype(struct bstp_port
*bp
, struct bstp_config_unit
*cu
)
789 /* default return type */
790 type
= BSTP_PDU_OTHER
;
792 switch (cu
->cu_role
) {
793 case BSTP_ROLE_DESIGNATED
:
794 if (bstp_info_superior(&bp
->bp_port_pv
, &cu
->cu_pv
)) {
795 /* bpdu priority is superior */
796 type
= BSTP_PDU_SUPERIOR
;
797 } else if (bstp_info_cmp(&bp
->bp_port_pv
, &cu
->cu_pv
) ==
799 if (bp
->bp_port_msg_age
!= cu
->cu_message_age
||
800 bp
->bp_port_max_age
!= cu
->cu_max_age
||
801 bp
->bp_port_fdelay
!= cu
->cu_forward_delay
||
802 bp
->bp_port_htime
!= cu
->cu_hello_time
) {
803 /* bpdu priority is equal and timers differ */
804 type
= BSTP_PDU_SUPERIOR
;
807 type
= BSTP_PDU_REPEATED
;
810 /* bpdu priority is worse */
811 type
= BSTP_PDU_INFERIOR
;
817 case BSTP_ROLE_ALTERNATE
:
818 case BSTP_ROLE_BACKUP
:
819 if (bstp_info_cmp(&bp
->bp_port_pv
, &cu
->cu_pv
) <= INFO_SAME
) {
821 * not a designated port and priority is the same or
824 type
= BSTP_PDU_INFERIORALT
;
833 bstp_pdu_bettersame(struct bstp_port
*bp
, int newinfo
)
835 if (newinfo
== BSTP_INFO_RECEIVED
&&
836 bp
->bp_infois
== BSTP_INFO_RECEIVED
&&
837 bstp_info_cmp(&bp
->bp_port_pv
, &bp
->bp_msg_cu
.cu_pv
) >= INFO_SAME
) {
841 if (newinfo
== BSTP_INFO_MINE
&&
842 bp
->bp_infois
== BSTP_INFO_MINE
&&
843 bstp_info_cmp(&bp
->bp_port_pv
, &bp
->bp_desg_pv
) >= INFO_SAME
) {
851 bstp_info_cmp(struct bstp_pri_vector
*pv
,
852 struct bstp_pri_vector
*cpv
)
854 if (cpv
->pv_root_id
< pv
->pv_root_id
) {
857 if (cpv
->pv_root_id
> pv
->pv_root_id
) {
861 if (cpv
->pv_cost
< pv
->pv_cost
) {
864 if (cpv
->pv_cost
> pv
->pv_cost
) {
868 if (cpv
->pv_dbridge_id
< pv
->pv_dbridge_id
) {
871 if (cpv
->pv_dbridge_id
> pv
->pv_dbridge_id
) {
875 if (cpv
->pv_dport_id
< pv
->pv_dport_id
) {
878 if (cpv
->pv_dport_id
> pv
->pv_dport_id
) {
886 * This message priority vector is superior to the port priority vector and
887 * will replace it if, and only if, the message priority vector is better than
888 * the port priority vector, or the message has been transmitted from the same
889 * designated bridge and designated port as the port priority vector.
892 bstp_info_superior(struct bstp_pri_vector
*pv
,
893 struct bstp_pri_vector
*cpv
)
895 if (bstp_info_cmp(pv
, cpv
) == INFO_BETTER
||
896 (bstp_same_bridgeid(pv
->pv_dbridge_id
, cpv
->pv_dbridge_id
) &&
897 (cpv
->pv_dport_id
& 0xfff) == (pv
->pv_dport_id
& 0xfff))) {
904 bstp_assign_roles(struct bstp_state
*bs
)
906 struct bstp_port
*bp
, *rbp
= NULL
;
907 struct bstp_pri_vector pv
;
909 /* default to our priority vector */
910 bs
->bs_root_pv
= bs
->bs_bridge_pv
;
911 bs
->bs_root_msg_age
= 0;
912 bs
->bs_root_max_age
= bs
->bs_bridge_max_age
;
913 bs
->bs_root_fdelay
= bs
->bs_bridge_fdelay
;
914 bs
->bs_root_htime
= bs
->bs_bridge_htime
;
915 bs
->bs_root_port
= NULL
;
917 /* check if any recieved info supersedes us */
918 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
919 if (bp
->bp_infois
!= BSTP_INFO_RECEIVED
) {
924 pv
.pv_cost
+= bp
->bp_path_cost
;
927 * The root priority vector is the best of the set comprising
928 * the bridge priority vector plus all root path priority
929 * vectors whose bridge address is not equal to us.
931 if (bstp_same_bridgeid(pv
.pv_dbridge_id
,
932 bs
->bs_bridge_pv
.pv_dbridge_id
) == 0 &&
933 bstp_info_cmp(&bs
->bs_root_pv
, &pv
) == INFO_BETTER
) {
934 /* the port vector replaces the root */
936 bs
->bs_root_msg_age
= bp
->bp_port_msg_age
+
937 BSTP_MESSAGE_AGE_INCR
;
938 bs
->bs_root_max_age
= bp
->bp_port_max_age
;
939 bs
->bs_root_fdelay
= bp
->bp_port_fdelay
;
940 bs
->bs_root_htime
= bp
->bp_port_htime
;
945 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
946 /* calculate the port designated vector */
947 bp
->bp_desg_pv
.pv_root_id
= bs
->bs_root_pv
.pv_root_id
;
948 bp
->bp_desg_pv
.pv_cost
= bs
->bs_root_pv
.pv_cost
;
949 bp
->bp_desg_pv
.pv_dbridge_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
950 bp
->bp_desg_pv
.pv_dport_id
= bp
->bp_port_id
;
951 bp
->bp_desg_pv
.pv_port_id
= bp
->bp_port_id
;
953 /* calculate designated times */
954 bp
->bp_desg_msg_age
= bs
->bs_root_msg_age
;
955 bp
->bp_desg_max_age
= bs
->bs_root_max_age
;
956 bp
->bp_desg_fdelay
= bs
->bs_root_fdelay
;
957 bp
->bp_desg_htime
= bs
->bs_bridge_htime
;
960 switch (bp
->bp_infois
) {
961 case BSTP_INFO_DISABLED
:
962 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
966 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
967 bstp_update_info(bp
);
971 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
972 /* update the port info if stale */
973 if (bstp_info_cmp(&bp
->bp_port_pv
,
974 &bp
->bp_desg_pv
) != INFO_SAME
||
976 (bp
->bp_port_msg_age
!= rbp
->bp_port_msg_age
||
977 bp
->bp_port_max_age
!= rbp
->bp_port_max_age
||
978 bp
->bp_port_fdelay
!= rbp
->bp_port_fdelay
||
979 bp
->bp_port_htime
!= rbp
->bp_port_htime
))) {
980 bstp_update_info(bp
);
984 case BSTP_INFO_RECEIVED
:
987 * root priority is derived from this
988 * port, make it the root port.
990 bstp_set_port_role(bp
, BSTP_ROLE_ROOT
);
991 bs
->bs_root_port
= bp
;
992 } else if (bstp_info_cmp(&bp
->bp_port_pv
,
993 &bp
->bp_desg_pv
) == INFO_BETTER
) {
995 * the port priority is lower than the root
998 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
999 bstp_update_info(bp
);
1001 if (bstp_same_bridgeid(
1002 bp
->bp_port_pv
.pv_dbridge_id
,
1003 bs
->bs_bridge_pv
.pv_dbridge_id
)) {
1005 * the designated bridge refers to
1006 * another port on this bridge.
1008 bstp_set_port_role(bp
,
1012 * the port is an inferior path to the
1015 bstp_set_port_role(bp
,
1016 BSTP_ROLE_ALTERNATE
);
1025 bstp_update_state(struct bstp_state
*bs
, struct bstp_port
*bp
)
1027 struct bstp_port
*bp2
;
1030 BSTP_LOCK_ASSERT(bs
);
1032 /* check if all the ports have syncronised again */
1033 if (!bs
->bs_allsynced
) {
1035 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1036 if (!(bp2
->bp_synced
||
1037 bp2
->bp_role
== BSTP_ROLE_ROOT
)) {
1042 bs
->bs_allsynced
= synced
;
1045 bstp_update_roles(bs
, bp
);
1050 bstp_update_roles(struct bstp_state
*bs
, struct bstp_port
*bp
)
1052 switch (bp
->bp_role
) {
1053 case BSTP_ROLE_DISABLED
:
1054 /* Clear any flags if set */
1055 if (bp
->bp_sync
|| !bp
->bp_synced
|| bp
->bp_reroot
) {
1062 case BSTP_ROLE_ALTERNATE
:
1063 case BSTP_ROLE_BACKUP
:
1064 if ((bs
->bs_allsynced
&& !bp
->bp_agree
) ||
1065 (bp
->bp_proposed
&& bp
->bp_agree
)) {
1066 bp
->bp_proposed
= 0;
1068 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1069 DPRINTF("%s -> ALTERNATE_AGREED\n",
1070 bp
->bp_ifp
->if_xname
);
1073 if (bp
->bp_proposed
&& !bp
->bp_agree
) {
1074 bstp_set_all_sync(bs
);
1075 bp
->bp_proposed
= 0;
1076 DPRINTF("%s -> ALTERNATE_PROPOSED\n",
1077 bp
->bp_ifp
->if_xname
);
1080 /* Clear any flags if set */
1081 if (bp
->bp_sync
|| !bp
->bp_synced
|| bp
->bp_reroot
) {
1085 DPRINTF("%s -> ALTERNATE_PORT\n", bp
->bp_ifp
->if_xname
);
1089 case BSTP_ROLE_ROOT
:
1090 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&& !bp
->bp_reroot
) {
1091 bstp_set_all_reroot(bs
);
1092 DPRINTF("%s -> ROOT_REROOT\n", bp
->bp_ifp
->if_xname
);
1095 if ((bs
->bs_allsynced
&& !bp
->bp_agree
) ||
1096 (bp
->bp_proposed
&& bp
->bp_agree
)) {
1097 bp
->bp_proposed
= 0;
1100 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1101 DPRINTF("%s -> ROOT_AGREED\n", bp
->bp_ifp
->if_xname
);
1104 if (bp
->bp_proposed
&& !bp
->bp_agree
) {
1105 bstp_set_all_sync(bs
);
1106 bp
->bp_proposed
= 0;
1107 DPRINTF("%s -> ROOT_PROPOSED\n", bp
->bp_ifp
->if_xname
);
1110 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1111 (bp
->bp_forward_delay_timer
.active
== 0 ||
1112 (bstp_rerooted(bs
, bp
) &&
1113 bp
->bp_recent_backup_timer
.active
== 0 &&
1114 bp
->bp_protover
== BSTP_PROTO_RSTP
))) {
1115 switch (bp
->bp_state
) {
1116 case BSTP_IFSTATE_DISCARDING
:
1117 bstp_set_port_state(bp
, BSTP_IFSTATE_LEARNING
);
1119 case BSTP_IFSTATE_LEARNING
:
1120 bstp_set_port_state(bp
,
1121 BSTP_IFSTATE_FORWARDING
);
1126 if (bp
->bp_state
== BSTP_IFSTATE_FORWARDING
&& bp
->bp_reroot
) {
1128 DPRINTF("%s -> ROOT_REROOTED\n", bp
->bp_ifp
->if_xname
);
1132 case BSTP_ROLE_DESIGNATED
:
1133 if (bp
->bp_recent_root_timer
.active
== 0 && bp
->bp_reroot
) {
1135 DPRINTF("%s -> DESIGNATED_RETIRED\n",
1136 bp
->bp_ifp
->if_xname
);
1139 if ((bp
->bp_state
== BSTP_IFSTATE_DISCARDING
&&
1140 !bp
->bp_synced
) || (bp
->bp_agreed
&& !bp
->bp_synced
) ||
1141 (bp
->bp_operedge
&& !bp
->bp_synced
) ||
1142 (bp
->bp_sync
&& bp
->bp_synced
)) {
1143 bstp_timer_stop(&bp
->bp_recent_root_timer
);
1146 DPRINTF("%s -> DESIGNATED_SYNCED\n",
1147 bp
->bp_ifp
->if_xname
);
1150 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1151 !bp
->bp_agreed
&& !bp
->bp_proposing
&&
1153 bp
->bp_proposing
= 1;
1154 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1155 bstp_timer_start(&bp
->bp_edge_delay_timer
,
1156 (bp
->bp_ptp_link
? BSTP_DEFAULT_MIGRATE_DELAY
:
1157 bp
->bp_desg_max_age
));
1158 DPRINTF("%s -> DESIGNATED_PROPOSE\n",
1159 bp
->bp_ifp
->if_xname
);
1162 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1163 (bp
->bp_forward_delay_timer
.active
== 0 || bp
->bp_agreed
||
1165 (bp
->bp_recent_root_timer
.active
== 0 || !bp
->bp_reroot
) &&
1167 #ifdef BRIDGESTP_DEBUG
1168 if (bp
->bp_agreed
) {
1169 DPRINTF("%s -> AGREED\n", bp
->bp_ifp
->if_xname
);
1171 #endif /* BRIDGESTP_DEBUG */
1173 * If agreed|operedge then go straight to forwarding,
1174 * otherwise follow discard -> learn -> forward.
1176 if (bp
->bp_agreed
|| bp
->bp_operedge
||
1177 bp
->bp_state
== BSTP_IFSTATE_LEARNING
) {
1178 bstp_set_port_state(bp
,
1179 BSTP_IFSTATE_FORWARDING
);
1180 bp
->bp_agreed
= bp
->bp_protover
;
1181 } else if (bp
->bp_state
== BSTP_IFSTATE_DISCARDING
) {
1182 bstp_set_port_state(bp
, BSTP_IFSTATE_LEARNING
);
1186 if (((bp
->bp_sync
&& !bp
->bp_synced
) ||
1187 (bp
->bp_reroot
&& bp
->bp_recent_root_timer
.active
) ||
1188 (bp
->bp_flags
& BSTP_PORT_DISPUTED
)) && !bp
->bp_operedge
&&
1189 bp
->bp_state
!= BSTP_IFSTATE_DISCARDING
) {
1190 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1191 bp
->bp_flags
&= ~BSTP_PORT_DISPUTED
;
1192 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1193 bp
->bp_protover
== BSTP_PROTO_RSTP
?
1194 bp
->bp_desg_htime
: bp
->bp_desg_fdelay
);
1195 DPRINTF("%s -> DESIGNATED_DISCARD\n",
1196 bp
->bp_ifp
->if_xname
);
1201 if (bp
->bp_flags
& BSTP_PORT_NEWINFO
) {
1202 bstp_transmit(bs
, bp
);
1207 bstp_update_tc(struct bstp_port
*bp
)
1209 switch (bp
->bp_tcstate
) {
1210 case BSTP_TCSTATE_ACTIVE
:
1211 if ((bp
->bp_role
!= BSTP_ROLE_DESIGNATED
&&
1212 bp
->bp_role
!= BSTP_ROLE_ROOT
) || bp
->bp_operedge
) {
1213 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1216 if (bp
->bp_rcvdtcn
) {
1217 bstp_set_port_tc(bp
, BSTP_TCSTATE_TCN
);
1219 if (bp
->bp_rcvdtc
) {
1220 bstp_set_port_tc(bp
, BSTP_TCSTATE_TC
);
1223 if (bp
->bp_tc_prop
&& !bp
->bp_operedge
) {
1224 bstp_set_port_tc(bp
, BSTP_TCSTATE_PROPAG
);
1227 if (bp
->bp_rcvdtca
) {
1228 bstp_set_port_tc(bp
, BSTP_TCSTATE_ACK
);
1232 case BSTP_TCSTATE_INACTIVE
:
1233 if ((bp
->bp_state
== BSTP_IFSTATE_LEARNING
||
1234 bp
->bp_state
== BSTP_IFSTATE_FORWARDING
) &&
1235 bp
->bp_fdbflush
== 0) {
1236 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1240 case BSTP_TCSTATE_LEARNING
:
1241 if (bp
->bp_rcvdtc
|| bp
->bp_rcvdtcn
|| bp
->bp_rcvdtca
||
1243 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1244 } else if (bp
->bp_role
!= BSTP_ROLE_DESIGNATED
&&
1245 bp
->bp_role
!= BSTP_ROLE_ROOT
&&
1246 bp
->bp_state
== BSTP_IFSTATE_DISCARDING
) {
1247 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
1250 if ((bp
->bp_role
== BSTP_ROLE_DESIGNATED
||
1251 bp
->bp_role
== BSTP_ROLE_ROOT
) &&
1252 bp
->bp_state
== BSTP_IFSTATE_FORWARDING
&&
1254 bstp_set_port_tc(bp
, BSTP_TCSTATE_DETECTED
);
1258 /* these are transient states and go straight back to ACTIVE */
1259 case BSTP_TCSTATE_DETECTED
:
1260 case BSTP_TCSTATE_TCN
:
1261 case BSTP_TCSTATE_TC
:
1262 case BSTP_TCSTATE_PROPAG
:
1263 case BSTP_TCSTATE_ACK
:
1264 DPRINTF("Invalid TC state for %s\n",
1265 bp
->bp_ifp
->if_xname
);
1271 bstp_update_info(struct bstp_port
*bp
)
1273 struct bstp_state
*bs
= bp
->bp_bs
;
1275 bp
->bp_proposing
= 0;
1276 bp
->bp_proposed
= 0;
1278 if (bp
->bp_agreed
&& !bstp_pdu_bettersame(bp
, BSTP_INFO_MINE
)) {
1282 if (bp
->bp_synced
&& !bp
->bp_agreed
) {
1284 bs
->bs_allsynced
= 0;
1287 /* copy the designated pv to the port */
1288 bp
->bp_port_pv
= bp
->bp_desg_pv
;
1289 bp
->bp_port_msg_age
= bp
->bp_desg_msg_age
;
1290 bp
->bp_port_max_age
= bp
->bp_desg_max_age
;
1291 bp
->bp_port_fdelay
= bp
->bp_desg_fdelay
;
1292 bp
->bp_port_htime
= bp
->bp_desg_htime
;
1293 bp
->bp_infois
= BSTP_INFO_MINE
;
1295 /* Set transmit flag but do not immediately send */
1296 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1299 /* set tcprop on every port other than the caller */
1301 bstp_set_other_tcprop(struct bstp_port
*bp
)
1303 struct bstp_state
*bs
= bp
->bp_bs
;
1304 struct bstp_port
*bp2
;
1306 BSTP_LOCK_ASSERT(bs
);
1308 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1312 bp2
->bp_tc_prop
= 1;
1317 bstp_set_all_reroot(struct bstp_state
*bs
)
1319 struct bstp_port
*bp
;
1321 BSTP_LOCK_ASSERT(bs
);
1323 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
1328 bstp_set_all_sync(struct bstp_state
*bs
)
1330 struct bstp_port
*bp
;
1332 BSTP_LOCK_ASSERT(bs
);
1334 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1336 bp
->bp_synced
= 0; /* Not explicit in spec */
1339 bs
->bs_allsynced
= 0;
1343 bstp_set_port_state(struct bstp_port
*bp
, int state
)
1345 if (bp
->bp_state
== state
) {
1349 bp
->bp_state
= state
;
1351 switch (bp
->bp_state
) {
1352 case BSTP_IFSTATE_DISCARDING
:
1353 DPRINTF("state changed to DISCARDING on %s\n",
1354 bp
->bp_ifp
->if_xname
);
1357 case BSTP_IFSTATE_LEARNING
:
1358 DPRINTF("state changed to LEARNING on %s\n",
1359 bp
->bp_ifp
->if_xname
);
1361 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1362 bp
->bp_protover
== BSTP_PROTO_RSTP
?
1363 bp
->bp_desg_htime
: bp
->bp_desg_fdelay
);
1366 case BSTP_IFSTATE_FORWARDING
:
1367 DPRINTF("state changed to FORWARDING on %s\n",
1368 bp
->bp_ifp
->if_xname
);
1370 bstp_timer_stop(&bp
->bp_forward_delay_timer
);
1371 /* Record that we enabled forwarding */
1372 bp
->bp_forward_transitions
++;
1376 /* notify the parent bridge */
1377 bstp_task_enqueue(&bp
->bp_statetask
);
1381 bstp_set_port_role(struct bstp_port
*bp
, int role
)
1383 struct bstp_state
*bs
= bp
->bp_bs
;
1385 if (bp
->bp_role
== role
) {
1389 /* perform pre-change tasks */
1390 switch (bp
->bp_role
) {
1391 case BSTP_ROLE_DISABLED
:
1392 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1393 bp
->bp_desg_max_age
);
1396 case BSTP_ROLE_BACKUP
:
1397 bstp_timer_start(&bp
->bp_recent_backup_timer
,
1398 bp
->bp_desg_htime
* 2);
1400 case BSTP_ROLE_ALTERNATE
:
1401 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1402 bp
->bp_desg_fdelay
);
1408 case BSTP_ROLE_ROOT
:
1409 bstp_timer_start(&bp
->bp_recent_root_timer
,
1410 BSTP_DEFAULT_FORWARD_DELAY
);
1415 /* clear values not carried between roles */
1416 bp
->bp_proposing
= 0;
1417 bs
->bs_allsynced
= 0;
1419 /* initialise the new role */
1420 switch (bp
->bp_role
) {
1421 case BSTP_ROLE_DISABLED
:
1422 case BSTP_ROLE_ALTERNATE
:
1423 case BSTP_ROLE_BACKUP
:
1424 DPRINTF("%s role -> ALT/BACK/DISABLED\n",
1425 bp
->bp_ifp
->if_xname
);
1426 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1427 bstp_timer_stop(&bp
->bp_recent_root_timer
);
1428 bstp_timer_latch(&bp
->bp_forward_delay_timer
);
1434 case BSTP_ROLE_ROOT
:
1435 DPRINTF("%s role -> ROOT\n",
1436 bp
->bp_ifp
->if_xname
);
1437 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1438 bstp_timer_latch(&bp
->bp_recent_root_timer
);
1439 bp
->bp_proposing
= 0;
1442 case BSTP_ROLE_DESIGNATED
:
1443 DPRINTF("%s role -> DESIGNATED\n",
1444 bp
->bp_ifp
->if_xname
);
1445 bstp_timer_start(&bp
->bp_hello_timer
,
1451 /* let the TC state know that the role changed */
1456 bstp_set_port_proto(struct bstp_port
*bp
, int proto
)
1458 struct bstp_state
*bs
= bp
->bp_bs
;
1460 /* supported protocol versions */
1462 case BSTP_PROTO_STP
:
1463 /* we can downgrade protocols only */
1464 bstp_timer_stop(&bp
->bp_migrate_delay_timer
);
1465 /* clear unsupported features */
1466 bp
->bp_operedge
= 0;
1467 /* STP compat mode only uses 16 bits of the 32 */
1468 if (bp
->bp_path_cost
> 65535) {
1469 bp
->bp_path_cost
= 65535;
1473 case BSTP_PROTO_RSTP
:
1474 bstp_timer_start(&bp
->bp_migrate_delay_timer
,
1475 bs
->bs_migration_delay
);
1479 DPRINTF("Unsupported STP version %d\n", proto
);
1483 bp
->bp_protover
= proto
;
1484 bp
->bp_flags
&= ~BSTP_PORT_CANMIGRATE
;
1488 bstp_set_port_tc(struct bstp_port
*bp
, int state
)
1490 struct bstp_state
*bs
= bp
->bp_bs
;
1492 bp
->bp_tcstate
= state
;
1494 /* initialise the new state */
1495 switch (bp
->bp_tcstate
) {
1496 case BSTP_TCSTATE_ACTIVE
:
1497 DPRINTF("%s -> TC_ACTIVE\n", bp
->bp_ifp
->if_xname
);
1501 case BSTP_TCSTATE_INACTIVE
:
1502 bstp_timer_stop(&bp
->bp_tc_timer
);
1503 /* flush routes on the parent bridge */
1504 bp
->bp_fdbflush
= 1;
1505 bstp_task_enqueue(&bp
->bp_rtagetask
);
1507 DPRINTF("%s -> TC_INACTIVE\n", bp
->bp_ifp
->if_xname
);
1510 case BSTP_TCSTATE_LEARNING
:
1515 DPRINTF("%s -> TC_LEARNING\n", bp
->bp_ifp
->if_xname
);
1518 case BSTP_TCSTATE_DETECTED
:
1519 bstp_set_timer_tc(bp
);
1520 bstp_set_other_tcprop(bp
);
1521 /* send out notification */
1522 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1523 bstp_transmit(bs
, bp
);
1524 /* reviewed for getmicrotime usage */
1525 getmicrotime(&bs
->bs_last_tc_time
);
1526 DPRINTF("%s -> TC_DETECTED\n", bp
->bp_ifp
->if_xname
);
1527 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1530 case BSTP_TCSTATE_TCN
:
1531 bstp_set_timer_tc(bp
);
1532 DPRINTF("%s -> TC_TCN\n", bp
->bp_ifp
->if_xname
);
1534 case BSTP_TCSTATE_TC
:
1537 if (bp
->bp_role
== BSTP_ROLE_DESIGNATED
) {
1541 bstp_set_other_tcprop(bp
);
1542 DPRINTF("%s -> TC_TC\n", bp
->bp_ifp
->if_xname
);
1543 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1546 case BSTP_TCSTATE_PROPAG
:
1547 /* flush routes on the parent bridge */
1548 bp
->bp_fdbflush
= 1;
1549 bstp_task_enqueue(&bp
->bp_rtagetask
);
1551 bstp_set_timer_tc(bp
);
1552 DPRINTF("%s -> TC_PROPAG\n", bp
->bp_ifp
->if_xname
);
1553 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1556 case BSTP_TCSTATE_ACK
:
1557 bstp_timer_stop(&bp
->bp_tc_timer
);
1559 DPRINTF("%s -> TC_ACK\n", bp
->bp_ifp
->if_xname
);
1560 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1566 bstp_set_timer_tc(struct bstp_port
*bp
)
1568 struct bstp_state
*bs
= bp
->bp_bs
;
1570 if (bp
->bp_tc_timer
.active
) {
1574 switch (bp
->bp_protover
) {
1575 case BSTP_PROTO_RSTP
:
1576 bstp_timer_start(&bp
->bp_tc_timer
,
1577 bp
->bp_desg_htime
+ BSTP_TICK_VAL
);
1578 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1581 case BSTP_PROTO_STP
:
1582 bstp_timer_start(&bp
->bp_tc_timer
,
1583 bs
->bs_root_max_age
+ bs
->bs_root_fdelay
);
1589 bstp_set_timer_msgage(struct bstp_port
*bp
)
1591 if (bp
->bp_port_msg_age
+ BSTP_MESSAGE_AGE_INCR
<=
1592 bp
->bp_port_max_age
) {
1593 bstp_timer_start(&bp
->bp_message_age_timer
,
1594 bp
->bp_port_htime
* 3);
1596 /* expires immediately */
1597 bstp_timer_start(&bp
->bp_message_age_timer
, 0);
1602 bstp_rerooted(struct bstp_state
*bs
, struct bstp_port
*bp
)
1604 struct bstp_port
*bp2
;
1607 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1611 if (bp2
->bp_recent_root_timer
.active
) {
1620 bstp_set_htime(struct bstp_state
*bs
, int t
)
1622 /* convert seconds to ticks */
1625 /* value can only be changed in leagacy stp mode */
1626 if (bs
->bs_protover
!= BSTP_PROTO_STP
) {
1630 if (t
< BSTP_MIN_HELLO_TIME
|| t
> BSTP_MAX_HELLO_TIME
) {
1635 bs
->bs_bridge_htime
= t
;
1642 bstp_set_fdelay(struct bstp_state
*bs
, int t
)
1644 /* convert seconds to ticks */
1647 if (t
< BSTP_MIN_FORWARD_DELAY
|| t
> BSTP_MAX_FORWARD_DELAY
) {
1652 bs
->bs_bridge_fdelay
= t
;
1659 bstp_set_maxage(struct bstp_state
*bs
, int t
)
1661 /* convert seconds to ticks */
1664 if (t
< BSTP_MIN_MAX_AGE
|| t
> BSTP_MAX_MAX_AGE
) {
1669 bs
->bs_bridge_max_age
= t
;
1676 bstp_set_holdcount(struct bstp_state
*bs
, int count
)
1678 struct bstp_port
*bp
;
1680 if (count
< BSTP_MIN_HOLD_COUNT
||
1681 count
> BSTP_MAX_HOLD_COUNT
) {
1686 bs
->bs_txholdcount
= count
;
1687 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
1694 bstp_set_protocol(struct bstp_state
*bs
, int proto
)
1696 struct bstp_port
*bp
;
1699 /* Supported protocol versions */
1700 case BSTP_PROTO_STP
:
1701 case BSTP_PROTO_RSTP
:
1709 bs
->bs_protover
= proto
;
1710 bs
->bs_bridge_htime
= BSTP_DEFAULT_HELLO_TIME
;
1711 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1713 bp
->bp_infois
= BSTP_INFO_DISABLED
;
1715 bstp_set_port_proto(bp
, bs
->bs_protover
);
1716 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
1717 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
1718 bstp_timer_stop(&bp
->bp_recent_backup_timer
);
1726 bstp_set_priority(struct bstp_state
*bs
, int pri
)
1728 if (pri
< 0 || pri
> BSTP_MAX_PRIORITY
) {
1732 /* Limit to steps of 4096 */
1736 bs
->bs_bridge_priority
= pri
;
1743 bstp_set_port_priority(struct bstp_port
*bp
, int pri
)
1745 struct bstp_state
*bs
= bp
->bp_bs
;
1747 if (pri
< 0 || pri
> BSTP_MAX_PORT_PRIORITY
) {
1751 /* Limit to steps of 16 */
1755 bp
->bp_priority
= pri
;
1762 bstp_set_path_cost(struct bstp_port
*bp
, uint32_t path_cost
)
1764 struct bstp_state
*bs
= bp
->bp_bs
;
1766 if (path_cost
> BSTP_MAX_PATH_COST
) {
1770 /* STP compat mode only uses 16 bits of the 32 */
1771 if (bp
->bp_protover
== BSTP_PROTO_STP
&& path_cost
> 65535) {
1777 if (path_cost
== 0) { /* use auto */
1778 bp
->bp_flags
&= ~BSTP_PORT_ADMCOST
;
1779 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
1781 bp
->bp_path_cost
= path_cost
;
1782 bp
->bp_flags
|= BSTP_PORT_ADMCOST
;
1790 bstp_set_edge(struct bstp_port
*bp
, int set
)
1792 struct bstp_state
*bs
= bp
->bp_bs
;
1795 if ((bp
->bp_operedge
= set
) == 0) {
1796 bp
->bp_flags
&= ~BSTP_PORT_ADMEDGE
;
1798 bp
->bp_flags
|= BSTP_PORT_ADMEDGE
;
1805 bstp_set_autoedge(struct bstp_port
*bp
, int set
)
1807 struct bstp_state
*bs
= bp
->bp_bs
;
1811 bp
->bp_flags
|= BSTP_PORT_AUTOEDGE
;
1812 /* we may be able to transition straight to edge */
1813 if (bp
->bp_edge_delay_timer
.active
== 0) {
1814 bstp_edge_delay_expiry(bs
, bp
);
1817 bp
->bp_flags
&= ~BSTP_PORT_AUTOEDGE
;
1824 bstp_set_ptp(struct bstp_port
*bp
, int set
)
1826 struct bstp_state
*bs
= bp
->bp_bs
;
1829 bp
->bp_ptp_link
= set
;
1835 bstp_set_autoptp(struct bstp_port
*bp
, int set
)
1837 struct bstp_state
*bs
= bp
->bp_bs
;
1841 bp
->bp_flags
|= BSTP_PORT_AUTOPTP
;
1842 if (bp
->bp_role
!= BSTP_ROLE_DISABLED
) {
1843 bstp_ifupdstatus(bs
, bp
);
1846 bp
->bp_flags
&= ~BSTP_PORT_AUTOPTP
;
1853 * Calculate the path cost according to the link speed.
1856 bstp_calc_path_cost(struct bstp_port
*bp
)
1858 struct ifnet
*ifp
= bp
->bp_ifp
;
1861 /* If the priority has been manually set then retain the value */
1862 if (bp
->bp_flags
& BSTP_PORT_ADMCOST
) {
1863 return bp
->bp_path_cost
;
1866 if (bp
->bp_if_link_state
== LINK_STATE_DOWN
) {
1867 /* Recalc when the link comes up again */
1868 bp
->bp_flags
|= BSTP_PORT_PNDCOST
;
1869 return BSTP_DEFAULT_PATH_COST
;
1872 if (ifp
->if_baudrate
< 1000) {
1873 return BSTP_DEFAULT_PATH_COST
;
1876 /* formula from section 17.14, IEEE Std 802.1D-2004 */
1877 path_cost
= 20000000000ULL / (ifp
->if_baudrate
/ 1000);
1879 if (path_cost
> BSTP_MAX_PATH_COST
) {
1880 path_cost
= BSTP_MAX_PATH_COST
;
1883 /* STP compat mode only uses 16 bits of the 32 */
1884 if (bp
->bp_protover
== BSTP_PROTO_STP
&& path_cost
> 65535) {
1892 * Notify the bridge that a port state has changed, we need to do this from a
1893 * taskqueue to avoid a LOR.
1896 bstp_notify_state(void *arg
, __unused
int pending
)
1898 struct bstp_port
*bp
= (struct bstp_port
*)arg
;
1899 struct bstp_state
*bs
= bp
->bp_bs
;
1901 if (bp
->bp_active
== 1 && bs
->bs_state_cb
!= NULL
) {
1902 (*bs
->bs_state_cb
)(bp
->bp_ifp
, bp
->bp_state
);
1907 * Flush the routes on the bridge port, we need to do this from a
1908 * taskqueue to avoid a LOR.
1911 bstp_notify_rtage(void *arg
, __unused
int pending
)
1913 struct bstp_port
*bp
= (struct bstp_port
*)arg
;
1914 struct bstp_state
*bs
= bp
->bp_bs
;
1918 switch (bp
->bp_protover
) {
1919 case BSTP_PROTO_STP
:
1920 /* convert to seconds */
1921 age
= bp
->bp_desg_fdelay
/ BSTP_TICK_VAL
;
1924 case BSTP_PROTO_RSTP
:
1930 if (bp
->bp_active
== 1 && bs
->bs_rtage_cb
!= NULL
) {
1931 (*bs
->bs_rtage_cb
)(bp
->bp_ifp
, age
);
1934 /* flush is complete */
1936 bp
->bp_fdbflush
= 0;
1941 bstp_linkstate(struct ifnet
*ifp
, __unused
int state
)
1943 struct bstp_state
*bs
;
1944 struct bstp_port
*bp
;
1946 /* search for the stp port */
1947 lck_mtx_lock(bstp_list_mtx
);
1948 LIST_FOREACH(bs
, &bstp_list
, bs_list
) {
1950 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1951 if (bp
->bp_ifp
== ifp
) {
1952 bstp_ifupdstatus(bs
, bp
);
1953 bstp_update_state(bs
, bp
);
1954 /* it only exists once so return */
1956 lck_mtx_unlock(bstp_list_mtx
);
1962 lck_mtx_unlock(bstp_list_mtx
);
1966 bstp_ifupdstatus(struct bstp_state
*bs
, struct bstp_port
*bp
)
1968 struct ifnet
*ifp
= bp
->bp_ifp
;
1969 struct ifmediareq ifmr
;
1972 BSTP_LOCK_ASSERT(bs
);
1974 bzero((char *)&ifmr
, sizeof(ifmr
));
1975 error
= (*ifp
->if_ioctl
)(ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
);
1977 if ((error
== 0) && (ifp
->if_flags
& IFF_UP
)) {
1978 if (ifmr
.ifm_status
& IFM_ACTIVE
) {
1979 /* A full-duplex link is assumed to be point to point */
1980 if (bp
->bp_flags
& BSTP_PORT_AUTOPTP
) {
1982 ifmr
.ifm_active
& IFM_FDX
? 1 : 0;
1985 /* Calc the cost if the link was down previously */
1986 if (bp
->bp_flags
& BSTP_PORT_PNDCOST
) {
1987 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
1988 bp
->bp_flags
&= ~BSTP_PORT_PNDCOST
;
1991 if (bp
->bp_role
== BSTP_ROLE_DISABLED
) {
1992 bstp_enable_port(bs
, bp
);
1995 if (bp
->bp_role
!= BSTP_ROLE_DISABLED
) {
1996 bstp_disable_port(bs
, bp
);
1997 if ((bp
->bp_flags
& BSTP_PORT_ADMEDGE
) &&
1998 bp
->bp_protover
== BSTP_PROTO_RSTP
) {
1999 bp
->bp_operedge
= 1;
2006 if (bp
->bp_infois
!= BSTP_INFO_DISABLED
) {
2007 bstp_disable_port(bs
, bp
);
2012 bstp_enable_port(struct bstp_state
*bs
, struct bstp_port
*bp
)
2014 bp
->bp_infois
= BSTP_INFO_AGED
;
2015 bstp_assign_roles(bs
);
2019 bstp_disable_port(struct bstp_state
*bs
, struct bstp_port
*bp
)
2021 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2022 bstp_assign_roles(bs
);
2026 bstp_tick(void *arg
)
2028 struct bstp_state
*bs
= arg
;
2029 struct bstp_port
*bp
;
2034 if (bs
->bs_running
== 0) {
2038 /* slow timer to catch missed link events */
2039 if (bstp_timer_expired(&bs
->bs_link_timer
)) {
2040 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
2041 bstp_ifupdstatus(bs
, bp
);
2042 bstp_timer_start(&bs
->bs_link_timer
, BSTP_LINK_TIMER
);
2045 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2046 /* no events need to happen for these */
2047 bstp_timer_expired(&bp
->bp_tc_timer
);
2048 bstp_timer_expired(&bp
->bp_recent_root_timer
);
2049 bstp_timer_expired(&bp
->bp_forward_delay_timer
);
2050 bstp_timer_expired(&bp
->bp_recent_backup_timer
);
2052 if (bstp_timer_expired(&bp
->bp_hello_timer
)) {
2053 bstp_hello_timer_expiry(bs
, bp
);
2056 if (bstp_timer_expired(&bp
->bp_message_age_timer
)) {
2057 bstp_message_age_expiry(bs
, bp
);
2060 if (bstp_timer_expired(&bp
->bp_migrate_delay_timer
)) {
2061 bstp_migrate_delay_expiry(bs
, bp
);
2064 if (bstp_timer_expired(&bp
->bp_edge_delay_timer
)) {
2065 bstp_edge_delay_expiry(bs
, bp
);
2068 /* update the various state machines for the port */
2069 bstp_update_state(bs
, bp
);
2071 if (bp
->bp_txcount
> 0) {
2080 bsd_timeout(bstp_tick
, bs
, &ts
);
2084 bstp_timer_start(struct bstp_timer
*t
, uint16_t v
)
2092 bstp_timer_stop(struct bstp_timer
*t
)
2100 bstp_timer_latch(struct bstp_timer
*t
)
2107 bstp_timer_expired(struct bstp_timer
*t
)
2109 if (t
->active
== 0 || t
->latched
) {
2112 t
->value
-= BSTP_TICK_VAL
;
2113 if (t
->value
<= 0) {
2121 bstp_hello_timer_expiry(struct bstp_state
*bs
, struct bstp_port
*bp
)
2123 if ((bp
->bp_flags
& BSTP_PORT_NEWINFO
) ||
2124 bp
->bp_role
== BSTP_ROLE_DESIGNATED
||
2125 (bp
->bp_role
== BSTP_ROLE_ROOT
&&
2126 bp
->bp_tc_timer
.active
== 1)) {
2127 bstp_timer_start(&bp
->bp_hello_timer
, bp
->bp_desg_htime
);
2128 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
2129 bstp_transmit(bs
, bp
);
2134 bstp_message_age_expiry(struct bstp_state
*bs
, struct bstp_port
*bp
)
2136 if (bp
->bp_infois
== BSTP_INFO_RECEIVED
) {
2137 bp
->bp_infois
= BSTP_INFO_AGED
;
2138 bstp_assign_roles(bs
);
2139 DPRINTF("aged info on %s\n", bp
->bp_ifp
->if_xname
);
2144 bstp_migrate_delay_expiry(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
)
2146 bp
->bp_flags
|= BSTP_PORT_CANMIGRATE
;
2150 bstp_edge_delay_expiry(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
)
2152 if ((bp
->bp_flags
& BSTP_PORT_AUTOEDGE
) &&
2153 bp
->bp_protover
== BSTP_PROTO_RSTP
&& bp
->bp_proposing
&&
2154 bp
->bp_role
== BSTP_ROLE_DESIGNATED
) {
2155 bp
->bp_operedge
= 1;
2156 DPRINTF("%s -> edge port\n", bp
->bp_ifp
->if_xname
);
2161 bstp_addr_cmp(const uint8_t *a
, const uint8_t *b
)
2165 for (i
= 0, d
= 0; i
< ETHER_ADDR_LEN
&& d
== 0; i
++) {
2166 d
= ((int)a
[i
]) - ((int)b
[i
]);
2173 * compare the bridge address component of the bridgeid
2176 bstp_same_bridgeid(uint64_t id1
, uint64_t id2
)
2178 u_char addr1
[ETHER_ADDR_LEN
];
2179 u_char addr2
[ETHER_ADDR_LEN
];
2181 PV2ADDR(id1
, addr1
);
2182 PV2ADDR(id2
, addr2
);
2184 if (bstp_addr_cmp(addr1
, addr2
) == 0) {
2192 bstp_reinit(struct bstp_state
*bs
)
2194 struct bstp_port
*bp
;
2195 struct ifnet
*ifp
, *mif
;
2197 static const u_char llzero
[ETHER_ADDR_LEN
]; /* 00:00:00:00:00:00 */
2199 BSTP_LOCK_ASSERT(bs
);
2203 * Search through the Ethernet adapters and find the one with the
2204 * lowest value. The adapter which we take the MAC address from does
2205 * not need to be part of the bridge, it just needs to be a unique
2208 ifnet_head_lock_shared();
2209 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
2210 if (ifp
->if_type
!= IFT_ETHER
) {
2214 if (bstp_addr_cmp(IF_LLADDR(ifp
), llzero
) == 0) {
2222 if (bstp_addr_cmp(IF_LLADDR(ifp
), IF_LLADDR(mif
)) < 0) {
2229 if (LIST_EMPTY(&bs
->bs_bplist
) || mif
== NULL
) {
2230 /* Set the bridge and root id (lower bits) to zero */
2231 bs
->bs_bridge_pv
.pv_dbridge_id
=
2232 ((uint64_t)bs
->bs_bridge_priority
) << 48;
2233 bs
->bs_bridge_pv
.pv_root_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
2234 bs
->bs_root_pv
= bs
->bs_bridge_pv
;
2235 /* Disable any remaining ports, they will have no MAC address */
2236 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2237 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2238 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
2240 bsd_untimeout(bstp_tick
, bs
);
2244 e_addr
= IF_LLADDR(mif
);
2245 bs
->bs_bridge_pv
.pv_dbridge_id
=
2246 (((uint64_t)bs
->bs_bridge_priority
) << 48) |
2247 (((uint64_t)e_addr
[0]) << 40) |
2248 (((uint64_t)e_addr
[1]) << 32) |
2249 (((uint64_t)e_addr
[2]) << 24) |
2250 (((uint64_t)e_addr
[3]) << 16) |
2251 (((uint64_t)e_addr
[4]) << 8) |
2252 (((uint64_t)e_addr
[5]));
2254 bs
->bs_bridge_pv
.pv_root_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
2255 bs
->bs_bridge_pv
.pv_cost
= 0;
2256 bs
->bs_bridge_pv
.pv_dport_id
= 0;
2257 bs
->bs_bridge_pv
.pv_port_id
= 0;
2259 if (bs
->bs_running
) {
2260 bsd_untimeout(bstp_tick
, bs
);
2263 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2264 bp
->bp_port_id
= (bp
->bp_priority
<< 8) |
2265 (bp
->bp_ifp
->if_index
& 0xfff);
2266 bstp_ifupdstatus(bs
, bp
);
2269 bstp_assign_roles(bs
);
2270 bstp_timer_start(&bs
->bs_link_timer
, BSTP_LINK_TIMER
);
2274 bstp_attach(struct bstp_state
*bs
, struct bstp_cb_ops
*cb
)
2277 LIST_INIT(&bs
->bs_bplist
);
2279 bs
->bs_bridge_max_age
= BSTP_DEFAULT_MAX_AGE
;
2280 bs
->bs_bridge_htime
= BSTP_DEFAULT_HELLO_TIME
;
2281 bs
->bs_bridge_fdelay
= BSTP_DEFAULT_FORWARD_DELAY
;
2282 bs
->bs_bridge_priority
= BSTP_DEFAULT_BRIDGE_PRIORITY
;
2283 bs
->bs_hold_time
= BSTP_DEFAULT_HOLD_TIME
;
2284 bs
->bs_migration_delay
= BSTP_DEFAULT_MIGRATE_DELAY
;
2285 bs
->bs_txholdcount
= BSTP_DEFAULT_HOLD_COUNT
;
2286 bs
->bs_protover
= BSTP_PROTO_RSTP
;
2287 bs
->bs_state_cb
= cb
->bcb_state
;
2288 bs
->bs_rtage_cb
= cb
->bcb_rtage
;
2290 /* reviewed for getmicrotime usage */
2291 getmicrotime(&bs
->bs_last_tc_time
);
2293 lck_mtx_lock(bstp_list_mtx
);
2294 LIST_INSERT_HEAD(&bstp_list
, bs
, bs_list
);
2295 lck_mtx_unlock(bstp_list_mtx
);
2299 bstp_detach(struct bstp_state
*bs
)
2301 KASSERT(LIST_EMPTY(&bs
->bs_bplist
), ("bstp still active"));
2303 lck_mtx_lock(bstp_list_mtx
);
2304 LIST_REMOVE(bs
, bs_list
);
2305 lck_mtx_unlock(bstp_list_mtx
);
2306 bsd_untimeout(bstp_tick
, bs
);
2307 BSTP_LOCK_DESTROY(bs
);
2311 bstp_init(struct bstp_state
*bs
)
2319 bsd_timeout(bstp_tick
, bs
, &ts
);
2326 bstp_stop(struct bstp_state
*bs
)
2328 struct bstp_port
*bp
;
2332 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
2333 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
2336 bsd_untimeout(bstp_tick
, bs
);
2341 bstp_create(struct bstp_state
*bs
, struct bstp_port
*bp
, struct ifnet
*ifp
)
2343 bzero(bp
, sizeof(struct bstp_port
));
2348 bp
->bp_priority
= BSTP_DEFAULT_PORT_PRIORITY
;
2349 BSTP_TASK_INIT(&bp
->bp_statetask
, bstp_notify_state
, bp
);
2350 BSTP_TASK_INIT(&bp
->bp_rtagetask
, bstp_notify_rtage
, bp
);
2353 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2354 bp
->bp_flags
= BSTP_PORT_AUTOEDGE
| BSTP_PORT_AUTOPTP
;
2355 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
2356 bstp_set_port_proto(bp
, bs
->bs_protover
);
2357 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
2358 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
2359 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
2365 bstp_enable(struct bstp_port
*bp
)
2367 struct bstp_state
*bs
= bp
->bp_bs
;
2368 struct ifnet
*ifp
= bp
->bp_ifp
;
2370 KASSERT(bp
->bp_active
== 0, ("already a bstp member"));
2372 switch (ifp
->if_type
) {
2373 case IFT_ETHER
: /* These can do spanning tree. */
2376 /* Nothing else can. */
2381 LIST_INSERT_HEAD(&bs
->bs_bplist
, bp
, bp_next
);
2383 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
2385 bstp_update_roles(bs
, bp
);
2391 bstp_disable(struct bstp_port
*bp
)
2393 struct bstp_state
*bs
= bp
->bp_bs
;
2395 KASSERT(bp
->bp_active
== 1, ("not a bstp member"));
2398 bstp_disable_port(bs
, bp
);
2399 LIST_REMOVE(bp
, bp_next
);
2406 * The bstp_port structure is about to be freed by the parent bridge.
2409 bstp_destroy(struct bstp_port
*bp
)
2411 KASSERT(bp
->bp_active
== 0, ("port is still attached"));
2412 bstp_task_drain(&bp
->bp_statetask
);
2413 bstp_task_drain(&bp
->bp_rtagetask
);
2417 __private_extern__
void
2420 lck_grp_attr_t
*lck_grp_attr
= NULL
;
2422 lck_grp_attr
= lck_grp_attr_alloc_init();
2423 bstp_lock_grp
= lck_grp_alloc_init("bstp", lck_grp_attr
);
2424 bstp_lock_attr
= lck_attr_alloc_init();
2426 lck_attr_setdebug(bstp_lock_attr
);
2428 lck_mtx_init(bstp_list_mtx
, bstp_lock_grp
, bstp_lock_attr
);
2429 lck_grp_attr_free(lck_grp_attr
);
2431 LIST_INIT(&bstp_list
);
2433 bstp_create_task_thread();
2439 bstp_create_task_thread(void)
2441 kern_return_t error
;
2443 lck_grp_attr_t
*lck_grp_attr
= NULL
;
2445 lck_grp_attr
= lck_grp_attr_alloc_init();
2446 bstp_task_grp
= lck_grp_alloc_init("bstp_task", lck_grp_attr
);
2447 bstp_task_attr
= lck_attr_alloc_init();
2449 lck_attr_setdebug(bstp_task_attr
);
2451 lck_mtx_init(bstp_task_mtx
, bstp_lock_grp
, bstp_lock_attr
);
2452 lck_grp_attr_free(lck_grp_attr
);
2454 error
= kernel_thread_start((thread_continue_t
)bstp_task_thread_func
, NULL
, &bstp_task_thread
);
2459 bstp_task_thread_func(void)
2461 struct bstp_task
*bt
, *tvar
;
2463 lck_mtx_lock(bstp_task_mtx
);
2466 while (TAILQ_EMPTY(&bstp_task_queue
)) {
2467 wakeup(&bstp_task_queue_running
);
2468 msleep(&bstp_task_queue
, bstp_task_mtx
, PZERO
, "bstp_task_queue", NULL
);
2471 TAILQ_FOREACH_SAFE(bt
, &bstp_task_queue
, bt_next
, tvar
) {
2472 int count
= bt
->bt_count
;
2476 bstp_task_queue_running
= bt
;
2477 lck_mtx_unlock(bstp_task_mtx
);
2479 (*bt
->bt_func
)(bt
->bt_context
, count
);
2481 lck_mtx_lock(bstp_task_mtx
);
2482 bstp_task_queue_running
= NULL
;
2484 if (bt
->bt_count
== 0) {
2485 TAILQ_REMOVE(&bstp_task_queue
, bt
, bt_next
);
2494 bstp_task_enqueue(struct bstp_task
*bt
)
2496 lck_mtx_lock(bstp_task_mtx
);
2500 lck_mtx_unlock(bstp_task_mtx
);
2501 wakeup(&bstp_task_queue
);
2506 TAILQ_INSERT_TAIL(&bstp_task_queue
, bt
, bt_next
);
2508 lck_mtx_unlock(bstp_task_mtx
);
2510 wakeup(&bstp_task_queue
);
2514 bstp_task_drain(struct bstp_task
*bt
)
2516 lck_mtx_lock(bstp_task_mtx
);
2518 while (bt
->bt_count
!= 0 || bstp_task_queue_running
== bt
) {
2519 wakeup(&bstp_task_queue
);
2520 msleep(&bstp_task_queue_running
, bstp_task_mtx
, PZERO
, "bstp_task_queue", NULL
);
2522 lck_mtx_unlock(bstp_task_mtx
);