root/net/bridgestp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. LIST_HEAD
  2. bstp_transmit
  3. bstp_transmit_bpdu
  4. bstp_transmit_tcn
  5. bstp_decode_bpdu
  6. bstp_send_bpdu
  7. bstp_pdu_flags
  8. bstp_input
  9. bstp_received_stp
  10. bstp_received_rstp
  11. bstp_received_tcn
  12. bstp_received_bpdu
  13. bstp_pdu_rcvtype
  14. bstp_pdu_bettersame
  15. bstp_info_cmp
  16. bstp_info_superior
  17. bstp_assign_roles
  18. bstp_update_state
  19. bstp_update_roles
  20. bstp_update_tc
  21. bstp_update_info
  22. bstp_set_other_tcprop
  23. bstp_set_all_reroot
  24. bstp_set_all_sync
  25. bstp_set_port_state
  26. bstp_set_port_role
  27. bstp_set_port_proto
  28. bstp_set_port_tc
  29. bstp_set_timer_tc
  30. bstp_set_timer_msgage
  31. bstp_rerooted
  32. bstp_calc_path_cost
  33. bstp_notify_rtage
  34. bstp_ifstate
  35. bstp_ifupdstatus
  36. bstp_enable_port
  37. bstp_disable_port
  38. bstp_tick
  39. bstp_timer_start
  40. bstp_timer_stop
  41. bstp_timer_latch
  42. bstp_timer_expired
  43. bstp_hello_timer_expiry
  44. bstp_message_age_expiry
  45. bstp_migrate_delay_expiry
  46. bstp_edge_delay_expiry
  47. bstp_addr_cmp
  48. bstp_same_bridgeid
  49. bstp_initialization
  50. bstp_create
  51. bstp_destroy
  52. bstp_stop
  53. bstp_add
  54. bstp_delete
  55. bstp_getstate
  56. bstp_ifsflags
  57. bstp_ioctl

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

/* [<][>][^][v][top][bottom][index][help] */