LCOV - code coverage report
Current view: top level - net - bridgestp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1083 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 56 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13