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