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/callout.h>
75 //#include <sys/module.h>
78 //#include <sys/mutex.h>
79 //#include <sys/taskqueue.h>
82 #include <net/if_dl.h>
83 #include <net/if_types.h>
84 #include <net/if_llc.h>
85 #include <net/if_media.h>
87 #include <net/kpi_interface.h>
89 #include <netinet/in.h>
90 #include <netinet/in_systm.h>
91 #include <netinet/in_var.h>
92 #include <netinet/if_ether.h>
93 #include <net/bridgestp.h>
95 #include <kern/thread.h>
97 decl_lck_mtx_data(static, bstp_task_mtx_data
);
98 static lck_mtx_t
*bstp_task_mtx
= &bstp_task_mtx_data
;
99 static lck_grp_t
*bstp_task_grp
= NULL
;
100 static lck_attr_t
*bstp_task_attr
= NULL
;
101 static thread_t bstp_task_thread
;
102 static TAILQ_HEAD(bstp_task_queue
, bstp_task
)
103 bstp_task_queue
= TAILQ_HEAD_INITIALIZER(bstp_task_queue
);
104 static struct bstp_task
*bstp_task_queue_running
= NULL
;
106 static void bstp_create_task_thread(void);
107 static void bstp_task_thread_func(void);
109 static void bstp_task_enqueue(struct bstp_task
*);
110 static void bstp_task_drain(struct bstp_task
*);
112 #define BSTP_TASK_INIT(bt, func, context) do { \
113 (bt)->bt_count = 0; \
114 (bt)->bt_func = func; \
115 (bt)->bt_context = context; \
120 #define BSTP_LOCK_INIT(_bs) (_bs)->bs_mtx = lck_mtx_alloc_init(bstp_lock_grp, bstp_lock_attr)
121 #define BSTP_LOCK_DESTROY(_bs) lck_mtx_free((_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)
127 #ifdef BRIDGESTP_DEBUG
128 #define DPRINTF(fmt, arg...) printf("bstp: " fmt, ##arg)
130 #define DPRINTF(fmt, arg...)
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; \
142 #define INFO_BETTER 1
144 #define INFO_WORSE -1
146 LIST_HEAD(, bstp_state
) bstp_list
;
147 decl_lck_mtx_data(static, bstp_list_mtx_data
);
148 static lck_mtx_t
*bstp_list_mtx
= &bstp_list_mtx_data
;
149 static lck_grp_t
*bstp_lock_grp
= NULL
;
150 static lck_attr_t
*bstp_lock_attr
= NULL
;
152 static void bstp_transmit(struct bstp_state
*, struct bstp_port
*);
153 static void bstp_transmit_bpdu(struct bstp_state
*, struct bstp_port
*);
154 static void bstp_transmit_tcn(struct bstp_state
*, struct bstp_port
*);
155 static void bstp_decode_bpdu(struct bstp_port
*, struct bstp_cbpdu
*,
156 struct bstp_config_unit
*);
157 static void bstp_send_bpdu(struct bstp_state
*, struct bstp_port
*,
158 struct bstp_cbpdu
*);
159 static void bstp_enqueue(struct ifnet
*, struct mbuf
*);
160 static int bstp_pdu_flags(struct bstp_port
*);
161 static void bstp_received_stp(struct bstp_state
*, struct bstp_port
*,
162 struct mbuf
**, struct bstp_tbpdu
*);
163 static void bstp_received_rstp(struct bstp_state
*, struct bstp_port
*,
164 struct mbuf
**, struct bstp_tbpdu
*);
165 static void bstp_received_tcn(struct bstp_state
*, struct bstp_port
*,
166 struct bstp_tcn_unit
*);
167 static void bstp_received_bpdu(struct bstp_state
*, struct bstp_port
*,
168 struct bstp_config_unit
*);
169 static int bstp_pdu_rcvtype(struct bstp_port
*, struct bstp_config_unit
*);
170 static int bstp_pdu_bettersame(struct bstp_port
*, int);
171 static int bstp_info_cmp(struct bstp_pri_vector
*,
172 struct bstp_pri_vector
*);
173 static int bstp_info_superior(struct bstp_pri_vector
*,
174 struct bstp_pri_vector
*);
175 static void bstp_assign_roles(struct bstp_state
*);
176 static void bstp_update_roles(struct bstp_state
*, struct bstp_port
*);
177 static void bstp_update_state(struct bstp_state
*, struct bstp_port
*);
178 static void bstp_update_tc(struct bstp_port
*);
179 static void bstp_update_info(struct bstp_port
*);
180 static void bstp_set_other_tcprop(struct bstp_port
*);
181 static void bstp_set_all_reroot(struct bstp_state
*);
182 static void bstp_set_all_sync(struct bstp_state
*);
183 static void bstp_set_port_state(struct bstp_port
*, int);
184 static void bstp_set_port_role(struct bstp_port
*, int);
185 static void bstp_set_port_proto(struct bstp_port
*, int);
186 static void bstp_set_port_tc(struct bstp_port
*, int);
187 static void bstp_set_timer_tc(struct bstp_port
*);
188 static void bstp_set_timer_msgage(struct bstp_port
*);
189 static int bstp_rerooted(struct bstp_state
*, struct bstp_port
*);
190 static uint32_t bstp_calc_path_cost(struct bstp_port
*);
191 static void bstp_notify_state(void *, int);
192 static void bstp_notify_rtage(void *, int);
193 static void bstp_ifupdstatus(struct bstp_state
*, struct bstp_port
*);
194 static void bstp_enable_port(struct bstp_state
*, struct bstp_port
*);
195 static void bstp_disable_port(struct bstp_state
*, struct bstp_port
*);
196 static void bstp_tick(void *);
197 static void bstp_timer_start(struct bstp_timer
*, uint16_t);
198 static void bstp_timer_stop(struct bstp_timer
*);
199 static void bstp_timer_latch(struct bstp_timer
*);
200 static int bstp_timer_expired(struct bstp_timer
*);
201 static void bstp_hello_timer_expiry(struct bstp_state
*,
203 static void bstp_message_age_expiry(struct bstp_state
*,
205 static void bstp_migrate_delay_expiry(struct bstp_state
*,
207 static void bstp_edge_delay_expiry(struct bstp_state
*,
209 static int bstp_addr_cmp(const uint8_t *, const uint8_t *);
210 static int bstp_same_bridgeid(uint64_t, uint64_t);
211 static void bstp_reinit(struct bstp_state
*);
214 bstp_transmit(struct bstp_state
*bs
, struct bstp_port
*bp
)
216 if (bs
->bs_running
== 0) {
221 * a PDU can only be sent if we have tx quota left and the
222 * hello timer is running.
224 if (bp
->bp_hello_timer
.active
== 0) {
225 /* Test if it needs to be reset */
226 bstp_hello_timer_expiry(bs
, bp
);
229 if (bp
->bp_txcount
> bs
->bs_txholdcount
) {
230 /* Ran out of karma */
234 if (bp
->bp_protover
== BSTP_PROTO_RSTP
) {
235 bstp_transmit_bpdu(bs
, bp
);
238 switch (bp
->bp_role
) {
239 case BSTP_ROLE_DESIGNATED
:
240 bstp_transmit_bpdu(bs
, bp
);
245 bstp_transmit_tcn(bs
, bp
);
249 bstp_timer_start(&bp
->bp_hello_timer
, bp
->bp_desg_htime
);
250 bp
->bp_flags
&= ~BSTP_PORT_NEWINFO
;
254 bstp_transmit_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
)
256 struct bstp_cbpdu bpdu
;
258 BSTP_LOCK_ASSERT(bs
);
260 bpdu
.cbu_rootpri
= htons(bp
->bp_desg_pv
.pv_root_id
>> 48);
261 PV2ADDR(bp
->bp_desg_pv
.pv_root_id
, bpdu
.cbu_rootaddr
);
263 bpdu
.cbu_rootpathcost
= htonl(bp
->bp_desg_pv
.pv_cost
);
265 bpdu
.cbu_bridgepri
= htons(bp
->bp_desg_pv
.pv_dbridge_id
>> 48);
266 PV2ADDR(bp
->bp_desg_pv
.pv_dbridge_id
, bpdu
.cbu_bridgeaddr
);
268 bpdu
.cbu_portid
= htons(bp
->bp_port_id
);
269 bpdu
.cbu_messageage
= htons(bp
->bp_desg_msg_age
);
270 bpdu
.cbu_maxage
= htons(bp
->bp_desg_max_age
);
271 bpdu
.cbu_hellotime
= htons(bp
->bp_desg_htime
);
272 bpdu
.cbu_forwarddelay
= htons(bp
->bp_desg_fdelay
);
274 bpdu
.cbu_flags
= bstp_pdu_flags(bp
);
276 switch (bp
->bp_protover
) {
278 bpdu
.cbu_bpdutype
= BSTP_MSGTYPE_CFG
;
281 case BSTP_PROTO_RSTP
:
282 bpdu
.cbu_bpdutype
= BSTP_MSGTYPE_RSTP
;
286 bstp_send_bpdu(bs
, bp
, &bpdu
);
290 bstp_transmit_tcn(struct bstp_state
*bs
, struct bstp_port
*bp
)
292 struct bstp_tbpdu bpdu
;
293 struct ifnet
*ifp
= bp
->bp_ifp
;
294 struct ether_header
*eh
;
296 int touched
= bs
? 1 : 0;
300 KASSERT(bp
== bs
->bs_root_port
, ("%s: bad root port\n", __func__
));
302 if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
306 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
311 m
->m_pkthdr
.rcvif
= ifp
;
312 m
->m_pkthdr
.len
= sizeof(*eh
) + sizeof(bpdu
);
313 m
->m_len
= m
->m_pkthdr
.len
;
315 eh
= mtod(m
, struct ether_header
*);
317 memcpy(eh
->ether_shost
, IF_LLADDR(ifp
), ETHER_ADDR_LEN
);
318 memcpy(eh
->ether_dhost
, bstp_etheraddr
, ETHER_ADDR_LEN
);
319 eh
->ether_type
= htons(sizeof(bpdu
));
321 bpdu
.tbu_ssap
= bpdu
.tbu_dsap
= LLC_8021D_LSAP
;
322 bpdu
.tbu_ctl
= LLC_UI
;
323 bpdu
.tbu_protoid
= 0;
324 bpdu
.tbu_protover
= 0;
325 bpdu
.tbu_bpdutype
= BSTP_MSGTYPE_TCN
;
327 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), &bpdu
, sizeof(bpdu
));
330 bstp_enqueue(ifp
, m
);
334 bstp_decode_bpdu(struct bstp_port
*bp
, struct bstp_cbpdu
*cpdu
,
335 struct bstp_config_unit
*cu
)
339 cu
->cu_pv
.pv_root_id
=
340 (((uint64_t)ntohs(cpdu
->cbu_rootpri
)) << 48) |
341 (((uint64_t)cpdu
->cbu_rootaddr
[0]) << 40) |
342 (((uint64_t)cpdu
->cbu_rootaddr
[1]) << 32) |
343 (((uint64_t)cpdu
->cbu_rootaddr
[2]) << 24) |
344 (((uint64_t)cpdu
->cbu_rootaddr
[3]) << 16) |
345 (((uint64_t)cpdu
->cbu_rootaddr
[4]) << 8) |
346 (((uint64_t)cpdu
->cbu_rootaddr
[5]) << 0);
348 cu
->cu_pv
.pv_dbridge_id
=
349 (((uint64_t)ntohs(cpdu
->cbu_bridgepri
)) << 48) |
350 (((uint64_t)cpdu
->cbu_bridgeaddr
[0]) << 40) |
351 (((uint64_t)cpdu
->cbu_bridgeaddr
[1]) << 32) |
352 (((uint64_t)cpdu
->cbu_bridgeaddr
[2]) << 24) |
353 (((uint64_t)cpdu
->cbu_bridgeaddr
[3]) << 16) |
354 (((uint64_t)cpdu
->cbu_bridgeaddr
[4]) << 8) |
355 (((uint64_t)cpdu
->cbu_bridgeaddr
[5]) << 0);
357 cu
->cu_pv
.pv_cost
= ntohl(cpdu
->cbu_rootpathcost
);
358 cu
->cu_message_age
= ntohs(cpdu
->cbu_messageage
);
359 cu
->cu_max_age
= ntohs(cpdu
->cbu_maxage
);
360 cu
->cu_hello_time
= ntohs(cpdu
->cbu_hellotime
);
361 cu
->cu_forward_delay
= ntohs(cpdu
->cbu_forwarddelay
);
362 cu
->cu_pv
.pv_dport_id
= ntohs(cpdu
->cbu_portid
);
363 cu
->cu_pv
.pv_port_id
= bp
->bp_port_id
;
364 cu
->cu_message_type
= cpdu
->cbu_bpdutype
;
366 /* Strip off unused flags in STP mode */
367 flags
= cpdu
->cbu_flags
;
368 switch (cpdu
->cbu_protover
) {
370 flags
&= BSTP_PDU_STPMASK
;
371 /* A STP BPDU explicitly conveys a Designated Port */
372 cu
->cu_role
= BSTP_ROLE_DESIGNATED
;
375 case BSTP_PROTO_RSTP
:
376 flags
&= BSTP_PDU_RSTPMASK
;
380 cu
->cu_topology_change_ack
=
381 (flags
& BSTP_PDU_F_TCA
) ? 1 : 0;
383 (flags
& BSTP_PDU_F_P
) ? 1 : 0;
385 (flags
& BSTP_PDU_F_A
) ? 1 : 0;
387 (flags
& BSTP_PDU_F_L
) ? 1 : 0;
389 (flags
& BSTP_PDU_F_F
) ? 1 : 0;
390 cu
->cu_topology_change
=
391 (flags
& BSTP_PDU_F_TC
) ? 1 : 0;
393 switch ((flags
& BSTP_PDU_PRMASK
) >> BSTP_PDU_PRSHIFT
) {
394 case BSTP_PDU_F_ROOT
:
395 cu
->cu_role
= BSTP_ROLE_ROOT
;
398 cu
->cu_role
= BSTP_ROLE_ALTERNATE
;
400 case BSTP_PDU_F_DESG
:
401 cu
->cu_role
= BSTP_ROLE_DESIGNATED
;
407 bstp_send_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
,
408 struct bstp_cbpdu
*bpdu
)
412 struct ether_header
*eh
;
414 BSTP_LOCK_ASSERT(bs
);
418 if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
422 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
427 eh
= mtod(m
, struct ether_header
*);
429 bpdu
->cbu_ssap
= bpdu
->cbu_dsap
= LLC_8021D_LSAP
;
430 bpdu
->cbu_ctl
= LLC_UI
;
431 bpdu
->cbu_protoid
= htons(BSTP_PROTO_ID
);
433 memcpy(eh
->ether_shost
, IF_LLADDR(ifp
), ETHER_ADDR_LEN
);
434 memcpy(eh
->ether_dhost
, bstp_etheraddr
, ETHER_ADDR_LEN
);
436 switch (bpdu
->cbu_bpdutype
) {
437 case BSTP_MSGTYPE_CFG
:
438 bpdu
->cbu_protover
= BSTP_PROTO_STP
;
439 m
->m_pkthdr
.len
= sizeof(*eh
) + BSTP_BPDU_STP_LEN
;
440 eh
->ether_type
= htons(BSTP_BPDU_STP_LEN
);
441 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), bpdu
,
445 case BSTP_MSGTYPE_RSTP
:
446 bpdu
->cbu_protover
= BSTP_PROTO_RSTP
;
447 bpdu
->cbu_versionlen
= htons(0);
448 m
->m_pkthdr
.len
= sizeof(*eh
) + BSTP_BPDU_RSTP_LEN
;
449 eh
->ether_type
= htons(BSTP_BPDU_RSTP_LEN
);
450 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), bpdu
,
455 panic("not implemented");
457 m
->m_pkthdr
.rcvif
= ifp
;
458 m
->m_len
= m
->m_pkthdr
.len
;
461 bstp_enqueue(ifp
, m
);
465 bstp_enqueue(struct ifnet
*dst_ifp
, struct mbuf
*m
)
468 u_int32_t len
= m
->m_pkthdr
.len
;
470 m
->m_flags
|= M_PROTO1
; //set to avoid loops
472 error
= ifnet_output_raw(dst_ifp
, 0, m
);
474 (void) ifnet_stat_increment_out(dst_ifp
, 1, len
, 0);
476 (void) ifnet_stat_increment_out(dst_ifp
, 0, 0, 1);
481 bstp_pdu_flags(struct bstp_port
*bp
)
485 if (bp
->bp_proposing
&& bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
) {
486 flags
|= BSTP_PDU_F_P
;
490 flags
|= BSTP_PDU_F_A
;
493 if (bp
->bp_tc_timer
.active
) {
494 flags
|= BSTP_PDU_F_TC
;
498 flags
|= BSTP_PDU_F_TCA
;
501 switch (bp
->bp_state
) {
502 case BSTP_IFSTATE_LEARNING
:
503 flags
|= BSTP_PDU_F_L
;
506 case BSTP_IFSTATE_FORWARDING
:
507 flags
|= (BSTP_PDU_F_L
| BSTP_PDU_F_F
);
511 switch (bp
->bp_role
) {
514 (BSTP_PDU_F_ROOT
<< BSTP_PDU_PRSHIFT
);
517 case BSTP_ROLE_ALTERNATE
:
518 case BSTP_ROLE_BACKUP
: /* fall through */
520 (BSTP_PDU_F_ALT
<< BSTP_PDU_PRSHIFT
);
523 case BSTP_ROLE_DESIGNATED
:
525 (BSTP_PDU_F_DESG
<< BSTP_PDU_PRSHIFT
);
529 /* Strip off unused flags in either mode */
530 switch (bp
->bp_protover
) {
532 flags
&= BSTP_PDU_STPMASK
;
534 case BSTP_PROTO_RSTP
:
535 flags
&= BSTP_PDU_RSTPMASK
;
542 bstp_input(struct bstp_port
*bp
, __unused
struct ifnet
*ifp
, struct mbuf
*m
)
544 struct bstp_state
*bs
= bp
->bp_bs
;
545 struct ether_header
*eh
;
546 struct bstp_tbpdu tpdu
;
549 if (bp
->bp_active
== 0) {
556 eh
= mtod(m
, struct ether_header
*);
558 len
= ntohs(eh
->ether_type
);
559 if (len
< sizeof(tpdu
)) {
563 m_adj(m
, ETHER_HDR_LEN
);
565 if (m
->m_pkthdr
.len
> len
) {
566 m_adj(m
, len
- m
->m_pkthdr
.len
);
568 if ((unsigned int)m
->m_len
< sizeof(tpdu
) &&
569 (m
= m_pullup(m
, sizeof(tpdu
))) == NULL
) {
573 memcpy(&tpdu
, mtod(m
, caddr_t
), sizeof(tpdu
));
575 /* basic packet checks */
576 if (tpdu
.tbu_dsap
!= LLC_8021D_LSAP
||
577 tpdu
.tbu_ssap
!= LLC_8021D_LSAP
||
578 tpdu
.tbu_ctl
!= LLC_UI
) {
581 if (tpdu
.tbu_protoid
!= BSTP_PROTO_ID
) {
586 * We can treat later versions of the PDU as the same as the maximum
587 * version we implement. All additional parameters/flags are ignored.
589 if (tpdu
.tbu_protover
> BSTP_PROTO_MAX
) {
590 tpdu
.tbu_protover
= BSTP_PROTO_MAX
;
593 if (tpdu
.tbu_protover
!= bp
->bp_protover
) {
595 * Wait for the migration delay timer to expire before changing
596 * protocol version to avoid flip-flops.
598 if (bp
->bp_flags
& BSTP_PORT_CANMIGRATE
) {
599 bstp_set_port_proto(bp
, tpdu
.tbu_protover
);
605 /* Clear operedge upon receiving a PDU on the port */
607 bstp_timer_start(&bp
->bp_edge_delay_timer
,
608 BSTP_DEFAULT_MIGRATE_DELAY
);
610 switch (tpdu
.tbu_protover
) {
612 bstp_received_stp(bs
, bp
, &m
, &tpdu
);
615 case BSTP_PROTO_RSTP
:
616 bstp_received_rstp(bs
, bp
, &m
, &tpdu
);
628 bstp_received_stp(struct bstp_state
*bs
, struct bstp_port
*bp
,
629 struct mbuf
**mp
, struct bstp_tbpdu
*tpdu
)
631 struct bstp_cbpdu cpdu
;
632 struct bstp_config_unit
*cu
= &bp
->bp_msg_cu
;
633 struct bstp_tcn_unit tu
;
635 switch (tpdu
->tbu_bpdutype
) {
636 case BSTP_MSGTYPE_TCN
:
637 tu
.tu_message_type
= tpdu
->tbu_bpdutype
;
638 bstp_received_tcn(bs
, bp
, &tu
);
640 case BSTP_MSGTYPE_CFG
:
641 if ((*mp
)->m_len
< BSTP_BPDU_STP_LEN
&&
642 (*mp
= m_pullup(*mp
, BSTP_BPDU_STP_LEN
)) == NULL
) {
645 memcpy(&cpdu
, mtod(*mp
, caddr_t
), BSTP_BPDU_STP_LEN
);
647 bstp_decode_bpdu(bp
, &cpdu
, cu
);
648 bstp_received_bpdu(bs
, bp
, cu
);
654 bstp_received_rstp(struct bstp_state
*bs
, struct bstp_port
*bp
,
655 struct mbuf
**mp
, struct bstp_tbpdu
*tpdu
)
657 struct bstp_cbpdu cpdu
;
658 struct bstp_config_unit
*cu
= &bp
->bp_msg_cu
;
660 if (tpdu
->tbu_bpdutype
!= BSTP_MSGTYPE_RSTP
) {
664 if ((*mp
)->m_len
< BSTP_BPDU_RSTP_LEN
&&
665 (*mp
= m_pullup(*mp
, BSTP_BPDU_RSTP_LEN
)) == NULL
) {
668 memcpy(&cpdu
, mtod(*mp
, caddr_t
), BSTP_BPDU_RSTP_LEN
);
670 bstp_decode_bpdu(bp
, &cpdu
, cu
);
671 bstp_received_bpdu(bs
, bp
, cu
);
675 bstp_received_tcn(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
,
676 __unused
struct bstp_tcn_unit
*tcn
)
683 bstp_received_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
,
684 struct bstp_config_unit
*cu
)
688 BSTP_LOCK_ASSERT(bs
);
690 /* We need to have transitioned to INFO_MINE before proceeding */
691 switch (bp
->bp_infois
) {
692 case BSTP_INFO_DISABLED
:
697 type
= bstp_pdu_rcvtype(bp
, cu
);
700 case BSTP_PDU_SUPERIOR
:
701 bs
->bs_allsynced
= 0;
703 bp
->bp_proposing
= 0;
705 if (cu
->cu_proposal
&& cu
->cu_forwarding
== 0) {
708 if (cu
->cu_topology_change
) {
711 if (cu
->cu_topology_change_ack
) {
716 !bstp_pdu_bettersame(bp
, BSTP_INFO_RECEIVED
)) {
720 /* copy the received priority and timers to the port */
721 bp
->bp_port_pv
= cu
->cu_pv
;
722 bp
->bp_port_msg_age
= cu
->cu_message_age
;
723 bp
->bp_port_max_age
= cu
->cu_max_age
;
724 bp
->bp_port_fdelay
= cu
->cu_forward_delay
;
726 (cu
->cu_hello_time
> BSTP_MIN_HELLO_TIME
?
727 cu
->cu_hello_time
: BSTP_MIN_HELLO_TIME
);
729 /* set expiry for the new info */
730 bstp_set_timer_msgage(bp
);
732 bp
->bp_infois
= BSTP_INFO_RECEIVED
;
733 bstp_assign_roles(bs
);
736 case BSTP_PDU_REPEATED
:
737 if (cu
->cu_proposal
&& cu
->cu_forwarding
== 0) {
740 if (cu
->cu_topology_change
) {
743 if (cu
->cu_topology_change_ack
) {
747 /* rearm the age timer */
748 bstp_set_timer_msgage(bp
);
751 case BSTP_PDU_INFERIOR
:
752 if (cu
->cu_learning
) {
754 bp
->bp_proposing
= 0;
758 case BSTP_PDU_INFERIORALT
:
760 * only point to point links are allowed fast
761 * transitions to forwarding.
763 if (cu
->cu_agree
&& bp
->bp_ptp_link
) {
765 bp
->bp_proposing
= 0;
770 if (cu
->cu_topology_change
) {
773 if (cu
->cu_topology_change_ack
) {
779 return; /* do nothing */
781 /* update the state machines with the new data */
782 bstp_update_state(bs
, bp
);
786 bstp_pdu_rcvtype(struct bstp_port
*bp
, struct bstp_config_unit
*cu
)
790 /* default return type */
791 type
= BSTP_PDU_OTHER
;
793 switch (cu
->cu_role
) {
794 case BSTP_ROLE_DESIGNATED
:
795 if (bstp_info_superior(&bp
->bp_port_pv
, &cu
->cu_pv
)) {
796 /* bpdu priority is superior */
797 type
= BSTP_PDU_SUPERIOR
;
798 } else if (bstp_info_cmp(&bp
->bp_port_pv
, &cu
->cu_pv
) ==
800 if (bp
->bp_port_msg_age
!= cu
->cu_message_age
||
801 bp
->bp_port_max_age
!= cu
->cu_max_age
||
802 bp
->bp_port_fdelay
!= cu
->cu_forward_delay
||
803 bp
->bp_port_htime
!= cu
->cu_hello_time
) {
804 /* bpdu priority is equal and timers differ */
805 type
= BSTP_PDU_SUPERIOR
;
808 type
= BSTP_PDU_REPEATED
;
811 /* bpdu priority is worse */
812 type
= BSTP_PDU_INFERIOR
;
818 case BSTP_ROLE_ALTERNATE
:
819 case BSTP_ROLE_BACKUP
:
820 if (bstp_info_cmp(&bp
->bp_port_pv
, &cu
->cu_pv
) <= INFO_SAME
) {
822 * not a designated port and priority is the same or
825 type
= BSTP_PDU_INFERIORALT
;
834 bstp_pdu_bettersame(struct bstp_port
*bp
, int newinfo
)
836 if (newinfo
== BSTP_INFO_RECEIVED
&&
837 bp
->bp_infois
== BSTP_INFO_RECEIVED
&&
838 bstp_info_cmp(&bp
->bp_port_pv
, &bp
->bp_msg_cu
.cu_pv
) >= INFO_SAME
) {
842 if (newinfo
== BSTP_INFO_MINE
&&
843 bp
->bp_infois
== BSTP_INFO_MINE
&&
844 bstp_info_cmp(&bp
->bp_port_pv
, &bp
->bp_desg_pv
) >= INFO_SAME
) {
852 bstp_info_cmp(struct bstp_pri_vector
*pv
,
853 struct bstp_pri_vector
*cpv
)
855 if (cpv
->pv_root_id
< pv
->pv_root_id
) {
858 if (cpv
->pv_root_id
> pv
->pv_root_id
) {
862 if (cpv
->pv_cost
< pv
->pv_cost
) {
865 if (cpv
->pv_cost
> pv
->pv_cost
) {
869 if (cpv
->pv_dbridge_id
< pv
->pv_dbridge_id
) {
872 if (cpv
->pv_dbridge_id
> pv
->pv_dbridge_id
) {
876 if (cpv
->pv_dport_id
< pv
->pv_dport_id
) {
879 if (cpv
->pv_dport_id
> pv
->pv_dport_id
) {
887 * This message priority vector is superior to the port priority vector and
888 * will replace it if, and only if, the message priority vector is better than
889 * the port priority vector, or the message has been transmitted from the same
890 * designated bridge and designated port as the port priority vector.
893 bstp_info_superior(struct bstp_pri_vector
*pv
,
894 struct bstp_pri_vector
*cpv
)
896 if (bstp_info_cmp(pv
, cpv
) == INFO_BETTER
||
897 (bstp_same_bridgeid(pv
->pv_dbridge_id
, cpv
->pv_dbridge_id
) &&
898 (cpv
->pv_dport_id
& 0xfff) == (pv
->pv_dport_id
& 0xfff))) {
905 bstp_assign_roles(struct bstp_state
*bs
)
907 struct bstp_port
*bp
, *rbp
= NULL
;
908 struct bstp_pri_vector pv
;
910 /* default to our priority vector */
911 bs
->bs_root_pv
= bs
->bs_bridge_pv
;
912 bs
->bs_root_msg_age
= 0;
913 bs
->bs_root_max_age
= bs
->bs_bridge_max_age
;
914 bs
->bs_root_fdelay
= bs
->bs_bridge_fdelay
;
915 bs
->bs_root_htime
= bs
->bs_bridge_htime
;
916 bs
->bs_root_port
= NULL
;
918 /* check if any recieved info supersedes us */
919 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
920 if (bp
->bp_infois
!= BSTP_INFO_RECEIVED
) {
925 pv
.pv_cost
+= bp
->bp_path_cost
;
928 * The root priority vector is the best of the set comprising
929 * the bridge priority vector plus all root path priority
930 * vectors whose bridge address is not equal to us.
932 if (bstp_same_bridgeid(pv
.pv_dbridge_id
,
933 bs
->bs_bridge_pv
.pv_dbridge_id
) == 0 &&
934 bstp_info_cmp(&bs
->bs_root_pv
, &pv
) == INFO_BETTER
) {
935 /* the port vector replaces the root */
937 bs
->bs_root_msg_age
= bp
->bp_port_msg_age
+
938 BSTP_MESSAGE_AGE_INCR
;
939 bs
->bs_root_max_age
= bp
->bp_port_max_age
;
940 bs
->bs_root_fdelay
= bp
->bp_port_fdelay
;
941 bs
->bs_root_htime
= bp
->bp_port_htime
;
946 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
947 /* calculate the port designated vector */
948 bp
->bp_desg_pv
.pv_root_id
= bs
->bs_root_pv
.pv_root_id
;
949 bp
->bp_desg_pv
.pv_cost
= bs
->bs_root_pv
.pv_cost
;
950 bp
->bp_desg_pv
.pv_dbridge_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
951 bp
->bp_desg_pv
.pv_dport_id
= bp
->bp_port_id
;
952 bp
->bp_desg_pv
.pv_port_id
= bp
->bp_port_id
;
954 /* calculate designated times */
955 bp
->bp_desg_msg_age
= bs
->bs_root_msg_age
;
956 bp
->bp_desg_max_age
= bs
->bs_root_max_age
;
957 bp
->bp_desg_fdelay
= bs
->bs_root_fdelay
;
958 bp
->bp_desg_htime
= bs
->bs_bridge_htime
;
961 switch (bp
->bp_infois
) {
962 case BSTP_INFO_DISABLED
:
963 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
967 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
968 bstp_update_info(bp
);
972 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
973 /* update the port info if stale */
974 if (bstp_info_cmp(&bp
->bp_port_pv
,
975 &bp
->bp_desg_pv
) != INFO_SAME
||
977 (bp
->bp_port_msg_age
!= rbp
->bp_port_msg_age
||
978 bp
->bp_port_max_age
!= rbp
->bp_port_max_age
||
979 bp
->bp_port_fdelay
!= rbp
->bp_port_fdelay
||
980 bp
->bp_port_htime
!= rbp
->bp_port_htime
))) {
981 bstp_update_info(bp
);
985 case BSTP_INFO_RECEIVED
:
988 * root priority is derived from this
989 * port, make it the root port.
991 bstp_set_port_role(bp
, BSTP_ROLE_ROOT
);
992 bs
->bs_root_port
= bp
;
993 } else if (bstp_info_cmp(&bp
->bp_port_pv
,
994 &bp
->bp_desg_pv
) == INFO_BETTER
) {
996 * the port priority is lower than the root
999 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
1000 bstp_update_info(bp
);
1002 if (bstp_same_bridgeid(
1003 bp
->bp_port_pv
.pv_dbridge_id
,
1004 bs
->bs_bridge_pv
.pv_dbridge_id
)) {
1006 * the designated bridge refers to
1007 * another port on this bridge.
1009 bstp_set_port_role(bp
,
1013 * the port is an inferior path to the
1016 bstp_set_port_role(bp
,
1017 BSTP_ROLE_ALTERNATE
);
1026 bstp_update_state(struct bstp_state
*bs
, struct bstp_port
*bp
)
1028 struct bstp_port
*bp2
;
1031 BSTP_LOCK_ASSERT(bs
);
1033 /* check if all the ports have syncronised again */
1034 if (!bs
->bs_allsynced
) {
1036 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1037 if (!(bp2
->bp_synced
||
1038 bp2
->bp_role
== BSTP_ROLE_ROOT
)) {
1043 bs
->bs_allsynced
= synced
;
1046 bstp_update_roles(bs
, bp
);
1051 bstp_update_roles(struct bstp_state
*bs
, struct bstp_port
*bp
)
1053 switch (bp
->bp_role
) {
1054 case BSTP_ROLE_DISABLED
:
1055 /* Clear any flags if set */
1056 if (bp
->bp_sync
|| !bp
->bp_synced
|| bp
->bp_reroot
) {
1063 case BSTP_ROLE_ALTERNATE
:
1064 case BSTP_ROLE_BACKUP
:
1065 if ((bs
->bs_allsynced
&& !bp
->bp_agree
) ||
1066 (bp
->bp_proposed
&& bp
->bp_agree
)) {
1067 bp
->bp_proposed
= 0;
1069 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1070 DPRINTF("%s -> ALTERNATE_AGREED\n",
1071 bp
->bp_ifp
->if_xname
);
1074 if (bp
->bp_proposed
&& !bp
->bp_agree
) {
1075 bstp_set_all_sync(bs
);
1076 bp
->bp_proposed
= 0;
1077 DPRINTF("%s -> ALTERNATE_PROPOSED\n",
1078 bp
->bp_ifp
->if_xname
);
1081 /* Clear any flags if set */
1082 if (bp
->bp_sync
|| !bp
->bp_synced
|| bp
->bp_reroot
) {
1086 DPRINTF("%s -> ALTERNATE_PORT\n", bp
->bp_ifp
->if_xname
);
1090 case BSTP_ROLE_ROOT
:
1091 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&& !bp
->bp_reroot
) {
1092 bstp_set_all_reroot(bs
);
1093 DPRINTF("%s -> ROOT_REROOT\n", bp
->bp_ifp
->if_xname
);
1096 if ((bs
->bs_allsynced
&& !bp
->bp_agree
) ||
1097 (bp
->bp_proposed
&& bp
->bp_agree
)) {
1098 bp
->bp_proposed
= 0;
1101 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1102 DPRINTF("%s -> ROOT_AGREED\n", bp
->bp_ifp
->if_xname
);
1105 if (bp
->bp_proposed
&& !bp
->bp_agree
) {
1106 bstp_set_all_sync(bs
);
1107 bp
->bp_proposed
= 0;
1108 DPRINTF("%s -> ROOT_PROPOSED\n", bp
->bp_ifp
->if_xname
);
1111 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1112 (bp
->bp_forward_delay_timer
.active
== 0 ||
1113 (bstp_rerooted(bs
, bp
) &&
1114 bp
->bp_recent_backup_timer
.active
== 0 &&
1115 bp
->bp_protover
== BSTP_PROTO_RSTP
))) {
1116 switch (bp
->bp_state
) {
1117 case BSTP_IFSTATE_DISCARDING
:
1118 bstp_set_port_state(bp
, BSTP_IFSTATE_LEARNING
);
1120 case BSTP_IFSTATE_LEARNING
:
1121 bstp_set_port_state(bp
,
1122 BSTP_IFSTATE_FORWARDING
);
1127 if (bp
->bp_state
== BSTP_IFSTATE_FORWARDING
&& bp
->bp_reroot
) {
1129 DPRINTF("%s -> ROOT_REROOTED\n", bp
->bp_ifp
->if_xname
);
1133 case BSTP_ROLE_DESIGNATED
:
1134 if (bp
->bp_recent_root_timer
.active
== 0 && bp
->bp_reroot
) {
1136 DPRINTF("%s -> DESIGNATED_RETIRED\n",
1137 bp
->bp_ifp
->if_xname
);
1140 if ((bp
->bp_state
== BSTP_IFSTATE_DISCARDING
&&
1141 !bp
->bp_synced
) || (bp
->bp_agreed
&& !bp
->bp_synced
) ||
1142 (bp
->bp_operedge
&& !bp
->bp_synced
) ||
1143 (bp
->bp_sync
&& bp
->bp_synced
)) {
1144 bstp_timer_stop(&bp
->bp_recent_root_timer
);
1147 DPRINTF("%s -> DESIGNATED_SYNCED\n",
1148 bp
->bp_ifp
->if_xname
);
1151 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1152 !bp
->bp_agreed
&& !bp
->bp_proposing
&&
1154 bp
->bp_proposing
= 1;
1155 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1156 bstp_timer_start(&bp
->bp_edge_delay_timer
,
1157 (bp
->bp_ptp_link
? BSTP_DEFAULT_MIGRATE_DELAY
:
1158 bp
->bp_desg_max_age
));
1159 DPRINTF("%s -> DESIGNATED_PROPOSE\n",
1160 bp
->bp_ifp
->if_xname
);
1163 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1164 (bp
->bp_forward_delay_timer
.active
== 0 || bp
->bp_agreed
||
1166 (bp
->bp_recent_root_timer
.active
== 0 || !bp
->bp_reroot
) &&
1168 #ifdef BRIDGESTP_DEBUG
1169 if (bp
->bp_agreed
) {
1170 DPRINTF("%s -> AGREED\n", bp
->bp_ifp
->if_xname
);
1172 #endif /* BRIDGESTP_DEBUG */
1174 * If agreed|operedge then go straight to forwarding,
1175 * otherwise follow discard -> learn -> forward.
1177 if (bp
->bp_agreed
|| bp
->bp_operedge
||
1178 bp
->bp_state
== BSTP_IFSTATE_LEARNING
) {
1179 bstp_set_port_state(bp
,
1180 BSTP_IFSTATE_FORWARDING
);
1181 bp
->bp_agreed
= bp
->bp_protover
;
1182 } else if (bp
->bp_state
== BSTP_IFSTATE_DISCARDING
) {
1183 bstp_set_port_state(bp
, BSTP_IFSTATE_LEARNING
);
1187 if (((bp
->bp_sync
&& !bp
->bp_synced
) ||
1188 (bp
->bp_reroot
&& bp
->bp_recent_root_timer
.active
) ||
1189 (bp
->bp_flags
& BSTP_PORT_DISPUTED
)) && !bp
->bp_operedge
&&
1190 bp
->bp_state
!= BSTP_IFSTATE_DISCARDING
) {
1191 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1192 bp
->bp_flags
&= ~BSTP_PORT_DISPUTED
;
1193 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1194 bp
->bp_protover
== BSTP_PROTO_RSTP
?
1195 bp
->bp_desg_htime
: bp
->bp_desg_fdelay
);
1196 DPRINTF("%s -> DESIGNATED_DISCARD\n",
1197 bp
->bp_ifp
->if_xname
);
1202 if (bp
->bp_flags
& BSTP_PORT_NEWINFO
) {
1203 bstp_transmit(bs
, bp
);
1208 bstp_update_tc(struct bstp_port
*bp
)
1210 switch (bp
->bp_tcstate
) {
1211 case BSTP_TCSTATE_ACTIVE
:
1212 if ((bp
->bp_role
!= BSTP_ROLE_DESIGNATED
&&
1213 bp
->bp_role
!= BSTP_ROLE_ROOT
) || bp
->bp_operedge
) {
1214 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1217 if (bp
->bp_rcvdtcn
) {
1218 bstp_set_port_tc(bp
, BSTP_TCSTATE_TCN
);
1220 if (bp
->bp_rcvdtc
) {
1221 bstp_set_port_tc(bp
, BSTP_TCSTATE_TC
);
1224 if (bp
->bp_tc_prop
&& !bp
->bp_operedge
) {
1225 bstp_set_port_tc(bp
, BSTP_TCSTATE_PROPAG
);
1228 if (bp
->bp_rcvdtca
) {
1229 bstp_set_port_tc(bp
, BSTP_TCSTATE_ACK
);
1233 case BSTP_TCSTATE_INACTIVE
:
1234 if ((bp
->bp_state
== BSTP_IFSTATE_LEARNING
||
1235 bp
->bp_state
== BSTP_IFSTATE_FORWARDING
) &&
1236 bp
->bp_fdbflush
== 0) {
1237 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1241 case BSTP_TCSTATE_LEARNING
:
1242 if (bp
->bp_rcvdtc
|| bp
->bp_rcvdtcn
|| bp
->bp_rcvdtca
||
1244 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1245 } else if (bp
->bp_role
!= BSTP_ROLE_DESIGNATED
&&
1246 bp
->bp_role
!= BSTP_ROLE_ROOT
&&
1247 bp
->bp_state
== BSTP_IFSTATE_DISCARDING
) {
1248 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
1251 if ((bp
->bp_role
== BSTP_ROLE_DESIGNATED
||
1252 bp
->bp_role
== BSTP_ROLE_ROOT
) &&
1253 bp
->bp_state
== BSTP_IFSTATE_FORWARDING
&&
1255 bstp_set_port_tc(bp
, BSTP_TCSTATE_DETECTED
);
1259 /* these are transient states and go straight back to ACTIVE */
1260 case BSTP_TCSTATE_DETECTED
:
1261 case BSTP_TCSTATE_TCN
:
1262 case BSTP_TCSTATE_TC
:
1263 case BSTP_TCSTATE_PROPAG
:
1264 case BSTP_TCSTATE_ACK
:
1265 DPRINTF("Invalid TC state for %s\n",
1266 bp
->bp_ifp
->if_xname
);
1272 bstp_update_info(struct bstp_port
*bp
)
1274 struct bstp_state
*bs
= bp
->bp_bs
;
1276 bp
->bp_proposing
= 0;
1277 bp
->bp_proposed
= 0;
1279 if (bp
->bp_agreed
&& !bstp_pdu_bettersame(bp
, BSTP_INFO_MINE
)) {
1283 if (bp
->bp_synced
&& !bp
->bp_agreed
) {
1285 bs
->bs_allsynced
= 0;
1288 /* copy the designated pv to the port */
1289 bp
->bp_port_pv
= bp
->bp_desg_pv
;
1290 bp
->bp_port_msg_age
= bp
->bp_desg_msg_age
;
1291 bp
->bp_port_max_age
= bp
->bp_desg_max_age
;
1292 bp
->bp_port_fdelay
= bp
->bp_desg_fdelay
;
1293 bp
->bp_port_htime
= bp
->bp_desg_htime
;
1294 bp
->bp_infois
= BSTP_INFO_MINE
;
1296 /* Set transmit flag but do not immediately send */
1297 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1300 /* set tcprop on every port other than the caller */
1302 bstp_set_other_tcprop(struct bstp_port
*bp
)
1304 struct bstp_state
*bs
= bp
->bp_bs
;
1305 struct bstp_port
*bp2
;
1307 BSTP_LOCK_ASSERT(bs
);
1309 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1313 bp2
->bp_tc_prop
= 1;
1318 bstp_set_all_reroot(struct bstp_state
*bs
)
1320 struct bstp_port
*bp
;
1322 BSTP_LOCK_ASSERT(bs
);
1324 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
1329 bstp_set_all_sync(struct bstp_state
*bs
)
1331 struct bstp_port
*bp
;
1333 BSTP_LOCK_ASSERT(bs
);
1335 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1337 bp
->bp_synced
= 0; /* Not explicit in spec */
1340 bs
->bs_allsynced
= 0;
1344 bstp_set_port_state(struct bstp_port
*bp
, int state
)
1346 if (bp
->bp_state
== state
) {
1350 bp
->bp_state
= state
;
1352 switch (bp
->bp_state
) {
1353 case BSTP_IFSTATE_DISCARDING
:
1354 DPRINTF("state changed to DISCARDING on %s\n",
1355 bp
->bp_ifp
->if_xname
);
1358 case BSTP_IFSTATE_LEARNING
:
1359 DPRINTF("state changed to LEARNING on %s\n",
1360 bp
->bp_ifp
->if_xname
);
1362 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1363 bp
->bp_protover
== BSTP_PROTO_RSTP
?
1364 bp
->bp_desg_htime
: bp
->bp_desg_fdelay
);
1367 case BSTP_IFSTATE_FORWARDING
:
1368 DPRINTF("state changed to FORWARDING on %s\n",
1369 bp
->bp_ifp
->if_xname
);
1371 bstp_timer_stop(&bp
->bp_forward_delay_timer
);
1372 /* Record that we enabled forwarding */
1373 bp
->bp_forward_transitions
++;
1377 /* notify the parent bridge */
1378 bstp_task_enqueue(&bp
->bp_statetask
);
1382 bstp_set_port_role(struct bstp_port
*bp
, int role
)
1384 struct bstp_state
*bs
= bp
->bp_bs
;
1386 if (bp
->bp_role
== role
) {
1390 /* perform pre-change tasks */
1391 switch (bp
->bp_role
) {
1392 case BSTP_ROLE_DISABLED
:
1393 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1394 bp
->bp_desg_max_age
);
1397 case BSTP_ROLE_BACKUP
:
1398 bstp_timer_start(&bp
->bp_recent_backup_timer
,
1399 bp
->bp_desg_htime
* 2);
1401 case BSTP_ROLE_ALTERNATE
:
1402 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1403 bp
->bp_desg_fdelay
);
1409 case BSTP_ROLE_ROOT
:
1410 bstp_timer_start(&bp
->bp_recent_root_timer
,
1411 BSTP_DEFAULT_FORWARD_DELAY
);
1416 /* clear values not carried between roles */
1417 bp
->bp_proposing
= 0;
1418 bs
->bs_allsynced
= 0;
1420 /* initialise the new role */
1421 switch (bp
->bp_role
) {
1422 case BSTP_ROLE_DISABLED
:
1423 case BSTP_ROLE_ALTERNATE
:
1424 case BSTP_ROLE_BACKUP
:
1425 DPRINTF("%s role -> ALT/BACK/DISABLED\n",
1426 bp
->bp_ifp
->if_xname
);
1427 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1428 bstp_timer_stop(&bp
->bp_recent_root_timer
);
1429 bstp_timer_latch(&bp
->bp_forward_delay_timer
);
1435 case BSTP_ROLE_ROOT
:
1436 DPRINTF("%s role -> ROOT\n",
1437 bp
->bp_ifp
->if_xname
);
1438 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1439 bstp_timer_latch(&bp
->bp_recent_root_timer
);
1440 bp
->bp_proposing
= 0;
1443 case BSTP_ROLE_DESIGNATED
:
1444 DPRINTF("%s role -> DESIGNATED\n",
1445 bp
->bp_ifp
->if_xname
);
1446 bstp_timer_start(&bp
->bp_hello_timer
,
1452 /* let the TC state know that the role changed */
1457 bstp_set_port_proto(struct bstp_port
*bp
, int proto
)
1459 struct bstp_state
*bs
= bp
->bp_bs
;
1461 /* supported protocol versions */
1463 case BSTP_PROTO_STP
:
1464 /* we can downgrade protocols only */
1465 bstp_timer_stop(&bp
->bp_migrate_delay_timer
);
1466 /* clear unsupported features */
1467 bp
->bp_operedge
= 0;
1468 /* STP compat mode only uses 16 bits of the 32 */
1469 if (bp
->bp_path_cost
> 65535) {
1470 bp
->bp_path_cost
= 65535;
1474 case BSTP_PROTO_RSTP
:
1475 bstp_timer_start(&bp
->bp_migrate_delay_timer
,
1476 bs
->bs_migration_delay
);
1480 DPRINTF("Unsupported STP version %d\n", proto
);
1484 bp
->bp_protover
= proto
;
1485 bp
->bp_flags
&= ~BSTP_PORT_CANMIGRATE
;
1489 bstp_set_port_tc(struct bstp_port
*bp
, int state
)
1491 struct bstp_state
*bs
= bp
->bp_bs
;
1493 bp
->bp_tcstate
= state
;
1495 /* initialise the new state */
1496 switch (bp
->bp_tcstate
) {
1497 case BSTP_TCSTATE_ACTIVE
:
1498 DPRINTF("%s -> TC_ACTIVE\n", bp
->bp_ifp
->if_xname
);
1502 case BSTP_TCSTATE_INACTIVE
:
1503 bstp_timer_stop(&bp
->bp_tc_timer
);
1504 /* flush routes on the parent bridge */
1505 bp
->bp_fdbflush
= 1;
1506 bstp_task_enqueue(&bp
->bp_rtagetask
);
1508 DPRINTF("%s -> TC_INACTIVE\n", bp
->bp_ifp
->if_xname
);
1511 case BSTP_TCSTATE_LEARNING
:
1516 DPRINTF("%s -> TC_LEARNING\n", bp
->bp_ifp
->if_xname
);
1519 case BSTP_TCSTATE_DETECTED
:
1520 bstp_set_timer_tc(bp
);
1521 bstp_set_other_tcprop(bp
);
1522 /* send out notification */
1523 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1524 bstp_transmit(bs
, bp
);
1525 /* reviewed for getmicrotime usage */
1526 getmicrotime(&bs
->bs_last_tc_time
);
1527 DPRINTF("%s -> TC_DETECTED\n", bp
->bp_ifp
->if_xname
);
1528 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1531 case BSTP_TCSTATE_TCN
:
1532 bstp_set_timer_tc(bp
);
1533 DPRINTF("%s -> TC_TCN\n", bp
->bp_ifp
->if_xname
);
1535 case BSTP_TCSTATE_TC
:
1538 if (bp
->bp_role
== BSTP_ROLE_DESIGNATED
) {
1542 bstp_set_other_tcprop(bp
);
1543 DPRINTF("%s -> TC_TC\n", bp
->bp_ifp
->if_xname
);
1544 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1547 case BSTP_TCSTATE_PROPAG
:
1548 /* flush routes on the parent bridge */
1549 bp
->bp_fdbflush
= 1;
1550 bstp_task_enqueue(&bp
->bp_rtagetask
);
1552 bstp_set_timer_tc(bp
);
1553 DPRINTF("%s -> TC_PROPAG\n", bp
->bp_ifp
->if_xname
);
1554 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1557 case BSTP_TCSTATE_ACK
:
1558 bstp_timer_stop(&bp
->bp_tc_timer
);
1560 DPRINTF("%s -> TC_ACK\n", bp
->bp_ifp
->if_xname
);
1561 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1567 bstp_set_timer_tc(struct bstp_port
*bp
)
1569 struct bstp_state
*bs
= bp
->bp_bs
;
1571 if (bp
->bp_tc_timer
.active
) {
1575 switch (bp
->bp_protover
) {
1576 case BSTP_PROTO_RSTP
:
1577 bstp_timer_start(&bp
->bp_tc_timer
,
1578 bp
->bp_desg_htime
+ BSTP_TICK_VAL
);
1579 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1582 case BSTP_PROTO_STP
:
1583 bstp_timer_start(&bp
->bp_tc_timer
,
1584 bs
->bs_root_max_age
+ bs
->bs_root_fdelay
);
1590 bstp_set_timer_msgage(struct bstp_port
*bp
)
1592 if (bp
->bp_port_msg_age
+ BSTP_MESSAGE_AGE_INCR
<=
1593 bp
->bp_port_max_age
) {
1594 bstp_timer_start(&bp
->bp_message_age_timer
,
1595 bp
->bp_port_htime
* 3);
1597 /* expires immediately */
1598 bstp_timer_start(&bp
->bp_message_age_timer
, 0);
1603 bstp_rerooted(struct bstp_state
*bs
, struct bstp_port
*bp
)
1605 struct bstp_port
*bp2
;
1608 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1612 if (bp2
->bp_recent_root_timer
.active
) {
1621 bstp_set_htime(struct bstp_state
*bs
, int t
)
1623 /* convert seconds to ticks */
1626 /* value can only be changed in leagacy stp mode */
1627 if (bs
->bs_protover
!= BSTP_PROTO_STP
) {
1631 if (t
< BSTP_MIN_HELLO_TIME
|| t
> BSTP_MAX_HELLO_TIME
) {
1636 bs
->bs_bridge_htime
= t
;
1643 bstp_set_fdelay(struct bstp_state
*bs
, int t
)
1645 /* convert seconds to ticks */
1648 if (t
< BSTP_MIN_FORWARD_DELAY
|| t
> BSTP_MAX_FORWARD_DELAY
) {
1653 bs
->bs_bridge_fdelay
= t
;
1660 bstp_set_maxage(struct bstp_state
*bs
, int t
)
1662 /* convert seconds to ticks */
1665 if (t
< BSTP_MIN_MAX_AGE
|| t
> BSTP_MAX_MAX_AGE
) {
1670 bs
->bs_bridge_max_age
= t
;
1677 bstp_set_holdcount(struct bstp_state
*bs
, int count
)
1679 struct bstp_port
*bp
;
1681 if (count
< BSTP_MIN_HOLD_COUNT
||
1682 count
> BSTP_MAX_HOLD_COUNT
) {
1687 bs
->bs_txholdcount
= count
;
1688 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
1695 bstp_set_protocol(struct bstp_state
*bs
, int proto
)
1697 struct bstp_port
*bp
;
1700 /* Supported protocol versions */
1701 case BSTP_PROTO_STP
:
1702 case BSTP_PROTO_RSTP
:
1710 bs
->bs_protover
= proto
;
1711 bs
->bs_bridge_htime
= BSTP_DEFAULT_HELLO_TIME
;
1712 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1714 bp
->bp_infois
= BSTP_INFO_DISABLED
;
1716 bstp_set_port_proto(bp
, bs
->bs_protover
);
1717 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
1718 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
1719 bstp_timer_stop(&bp
->bp_recent_backup_timer
);
1727 bstp_set_priority(struct bstp_state
*bs
, int pri
)
1729 if (pri
< 0 || pri
> BSTP_MAX_PRIORITY
) {
1733 /* Limit to steps of 4096 */
1737 bs
->bs_bridge_priority
= pri
;
1744 bstp_set_port_priority(struct bstp_port
*bp
, int pri
)
1746 struct bstp_state
*bs
= bp
->bp_bs
;
1748 if (pri
< 0 || pri
> BSTP_MAX_PORT_PRIORITY
) {
1752 /* Limit to steps of 16 */
1756 bp
->bp_priority
= pri
;
1763 bstp_set_path_cost(struct bstp_port
*bp
, uint32_t path_cost
)
1765 struct bstp_state
*bs
= bp
->bp_bs
;
1767 if (path_cost
> BSTP_MAX_PATH_COST
) {
1771 /* STP compat mode only uses 16 bits of the 32 */
1772 if (bp
->bp_protover
== BSTP_PROTO_STP
&& path_cost
> 65535) {
1778 if (path_cost
== 0) { /* use auto */
1779 bp
->bp_flags
&= ~BSTP_PORT_ADMCOST
;
1780 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
1782 bp
->bp_path_cost
= path_cost
;
1783 bp
->bp_flags
|= BSTP_PORT_ADMCOST
;
1791 bstp_set_edge(struct bstp_port
*bp
, int set
)
1793 struct bstp_state
*bs
= bp
->bp_bs
;
1796 if ((bp
->bp_operedge
= set
) == 0) {
1797 bp
->bp_flags
&= ~BSTP_PORT_ADMEDGE
;
1799 bp
->bp_flags
|= BSTP_PORT_ADMEDGE
;
1806 bstp_set_autoedge(struct bstp_port
*bp
, int set
)
1808 struct bstp_state
*bs
= bp
->bp_bs
;
1812 bp
->bp_flags
|= BSTP_PORT_AUTOEDGE
;
1813 /* we may be able to transition straight to edge */
1814 if (bp
->bp_edge_delay_timer
.active
== 0) {
1815 bstp_edge_delay_expiry(bs
, bp
);
1818 bp
->bp_flags
&= ~BSTP_PORT_AUTOEDGE
;
1825 bstp_set_ptp(struct bstp_port
*bp
, int set
)
1827 struct bstp_state
*bs
= bp
->bp_bs
;
1830 bp
->bp_ptp_link
= set
;
1836 bstp_set_autoptp(struct bstp_port
*bp
, int set
)
1838 struct bstp_state
*bs
= bp
->bp_bs
;
1842 bp
->bp_flags
|= BSTP_PORT_AUTOPTP
;
1843 if (bp
->bp_role
!= BSTP_ROLE_DISABLED
) {
1844 bstp_ifupdstatus(bs
, bp
);
1847 bp
->bp_flags
&= ~BSTP_PORT_AUTOPTP
;
1854 * Calculate the path cost according to the link speed.
1857 bstp_calc_path_cost(struct bstp_port
*bp
)
1859 struct ifnet
*ifp
= bp
->bp_ifp
;
1862 /* If the priority has been manually set then retain the value */
1863 if (bp
->bp_flags
& BSTP_PORT_ADMCOST
) {
1864 return bp
->bp_path_cost
;
1867 if (bp
->bp_if_link_state
== LINK_STATE_DOWN
) {
1868 /* Recalc when the link comes up again */
1869 bp
->bp_flags
|= BSTP_PORT_PNDCOST
;
1870 return BSTP_DEFAULT_PATH_COST
;
1873 if (ifp
->if_baudrate
< 1000) {
1874 return BSTP_DEFAULT_PATH_COST
;
1877 /* formula from section 17.14, IEEE Std 802.1D-2004 */
1878 path_cost
= 20000000000ULL / (ifp
->if_baudrate
/ 1000);
1880 if (path_cost
> BSTP_MAX_PATH_COST
) {
1881 path_cost
= BSTP_MAX_PATH_COST
;
1884 /* STP compat mode only uses 16 bits of the 32 */
1885 if (bp
->bp_protover
== BSTP_PROTO_STP
&& path_cost
> 65535) {
1893 * Notify the bridge that a port state has changed, we need to do this from a
1894 * taskqueue to avoid a LOR.
1897 bstp_notify_state(void *arg
, __unused
int pending
)
1899 struct bstp_port
*bp
= (struct bstp_port
*)arg
;
1900 struct bstp_state
*bs
= bp
->bp_bs
;
1902 if (bp
->bp_active
== 1 && bs
->bs_state_cb
!= NULL
) {
1903 (*bs
->bs_state_cb
)(bp
->bp_ifp
, bp
->bp_state
);
1908 * Flush the routes on the bridge port, we need to do this from a
1909 * taskqueue to avoid a LOR.
1912 bstp_notify_rtage(void *arg
, __unused
int pending
)
1914 struct bstp_port
*bp
= (struct bstp_port
*)arg
;
1915 struct bstp_state
*bs
= bp
->bp_bs
;
1919 switch (bp
->bp_protover
) {
1920 case BSTP_PROTO_STP
:
1921 /* convert to seconds */
1922 age
= bp
->bp_desg_fdelay
/ BSTP_TICK_VAL
;
1925 case BSTP_PROTO_RSTP
:
1931 if (bp
->bp_active
== 1 && bs
->bs_rtage_cb
!= NULL
) {
1932 (*bs
->bs_rtage_cb
)(bp
->bp_ifp
, age
);
1935 /* flush is complete */
1937 bp
->bp_fdbflush
= 0;
1942 bstp_linkstate(struct ifnet
*ifp
, __unused
int state
)
1944 struct bstp_state
*bs
;
1945 struct bstp_port
*bp
;
1947 /* search for the stp port */
1948 lck_mtx_lock(bstp_list_mtx
);
1949 LIST_FOREACH(bs
, &bstp_list
, bs_list
) {
1951 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1952 if (bp
->bp_ifp
== ifp
) {
1953 bstp_ifupdstatus(bs
, bp
);
1954 bstp_update_state(bs
, bp
);
1955 /* it only exists once so return */
1957 lck_mtx_unlock(bstp_list_mtx
);
1963 lck_mtx_unlock(bstp_list_mtx
);
1967 bstp_ifupdstatus(struct bstp_state
*bs
, struct bstp_port
*bp
)
1969 struct ifnet
*ifp
= bp
->bp_ifp
;
1970 struct ifmediareq ifmr
;
1973 BSTP_LOCK_ASSERT(bs
);
1975 bzero((char *)&ifmr
, sizeof(ifmr
));
1976 error
= (*ifp
->if_ioctl
)(ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
);
1978 if ((error
== 0) && (ifp
->if_flags
& IFF_UP
)) {
1979 if (ifmr
.ifm_status
& IFM_ACTIVE
) {
1980 /* A full-duplex link is assumed to be point to point */
1981 if (bp
->bp_flags
& BSTP_PORT_AUTOPTP
) {
1983 ifmr
.ifm_active
& IFM_FDX
? 1 : 0;
1986 /* Calc the cost if the link was down previously */
1987 if (bp
->bp_flags
& BSTP_PORT_PNDCOST
) {
1988 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
1989 bp
->bp_flags
&= ~BSTP_PORT_PNDCOST
;
1992 if (bp
->bp_role
== BSTP_ROLE_DISABLED
) {
1993 bstp_enable_port(bs
, bp
);
1996 if (bp
->bp_role
!= BSTP_ROLE_DISABLED
) {
1997 bstp_disable_port(bs
, bp
);
1998 if ((bp
->bp_flags
& BSTP_PORT_ADMEDGE
) &&
1999 bp
->bp_protover
== BSTP_PROTO_RSTP
) {
2000 bp
->bp_operedge
= 1;
2007 if (bp
->bp_infois
!= BSTP_INFO_DISABLED
) {
2008 bstp_disable_port(bs
, bp
);
2013 bstp_enable_port(struct bstp_state
*bs
, struct bstp_port
*bp
)
2015 bp
->bp_infois
= BSTP_INFO_AGED
;
2016 bstp_assign_roles(bs
);
2020 bstp_disable_port(struct bstp_state
*bs
, struct bstp_port
*bp
)
2022 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2023 bstp_assign_roles(bs
);
2027 bstp_tick(void *arg
)
2029 struct bstp_state
*bs
= arg
;
2030 struct bstp_port
*bp
;
2035 if (bs
->bs_running
== 0) {
2039 /* slow timer to catch missed link events */
2040 if (bstp_timer_expired(&bs
->bs_link_timer
)) {
2041 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
2042 bstp_ifupdstatus(bs
, bp
);
2043 bstp_timer_start(&bs
->bs_link_timer
, BSTP_LINK_TIMER
);
2046 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2047 /* no events need to happen for these */
2048 bstp_timer_expired(&bp
->bp_tc_timer
);
2049 bstp_timer_expired(&bp
->bp_recent_root_timer
);
2050 bstp_timer_expired(&bp
->bp_forward_delay_timer
);
2051 bstp_timer_expired(&bp
->bp_recent_backup_timer
);
2053 if (bstp_timer_expired(&bp
->bp_hello_timer
)) {
2054 bstp_hello_timer_expiry(bs
, bp
);
2057 if (bstp_timer_expired(&bp
->bp_message_age_timer
)) {
2058 bstp_message_age_expiry(bs
, bp
);
2061 if (bstp_timer_expired(&bp
->bp_migrate_delay_timer
)) {
2062 bstp_migrate_delay_expiry(bs
, bp
);
2065 if (bstp_timer_expired(&bp
->bp_edge_delay_timer
)) {
2066 bstp_edge_delay_expiry(bs
, bp
);
2069 /* update the various state machines for the port */
2070 bstp_update_state(bs
, bp
);
2072 if (bp
->bp_txcount
> 0) {
2081 bsd_timeout(bstp_tick
, bs
, &ts
);
2085 bstp_timer_start(struct bstp_timer
*t
, uint16_t v
)
2093 bstp_timer_stop(struct bstp_timer
*t
)
2101 bstp_timer_latch(struct bstp_timer
*t
)
2108 bstp_timer_expired(struct bstp_timer
*t
)
2110 if (t
->active
== 0 || t
->latched
) {
2113 t
->value
-= BSTP_TICK_VAL
;
2114 if (t
->value
<= 0) {
2122 bstp_hello_timer_expiry(struct bstp_state
*bs
, struct bstp_port
*bp
)
2124 if ((bp
->bp_flags
& BSTP_PORT_NEWINFO
) ||
2125 bp
->bp_role
== BSTP_ROLE_DESIGNATED
||
2126 (bp
->bp_role
== BSTP_ROLE_ROOT
&&
2127 bp
->bp_tc_timer
.active
== 1)) {
2128 bstp_timer_start(&bp
->bp_hello_timer
, bp
->bp_desg_htime
);
2129 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
2130 bstp_transmit(bs
, bp
);
2135 bstp_message_age_expiry(struct bstp_state
*bs
, struct bstp_port
*bp
)
2137 if (bp
->bp_infois
== BSTP_INFO_RECEIVED
) {
2138 bp
->bp_infois
= BSTP_INFO_AGED
;
2139 bstp_assign_roles(bs
);
2140 DPRINTF("aged info on %s\n", bp
->bp_ifp
->if_xname
);
2145 bstp_migrate_delay_expiry(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
)
2147 bp
->bp_flags
|= BSTP_PORT_CANMIGRATE
;
2151 bstp_edge_delay_expiry(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
)
2153 if ((bp
->bp_flags
& BSTP_PORT_AUTOEDGE
) &&
2154 bp
->bp_protover
== BSTP_PROTO_RSTP
&& bp
->bp_proposing
&&
2155 bp
->bp_role
== BSTP_ROLE_DESIGNATED
) {
2156 bp
->bp_operedge
= 1;
2157 DPRINTF("%s -> edge port\n", bp
->bp_ifp
->if_xname
);
2162 bstp_addr_cmp(const uint8_t *a
, const uint8_t *b
)
2166 for (i
= 0, d
= 0; i
< ETHER_ADDR_LEN
&& d
== 0; i
++) {
2167 d
= ((int)a
[i
]) - ((int)b
[i
]);
2174 * compare the bridge address component of the bridgeid
2177 bstp_same_bridgeid(uint64_t id1
, uint64_t id2
)
2179 u_char addr1
[ETHER_ADDR_LEN
];
2180 u_char addr2
[ETHER_ADDR_LEN
];
2182 PV2ADDR(id1
, addr1
);
2183 PV2ADDR(id2
, addr2
);
2185 if (bstp_addr_cmp(addr1
, addr2
) == 0) {
2193 bstp_reinit(struct bstp_state
*bs
)
2195 struct bstp_port
*bp
;
2196 struct ifnet
*ifp
, *mif
;
2198 static const u_char llzero
[ETHER_ADDR_LEN
]; /* 00:00:00:00:00:00 */
2200 BSTP_LOCK_ASSERT(bs
);
2204 * Search through the Ethernet adapters and find the one with the
2205 * lowest value. The adapter which we take the MAC address from does
2206 * not need to be part of the bridge, it just needs to be a unique
2209 ifnet_head_lock_shared();
2210 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
2211 if (ifp
->if_type
!= IFT_ETHER
) {
2215 if (bstp_addr_cmp(IF_LLADDR(ifp
), llzero
) == 0) {
2223 if (bstp_addr_cmp(IF_LLADDR(ifp
), IF_LLADDR(mif
)) < 0) {
2230 if (LIST_EMPTY(&bs
->bs_bplist
) || mif
== NULL
) {
2231 /* Set the bridge and root id (lower bits) to zero */
2232 bs
->bs_bridge_pv
.pv_dbridge_id
=
2233 ((uint64_t)bs
->bs_bridge_priority
) << 48;
2234 bs
->bs_bridge_pv
.pv_root_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
2235 bs
->bs_root_pv
= bs
->bs_bridge_pv
;
2236 /* Disable any remaining ports, they will have no MAC address */
2237 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2238 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2239 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
2241 bsd_untimeout(bstp_tick
, bs
);
2245 e_addr
= IF_LLADDR(mif
);
2246 bs
->bs_bridge_pv
.pv_dbridge_id
=
2247 (((uint64_t)bs
->bs_bridge_priority
) << 48) |
2248 (((uint64_t)e_addr
[0]) << 40) |
2249 (((uint64_t)e_addr
[1]) << 32) |
2250 (((uint64_t)e_addr
[2]) << 24) |
2251 (((uint64_t)e_addr
[3]) << 16) |
2252 (((uint64_t)e_addr
[4]) << 8) |
2253 (((uint64_t)e_addr
[5]));
2255 bs
->bs_bridge_pv
.pv_root_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
2256 bs
->bs_bridge_pv
.pv_cost
= 0;
2257 bs
->bs_bridge_pv
.pv_dport_id
= 0;
2258 bs
->bs_bridge_pv
.pv_port_id
= 0;
2260 if (bs
->bs_running
) {
2261 bsd_untimeout(bstp_tick
, bs
);
2264 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2265 bp
->bp_port_id
= (bp
->bp_priority
<< 8) |
2266 (bp
->bp_ifp
->if_index
& 0xfff);
2267 bstp_ifupdstatus(bs
, bp
);
2270 bstp_assign_roles(bs
);
2271 bstp_timer_start(&bs
->bs_link_timer
, BSTP_LINK_TIMER
);
2275 bstp_attach(struct bstp_state
*bs
, struct bstp_cb_ops
*cb
)
2278 LIST_INIT(&bs
->bs_bplist
);
2280 bs
->bs_bridge_max_age
= BSTP_DEFAULT_MAX_AGE
;
2281 bs
->bs_bridge_htime
= BSTP_DEFAULT_HELLO_TIME
;
2282 bs
->bs_bridge_fdelay
= BSTP_DEFAULT_FORWARD_DELAY
;
2283 bs
->bs_bridge_priority
= BSTP_DEFAULT_BRIDGE_PRIORITY
;
2284 bs
->bs_hold_time
= BSTP_DEFAULT_HOLD_TIME
;
2285 bs
->bs_migration_delay
= BSTP_DEFAULT_MIGRATE_DELAY
;
2286 bs
->bs_txholdcount
= BSTP_DEFAULT_HOLD_COUNT
;
2287 bs
->bs_protover
= BSTP_PROTO_RSTP
;
2288 bs
->bs_state_cb
= cb
->bcb_state
;
2289 bs
->bs_rtage_cb
= cb
->bcb_rtage
;
2291 /* reviewed for getmicrotime usage */
2292 getmicrotime(&bs
->bs_last_tc_time
);
2294 lck_mtx_lock(bstp_list_mtx
);
2295 LIST_INSERT_HEAD(&bstp_list
, bs
, bs_list
);
2296 lck_mtx_unlock(bstp_list_mtx
);
2300 bstp_detach(struct bstp_state
*bs
)
2302 KASSERT(LIST_EMPTY(&bs
->bs_bplist
), ("bstp still active"));
2304 lck_mtx_lock(bstp_list_mtx
);
2305 LIST_REMOVE(bs
, bs_list
);
2306 lck_mtx_unlock(bstp_list_mtx
);
2307 bsd_untimeout(bstp_tick
, bs
);
2308 BSTP_LOCK_DESTROY(bs
);
2312 bstp_init(struct bstp_state
*bs
)
2320 bsd_timeout(bstp_tick
, bs
, &ts
);
2327 bstp_stop(struct bstp_state
*bs
)
2329 struct bstp_port
*bp
;
2333 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
2334 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
2337 bsd_untimeout(bstp_tick
, bs
);
2342 bstp_create(struct bstp_state
*bs
, struct bstp_port
*bp
, struct ifnet
*ifp
)
2344 bzero(bp
, sizeof(struct bstp_port
));
2349 bp
->bp_priority
= BSTP_DEFAULT_PORT_PRIORITY
;
2350 BSTP_TASK_INIT(&bp
->bp_statetask
, bstp_notify_state
, bp
);
2351 BSTP_TASK_INIT(&bp
->bp_rtagetask
, bstp_notify_rtage
, bp
);
2354 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2355 bp
->bp_flags
= BSTP_PORT_AUTOEDGE
| BSTP_PORT_AUTOPTP
;
2356 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
2357 bstp_set_port_proto(bp
, bs
->bs_protover
);
2358 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
2359 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
2360 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
2366 bstp_enable(struct bstp_port
*bp
)
2368 struct bstp_state
*bs
= bp
->bp_bs
;
2369 struct ifnet
*ifp
= bp
->bp_ifp
;
2371 KASSERT(bp
->bp_active
== 0, ("already a bstp member"));
2373 switch (ifp
->if_type
) {
2374 case IFT_ETHER
: /* These can do spanning tree. */
2377 /* Nothing else can. */
2382 LIST_INSERT_HEAD(&bs
->bs_bplist
, bp
, bp_next
);
2384 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
2386 bstp_update_roles(bs
, bp
);
2392 bstp_disable(struct bstp_port
*bp
)
2394 struct bstp_state
*bs
= bp
->bp_bs
;
2396 KASSERT(bp
->bp_active
== 1, ("not a bstp member"));
2399 bstp_disable_port(bs
, bp
);
2400 LIST_REMOVE(bp
, bp_next
);
2407 * The bstp_port structure is about to be freed by the parent bridge.
2410 bstp_destroy(struct bstp_port
*bp
)
2412 KASSERT(bp
->bp_active
== 0, ("port is still attached"));
2413 bstp_task_drain(&bp
->bp_statetask
);
2414 bstp_task_drain(&bp
->bp_rtagetask
);
2418 __private_extern__
void
2421 lck_grp_attr_t
*lck_grp_attr
= NULL
;
2423 lck_grp_attr
= lck_grp_attr_alloc_init();
2424 bstp_lock_grp
= lck_grp_alloc_init("bstp", lck_grp_attr
);
2425 bstp_lock_attr
= lck_attr_alloc_init();
2427 lck_attr_setdebug(bstp_lock_attr
);
2429 lck_mtx_init(bstp_list_mtx
, bstp_lock_grp
, bstp_lock_attr
);
2430 lck_grp_attr_free(lck_grp_attr
);
2432 LIST_INIT(&bstp_list
);
2434 bstp_create_task_thread();
2440 bstp_create_task_thread(void)
2442 kern_return_t error
;
2444 lck_grp_attr_t
*lck_grp_attr
= NULL
;
2446 lck_grp_attr
= lck_grp_attr_alloc_init();
2447 bstp_task_grp
= lck_grp_alloc_init("bstp_task", lck_grp_attr
);
2448 bstp_task_attr
= lck_attr_alloc_init();
2450 lck_attr_setdebug(bstp_task_attr
);
2452 lck_mtx_init(bstp_task_mtx
, bstp_lock_grp
, bstp_lock_attr
);
2453 lck_grp_attr_free(lck_grp_attr
);
2455 error
= kernel_thread_start((thread_continue_t
)bstp_task_thread_func
, NULL
, &bstp_task_thread
);
2460 bstp_task_thread_func(void)
2462 struct bstp_task
*bt
, *tvar
;
2464 lck_mtx_lock(bstp_task_mtx
);
2467 while (TAILQ_EMPTY(&bstp_task_queue
)) {
2468 wakeup(&bstp_task_queue_running
);
2469 msleep(&bstp_task_queue
, bstp_task_mtx
, PZERO
, "bstp_task_queue", NULL
);
2472 TAILQ_FOREACH_SAFE(bt
, &bstp_task_queue
, bt_next
, tvar
) {
2473 int count
= bt
->bt_count
;
2477 bstp_task_queue_running
= bt
;
2478 lck_mtx_unlock(bstp_task_mtx
);
2480 (*bt
->bt_func
)(bt
->bt_context
, count
);
2482 lck_mtx_lock(bstp_task_mtx
);
2483 bstp_task_queue_running
= NULL
;
2485 if (bt
->bt_count
== 0) {
2486 TAILQ_REMOVE(&bstp_task_queue
, bt
, bt_next
);
2495 bstp_task_enqueue(struct bstp_task
*bt
)
2497 lck_mtx_lock(bstp_task_mtx
);
2501 lck_mtx_unlock(bstp_task_mtx
);
2502 wakeup(&bstp_task_queue
);
2507 TAILQ_INSERT_TAIL(&bstp_task_queue
, bt
, bt_next
);
2509 lck_mtx_unlock(bstp_task_mtx
);
2511 wakeup(&bstp_task_queue
);
2515 bstp_task_drain(struct bstp_task
*bt
)
2517 lck_mtx_lock(bstp_task_mtx
);
2519 while (bt
->bt_count
!= 0 || bstp_task_queue_running
== bt
) {
2520 wakeup(&bstp_task_queue
);
2521 msleep(&bstp_task_queue_running
, bstp_task_mtx
, PZERO
, "bstp_task_queue", NULL
);
2523 lck_mtx_unlock(bstp_task_mtx
);