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


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

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

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

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

Cache object: 35a04a8f70a6270adaff8b70b1793073


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