[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

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