The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/bridgestp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e67c100f6c4b7b6fb6ce1ca31d59ade1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.