Annotation of sys/net/bridgestp.c, Revision 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