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

Cache object: 25aa72ef01fc03f7b1353673b7a346a8


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