1 /* $NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $ */
4 * Copyright (c) 2009-2010 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)
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 */
232 if (bp
->bp_protover
== BSTP_PROTO_RSTP
) {
233 bstp_transmit_bpdu(bs
, bp
);
236 switch (bp
->bp_role
) {
237 case BSTP_ROLE_DESIGNATED
:
238 bstp_transmit_bpdu(bs
, bp
);
243 bstp_transmit_tcn(bs
, bp
);
247 bstp_timer_start(&bp
->bp_hello_timer
, bp
->bp_desg_htime
);
248 bp
->bp_flags
&= ~BSTP_PORT_NEWINFO
;
252 bstp_transmit_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
)
254 struct bstp_cbpdu bpdu
;
256 BSTP_LOCK_ASSERT(bs
);
258 bpdu
.cbu_rootpri
= htons(bp
->bp_desg_pv
.pv_root_id
>> 48);
259 PV2ADDR(bp
->bp_desg_pv
.pv_root_id
, bpdu
.cbu_rootaddr
);
261 bpdu
.cbu_rootpathcost
= htonl(bp
->bp_desg_pv
.pv_cost
);
263 bpdu
.cbu_bridgepri
= htons(bp
->bp_desg_pv
.pv_dbridge_id
>> 48);
264 PV2ADDR(bp
->bp_desg_pv
.pv_dbridge_id
, bpdu
.cbu_bridgeaddr
);
266 bpdu
.cbu_portid
= htons(bp
->bp_port_id
);
267 bpdu
.cbu_messageage
= htons(bp
->bp_desg_msg_age
);
268 bpdu
.cbu_maxage
= htons(bp
->bp_desg_max_age
);
269 bpdu
.cbu_hellotime
= htons(bp
->bp_desg_htime
);
270 bpdu
.cbu_forwarddelay
= htons(bp
->bp_desg_fdelay
);
272 bpdu
.cbu_flags
= bstp_pdu_flags(bp
);
274 switch (bp
->bp_protover
) {
276 bpdu
.cbu_bpdutype
= BSTP_MSGTYPE_CFG
;
279 case BSTP_PROTO_RSTP
:
280 bpdu
.cbu_bpdutype
= BSTP_MSGTYPE_RSTP
;
284 bstp_send_bpdu(bs
, bp
, &bpdu
);
288 bstp_transmit_tcn(struct bstp_state
*bs
, struct bstp_port
*bp
)
290 struct bstp_tbpdu bpdu
;
291 struct ifnet
*ifp
= bp
->bp_ifp
;
292 struct ether_header
*eh
;
294 int touched
= bs
? 1 : 0;
298 KASSERT(bp
== bs
->bs_root_port
, ("%s: bad root port\n", __func__
));
300 if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
303 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
307 m
->m_pkthdr
.rcvif
= ifp
;
308 m
->m_pkthdr
.len
= sizeof(*eh
) + sizeof(bpdu
);
309 m
->m_len
= m
->m_pkthdr
.len
;
311 eh
= mtod(m
, struct ether_header
*);
313 memcpy(eh
->ether_shost
, ifnet_lladdr(ifp
), ETHER_ADDR_LEN
);
314 memcpy(eh
->ether_dhost
, bstp_etheraddr
, ETHER_ADDR_LEN
);
315 eh
->ether_type
= htons(sizeof(bpdu
));
317 bpdu
.tbu_ssap
= bpdu
.tbu_dsap
= LLC_8021D_LSAP
;
318 bpdu
.tbu_ctl
= LLC_UI
;
319 bpdu
.tbu_protoid
= 0;
320 bpdu
.tbu_protover
= 0;
321 bpdu
.tbu_bpdutype
= BSTP_MSGTYPE_TCN
;
323 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), &bpdu
, sizeof(bpdu
));
326 bstp_enqueue(ifp
, m
);
330 bstp_decode_bpdu(struct bstp_port
*bp
, struct bstp_cbpdu
*cpdu
,
331 struct bstp_config_unit
*cu
)
335 cu
->cu_pv
.pv_root_id
=
336 (((uint64_t)ntohs(cpdu
->cbu_rootpri
)) << 48) |
337 (((uint64_t)cpdu
->cbu_rootaddr
[0]) << 40) |
338 (((uint64_t)cpdu
->cbu_rootaddr
[1]) << 32) |
339 (((uint64_t)cpdu
->cbu_rootaddr
[2]) << 24) |
340 (((uint64_t)cpdu
->cbu_rootaddr
[3]) << 16) |
341 (((uint64_t)cpdu
->cbu_rootaddr
[4]) << 8) |
342 (((uint64_t)cpdu
->cbu_rootaddr
[5]) << 0);
344 cu
->cu_pv
.pv_dbridge_id
=
345 (((uint64_t)ntohs(cpdu
->cbu_bridgepri
)) << 48) |
346 (((uint64_t)cpdu
->cbu_bridgeaddr
[0]) << 40) |
347 (((uint64_t)cpdu
->cbu_bridgeaddr
[1]) << 32) |
348 (((uint64_t)cpdu
->cbu_bridgeaddr
[2]) << 24) |
349 (((uint64_t)cpdu
->cbu_bridgeaddr
[3]) << 16) |
350 (((uint64_t)cpdu
->cbu_bridgeaddr
[4]) << 8) |
351 (((uint64_t)cpdu
->cbu_bridgeaddr
[5]) << 0);
353 cu
->cu_pv
.pv_cost
= ntohl(cpdu
->cbu_rootpathcost
);
354 cu
->cu_message_age
= ntohs(cpdu
->cbu_messageage
);
355 cu
->cu_max_age
= ntohs(cpdu
->cbu_maxage
);
356 cu
->cu_hello_time
= ntohs(cpdu
->cbu_hellotime
);
357 cu
->cu_forward_delay
= ntohs(cpdu
->cbu_forwarddelay
);
358 cu
->cu_pv
.pv_dport_id
= ntohs(cpdu
->cbu_portid
);
359 cu
->cu_pv
.pv_port_id
= bp
->bp_port_id
;
360 cu
->cu_message_type
= cpdu
->cbu_bpdutype
;
362 /* Strip off unused flags in STP mode */
363 flags
= cpdu
->cbu_flags
;
364 switch (cpdu
->cbu_protover
) {
366 flags
&= BSTP_PDU_STPMASK
;
367 /* A STP BPDU explicitly conveys a Designated Port */
368 cu
->cu_role
= BSTP_ROLE_DESIGNATED
;
371 case BSTP_PROTO_RSTP
:
372 flags
&= BSTP_PDU_RSTPMASK
;
376 cu
->cu_topology_change_ack
=
377 (flags
& BSTP_PDU_F_TCA
) ? 1 : 0;
379 (flags
& BSTP_PDU_F_P
) ? 1 : 0;
381 (flags
& BSTP_PDU_F_A
) ? 1 : 0;
383 (flags
& BSTP_PDU_F_L
) ? 1 : 0;
385 (flags
& BSTP_PDU_F_F
) ? 1 : 0;
386 cu
->cu_topology_change
=
387 (flags
& BSTP_PDU_F_TC
) ? 1 : 0;
389 switch ((flags
& BSTP_PDU_PRMASK
) >> BSTP_PDU_PRSHIFT
) {
390 case BSTP_PDU_F_ROOT
:
391 cu
->cu_role
= BSTP_ROLE_ROOT
;
394 cu
->cu_role
= BSTP_ROLE_ALTERNATE
;
396 case BSTP_PDU_F_DESG
:
397 cu
->cu_role
= BSTP_ROLE_DESIGNATED
;
403 bstp_send_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
,
404 struct bstp_cbpdu
*bpdu
)
408 struct ether_header
*eh
;
410 BSTP_LOCK_ASSERT(bs
);
414 if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
417 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
421 eh
= mtod(m
, struct ether_header
*);
423 bpdu
->cbu_ssap
= bpdu
->cbu_dsap
= LLC_8021D_LSAP
;
424 bpdu
->cbu_ctl
= LLC_UI
;
425 bpdu
->cbu_protoid
= htons(BSTP_PROTO_ID
);
427 memcpy(eh
->ether_shost
, ifnet_lladdr(ifp
), ETHER_ADDR_LEN
);
428 memcpy(eh
->ether_dhost
, bstp_etheraddr
, ETHER_ADDR_LEN
);
430 switch (bpdu
->cbu_bpdutype
) {
431 case BSTP_MSGTYPE_CFG
:
432 bpdu
->cbu_protover
= BSTP_PROTO_STP
;
433 m
->m_pkthdr
.len
= sizeof(*eh
) + BSTP_BPDU_STP_LEN
;
434 eh
->ether_type
= htons(BSTP_BPDU_STP_LEN
);
435 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), bpdu
,
439 case BSTP_MSGTYPE_RSTP
:
440 bpdu
->cbu_protover
= BSTP_PROTO_RSTP
;
441 bpdu
->cbu_versionlen
= htons(0);
442 m
->m_pkthdr
.len
= sizeof(*eh
) + BSTP_BPDU_RSTP_LEN
;
443 eh
->ether_type
= htons(BSTP_BPDU_RSTP_LEN
);
444 memcpy(mtod(m
, caddr_t
) + sizeof(*eh
), bpdu
,
449 panic("not implemented");
451 m
->m_pkthdr
.rcvif
= ifp
;
452 m
->m_len
= m
->m_pkthdr
.len
;
455 bstp_enqueue(ifp
, m
);
459 bstp_enqueue(struct ifnet
*dst_ifp
, struct mbuf
*m
)
462 u_int32_t len
= m
->m_pkthdr
.len
;
464 m
->m_flags
|= M_PROTO1
; //set to avoid loops
466 error
= ifnet_output_raw(dst_ifp
, 0, m
);
468 (void) ifnet_stat_increment_out(dst_ifp
, 1, len
, 0);
470 (void) ifnet_stat_increment_out(dst_ifp
, 0, 0, 1);
475 bstp_pdu_flags(struct bstp_port
*bp
)
479 if (bp
->bp_proposing
&& bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
)
480 flags
|= BSTP_PDU_F_P
;
483 flags
|= BSTP_PDU_F_A
;
485 if (bp
->bp_tc_timer
.active
)
486 flags
|= BSTP_PDU_F_TC
;
489 flags
|= BSTP_PDU_F_TCA
;
491 switch (bp
->bp_state
) {
492 case BSTP_IFSTATE_LEARNING
:
493 flags
|= BSTP_PDU_F_L
;
496 case BSTP_IFSTATE_FORWARDING
:
497 flags
|= (BSTP_PDU_F_L
| BSTP_PDU_F_F
);
501 switch (bp
->bp_role
) {
504 (BSTP_PDU_F_ROOT
<< BSTP_PDU_PRSHIFT
);
507 case BSTP_ROLE_ALTERNATE
:
508 case BSTP_ROLE_BACKUP
: /* fall through */
510 (BSTP_PDU_F_ALT
<< BSTP_PDU_PRSHIFT
);
513 case BSTP_ROLE_DESIGNATED
:
515 (BSTP_PDU_F_DESG
<< BSTP_PDU_PRSHIFT
);
519 /* Strip off unused flags in either mode */
520 switch (bp
->bp_protover
) {
522 flags
&= BSTP_PDU_STPMASK
;
524 case BSTP_PROTO_RSTP
:
525 flags
&= BSTP_PDU_RSTPMASK
;
532 bstp_input(struct bstp_port
*bp
, __unused
struct ifnet
*ifp
, struct mbuf
*m
)
534 struct bstp_state
*bs
= bp
->bp_bs
;
535 struct ether_header
*eh
;
536 struct bstp_tbpdu tpdu
;
539 if (bp
->bp_active
== 0) {
546 eh
= mtod(m
, struct ether_header
*);
548 len
= ntohs(eh
->ether_type
);
549 if (len
< sizeof(tpdu
))
552 m_adj(m
, ETHER_HDR_LEN
);
554 if (m
->m_pkthdr
.len
> len
)
555 m_adj(m
, len
- m
->m_pkthdr
.len
);
556 if ((unsigned int)m
->m_len
< sizeof(tpdu
) &&
557 (m
= m_pullup(m
, sizeof(tpdu
))) == NULL
)
560 memcpy(&tpdu
, mtod(m
, caddr_t
), sizeof(tpdu
));
562 /* basic packet checks */
563 if (tpdu
.tbu_dsap
!= LLC_8021D_LSAP
||
564 tpdu
.tbu_ssap
!= LLC_8021D_LSAP
||
565 tpdu
.tbu_ctl
!= LLC_UI
)
567 if (tpdu
.tbu_protoid
!= BSTP_PROTO_ID
)
571 * We can treat later versions of the PDU as the same as the maximum
572 * version we implement. All additional parameters/flags are ignored.
574 if (tpdu
.tbu_protover
> BSTP_PROTO_MAX
)
575 tpdu
.tbu_protover
= BSTP_PROTO_MAX
;
577 if (tpdu
.tbu_protover
!= bp
->bp_protover
) {
579 * Wait for the migration delay timer to expire before changing
580 * protocol version to avoid flip-flops.
582 if (bp
->bp_flags
& BSTP_PORT_CANMIGRATE
)
583 bstp_set_port_proto(bp
, tpdu
.tbu_protover
);
588 /* Clear operedge upon receiving a PDU on the port */
590 bstp_timer_start(&bp
->bp_edge_delay_timer
,
591 BSTP_DEFAULT_MIGRATE_DELAY
);
593 switch (tpdu
.tbu_protover
) {
595 bstp_received_stp(bs
, bp
, &m
, &tpdu
);
598 case BSTP_PROTO_RSTP
:
599 bstp_received_rstp(bs
, bp
, &m
, &tpdu
);
610 bstp_received_stp(struct bstp_state
*bs
, struct bstp_port
*bp
,
611 struct mbuf
**mp
, struct bstp_tbpdu
*tpdu
)
613 struct bstp_cbpdu cpdu
;
614 struct bstp_config_unit
*cu
= &bp
->bp_msg_cu
;
615 struct bstp_tcn_unit tu
;
617 switch (tpdu
->tbu_bpdutype
) {
618 case BSTP_MSGTYPE_TCN
:
619 tu
.tu_message_type
= tpdu
->tbu_bpdutype
;
620 bstp_received_tcn(bs
, bp
, &tu
);
622 case BSTP_MSGTYPE_CFG
:
623 if ((*mp
)->m_len
< BSTP_BPDU_STP_LEN
&&
624 (*mp
= m_pullup(*mp
, BSTP_BPDU_STP_LEN
)) == NULL
)
626 memcpy(&cpdu
, mtod(*mp
, caddr_t
), BSTP_BPDU_STP_LEN
);
628 bstp_decode_bpdu(bp
, &cpdu
, cu
);
629 bstp_received_bpdu(bs
, bp
, cu
);
635 bstp_received_rstp(struct bstp_state
*bs
, struct bstp_port
*bp
,
636 struct mbuf
**mp
, struct bstp_tbpdu
*tpdu
)
638 struct bstp_cbpdu cpdu
;
639 struct bstp_config_unit
*cu
= &bp
->bp_msg_cu
;
641 if (tpdu
->tbu_bpdutype
!= BSTP_MSGTYPE_RSTP
)
644 if ((*mp
)->m_len
< BSTP_BPDU_RSTP_LEN
&&
645 (*mp
= m_pullup(*mp
, BSTP_BPDU_RSTP_LEN
)) == NULL
)
647 memcpy(&cpdu
, mtod(*mp
, caddr_t
), BSTP_BPDU_RSTP_LEN
);
649 bstp_decode_bpdu(bp
, &cpdu
, cu
);
650 bstp_received_bpdu(bs
, bp
, cu
);
654 bstp_received_tcn(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
,
655 __unused
struct bstp_tcn_unit
*tcn
)
662 bstp_received_bpdu(struct bstp_state
*bs
, struct bstp_port
*bp
,
663 struct bstp_config_unit
*cu
)
667 BSTP_LOCK_ASSERT(bs
);
669 /* We need to have transitioned to INFO_MINE before proceeding */
670 switch (bp
->bp_infois
) {
671 case BSTP_INFO_DISABLED
:
676 type
= bstp_pdu_rcvtype(bp
, cu
);
679 case BSTP_PDU_SUPERIOR
:
680 bs
->bs_allsynced
= 0;
682 bp
->bp_proposing
= 0;
684 if (cu
->cu_proposal
&& cu
->cu_forwarding
== 0)
686 if (cu
->cu_topology_change
)
688 if (cu
->cu_topology_change_ack
)
692 !bstp_pdu_bettersame(bp
, BSTP_INFO_RECEIVED
))
695 /* copy the received priority and timers to the port */
696 bp
->bp_port_pv
= cu
->cu_pv
;
697 bp
->bp_port_msg_age
= cu
->cu_message_age
;
698 bp
->bp_port_max_age
= cu
->cu_max_age
;
699 bp
->bp_port_fdelay
= cu
->cu_forward_delay
;
701 (cu
->cu_hello_time
> BSTP_MIN_HELLO_TIME
?
702 cu
->cu_hello_time
: BSTP_MIN_HELLO_TIME
);
704 /* set expiry for the new info */
705 bstp_set_timer_msgage(bp
);
707 bp
->bp_infois
= BSTP_INFO_RECEIVED
;
708 bstp_assign_roles(bs
);
711 case BSTP_PDU_REPEATED
:
712 if (cu
->cu_proposal
&& cu
->cu_forwarding
== 0)
714 if (cu
->cu_topology_change
)
716 if (cu
->cu_topology_change_ack
)
719 /* rearm the age timer */
720 bstp_set_timer_msgage(bp
);
723 case BSTP_PDU_INFERIOR
:
724 if (cu
->cu_learning
) {
726 bp
->bp_proposing
= 0;
730 case BSTP_PDU_INFERIORALT
:
732 * only point to point links are allowed fast
733 * transitions to forwarding.
735 if (cu
->cu_agree
&& bp
->bp_ptp_link
) {
737 bp
->bp_proposing
= 0;
741 if (cu
->cu_topology_change
)
743 if (cu
->cu_topology_change_ack
)
748 return; /* do nothing */
750 /* update the state machines with the new data */
751 bstp_update_state(bs
, bp
);
755 bstp_pdu_rcvtype(struct bstp_port
*bp
, struct bstp_config_unit
*cu
)
759 /* default return type */
760 type
= BSTP_PDU_OTHER
;
762 switch (cu
->cu_role
) {
763 case BSTP_ROLE_DESIGNATED
:
764 if (bstp_info_superior(&bp
->bp_port_pv
, &cu
->cu_pv
))
765 /* bpdu priority is superior */
766 type
= BSTP_PDU_SUPERIOR
;
767 else if (bstp_info_cmp(&bp
->bp_port_pv
, &cu
->cu_pv
) ==
769 if (bp
->bp_port_msg_age
!= cu
->cu_message_age
||
770 bp
->bp_port_max_age
!= cu
->cu_max_age
||
771 bp
->bp_port_fdelay
!= cu
->cu_forward_delay
||
772 bp
->bp_port_htime
!= cu
->cu_hello_time
)
773 /* bpdu priority is equal and timers differ */
774 type
= BSTP_PDU_SUPERIOR
;
777 type
= BSTP_PDU_REPEATED
;
779 /* bpdu priority is worse */
780 type
= BSTP_PDU_INFERIOR
;
785 case BSTP_ROLE_ALTERNATE
:
786 case BSTP_ROLE_BACKUP
:
787 if (bstp_info_cmp(&bp
->bp_port_pv
, &cu
->cu_pv
) <= INFO_SAME
)
789 * not a designated port and priority is the same or
792 type
= BSTP_PDU_INFERIORALT
;
800 bstp_pdu_bettersame(struct bstp_port
*bp
, int newinfo
)
802 if (newinfo
== BSTP_INFO_RECEIVED
&&
803 bp
->bp_infois
== BSTP_INFO_RECEIVED
&&
804 bstp_info_cmp(&bp
->bp_port_pv
, &bp
->bp_msg_cu
.cu_pv
) >= INFO_SAME
)
807 if (newinfo
== BSTP_INFO_MINE
&&
808 bp
->bp_infois
== BSTP_INFO_MINE
&&
809 bstp_info_cmp(&bp
->bp_port_pv
, &bp
->bp_desg_pv
) >= INFO_SAME
)
816 bstp_info_cmp(struct bstp_pri_vector
*pv
,
817 struct bstp_pri_vector
*cpv
)
819 if (cpv
->pv_root_id
< pv
->pv_root_id
)
820 return (INFO_BETTER
);
821 if (cpv
->pv_root_id
> pv
->pv_root_id
)
824 if (cpv
->pv_cost
< pv
->pv_cost
)
825 return (INFO_BETTER
);
826 if (cpv
->pv_cost
> pv
->pv_cost
)
829 if (cpv
->pv_dbridge_id
< pv
->pv_dbridge_id
)
830 return (INFO_BETTER
);
831 if (cpv
->pv_dbridge_id
> pv
->pv_dbridge_id
)
834 if (cpv
->pv_dport_id
< pv
->pv_dport_id
)
835 return (INFO_BETTER
);
836 if (cpv
->pv_dport_id
> pv
->pv_dport_id
)
843 * This message priority vector is superior to the port priority vector and
844 * will replace it if, and only if, the message priority vector is better than
845 * the port priority vector, or the message has been transmitted from the same
846 * designated bridge and designated port as the port priority vector.
849 bstp_info_superior(struct bstp_pri_vector
*pv
,
850 struct bstp_pri_vector
*cpv
)
852 if (bstp_info_cmp(pv
, cpv
) == INFO_BETTER
||
853 (bstp_same_bridgeid(pv
->pv_dbridge_id
, cpv
->pv_dbridge_id
) &&
854 (cpv
->pv_dport_id
& 0xfff) == (pv
->pv_dport_id
& 0xfff)))
860 bstp_assign_roles(struct bstp_state
*bs
)
862 struct bstp_port
*bp
, *rbp
= NULL
;
863 struct bstp_pri_vector pv
;
865 /* default to our priority vector */
866 bs
->bs_root_pv
= bs
->bs_bridge_pv
;
867 bs
->bs_root_msg_age
= 0;
868 bs
->bs_root_max_age
= bs
->bs_bridge_max_age
;
869 bs
->bs_root_fdelay
= bs
->bs_bridge_fdelay
;
870 bs
->bs_root_htime
= bs
->bs_bridge_htime
;
871 bs
->bs_root_port
= NULL
;
873 /* check if any recieved info supersedes us */
874 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
875 if (bp
->bp_infois
!= BSTP_INFO_RECEIVED
)
879 pv
.pv_cost
+= bp
->bp_path_cost
;
882 * The root priority vector is the best of the set comprising
883 * the bridge priority vector plus all root path priority
884 * vectors whose bridge address is not equal to us.
886 if (bstp_same_bridgeid(pv
.pv_dbridge_id
,
887 bs
->bs_bridge_pv
.pv_dbridge_id
) == 0 &&
888 bstp_info_cmp(&bs
->bs_root_pv
, &pv
) == INFO_BETTER
) {
889 /* the port vector replaces the root */
891 bs
->bs_root_msg_age
= bp
->bp_port_msg_age
+
892 BSTP_MESSAGE_AGE_INCR
;
893 bs
->bs_root_max_age
= bp
->bp_port_max_age
;
894 bs
->bs_root_fdelay
= bp
->bp_port_fdelay
;
895 bs
->bs_root_htime
= bp
->bp_port_htime
;
900 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
901 /* calculate the port designated vector */
902 bp
->bp_desg_pv
.pv_root_id
= bs
->bs_root_pv
.pv_root_id
;
903 bp
->bp_desg_pv
.pv_cost
= bs
->bs_root_pv
.pv_cost
;
904 bp
->bp_desg_pv
.pv_dbridge_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
905 bp
->bp_desg_pv
.pv_dport_id
= bp
->bp_port_id
;
906 bp
->bp_desg_pv
.pv_port_id
= bp
->bp_port_id
;
908 /* calculate designated times */
909 bp
->bp_desg_msg_age
= bs
->bs_root_msg_age
;
910 bp
->bp_desg_max_age
= bs
->bs_root_max_age
;
911 bp
->bp_desg_fdelay
= bs
->bs_root_fdelay
;
912 bp
->bp_desg_htime
= bs
->bs_bridge_htime
;
915 switch (bp
->bp_infois
) {
916 case BSTP_INFO_DISABLED
:
917 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
921 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
922 bstp_update_info(bp
);
926 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
927 /* update the port info if stale */
928 if (bstp_info_cmp(&bp
->bp_port_pv
,
929 &bp
->bp_desg_pv
) != INFO_SAME
||
931 (bp
->bp_port_msg_age
!= rbp
->bp_port_msg_age
||
932 bp
->bp_port_max_age
!= rbp
->bp_port_max_age
||
933 bp
->bp_port_fdelay
!= rbp
->bp_port_fdelay
||
934 bp
->bp_port_htime
!= rbp
->bp_port_htime
)))
935 bstp_update_info(bp
);
938 case BSTP_INFO_RECEIVED
:
941 * root priority is derived from this
942 * port, make it the root port.
944 bstp_set_port_role(bp
, BSTP_ROLE_ROOT
);
945 bs
->bs_root_port
= bp
;
946 } else if (bstp_info_cmp(&bp
->bp_port_pv
,
947 &bp
->bp_desg_pv
) == INFO_BETTER
) {
949 * the port priority is lower than the root
952 bstp_set_port_role(bp
, BSTP_ROLE_DESIGNATED
);
953 bstp_update_info(bp
);
955 if (bstp_same_bridgeid(
956 bp
->bp_port_pv
.pv_dbridge_id
,
957 bs
->bs_bridge_pv
.pv_dbridge_id
)) {
959 * the designated bridge refers to
960 * another port on this bridge.
962 bstp_set_port_role(bp
,
966 * the port is an inferior path to the
969 bstp_set_port_role(bp
,
970 BSTP_ROLE_ALTERNATE
);
979 bstp_update_state(struct bstp_state
*bs
, struct bstp_port
*bp
)
981 struct bstp_port
*bp2
;
984 BSTP_LOCK_ASSERT(bs
);
986 /* check if all the ports have syncronised again */
987 if (!bs
->bs_allsynced
) {
989 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
990 if (!(bp2
->bp_synced
||
991 bp2
->bp_role
== BSTP_ROLE_ROOT
)) {
996 bs
->bs_allsynced
= synced
;
999 bstp_update_roles(bs
, bp
);
1004 bstp_update_roles(struct bstp_state
*bs
, struct bstp_port
*bp
)
1006 switch (bp
->bp_role
) {
1007 case BSTP_ROLE_DISABLED
:
1008 /* Clear any flags if set */
1009 if (bp
->bp_sync
|| !bp
->bp_synced
|| bp
->bp_reroot
) {
1016 case BSTP_ROLE_ALTERNATE
:
1017 case BSTP_ROLE_BACKUP
:
1018 if ((bs
->bs_allsynced
&& !bp
->bp_agree
) ||
1019 (bp
->bp_proposed
&& bp
->bp_agree
)) {
1020 bp
->bp_proposed
= 0;
1022 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1023 DPRINTF("%s -> ALTERNATE_AGREED\n",
1024 bp
->bp_ifp
->if_xname
);
1027 if (bp
->bp_proposed
&& !bp
->bp_agree
) {
1028 bstp_set_all_sync(bs
);
1029 bp
->bp_proposed
= 0;
1030 DPRINTF("%s -> ALTERNATE_PROPOSED\n",
1031 bp
->bp_ifp
->if_xname
);
1034 /* Clear any flags if set */
1035 if (bp
->bp_sync
|| !bp
->bp_synced
|| bp
->bp_reroot
) {
1039 DPRINTF("%s -> ALTERNATE_PORT\n", bp
->bp_ifp
->if_xname
);
1043 case BSTP_ROLE_ROOT
:
1044 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&& !bp
->bp_reroot
) {
1045 bstp_set_all_reroot(bs
);
1046 DPRINTF("%s -> ROOT_REROOT\n", bp
->bp_ifp
->if_xname
);
1049 if ((bs
->bs_allsynced
&& !bp
->bp_agree
) ||
1050 (bp
->bp_proposed
&& bp
->bp_agree
)) {
1051 bp
->bp_proposed
= 0;
1054 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1055 DPRINTF("%s -> ROOT_AGREED\n", bp
->bp_ifp
->if_xname
);
1058 if (bp
->bp_proposed
&& !bp
->bp_agree
) {
1059 bstp_set_all_sync(bs
);
1060 bp
->bp_proposed
= 0;
1061 DPRINTF("%s -> ROOT_PROPOSED\n", bp
->bp_ifp
->if_xname
);
1064 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1065 (bp
->bp_forward_delay_timer
.active
== 0 ||
1066 (bstp_rerooted(bs
, bp
) &&
1067 bp
->bp_recent_backup_timer
.active
== 0 &&
1068 bp
->bp_protover
== BSTP_PROTO_RSTP
))) {
1069 switch (bp
->bp_state
) {
1070 case BSTP_IFSTATE_DISCARDING
:
1071 bstp_set_port_state(bp
, BSTP_IFSTATE_LEARNING
);
1073 case BSTP_IFSTATE_LEARNING
:
1074 bstp_set_port_state(bp
,
1075 BSTP_IFSTATE_FORWARDING
);
1080 if (bp
->bp_state
== BSTP_IFSTATE_FORWARDING
&& bp
->bp_reroot
) {
1082 DPRINTF("%s -> ROOT_REROOTED\n", bp
->bp_ifp
->if_xname
);
1086 case BSTP_ROLE_DESIGNATED
:
1087 if (bp
->bp_recent_root_timer
.active
== 0 && bp
->bp_reroot
) {
1089 DPRINTF("%s -> DESIGNATED_RETIRED\n",
1090 bp
->bp_ifp
->if_xname
);
1093 if ((bp
->bp_state
== BSTP_IFSTATE_DISCARDING
&&
1094 !bp
->bp_synced
) || (bp
->bp_agreed
&& !bp
->bp_synced
) ||
1095 (bp
->bp_operedge
&& !bp
->bp_synced
) ||
1096 (bp
->bp_sync
&& bp
->bp_synced
)) {
1097 bstp_timer_stop(&bp
->bp_recent_root_timer
);
1100 DPRINTF("%s -> DESIGNATED_SYNCED\n",
1101 bp
->bp_ifp
->if_xname
);
1104 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1105 !bp
->bp_agreed
&& !bp
->bp_proposing
&&
1107 bp
->bp_proposing
= 1;
1108 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1109 bstp_timer_start(&bp
->bp_edge_delay_timer
,
1110 (bp
->bp_ptp_link
? BSTP_DEFAULT_MIGRATE_DELAY
:
1111 bp
->bp_desg_max_age
));
1112 DPRINTF("%s -> DESIGNATED_PROPOSE\n",
1113 bp
->bp_ifp
->if_xname
);
1116 if (bp
->bp_state
!= BSTP_IFSTATE_FORWARDING
&&
1117 (bp
->bp_forward_delay_timer
.active
== 0 || bp
->bp_agreed
||
1119 (bp
->bp_recent_root_timer
.active
== 0 || !bp
->bp_reroot
) &&
1121 #ifdef BRIDGESTP_DEBUG
1123 DPRINTF("%s -> AGREED\n", bp
->bp_ifp
->if_xname
);
1124 #endif /* BRIDGESTP_DEBUG */
1126 * If agreed|operedge then go straight to forwarding,
1127 * otherwise follow discard -> learn -> forward.
1129 if (bp
->bp_agreed
|| bp
->bp_operedge
||
1130 bp
->bp_state
== BSTP_IFSTATE_LEARNING
) {
1131 bstp_set_port_state(bp
,
1132 BSTP_IFSTATE_FORWARDING
);
1133 bp
->bp_agreed
= bp
->bp_protover
;
1134 } else if (bp
->bp_state
== BSTP_IFSTATE_DISCARDING
)
1135 bstp_set_port_state(bp
, BSTP_IFSTATE_LEARNING
);
1138 if (((bp
->bp_sync
&& !bp
->bp_synced
) ||
1139 (bp
->bp_reroot
&& bp
->bp_recent_root_timer
.active
) ||
1140 (bp
->bp_flags
& BSTP_PORT_DISPUTED
)) && !bp
->bp_operedge
&&
1141 bp
->bp_state
!= BSTP_IFSTATE_DISCARDING
) {
1142 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1143 bp
->bp_flags
&= ~BSTP_PORT_DISPUTED
;
1144 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1145 bp
->bp_protover
== BSTP_PROTO_RSTP
?
1146 bp
->bp_desg_htime
: bp
->bp_desg_fdelay
);
1147 DPRINTF("%s -> DESIGNATED_DISCARD\n",
1148 bp
->bp_ifp
->if_xname
);
1153 if (bp
->bp_flags
& BSTP_PORT_NEWINFO
)
1154 bstp_transmit(bs
, bp
);
1158 bstp_update_tc(struct bstp_port
*bp
)
1160 switch (bp
->bp_tcstate
) {
1161 case BSTP_TCSTATE_ACTIVE
:
1162 if ((bp
->bp_role
!= BSTP_ROLE_DESIGNATED
&&
1163 bp
->bp_role
!= BSTP_ROLE_ROOT
) || bp
->bp_operedge
)
1164 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1167 bstp_set_port_tc(bp
, BSTP_TCSTATE_TCN
);
1169 bstp_set_port_tc(bp
, BSTP_TCSTATE_TC
);
1171 if (bp
->bp_tc_prop
&& !bp
->bp_operedge
)
1172 bstp_set_port_tc(bp
, BSTP_TCSTATE_PROPAG
);
1175 bstp_set_port_tc(bp
, BSTP_TCSTATE_ACK
);
1178 case BSTP_TCSTATE_INACTIVE
:
1179 if ((bp
->bp_state
== BSTP_IFSTATE_LEARNING
||
1180 bp
->bp_state
== BSTP_IFSTATE_FORWARDING
) &&
1181 bp
->bp_fdbflush
== 0)
1182 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1185 case BSTP_TCSTATE_LEARNING
:
1186 if (bp
->bp_rcvdtc
|| bp
->bp_rcvdtcn
|| bp
->bp_rcvdtca
||
1188 bstp_set_port_tc(bp
, BSTP_TCSTATE_LEARNING
);
1189 else if (bp
->bp_role
!= BSTP_ROLE_DESIGNATED
&&
1190 bp
->bp_role
!= BSTP_ROLE_ROOT
&&
1191 bp
->bp_state
== BSTP_IFSTATE_DISCARDING
)
1192 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
1194 if ((bp
->bp_role
== BSTP_ROLE_DESIGNATED
||
1195 bp
->bp_role
== BSTP_ROLE_ROOT
) &&
1196 bp
->bp_state
== BSTP_IFSTATE_FORWARDING
&&
1198 bstp_set_port_tc(bp
, BSTP_TCSTATE_DETECTED
);
1201 /* these are transient states and go straight back to ACTIVE */
1202 case BSTP_TCSTATE_DETECTED
:
1203 case BSTP_TCSTATE_TCN
:
1204 case BSTP_TCSTATE_TC
:
1205 case BSTP_TCSTATE_PROPAG
:
1206 case BSTP_TCSTATE_ACK
:
1207 DPRINTF("Invalid TC state for %s\n",
1208 bp
->bp_ifp
->if_xname
);
1215 bstp_update_info(struct bstp_port
*bp
)
1217 struct bstp_state
*bs
= bp
->bp_bs
;
1219 bp
->bp_proposing
= 0;
1220 bp
->bp_proposed
= 0;
1222 if (bp
->bp_agreed
&& !bstp_pdu_bettersame(bp
, BSTP_INFO_MINE
))
1225 if (bp
->bp_synced
&& !bp
->bp_agreed
) {
1227 bs
->bs_allsynced
= 0;
1230 /* copy the designated pv to the port */
1231 bp
->bp_port_pv
= bp
->bp_desg_pv
;
1232 bp
->bp_port_msg_age
= bp
->bp_desg_msg_age
;
1233 bp
->bp_port_max_age
= bp
->bp_desg_max_age
;
1234 bp
->bp_port_fdelay
= bp
->bp_desg_fdelay
;
1235 bp
->bp_port_htime
= bp
->bp_desg_htime
;
1236 bp
->bp_infois
= BSTP_INFO_MINE
;
1238 /* Set transmit flag but do not immediately send */
1239 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1242 /* set tcprop on every port other than the caller */
1244 bstp_set_other_tcprop(struct bstp_port
*bp
)
1246 struct bstp_state
*bs
= bp
->bp_bs
;
1247 struct bstp_port
*bp2
;
1249 BSTP_LOCK_ASSERT(bs
);
1251 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1254 bp2
->bp_tc_prop
= 1;
1259 bstp_set_all_reroot(struct bstp_state
*bs
)
1261 struct bstp_port
*bp
;
1263 BSTP_LOCK_ASSERT(bs
);
1265 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
1270 bstp_set_all_sync(struct bstp_state
*bs
)
1272 struct bstp_port
*bp
;
1274 BSTP_LOCK_ASSERT(bs
);
1276 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1278 bp
->bp_synced
= 0; /* Not explicit in spec */
1281 bs
->bs_allsynced
= 0;
1285 bstp_set_port_state(struct bstp_port
*bp
, int state
)
1287 if (bp
->bp_state
== state
)
1290 bp
->bp_state
= state
;
1292 switch (bp
->bp_state
) {
1293 case BSTP_IFSTATE_DISCARDING
:
1294 DPRINTF("state changed to DISCARDING on %s\n",
1295 bp
->bp_ifp
->if_xname
);
1298 case BSTP_IFSTATE_LEARNING
:
1299 DPRINTF("state changed to LEARNING on %s\n",
1300 bp
->bp_ifp
->if_xname
);
1302 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1303 bp
->bp_protover
== BSTP_PROTO_RSTP
?
1304 bp
->bp_desg_htime
: bp
->bp_desg_fdelay
);
1307 case BSTP_IFSTATE_FORWARDING
:
1308 DPRINTF("state changed to FORWARDING on %s\n",
1309 bp
->bp_ifp
->if_xname
);
1311 bstp_timer_stop(&bp
->bp_forward_delay_timer
);
1312 /* Record that we enabled forwarding */
1313 bp
->bp_forward_transitions
++;
1317 /* notify the parent bridge */
1318 bstp_task_enqueue(&bp
->bp_statetask
);
1322 bstp_set_port_role(struct bstp_port
*bp
, int role
)
1324 struct bstp_state
*bs
= bp
->bp_bs
;
1326 if (bp
->bp_role
== role
)
1329 /* perform pre-change tasks */
1330 switch (bp
->bp_role
) {
1331 case BSTP_ROLE_DISABLED
:
1332 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1333 bp
->bp_desg_max_age
);
1336 case BSTP_ROLE_BACKUP
:
1337 bstp_timer_start(&bp
->bp_recent_backup_timer
,
1338 bp
->bp_desg_htime
* 2);
1340 case BSTP_ROLE_ALTERNATE
:
1341 bstp_timer_start(&bp
->bp_forward_delay_timer
,
1342 bp
->bp_desg_fdelay
);
1348 case BSTP_ROLE_ROOT
:
1349 bstp_timer_start(&bp
->bp_recent_root_timer
,
1350 BSTP_DEFAULT_FORWARD_DELAY
);
1355 /* clear values not carried between roles */
1356 bp
->bp_proposing
= 0;
1357 bs
->bs_allsynced
= 0;
1359 /* initialise the new role */
1360 switch (bp
->bp_role
) {
1361 case BSTP_ROLE_DISABLED
:
1362 case BSTP_ROLE_ALTERNATE
:
1363 case BSTP_ROLE_BACKUP
:
1364 DPRINTF("%s role -> ALT/BACK/DISABLED\n",
1365 bp
->bp_ifp
->if_xname
);
1366 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1367 bstp_timer_stop(&bp
->bp_recent_root_timer
);
1368 bstp_timer_latch(&bp
->bp_forward_delay_timer
);
1374 case BSTP_ROLE_ROOT
:
1375 DPRINTF("%s role -> ROOT\n",
1376 bp
->bp_ifp
->if_xname
);
1377 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
1378 bstp_timer_latch(&bp
->bp_recent_root_timer
);
1379 bp
->bp_proposing
= 0;
1382 case BSTP_ROLE_DESIGNATED
:
1383 DPRINTF("%s role -> DESIGNATED\n",
1384 bp
->bp_ifp
->if_xname
);
1385 bstp_timer_start(&bp
->bp_hello_timer
,
1391 /* let the TC state know that the role changed */
1396 bstp_set_port_proto(struct bstp_port
*bp
, int proto
)
1398 struct bstp_state
*bs
= bp
->bp_bs
;
1400 /* supported protocol versions */
1402 case BSTP_PROTO_STP
:
1403 /* we can downgrade protocols only */
1404 bstp_timer_stop(&bp
->bp_migrate_delay_timer
);
1405 /* clear unsupported features */
1406 bp
->bp_operedge
= 0;
1407 /* STP compat mode only uses 16 bits of the 32 */
1408 if (bp
->bp_path_cost
> 65535)
1409 bp
->bp_path_cost
= 65535;
1412 case BSTP_PROTO_RSTP
:
1413 bstp_timer_start(&bp
->bp_migrate_delay_timer
,
1414 bs
->bs_migration_delay
);
1418 DPRINTF("Unsupported STP version %d\n", proto
);
1422 bp
->bp_protover
= proto
;
1423 bp
->bp_flags
&= ~BSTP_PORT_CANMIGRATE
;
1427 bstp_set_port_tc(struct bstp_port
*bp
, int state
)
1429 struct bstp_state
*bs
= bp
->bp_bs
;
1431 bp
->bp_tcstate
= state
;
1433 /* initialise the new state */
1434 switch (bp
->bp_tcstate
) {
1435 case BSTP_TCSTATE_ACTIVE
:
1436 DPRINTF("%s -> TC_ACTIVE\n", bp
->bp_ifp
->if_xname
);
1440 case BSTP_TCSTATE_INACTIVE
:
1441 bstp_timer_stop(&bp
->bp_tc_timer
);
1442 /* flush routes on the parent bridge */
1443 bp
->bp_fdbflush
= 1;
1444 bstp_task_enqueue(&bp
->bp_rtagetask
);
1446 DPRINTF("%s -> TC_INACTIVE\n", bp
->bp_ifp
->if_xname
);
1449 case BSTP_TCSTATE_LEARNING
:
1454 DPRINTF("%s -> TC_LEARNING\n", bp
->bp_ifp
->if_xname
);
1457 case BSTP_TCSTATE_DETECTED
:
1458 bstp_set_timer_tc(bp
);
1459 bstp_set_other_tcprop(bp
);
1460 /* send out notification */
1461 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1462 bstp_transmit(bs
, bp
);
1463 /* reviewed for getmicrotime usage */
1464 getmicrotime(&bs
->bs_last_tc_time
);
1465 DPRINTF("%s -> TC_DETECTED\n", bp
->bp_ifp
->if_xname
);
1466 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1469 case BSTP_TCSTATE_TCN
:
1470 bstp_set_timer_tc(bp
);
1471 DPRINTF("%s -> TC_TCN\n", bp
->bp_ifp
->if_xname
);
1473 case BSTP_TCSTATE_TC
:
1476 if (bp
->bp_role
== BSTP_ROLE_DESIGNATED
)
1479 bstp_set_other_tcprop(bp
);
1480 DPRINTF("%s -> TC_TC\n", bp
->bp_ifp
->if_xname
);
1481 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1484 case BSTP_TCSTATE_PROPAG
:
1485 /* flush routes on the parent bridge */
1486 bp
->bp_fdbflush
= 1;
1487 bstp_task_enqueue(&bp
->bp_rtagetask
);
1489 bstp_set_timer_tc(bp
);
1490 DPRINTF("%s -> TC_PROPAG\n", bp
->bp_ifp
->if_xname
);
1491 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1494 case BSTP_TCSTATE_ACK
:
1495 bstp_timer_stop(&bp
->bp_tc_timer
);
1497 DPRINTF("%s -> TC_ACK\n", bp
->bp_ifp
->if_xname
);
1498 bp
->bp_tcstate
= BSTP_TCSTATE_ACTIVE
; /* UCT */
1504 bstp_set_timer_tc(struct bstp_port
*bp
)
1506 struct bstp_state
*bs
= bp
->bp_bs
;
1508 if (bp
->bp_tc_timer
.active
)
1511 switch (bp
->bp_protover
) {
1512 case BSTP_PROTO_RSTP
:
1513 bstp_timer_start(&bp
->bp_tc_timer
,
1514 bp
->bp_desg_htime
+ BSTP_TICK_VAL
);
1515 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
1518 case BSTP_PROTO_STP
:
1519 bstp_timer_start(&bp
->bp_tc_timer
,
1520 bs
->bs_root_max_age
+ bs
->bs_root_fdelay
);
1526 bstp_set_timer_msgage(struct bstp_port
*bp
)
1528 if (bp
->bp_port_msg_age
+ BSTP_MESSAGE_AGE_INCR
<=
1529 bp
->bp_port_max_age
) {
1530 bstp_timer_start(&bp
->bp_message_age_timer
,
1531 bp
->bp_port_htime
* 3);
1533 /* expires immediately */
1534 bstp_timer_start(&bp
->bp_message_age_timer
, 0);
1538 bstp_rerooted(struct bstp_state
*bs
, struct bstp_port
*bp
)
1540 struct bstp_port
*bp2
;
1543 LIST_FOREACH(bp2
, &bs
->bs_bplist
, bp_next
) {
1546 if (bp2
->bp_recent_root_timer
.active
) {
1555 bstp_set_htime(struct bstp_state
*bs
, int t
)
1557 /* convert seconds to ticks */
1560 /* value can only be changed in leagacy stp mode */
1561 if (bs
->bs_protover
!= BSTP_PROTO_STP
)
1564 if (t
< BSTP_MIN_HELLO_TIME
|| t
> BSTP_MAX_HELLO_TIME
)
1568 bs
->bs_bridge_htime
= t
;
1575 bstp_set_fdelay(struct bstp_state
*bs
, int t
)
1577 /* convert seconds to ticks */
1580 if (t
< BSTP_MIN_FORWARD_DELAY
|| t
> BSTP_MAX_FORWARD_DELAY
)
1584 bs
->bs_bridge_fdelay
= t
;
1591 bstp_set_maxage(struct bstp_state
*bs
, int t
)
1593 /* convert seconds to ticks */
1596 if (t
< BSTP_MIN_MAX_AGE
|| t
> BSTP_MAX_MAX_AGE
)
1600 bs
->bs_bridge_max_age
= t
;
1607 bstp_set_holdcount(struct bstp_state
*bs
, int count
)
1609 struct bstp_port
*bp
;
1611 if (count
< BSTP_MIN_HOLD_COUNT
||
1612 count
> BSTP_MAX_HOLD_COUNT
)
1616 bs
->bs_txholdcount
= count
;
1617 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
1624 bstp_set_protocol(struct bstp_state
*bs
, int proto
)
1626 struct bstp_port
*bp
;
1629 /* Supported protocol versions */
1630 case BSTP_PROTO_STP
:
1631 case BSTP_PROTO_RSTP
:
1639 bs
->bs_protover
= proto
;
1640 bs
->bs_bridge_htime
= BSTP_DEFAULT_HELLO_TIME
;
1641 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1643 bp
->bp_infois
= BSTP_INFO_DISABLED
;
1645 bstp_set_port_proto(bp
, bs
->bs_protover
);
1646 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
1647 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
1648 bstp_timer_stop(&bp
->bp_recent_backup_timer
);
1656 bstp_set_priority(struct bstp_state
*bs
, int pri
)
1658 if (pri
< 0 || pri
> BSTP_MAX_PRIORITY
)
1661 /* Limit to steps of 4096 */
1665 bs
->bs_bridge_priority
= pri
;
1672 bstp_set_port_priority(struct bstp_port
*bp
, int pri
)
1674 struct bstp_state
*bs
= bp
->bp_bs
;
1676 if (pri
< 0 || pri
> BSTP_MAX_PORT_PRIORITY
)
1679 /* Limit to steps of 16 */
1683 bp
->bp_priority
= pri
;
1690 bstp_set_path_cost(struct bstp_port
*bp
, uint32_t path_cost
)
1692 struct bstp_state
*bs
= bp
->bp_bs
;
1694 if (path_cost
> BSTP_MAX_PATH_COST
)
1697 /* STP compat mode only uses 16 bits of the 32 */
1698 if (bp
->bp_protover
== BSTP_PROTO_STP
&& path_cost
> 65535)
1703 if (path_cost
== 0) { /* use auto */
1704 bp
->bp_flags
&= ~BSTP_PORT_ADMCOST
;
1705 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
1707 bp
->bp_path_cost
= path_cost
;
1708 bp
->bp_flags
|= BSTP_PORT_ADMCOST
;
1716 bstp_set_edge(struct bstp_port
*bp
, int set
)
1718 struct bstp_state
*bs
= bp
->bp_bs
;
1721 if ((bp
->bp_operedge
= set
) == 0)
1722 bp
->bp_flags
&= ~BSTP_PORT_ADMEDGE
;
1724 bp
->bp_flags
|= BSTP_PORT_ADMEDGE
;
1730 bstp_set_autoedge(struct bstp_port
*bp
, int set
)
1732 struct bstp_state
*bs
= bp
->bp_bs
;
1736 bp
->bp_flags
|= BSTP_PORT_AUTOEDGE
;
1737 /* we may be able to transition straight to edge */
1738 if (bp
->bp_edge_delay_timer
.active
== 0)
1739 bstp_edge_delay_expiry(bs
, bp
);
1741 bp
->bp_flags
&= ~BSTP_PORT_AUTOEDGE
;
1747 bstp_set_ptp(struct bstp_port
*bp
, int set
)
1749 struct bstp_state
*bs
= bp
->bp_bs
;
1752 bp
->bp_ptp_link
= set
;
1758 bstp_set_autoptp(struct bstp_port
*bp
, int set
)
1760 struct bstp_state
*bs
= bp
->bp_bs
;
1764 bp
->bp_flags
|= BSTP_PORT_AUTOPTP
;
1765 if (bp
->bp_role
!= BSTP_ROLE_DISABLED
)
1766 bstp_ifupdstatus(bs
, bp
);
1768 bp
->bp_flags
&= ~BSTP_PORT_AUTOPTP
;
1774 * Calculate the path cost according to the link speed.
1777 bstp_calc_path_cost(struct bstp_port
*bp
)
1779 struct ifnet
*ifp
= bp
->bp_ifp
;
1782 /* If the priority has been manually set then retain the value */
1783 if (bp
->bp_flags
& BSTP_PORT_ADMCOST
)
1784 return bp
->bp_path_cost
;
1786 if (bp
->bp_if_link_state
== LINK_STATE_DOWN
) {
1787 /* Recalc when the link comes up again */
1788 bp
->bp_flags
|= BSTP_PORT_PNDCOST
;
1789 return (BSTP_DEFAULT_PATH_COST
);
1792 if (ifp
->if_baudrate
< 1000)
1793 return (BSTP_DEFAULT_PATH_COST
);
1795 /* formula from section 17.14, IEEE Std 802.1D-2004 */
1796 path_cost
= 20000000000ULL / (ifp
->if_baudrate
/ 1000);
1798 if (path_cost
> BSTP_MAX_PATH_COST
)
1799 path_cost
= BSTP_MAX_PATH_COST
;
1801 /* STP compat mode only uses 16 bits of the 32 */
1802 if (bp
->bp_protover
== BSTP_PROTO_STP
&& path_cost
> 65535)
1809 * Notify the bridge that a port state has changed, we need to do this from a
1810 * taskqueue to avoid a LOR.
1813 bstp_notify_state(void *arg
, __unused
int pending
)
1815 struct bstp_port
*bp
= (struct bstp_port
*)arg
;
1816 struct bstp_state
*bs
= bp
->bp_bs
;
1818 if (bp
->bp_active
== 1 && bs
->bs_state_cb
!= NULL
)
1819 (*bs
->bs_state_cb
)(bp
->bp_ifp
, bp
->bp_state
);
1823 * Flush the routes on the bridge port, we need to do this from a
1824 * taskqueue to avoid a LOR.
1827 bstp_notify_rtage(void *arg
, __unused
int pending
)
1829 struct bstp_port
*bp
= (struct bstp_port
*)arg
;
1830 struct bstp_state
*bs
= bp
->bp_bs
;
1834 switch (bp
->bp_protover
) {
1835 case BSTP_PROTO_STP
:
1836 /* convert to seconds */
1837 age
= bp
->bp_desg_fdelay
/ BSTP_TICK_VAL
;
1840 case BSTP_PROTO_RSTP
:
1846 if (bp
->bp_active
== 1 && bs
->bs_rtage_cb
!= NULL
)
1847 (*bs
->bs_rtage_cb
)(bp
->bp_ifp
, age
);
1849 /* flush is complete */
1851 bp
->bp_fdbflush
= 0;
1856 bstp_linkstate(struct ifnet
*ifp
, __unused
int state
)
1858 struct bstp_state
*bs
;
1859 struct bstp_port
*bp
;
1861 /* search for the stp port */
1862 lck_mtx_lock(bstp_list_mtx
);
1863 LIST_FOREACH(bs
, &bstp_list
, bs_list
) {
1865 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1866 if (bp
->bp_ifp
== ifp
) {
1867 bstp_ifupdstatus(bs
, bp
);
1868 bstp_update_state(bs
, bp
);
1869 /* it only exists once so return */
1871 lck_mtx_unlock(bstp_list_mtx
);
1877 lck_mtx_unlock(bstp_list_mtx
);
1881 bstp_ifupdstatus(struct bstp_state
*bs
, struct bstp_port
*bp
)
1883 struct ifnet
*ifp
= bp
->bp_ifp
;
1884 struct ifmediareq ifmr
;
1887 BSTP_LOCK_ASSERT(bs
);
1889 bzero((char *)&ifmr
, sizeof(ifmr
));
1890 error
= (*ifp
->if_ioctl
)(ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
);
1892 if ((error
== 0) && (ifp
->if_flags
& IFF_UP
)) {
1893 if (ifmr
.ifm_status
& IFM_ACTIVE
) {
1894 /* A full-duplex link is assumed to be point to point */
1895 if (bp
->bp_flags
& BSTP_PORT_AUTOPTP
) {
1897 ifmr
.ifm_active
& IFM_FDX
? 1 : 0;
1900 /* Calc the cost if the link was down previously */
1901 if (bp
->bp_flags
& BSTP_PORT_PNDCOST
) {
1902 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
1903 bp
->bp_flags
&= ~BSTP_PORT_PNDCOST
;
1906 if (bp
->bp_role
== BSTP_ROLE_DISABLED
)
1907 bstp_enable_port(bs
, bp
);
1909 if (bp
->bp_role
!= BSTP_ROLE_DISABLED
) {
1910 bstp_disable_port(bs
, bp
);
1911 if ((bp
->bp_flags
& BSTP_PORT_ADMEDGE
) &&
1912 bp
->bp_protover
== BSTP_PROTO_RSTP
)
1913 bp
->bp_operedge
= 1;
1919 if (bp
->bp_infois
!= BSTP_INFO_DISABLED
)
1920 bstp_disable_port(bs
, bp
);
1924 bstp_enable_port(struct bstp_state
*bs
, struct bstp_port
*bp
)
1926 bp
->bp_infois
= BSTP_INFO_AGED
;
1927 bstp_assign_roles(bs
);
1931 bstp_disable_port(struct bstp_state
*bs
, struct bstp_port
*bp
)
1933 bp
->bp_infois
= BSTP_INFO_DISABLED
;
1934 bstp_assign_roles(bs
);
1938 bstp_tick(void *arg
)
1940 struct bstp_state
*bs
= arg
;
1941 struct bstp_port
*bp
;
1946 if (bs
->bs_running
== 0)
1949 /* slow timer to catch missed link events */
1950 if (bstp_timer_expired(&bs
->bs_link_timer
)) {
1951 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
1952 bstp_ifupdstatus(bs
, bp
);
1953 bstp_timer_start(&bs
->bs_link_timer
, BSTP_LINK_TIMER
);
1956 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
1957 /* no events need to happen for these */
1958 bstp_timer_expired(&bp
->bp_tc_timer
);
1959 bstp_timer_expired(&bp
->bp_recent_root_timer
);
1960 bstp_timer_expired(&bp
->bp_forward_delay_timer
);
1961 bstp_timer_expired(&bp
->bp_recent_backup_timer
);
1963 if (bstp_timer_expired(&bp
->bp_hello_timer
))
1964 bstp_hello_timer_expiry(bs
, bp
);
1966 if (bstp_timer_expired(&bp
->bp_message_age_timer
))
1967 bstp_message_age_expiry(bs
, bp
);
1969 if (bstp_timer_expired(&bp
->bp_migrate_delay_timer
))
1970 bstp_migrate_delay_expiry(bs
, bp
);
1972 if (bstp_timer_expired(&bp
->bp_edge_delay_timer
))
1973 bstp_edge_delay_expiry(bs
, bp
);
1975 /* update the various state machines for the port */
1976 bstp_update_state(bs
, bp
);
1978 if (bp
->bp_txcount
> 0)
1986 bsd_timeout(bstp_tick
, bs
, &ts
);
1990 bstp_timer_start(struct bstp_timer
*t
, uint16_t v
)
1998 bstp_timer_stop(struct bstp_timer
*t
)
2006 bstp_timer_latch(struct bstp_timer
*t
)
2013 bstp_timer_expired(struct bstp_timer
*t
)
2015 if (t
->active
== 0 || t
->latched
)
2017 t
->value
-= BSTP_TICK_VAL
;
2018 if (t
->value
<= 0) {
2026 bstp_hello_timer_expiry(struct bstp_state
*bs
, struct bstp_port
*bp
)
2028 if ((bp
->bp_flags
& BSTP_PORT_NEWINFO
) ||
2029 bp
->bp_role
== BSTP_ROLE_DESIGNATED
||
2030 (bp
->bp_role
== BSTP_ROLE_ROOT
&&
2031 bp
->bp_tc_timer
.active
== 1)) {
2032 bstp_timer_start(&bp
->bp_hello_timer
, bp
->bp_desg_htime
);
2033 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
2034 bstp_transmit(bs
, bp
);
2039 bstp_message_age_expiry(struct bstp_state
*bs
, struct bstp_port
*bp
)
2041 if (bp
->bp_infois
== BSTP_INFO_RECEIVED
) {
2042 bp
->bp_infois
= BSTP_INFO_AGED
;
2043 bstp_assign_roles(bs
);
2044 DPRINTF("aged info on %s\n", bp
->bp_ifp
->if_xname
);
2049 bstp_migrate_delay_expiry(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
)
2051 bp
->bp_flags
|= BSTP_PORT_CANMIGRATE
;
2055 bstp_edge_delay_expiry(__unused
struct bstp_state
*bs
, struct bstp_port
*bp
)
2057 if ((bp
->bp_flags
& BSTP_PORT_AUTOEDGE
) &&
2058 bp
->bp_protover
== BSTP_PROTO_RSTP
&& bp
->bp_proposing
&&
2059 bp
->bp_role
== BSTP_ROLE_DESIGNATED
) {
2060 bp
->bp_operedge
= 1;
2061 DPRINTF("%s -> edge port\n", bp
->bp_ifp
->if_xname
);
2066 bstp_addr_cmp(const uint8_t *a
, const uint8_t *b
)
2070 for (i
= 0, d
= 0; i
< ETHER_ADDR_LEN
&& d
== 0; i
++) {
2071 d
= ((int)a
[i
]) - ((int)b
[i
]);
2078 * compare the bridge address component of the bridgeid
2081 bstp_same_bridgeid(uint64_t id1
, uint64_t id2
)
2083 u_char addr1
[ETHER_ADDR_LEN
];
2084 u_char addr2
[ETHER_ADDR_LEN
];
2086 PV2ADDR(id1
, addr1
);
2087 PV2ADDR(id2
, addr2
);
2089 if (bstp_addr_cmp(addr1
, addr2
) == 0)
2096 bstp_reinit(struct bstp_state
*bs
)
2098 struct bstp_port
*bp
;
2099 struct ifnet
*ifp
, *mif
;
2101 static const u_char llzero
[ETHER_ADDR_LEN
]; /* 00:00:00:00:00:00 */
2103 BSTP_LOCK_ASSERT(bs
);
2107 * Search through the Ethernet adapters and find the one with the
2108 * lowest value. The adapter which we take the MAC address from does
2109 * not need to be part of the bridge, it just needs to be a unique
2112 ifnet_head_lock_shared();
2113 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
2114 if (ifp
->if_type
!= IFT_ETHER
)
2117 if (bstp_addr_cmp(ifnet_lladdr(ifp
), llzero
) == 0)
2124 if (bstp_addr_cmp(ifnet_lladdr(ifp
), ifnet_lladdr(mif
)) < 0) {
2131 if (LIST_EMPTY(&bs
->bs_bplist
) || mif
== NULL
) {
2132 /* Set the bridge and root id (lower bits) to zero */
2133 bs
->bs_bridge_pv
.pv_dbridge_id
=
2134 ((uint64_t)bs
->bs_bridge_priority
) << 48;
2135 bs
->bs_bridge_pv
.pv_root_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
2136 bs
->bs_root_pv
= bs
->bs_bridge_pv
;
2137 /* Disable any remaining ports, they will have no MAC address */
2138 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2139 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2140 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
2142 bsd_untimeout(bstp_tick
, bs
);
2146 e_addr
= ifnet_lladdr(mif
);
2147 bs
->bs_bridge_pv
.pv_dbridge_id
=
2148 (((uint64_t)bs
->bs_bridge_priority
) << 48) |
2149 (((uint64_t)e_addr
[0]) << 40) |
2150 (((uint64_t)e_addr
[1]) << 32) |
2151 (((uint64_t)e_addr
[2]) << 24) |
2152 (((uint64_t)e_addr
[3]) << 16) |
2153 (((uint64_t)e_addr
[4]) << 8) |
2154 (((uint64_t)e_addr
[5]));
2156 bs
->bs_bridge_pv
.pv_root_id
= bs
->bs_bridge_pv
.pv_dbridge_id
;
2157 bs
->bs_bridge_pv
.pv_cost
= 0;
2158 bs
->bs_bridge_pv
.pv_dport_id
= 0;
2159 bs
->bs_bridge_pv
.pv_port_id
= 0;
2162 bsd_untimeout(bstp_tick
, bs
);
2164 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
) {
2165 bp
->bp_port_id
= (bp
->bp_priority
<< 8) |
2166 (bp
->bp_ifp
->if_index
& 0xfff);
2167 bstp_ifupdstatus(bs
, bp
);
2170 bstp_assign_roles(bs
);
2171 bstp_timer_start(&bs
->bs_link_timer
, BSTP_LINK_TIMER
);
2175 bstp_attach(struct bstp_state
*bs
, struct bstp_cb_ops
*cb
)
2178 LIST_INIT(&bs
->bs_bplist
);
2180 bs
->bs_bridge_max_age
= BSTP_DEFAULT_MAX_AGE
;
2181 bs
->bs_bridge_htime
= BSTP_DEFAULT_HELLO_TIME
;
2182 bs
->bs_bridge_fdelay
= BSTP_DEFAULT_FORWARD_DELAY
;
2183 bs
->bs_bridge_priority
= BSTP_DEFAULT_BRIDGE_PRIORITY
;
2184 bs
->bs_hold_time
= BSTP_DEFAULT_HOLD_TIME
;
2185 bs
->bs_migration_delay
= BSTP_DEFAULT_MIGRATE_DELAY
;
2186 bs
->bs_txholdcount
= BSTP_DEFAULT_HOLD_COUNT
;
2187 bs
->bs_protover
= BSTP_PROTO_RSTP
;
2188 bs
->bs_state_cb
= cb
->bcb_state
;
2189 bs
->bs_rtage_cb
= cb
->bcb_rtage
;
2191 /* reviewed for getmicrotime usage */
2192 getmicrotime(&bs
->bs_last_tc_time
);
2194 lck_mtx_lock(bstp_list_mtx
);
2195 LIST_INSERT_HEAD(&bstp_list
, bs
, bs_list
);
2196 lck_mtx_unlock(bstp_list_mtx
);
2200 bstp_detach(struct bstp_state
*bs
)
2202 KASSERT(LIST_EMPTY(&bs
->bs_bplist
), ("bstp still active"));
2204 lck_mtx_lock(bstp_list_mtx
);
2205 LIST_REMOVE(bs
, bs_list
);
2206 lck_mtx_unlock(bstp_list_mtx
);
2207 bsd_untimeout(bstp_tick
, bs
);
2208 BSTP_LOCK_DESTROY(bs
);
2212 bstp_init(struct bstp_state
*bs
)
2220 bsd_timeout(bstp_tick
, bs
, &ts
);
2227 bstp_stop(struct bstp_state
*bs
)
2229 struct bstp_port
*bp
;
2233 LIST_FOREACH(bp
, &bs
->bs_bplist
, bp_next
)
2234 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
2237 bsd_untimeout(bstp_tick
, bs
);
2242 bstp_create(struct bstp_state
*bs
, struct bstp_port
*bp
, struct ifnet
*ifp
)
2244 bzero(bp
, sizeof(struct bstp_port
));
2249 bp
->bp_priority
= BSTP_DEFAULT_PORT_PRIORITY
;
2250 BSTP_TASK_INIT(&bp
->bp_statetask
, bstp_notify_state
, bp
);
2251 BSTP_TASK_INIT(&bp
->bp_rtagetask
, bstp_notify_rtage
, bp
);
2254 bp
->bp_infois
= BSTP_INFO_DISABLED
;
2255 bp
->bp_flags
= BSTP_PORT_AUTOEDGE
|BSTP_PORT_AUTOPTP
;
2256 bstp_set_port_state(bp
, BSTP_IFSTATE_DISCARDING
);
2257 bstp_set_port_proto(bp
, bs
->bs_protover
);
2258 bstp_set_port_role(bp
, BSTP_ROLE_DISABLED
);
2259 bstp_set_port_tc(bp
, BSTP_TCSTATE_INACTIVE
);
2260 bp
->bp_path_cost
= bstp_calc_path_cost(bp
);
2266 bstp_enable(struct bstp_port
*bp
)
2268 struct bstp_state
*bs
= bp
->bp_bs
;
2269 struct ifnet
*ifp
= bp
->bp_ifp
;
2271 KASSERT(bp
->bp_active
== 0, ("already a bstp member"));
2273 switch (ifp
->if_type
) {
2274 case IFT_ETHER
: /* These can do spanning tree. */
2277 /* Nothing else can. */
2282 LIST_INSERT_HEAD(&bs
->bs_bplist
, bp
, bp_next
);
2284 bp
->bp_flags
|= BSTP_PORT_NEWINFO
;
2286 bstp_update_roles(bs
, bp
);
2292 bstp_disable(struct bstp_port
*bp
)
2294 struct bstp_state
*bs
= bp
->bp_bs
;
2296 KASSERT(bp
->bp_active
== 1, ("not a bstp member"));
2299 bstp_disable_port(bs
, bp
);
2300 LIST_REMOVE(bp
, bp_next
);
2307 * The bstp_port structure is about to be freed by the parent bridge.
2310 bstp_destroy(struct bstp_port
*bp
)
2312 KASSERT(bp
->bp_active
== 0, ("port is still attached"));
2313 bstp_task_drain(&bp
->bp_statetask
);
2314 bstp_task_drain(&bp
->bp_rtagetask
);
2318 __private_extern__
void
2321 lck_grp_attr_t
*lck_grp_attr
= NULL
;
2323 lck_grp_attr
= lck_grp_attr_alloc_init();
2324 bstp_lock_grp
= lck_grp_alloc_init("bstp", lck_grp_attr
);
2325 bstp_lock_attr
= lck_attr_alloc_init();
2327 lck_attr_setdebug(bstp_lock_attr
);
2329 lck_mtx_init(bstp_list_mtx
, bstp_lock_grp
, bstp_lock_attr
);
2330 lck_grp_attr_free(lck_grp_attr
);
2332 LIST_INIT(&bstp_list
);
2334 bstp_create_task_thread();
2340 bstp_create_task_thread(void)
2342 kern_return_t error
;
2344 lck_grp_attr_t
*lck_grp_attr
= NULL
;
2346 lck_grp_attr
= lck_grp_attr_alloc_init();
2347 bstp_task_grp
= lck_grp_alloc_init("bstp_task", lck_grp_attr
);
2348 bstp_task_attr
= lck_attr_alloc_init();
2350 lck_attr_setdebug(bstp_task_attr
);
2352 lck_mtx_init(bstp_task_mtx
, bstp_lock_grp
, bstp_lock_attr
);
2353 lck_grp_attr_free(lck_grp_attr
);
2355 error
= kernel_thread_start((thread_continue_t
)bstp_task_thread_func
, NULL
, &bstp_task_thread
);
2360 bstp_task_thread_func(void)
2362 struct bstp_task
*bt
, *tvar
;
2364 lck_mtx_lock(bstp_task_mtx
);
2367 while(TAILQ_EMPTY(&bstp_task_queue
)) {
2368 wakeup(&bstp_task_queue_running
);
2369 msleep(&bstp_task_queue
, bstp_task_mtx
, PZERO
, "bstp_task_queue", NULL
);
2372 TAILQ_FOREACH_SAFE(bt
, &bstp_task_queue
, bt_next
, tvar
) {
2373 int count
= bt
->bt_count
;
2377 bstp_task_queue_running
= bt
;
2378 lck_mtx_unlock(bstp_task_mtx
);
2380 (*bt
->bt_func
)(bt
->bt_context
, count
);
2382 lck_mtx_lock(bstp_task_mtx
);
2383 bstp_task_queue_running
= NULL
;
2385 if (bt
->bt_count
== 0)
2386 TAILQ_REMOVE(&bstp_task_queue
, bt
, bt_next
);
2394 bstp_task_enqueue(struct bstp_task
*bt
)
2396 lck_mtx_lock(bstp_task_mtx
);
2400 lck_mtx_unlock(bstp_task_mtx
);
2401 wakeup(&bstp_task_queue
);
2406 TAILQ_INSERT_TAIL(&bstp_task_queue
, bt
, bt_next
);
2408 lck_mtx_unlock(bstp_task_mtx
);
2410 wakeup(&bstp_task_queue
);
2414 bstp_task_drain(struct bstp_task
*bt
)
2416 lck_mtx_lock(bstp_task_mtx
);
2418 while (bt
->bt_count
!= 0 || bstp_task_queue_running
== bt
) {
2419 wakeup(&bstp_task_queue
);
2420 msleep(&bstp_task_queue_running
, bstp_task_mtx
, PZERO
, "bstp_task_queue", NULL
);
2422 lck_mtx_unlock(bstp_task_mtx
);