[BACK]Return to bridgestp.c CVS log [TXT][DIR] Up to [local] / sys / net

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