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

Cache object: 38e3acd1169d1cb65c3689b279297cdb


[ 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.