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