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


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

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

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

    1 /*      $NetBSD: bridgestp.c,v 1.5 2003/11/28 08:56:48 keihan Exp $     */
    2 
    3 /*
    4  * Copyright (c) 2000 Jason L. Wright (jason@thought.net)
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Jason L. Wright
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   24  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  *
   33  * OpenBSD: bridgestp.c,v 1.5 2001/03/22 03:48:29 jason Exp
   34  */
   35 
   36 /*
   37  * Implementation of the spanning tree protocol as defined in
   38  * ISO/IEC Final DIS 15802-3 (IEEE P802.1D/D17), May 25, 1998.
   39  * (In English: IEEE 802.1D, Draft 17, 1998)
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __FBSDID("$FreeBSD: releng/6.0/sys/net/bridgestp.c 151571 2005-10-23 02:37:28Z thompsa $");
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/mbuf.h>
   48 #include <sys/socket.h>
   49 #include <sys/sockio.h>
   50 #include <sys/kernel.h>
   51 #include <sys/callout.h>
   52 #include <sys/proc.h>
   53 #include <sys/lock.h>
   54 #include <sys/mutex.h>
   55 
   56 #include <net/if.h>
   57 #include <net/if_dl.h>
   58 #include <net/if_types.h>
   59 #include <net/if_llc.h>
   60 #include <net/if_media.h>
   61 
   62 #include <netinet/in.h>
   63 #include <netinet/in_systm.h>
   64 #include <netinet/in_var.h>
   65 #include <netinet/if_ether.h>
   66 #include <net/if_bridgevar.h>
   67 
   68 /* BPDU message types */
   69 #define BSTP_MSGTYPE_CFG        0x00            /* Configuration */
   70 #define BSTP_MSGTYPE_TCN        0x80            /* Topology chg notification */
   71 
   72 /* BPDU flags */
   73 #define BSTP_FLAG_TC            0x01            /* Topology change */
   74 #define BSTP_FLAG_TCA           0x80            /* Topology change ack */
   75 
   76 #define BSTP_MESSAGE_AGE_INCR   (1 * 256)       /* in 256ths of a second */
   77 #define BSTP_TICK_VAL           (1 * 256)       /* in 256ths of a second */
   78 
   79 /*
   80  * Because BPDU's do not make nicely aligned structures, two different
   81  * declarations are used: bstp_?bpdu (wire representation, packed) and
   82  * bstp_*_unit (internal, nicely aligned version).
   83  */
   84 
   85 /* configuration bridge protocol data unit */
   86 struct bstp_cbpdu {
   87         uint8_t         cbu_dsap;               /* LLC: destination sap */
   88         uint8_t         cbu_ssap;               /* LLC: source sap */
   89         uint8_t         cbu_ctl;                /* LLC: control */
   90         uint16_t        cbu_protoid;            /* protocol id */
   91         uint8_t         cbu_protover;           /* protocol version */
   92         uint8_t         cbu_bpdutype;           /* message type */
   93         uint8_t         cbu_flags;              /* flags (below) */
   94 
   95         /* root id */
   96         uint16_t        cbu_rootpri;            /* root priority */
   97         uint8_t cbu_rootaddr[6];        /* root address */
   98 
   99         uint32_t        cbu_rootpathcost;       /* root path cost */
  100 
  101         /* bridge id */
  102         uint16_t        cbu_bridgepri;          /* bridge priority */
  103         uint8_t         cbu_bridgeaddr[6];      /* bridge address */
  104 
  105         uint16_t        cbu_portid;             /* port id */
  106         uint16_t        cbu_messageage;         /* current message age */
  107         uint16_t        cbu_maxage;             /* maximum age */
  108         uint16_t        cbu_hellotime;          /* hello time */
  109         uint16_t        cbu_forwarddelay;       /* forwarding delay */
  110 } __attribute__((__packed__));
  111 
  112 /* topology change notification bridge protocol data unit */
  113 struct bstp_tbpdu {
  114         uint8_t         tbu_dsap;               /* LLC: destination sap */
  115         uint8_t         tbu_ssap;               /* LLC: source sap */
  116         uint8_t         tbu_ctl;                /* LLC: control */
  117         uint16_t        tbu_protoid;            /* protocol id */
  118         uint8_t         tbu_protover;           /* protocol version */
  119         uint8_t         tbu_bpdutype;           /* message type */
  120 } __attribute__((__packed__));
  121 
  122 const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
  123 
  124 void    bstp_initialize_port(struct bridge_softc *, struct bridge_iflist *);
  125 void    bstp_ifupdstatus(struct bridge_softc *, struct bridge_iflist *);
  126 void    bstp_enable_port(struct bridge_softc *, struct bridge_iflist *);
  127 void    bstp_disable_port(struct bridge_softc *, struct bridge_iflist *);
  128 void    bstp_enable_change_detection(struct bridge_iflist *);
  129 void    bstp_disable_change_detection(struct bridge_iflist *);
  130 int     bstp_root_bridge(struct bridge_softc *sc);
  131 int     bstp_supersedes_port_info(struct bridge_softc *,
  132             struct bridge_iflist *, struct bstp_config_unit *);
  133 int     bstp_designated_port(struct bridge_softc *, struct bridge_iflist *);
  134 int     bstp_designated_for_some_port(struct bridge_softc *);
  135 void    bstp_transmit_config(struct bridge_softc *, struct bridge_iflist *);
  136 void    bstp_transmit_tcn(struct bridge_softc *);
  137 void    bstp_received_config_bpdu(struct bridge_softc *,
  138             struct bridge_iflist *, struct bstp_config_unit *);
  139 void    bstp_received_tcn_bpdu(struct bridge_softc *, struct bridge_iflist *,
  140             struct bstp_tcn_unit *);
  141 void    bstp_record_config_information(struct bridge_softc *,
  142             struct bridge_iflist *, struct bstp_config_unit *);
  143 void    bstp_record_config_timeout_values(struct bridge_softc *,
  144             struct bstp_config_unit *);
  145 void    bstp_config_bpdu_generation(struct bridge_softc *);
  146 void    bstp_send_config_bpdu(struct bridge_softc *, struct bridge_iflist *,
  147             struct bstp_config_unit *);
  148 void    bstp_configuration_update(struct bridge_softc *);
  149 void    bstp_root_selection(struct bridge_softc *);
  150 void    bstp_designated_port_selection(struct bridge_softc *);
  151 void    bstp_become_designated_port(struct bridge_softc *,
  152             struct bridge_iflist *);
  153 void    bstp_port_state_selection(struct bridge_softc *);
  154 void    bstp_make_forwarding(struct bridge_softc *, struct bridge_iflist *);
  155 void    bstp_make_blocking(struct bridge_softc *, struct bridge_iflist *);
  156 void    bstp_set_port_state(struct bridge_iflist *, uint8_t);
  157 void    bstp_set_bridge_priority(struct bridge_softc *, uint64_t);
  158 void    bstp_set_port_priority(struct bridge_softc *, struct bridge_iflist *,
  159             uint16_t);
  160 void    bstp_set_path_cost(struct bridge_softc *, struct bridge_iflist *,
  161             uint32_t);
  162 void    bstp_topology_change_detection(struct bridge_softc *);
  163 void    bstp_topology_change_acknowledged(struct bridge_softc *);
  164 void    bstp_acknowledge_topology_change(struct bridge_softc *,
  165             struct bridge_iflist *);
  166 
  167 void    bstp_tick(void *);
  168 void    bstp_timer_start(struct bridge_timer *, uint16_t);
  169 void    bstp_timer_stop(struct bridge_timer *);
  170 int     bstp_timer_expired(struct bridge_timer *, uint16_t);
  171 
  172 void    bstp_hold_timer_expiry(struct bridge_softc *, struct bridge_iflist *);
  173 void    bstp_message_age_timer_expiry(struct bridge_softc *,
  174             struct bridge_iflist *);
  175 void    bstp_forward_delay_timer_expiry(struct bridge_softc *,
  176             struct bridge_iflist *);
  177 void    bstp_topology_change_timer_expiry(struct bridge_softc *);
  178 void    bstp_tcn_timer_expiry(struct bridge_softc *);
  179 void    bstp_hello_timer_expiry(struct bridge_softc *);
  180 
  181 void
  182 bstp_transmit_config(struct bridge_softc *sc, struct bridge_iflist *bif)
  183 {
  184         if (bif->bif_hold_timer.active) {
  185                 bif->bif_config_pending = 1;
  186                 return;
  187         }
  188 
  189         bif->bif_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
  190         bif->bif_config_bpdu.cu_rootid = sc->sc_designated_root;
  191         bif->bif_config_bpdu.cu_root_path_cost = sc->sc_root_path_cost;
  192         bif->bif_config_bpdu.cu_bridge_id = sc->sc_bridge_id;
  193         bif->bif_config_bpdu.cu_port_id = bif->bif_port_id;
  194 
  195         if (bstp_root_bridge(sc))
  196                 bif->bif_config_bpdu.cu_message_age = 0;
  197         else
  198                 bif->bif_config_bpdu.cu_message_age =
  199                     sc->sc_root_port->bif_message_age_timer.value +
  200                     BSTP_MESSAGE_AGE_INCR;
  201 
  202         bif->bif_config_bpdu.cu_max_age = sc->sc_max_age;
  203         bif->bif_config_bpdu.cu_hello_time = sc->sc_hello_time;
  204         bif->bif_config_bpdu.cu_forward_delay = sc->sc_forward_delay;
  205         bif->bif_config_bpdu.cu_topology_change_acknowledgment
  206             = bif->bif_topology_change_acknowledge;
  207         bif->bif_config_bpdu.cu_topology_change = sc->sc_topology_change;
  208 
  209         if (bif->bif_config_bpdu.cu_message_age < sc->sc_max_age) {
  210                 bif->bif_topology_change_acknowledge = 0;
  211                 bif->bif_config_pending = 0;
  212                 bstp_send_config_bpdu(sc, bif, &bif->bif_config_bpdu);
  213                 bstp_timer_start(&bif->bif_hold_timer, 0);
  214         }
  215 }
  216 
  217 void
  218 bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
  219     struct bstp_config_unit *cu)
  220 {
  221         struct ifnet *ifp;
  222         struct mbuf *m;
  223         struct ether_header *eh;
  224         struct bstp_cbpdu bpdu;
  225 
  226         BRIDGE_LOCK_ASSERT(sc);
  227 
  228         ifp = bif->bif_ifp;
  229 
  230         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  231                 return;
  232 
  233         MGETHDR(m, M_DONTWAIT, MT_DATA);
  234         if (m == NULL)
  235                 return;
  236 
  237         eh = mtod(m, struct ether_header *);
  238 
  239         m->m_pkthdr.rcvif = ifp;
  240         m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
  241         m->m_len = m->m_pkthdr.len;
  242 
  243         bpdu.cbu_ssap = bpdu.cbu_dsap = LLC_8021D_LSAP;
  244         bpdu.cbu_ctl = LLC_UI;
  245         bpdu.cbu_protoid = htons(0);
  246         bpdu.cbu_protover = 0;
  247         bpdu.cbu_bpdutype = cu->cu_message_type;
  248         bpdu.cbu_flags = (cu->cu_topology_change ? BSTP_FLAG_TC : 0) |
  249             (cu->cu_topology_change_acknowledgment ? BSTP_FLAG_TCA : 0);
  250 
  251         bpdu.cbu_rootpri = htons(cu->cu_rootid >> 48);
  252         bpdu.cbu_rootaddr[0] = cu->cu_rootid >> 40;
  253         bpdu.cbu_rootaddr[1] = cu->cu_rootid >> 32;
  254         bpdu.cbu_rootaddr[2] = cu->cu_rootid >> 24;
  255         bpdu.cbu_rootaddr[3] = cu->cu_rootid >> 16;
  256         bpdu.cbu_rootaddr[4] = cu->cu_rootid >> 8;
  257         bpdu.cbu_rootaddr[5] = cu->cu_rootid >> 0;
  258 
  259         bpdu.cbu_rootpathcost = htonl(cu->cu_root_path_cost);
  260 
  261         bpdu.cbu_bridgepri = htons(cu->cu_rootid >> 48);
  262         bpdu.cbu_bridgeaddr[0] = cu->cu_rootid >> 40;
  263         bpdu.cbu_bridgeaddr[1] = cu->cu_rootid >> 32;
  264         bpdu.cbu_bridgeaddr[2] = cu->cu_rootid >> 24;
  265         bpdu.cbu_bridgeaddr[3] = cu->cu_rootid >> 16;
  266         bpdu.cbu_bridgeaddr[4] = cu->cu_rootid >> 8;
  267         bpdu.cbu_bridgeaddr[5] = cu->cu_rootid >> 0;
  268 
  269         bpdu.cbu_portid = htons(cu->cu_port_id);
  270         bpdu.cbu_messageage = htons(cu->cu_message_age);
  271         bpdu.cbu_maxage = htons(cu->cu_max_age);
  272         bpdu.cbu_hellotime = htons(cu->cu_hello_time);
  273         bpdu.cbu_forwarddelay = htons(cu->cu_forward_delay);
  274 
  275         memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
  276         memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
  277         eh->ether_type = htons(sizeof(bpdu));
  278 
  279         memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
  280 
  281         /* XXX: safe here?!? */
  282         BRIDGE_UNLOCK(sc);
  283         bridge_enqueue(sc, ifp, m);
  284         BRIDGE_LOCK(sc);
  285 }
  286 
  287 int
  288 bstp_root_bridge(struct bridge_softc *sc)
  289 {
  290         return (sc->sc_designated_root == sc->sc_bridge_id);
  291 }
  292 
  293 int
  294 bstp_supersedes_port_info(struct bridge_softc *sc, struct bridge_iflist *bif,
  295     struct bstp_config_unit *cu)
  296 {
  297         if (cu->cu_rootid < bif->bif_designated_root)
  298                 return (1);
  299         if (cu->cu_rootid > bif->bif_designated_root)
  300                 return (0);
  301 
  302         if (cu->cu_root_path_cost < bif->bif_designated_cost)
  303                 return (1);
  304         if (cu->cu_root_path_cost > bif->bif_designated_cost)
  305                 return (0);
  306 
  307         if (cu->cu_bridge_id < bif->bif_designated_bridge)
  308                 return (1);
  309         if (cu->cu_bridge_id > bif->bif_designated_bridge)
  310                 return (0);
  311 
  312         if (sc->sc_bridge_id != cu->cu_bridge_id)
  313                 return (1);
  314         if (cu->cu_port_id <= bif->bif_designated_port)
  315                 return (1);
  316         return (0);
  317 }
  318 
  319 void
  320 bstp_record_config_information(struct bridge_softc *sc,
  321     struct bridge_iflist *bif, struct bstp_config_unit *cu)
  322 {
  323         bif->bif_designated_root = cu->cu_rootid;
  324         bif->bif_designated_cost = cu->cu_root_path_cost;
  325         bif->bif_designated_bridge = cu->cu_bridge_id;
  326         bif->bif_designated_port = cu->cu_port_id;
  327         bstp_timer_start(&bif->bif_message_age_timer, cu->cu_message_age);
  328 }
  329 
  330 void
  331 bstp_record_config_timeout_values(struct bridge_softc *sc,
  332     struct bstp_config_unit *config)
  333 {
  334         sc->sc_max_age = config->cu_max_age;
  335         sc->sc_hello_time = config->cu_hello_time;
  336         sc->sc_forward_delay = config->cu_forward_delay;
  337         sc->sc_topology_change = config->cu_topology_change;
  338 }
  339 
  340 void
  341 bstp_config_bpdu_generation(struct bridge_softc *sc)
  342 {
  343         struct bridge_iflist *bif;
  344 
  345         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  346                 if ((bif->bif_flags & IFBIF_STP) == 0)
  347                         continue;
  348                 if (bstp_designated_port(sc, bif) &&
  349                     (bif->bif_state != BSTP_IFSTATE_DISABLED))
  350                         bstp_transmit_config(sc, bif);
  351         }
  352 }
  353 
  354 int
  355 bstp_designated_port(struct bridge_softc *sc, struct bridge_iflist *bif)
  356 {
  357         return ((bif->bif_designated_bridge == sc->sc_bridge_id)
  358             && (bif->bif_designated_port == bif->bif_port_id));
  359 }
  360 
  361 void
  362 bstp_transmit_tcn(struct bridge_softc *sc)
  363 {
  364         struct bstp_tbpdu bpdu;
  365         struct bridge_iflist *bif = sc->sc_root_port;
  366         struct ifnet *ifp = bif->bif_ifp;
  367         struct ether_header *eh;
  368         struct mbuf *m;
  369 
  370         BRIDGE_LOCK_ASSERT(sc);
  371 
  372         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  373                 return;
  374 
  375         MGETHDR(m, M_DONTWAIT, MT_DATA);
  376         if (m == NULL)
  377                 return;
  378 
  379         m->m_pkthdr.rcvif = ifp;
  380         m->m_pkthdr.len = sizeof(*eh) + sizeof(bpdu);
  381         m->m_len = m->m_pkthdr.len;
  382 
  383         eh = mtod(m, struct ether_header *);
  384 
  385         memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
  386         memcpy(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN);
  387         eh->ether_type = htons(sizeof(bpdu));
  388 
  389         bpdu.tbu_ssap = bpdu.tbu_dsap = LLC_8021D_LSAP;
  390         bpdu.tbu_ctl = LLC_UI;
  391         bpdu.tbu_protoid = 0;
  392         bpdu.tbu_protover = 0;
  393         bpdu.tbu_bpdutype = BSTP_MSGTYPE_TCN;
  394 
  395         memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
  396 
  397         /* XXX: safe here?!? */
  398         BRIDGE_UNLOCK(sc);
  399         bridge_enqueue(sc, ifp, m);
  400         BRIDGE_LOCK(sc);
  401 }
  402 
  403 void
  404 bstp_configuration_update(struct bridge_softc *sc)
  405 {
  406         BRIDGE_LOCK_ASSERT(sc);
  407 
  408         bstp_root_selection(sc);
  409         bstp_designated_port_selection(sc);
  410 }
  411 
  412 void
  413 bstp_root_selection(struct bridge_softc *sc)
  414 {
  415         struct bridge_iflist *root_port = NULL, *bif;
  416 
  417         BRIDGE_LOCK_ASSERT(sc);
  418 
  419         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  420                 if ((bif->bif_flags & IFBIF_STP) == 0)
  421                         continue;
  422                 if (bstp_designated_port(sc, bif))
  423                         continue;
  424                 if (bif->bif_state == BSTP_IFSTATE_DISABLED)
  425                         continue;
  426                 if (bif->bif_designated_root >= sc->sc_bridge_id)
  427                         continue;
  428                 if (root_port == NULL)
  429                         goto set_port;
  430 
  431                 if (bif->bif_designated_root < root_port->bif_designated_root)
  432                         goto set_port;
  433                 if (bif->bif_designated_root > root_port->bif_designated_root)
  434                         continue;
  435 
  436                 if ((bif->bif_designated_cost + bif->bif_path_cost) <
  437                     (root_port->bif_designated_cost + root_port->bif_path_cost))
  438                         goto set_port;
  439                 if ((bif->bif_designated_cost + bif->bif_path_cost) >
  440                     (root_port->bif_designated_cost + root_port->bif_path_cost))
  441                         continue;
  442 
  443                 if (bif->bif_designated_bridge <
  444                     root_port->bif_designated_bridge)
  445                         goto set_port;
  446                 if (bif->bif_designated_bridge >
  447                     root_port->bif_designated_bridge)
  448                         continue;
  449 
  450                 if (bif->bif_designated_port < root_port->bif_designated_port)
  451                         goto set_port;
  452                 if (bif->bif_designated_port > root_port->bif_designated_port)
  453                         continue;
  454 
  455                 if (bif->bif_port_id >= root_port->bif_port_id)
  456                         continue;
  457 set_port:
  458                 root_port = bif;
  459         }
  460 
  461         sc->sc_root_port = root_port;
  462         if (root_port == NULL) {
  463                 sc->sc_designated_root = sc->sc_bridge_id;
  464                 sc->sc_root_path_cost = 0;
  465         } else {
  466                 sc->sc_designated_root = root_port->bif_designated_root;
  467                 sc->sc_root_path_cost = root_port->bif_designated_cost +
  468                     root_port->bif_path_cost;
  469         }
  470 }
  471 
  472 void
  473 bstp_designated_port_selection(struct bridge_softc *sc)
  474 {
  475         struct bridge_iflist *bif;
  476 
  477         BRIDGE_LOCK_ASSERT(sc);
  478 
  479         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  480                 if ((bif->bif_flags & IFBIF_STP) == 0)
  481                         continue;
  482                 if (bstp_designated_port(sc, bif))
  483                         goto designated;
  484                 if (bif->bif_designated_root != sc->sc_designated_root)
  485                         goto designated;
  486 
  487                 if (sc->sc_root_path_cost < bif->bif_designated_cost)
  488                         goto designated;
  489                 if (sc->sc_root_path_cost > bif->bif_designated_cost)
  490                         continue;
  491 
  492                 if (sc->sc_bridge_id < bif->bif_designated_bridge)
  493                         goto designated;
  494                 if (sc->sc_bridge_id > bif->bif_designated_bridge)
  495                         continue;
  496 
  497                 if (bif->bif_port_id > bif->bif_designated_port)
  498                         continue;
  499 designated:
  500                 bstp_become_designated_port(sc, bif);
  501         }
  502 }
  503 
  504 void
  505 bstp_become_designated_port(struct bridge_softc *sc, struct bridge_iflist *bif)
  506 {
  507         bif->bif_designated_root = sc->sc_designated_root;
  508         bif->bif_designated_cost = sc->sc_root_path_cost;
  509         bif->bif_designated_bridge = sc->sc_bridge_id;
  510         bif->bif_designated_port = bif->bif_port_id;
  511 }
  512 
  513 void
  514 bstp_port_state_selection(struct bridge_softc *sc)
  515 {
  516         struct bridge_iflist *bif;
  517 
  518         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  519                 if ((bif->bif_flags & IFBIF_STP) == 0)
  520                         continue;
  521                 if (bif == sc->sc_root_port) {
  522                         bif->bif_config_pending = 0;
  523                         bif->bif_topology_change_acknowledge = 0;
  524                         bstp_make_forwarding(sc, bif);
  525                 } else if (bstp_designated_port(sc, bif)) {
  526                         bstp_timer_stop(&bif->bif_message_age_timer);
  527                         bstp_make_forwarding(sc, bif);
  528                 } else {
  529                         bif->bif_config_pending = 0;
  530                         bif->bif_topology_change_acknowledge = 0;
  531                         bstp_make_blocking(sc, bif);
  532                 }
  533         }
  534 }
  535 
  536 void
  537 bstp_make_forwarding(struct bridge_softc *sc, struct bridge_iflist *bif)
  538 {
  539         if (bif->bif_state == BSTP_IFSTATE_BLOCKING) {
  540                 bstp_set_port_state(bif, BSTP_IFSTATE_LISTENING);
  541                 bstp_timer_start(&bif->bif_forward_delay_timer, 0);
  542         }
  543 }
  544 
  545 void
  546 bstp_make_blocking(struct bridge_softc *sc, struct bridge_iflist *bif)
  547 {
  548         BRIDGE_LOCK_ASSERT(sc);
  549 
  550         if ((bif->bif_state != BSTP_IFSTATE_DISABLED) &&
  551             (bif->bif_state != BSTP_IFSTATE_BLOCKING)) {
  552                 if ((bif->bif_state == BSTP_IFSTATE_FORWARDING) ||
  553                     (bif->bif_state == BSTP_IFSTATE_LEARNING)) {
  554                         if (bif->bif_change_detection_enabled) {
  555                                 bstp_topology_change_detection(sc);
  556                         }
  557                 }
  558                 bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
  559                 bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
  560                 bstp_timer_stop(&bif->bif_forward_delay_timer);
  561         }
  562 }
  563 
  564 void
  565 bstp_set_port_state(struct bridge_iflist *bif, uint8_t state)
  566 {
  567         bif->bif_state = state;
  568 }
  569 
  570 void
  571 bstp_topology_change_detection(struct bridge_softc *sc)
  572 {
  573         if (bstp_root_bridge(sc)) {
  574                 sc->sc_topology_change = 1;
  575                 bstp_timer_start(&sc->sc_topology_change_timer, 0);
  576         } else if (!sc->sc_topology_change_detected) {
  577                 bstp_transmit_tcn(sc);
  578                 bstp_timer_start(&sc->sc_tcn_timer, 0);
  579         }
  580         sc->sc_topology_change_detected = 1;
  581 }
  582 
  583 void
  584 bstp_topology_change_acknowledged(struct bridge_softc *sc)
  585 {
  586         sc->sc_topology_change_detected = 0;
  587         bstp_timer_stop(&sc->sc_tcn_timer);
  588 }
  589 
  590 void
  591 bstp_acknowledge_topology_change(struct bridge_softc *sc,
  592     struct bridge_iflist *bif)
  593 {
  594         bif->bif_topology_change_acknowledge = 1;
  595         bstp_transmit_config(sc, bif);
  596 }
  597 
  598 struct mbuf *
  599 bstp_input(struct ifnet *ifp, struct mbuf *m)
  600 {
  601         struct bridge_softc *sc = ifp->if_bridge;
  602         struct bridge_iflist *bif = NULL;
  603         struct ether_header *eh;
  604         struct bstp_tbpdu tpdu;
  605         struct bstp_cbpdu cpdu;
  606         struct bstp_config_unit cu;
  607         struct bstp_tcn_unit tu;
  608         uint16_t len;
  609 
  610         BRIDGE_LOCK_ASSERT(sc);
  611 
  612         eh = mtod(m, struct ether_header *);
  613 
  614         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  615                 if ((bif->bif_flags & IFBIF_STP) == 0)
  616                         continue;
  617                 if (bif->bif_ifp == ifp)
  618                         break;
  619         }
  620         if (bif == NULL)
  621                 goto out;
  622 
  623         len = ntohs(eh->ether_type);
  624         if (len < sizeof(tpdu))
  625                 goto out;
  626 
  627         m_adj(m, ETHER_HDR_LEN);
  628 
  629         if (m->m_pkthdr.len > len)
  630                 m_adj(m, len - m->m_pkthdr.len);
  631         if (m->m_len < sizeof(tpdu) &&
  632             (m = m_pullup(m, sizeof(tpdu))) == NULL)
  633                 goto out;
  634 
  635         memcpy(&tpdu, mtod(m, caddr_t), sizeof(tpdu));
  636 
  637         if (tpdu.tbu_dsap != LLC_8021D_LSAP ||
  638             tpdu.tbu_ssap != LLC_8021D_LSAP ||
  639             tpdu.tbu_ctl != LLC_UI)
  640                 goto out;
  641         if (tpdu.tbu_protoid != 0 || tpdu.tbu_protover != 0)
  642                 goto out;
  643 
  644         switch (tpdu.tbu_bpdutype) {
  645         case BSTP_MSGTYPE_TCN:
  646                 tu.tu_message_type = tpdu.tbu_bpdutype;
  647                 bstp_received_tcn_bpdu(sc, bif, &tu);
  648                 break;
  649         case BSTP_MSGTYPE_CFG:
  650                 if (m->m_len < sizeof(cpdu) &&
  651                     (m = m_pullup(m, sizeof(cpdu))) == NULL)
  652                         goto out;
  653                 memcpy(&cpdu, mtod(m, caddr_t), sizeof(cpdu));
  654 
  655                 cu.cu_rootid =
  656                     (((uint64_t)ntohs(cpdu.cbu_rootpri)) << 48) |
  657                     (((uint64_t)cpdu.cbu_rootaddr[0]) << 40) |
  658                     (((uint64_t)cpdu.cbu_rootaddr[1]) << 32) |
  659                     (((uint64_t)cpdu.cbu_rootaddr[2]) << 24) |
  660                     (((uint64_t)cpdu.cbu_rootaddr[3]) << 16) |
  661                     (((uint64_t)cpdu.cbu_rootaddr[4]) << 8) |
  662                     (((uint64_t)cpdu.cbu_rootaddr[5]) << 0);
  663 
  664                 cu.cu_bridge_id =
  665                     (((uint64_t)ntohs(cpdu.cbu_bridgepri)) << 48) |
  666                     (((uint64_t)cpdu.cbu_bridgeaddr[0]) << 40) |
  667                     (((uint64_t)cpdu.cbu_bridgeaddr[1]) << 32) |
  668                     (((uint64_t)cpdu.cbu_bridgeaddr[2]) << 24) |
  669                     (((uint64_t)cpdu.cbu_bridgeaddr[3]) << 16) |
  670                     (((uint64_t)cpdu.cbu_bridgeaddr[4]) << 8) |
  671                     (((uint64_t)cpdu.cbu_bridgeaddr[5]) << 0);
  672 
  673                 cu.cu_root_path_cost = ntohl(cpdu.cbu_rootpathcost);
  674                 cu.cu_message_age = ntohs(cpdu.cbu_messageage);
  675                 cu.cu_max_age = ntohs(cpdu.cbu_maxage);
  676                 cu.cu_hello_time = ntohs(cpdu.cbu_hellotime);
  677                 cu.cu_forward_delay = ntohs(cpdu.cbu_forwarddelay);
  678                 cu.cu_port_id = ntohs(cpdu.cbu_portid);
  679                 cu.cu_message_type = cpdu.cbu_bpdutype;
  680                 cu.cu_topology_change_acknowledgment =
  681                     (cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0;
  682                 cu.cu_topology_change =
  683                     (cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0;
  684                 bstp_received_config_bpdu(sc, bif, &cu);
  685                 break;
  686         default:
  687                 goto out;
  688         }
  689 
  690  out:
  691         if (m)
  692                 m_freem(m);
  693         return (NULL);
  694 }
  695 
  696 void
  697 bstp_received_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
  698     struct bstp_config_unit *cu)
  699 {
  700         int root;
  701 
  702         BRIDGE_LOCK_ASSERT(sc);
  703 
  704         root = bstp_root_bridge(sc);
  705 
  706         if (bif->bif_state != BSTP_IFSTATE_DISABLED) {
  707                 if (bstp_supersedes_port_info(sc, bif, cu)) {
  708                         bstp_record_config_information(sc, bif, cu);
  709                         bstp_configuration_update(sc);
  710                         bstp_port_state_selection(sc);
  711 
  712                         if ((bstp_root_bridge(sc) == 0) && root) {
  713                                 bstp_timer_stop(&sc->sc_hello_timer);
  714 
  715                                 if (sc->sc_topology_change_detected) {
  716                                         bstp_timer_stop(
  717                                             &sc->sc_topology_change_timer);
  718                                         bstp_transmit_tcn(sc);
  719                                         bstp_timer_start(&sc->sc_tcn_timer, 0);
  720                                 }
  721                         }
  722 
  723                         if (bif == sc->sc_root_port) {
  724                                 bstp_record_config_timeout_values(sc, cu);
  725                                 bstp_config_bpdu_generation(sc);
  726 
  727                                 if (cu->cu_topology_change_acknowledgment)
  728                                         bstp_topology_change_acknowledged(sc);
  729                         }
  730                 } else if (bstp_designated_port(sc, bif))
  731                         bstp_transmit_config(sc, bif);
  732         }
  733 }
  734 
  735 void
  736 bstp_received_tcn_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
  737     struct bstp_tcn_unit *tcn)
  738 {
  739         if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
  740             bstp_designated_port(sc, bif)) {
  741                 bstp_topology_change_detection(sc);
  742                 bstp_acknowledge_topology_change(sc, bif);
  743         }
  744 }
  745 
  746 void
  747 bstp_hello_timer_expiry(struct bridge_softc *sc)
  748 {
  749         bstp_config_bpdu_generation(sc);
  750         bstp_timer_start(&sc->sc_hello_timer, 0);
  751 }
  752 
  753 void
  754 bstp_message_age_timer_expiry(struct bridge_softc *sc,
  755     struct bridge_iflist *bif)
  756 {
  757         int root;
  758 
  759         root = bstp_root_bridge(sc);
  760         bstp_become_designated_port(sc, bif);
  761         bstp_configuration_update(sc);
  762         bstp_port_state_selection(sc);
  763 
  764         if ((bstp_root_bridge(sc)) && (root == 0)) {
  765                 sc->sc_max_age = sc->sc_bridge_max_age;
  766                 sc->sc_hello_time = sc->sc_bridge_hello_time;
  767                 sc->sc_forward_delay = sc->sc_bridge_forward_delay;
  768 
  769                 bstp_topology_change_detection(sc);
  770                 bstp_timer_stop(&sc->sc_tcn_timer);
  771                 bstp_config_bpdu_generation(sc);
  772                 bstp_timer_start(&sc->sc_hello_timer, 0);
  773         }
  774 }
  775 
  776 void
  777 bstp_forward_delay_timer_expiry(struct bridge_softc *sc,
  778     struct bridge_iflist *bif)
  779 {
  780         if (bif->bif_state == BSTP_IFSTATE_LISTENING) {
  781                 bstp_set_port_state(bif, BSTP_IFSTATE_LEARNING);
  782                 bstp_timer_start(&bif->bif_forward_delay_timer, 0);
  783         } else if (bif->bif_state == BSTP_IFSTATE_LEARNING) {
  784                 bstp_set_port_state(bif, BSTP_IFSTATE_FORWARDING);
  785                 if (bstp_designated_for_some_port(sc) &&
  786                     bif->bif_change_detection_enabled)
  787                         bstp_topology_change_detection(sc);
  788         }
  789 }
  790 
  791 int
  792 bstp_designated_for_some_port(struct bridge_softc *sc)
  793 {
  794 
  795         struct bridge_iflist *bif;
  796 
  797         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  798                 if ((bif->bif_flags & IFBIF_STP) == 0)
  799                         continue;
  800                 if (bif->bif_designated_bridge == sc->sc_bridge_id)
  801                         return (1);
  802         }
  803         return (0);
  804 }
  805 
  806 void
  807 bstp_tcn_timer_expiry(struct bridge_softc *sc)
  808 {
  809         bstp_transmit_tcn(sc);
  810         bstp_timer_start(&sc->sc_tcn_timer, 0);
  811 }
  812 
  813 void
  814 bstp_topology_change_timer_expiry(struct bridge_softc *sc)
  815 {
  816         sc->sc_topology_change_detected = 0;
  817         sc->sc_topology_change = 0;
  818 }
  819 
  820 void
  821 bstp_hold_timer_expiry(struct bridge_softc *sc, struct bridge_iflist *bif)
  822 {
  823         if (bif->bif_config_pending)
  824                 bstp_transmit_config(sc, bif);
  825 }
  826 
  827 void
  828 bstp_initialization(struct bridge_softc *sc)
  829 {
  830         struct bridge_iflist *bif, *mif;
  831 
  832         BRIDGE_LOCK_ASSERT(sc);
  833 
  834         mif = NULL;
  835         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  836                 if ((bif->bif_flags & IFBIF_STP) == 0)
  837                         continue;
  838                 if (bif->bif_ifp->if_type != IFT_ETHER)
  839                         continue;
  840                 bif->bif_port_id = (bif->bif_priority << 8) |
  841                     (bif->bif_ifp->if_index & 0xff);
  842 
  843                 if (mif == NULL) {
  844                         mif = bif;
  845                         continue;
  846                 }
  847                 if (memcmp(IF_LLADDR(bif->bif_ifp),
  848                     IF_LLADDR(mif->bif_ifp), ETHER_ADDR_LEN) < 0) {
  849                         mif = bif;
  850                         continue;
  851                 }
  852         }
  853         if (mif == NULL) {
  854                 bstp_stop(sc);
  855                 return;
  856         }
  857 
  858         sc->sc_bridge_id =
  859             (((uint64_t)sc->sc_bridge_priority) << 48) |
  860             (((uint64_t)IF_LLADDR(mif->bif_ifp)[0]) << 40) |
  861             (((uint64_t)IF_LLADDR(mif->bif_ifp)[1]) << 32) |
  862             (IF_LLADDR(mif->bif_ifp)[2] << 24) |
  863             (IF_LLADDR(mif->bif_ifp)[3] << 16) |
  864             (IF_LLADDR(mif->bif_ifp)[4] << 8) |
  865             (IF_LLADDR(mif->bif_ifp)[5]);
  866 
  867         sc->sc_designated_root = sc->sc_bridge_id;
  868         sc->sc_root_path_cost = 0;
  869         sc->sc_root_port = NULL;
  870 
  871         sc->sc_max_age = sc->sc_bridge_max_age;
  872         sc->sc_hello_time = sc->sc_bridge_hello_time;
  873         sc->sc_forward_delay = sc->sc_bridge_forward_delay;
  874         sc->sc_topology_change_detected = 0;
  875         sc->sc_topology_change = 0;
  876         bstp_timer_stop(&sc->sc_tcn_timer);
  877         bstp_timer_stop(&sc->sc_topology_change_timer);
  878 
  879         if (callout_pending(&sc->sc_bstpcallout) == 0)
  880                 callout_reset(&sc->sc_bstpcallout, hz,
  881                     bstp_tick, sc);
  882 
  883         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  884                 if (bif->bif_flags & IFBIF_STP)
  885                         bstp_enable_port(sc, bif);
  886                 else
  887                         bstp_disable_port(sc, bif);
  888         }
  889 
  890         bstp_port_state_selection(sc);
  891         bstp_config_bpdu_generation(sc);
  892         bstp_timer_start(&sc->sc_hello_timer, 0);
  893 }
  894 
  895 void
  896 bstp_stop(struct bridge_softc *sc)
  897 {
  898         struct bridge_iflist *bif;
  899 
  900         BRIDGE_LOCK_ASSERT(sc);
  901 
  902         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  903                 bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
  904                 bstp_timer_stop(&bif->bif_hold_timer);
  905                 bstp_timer_stop(&bif->bif_message_age_timer);
  906                 bstp_timer_stop(&bif->bif_forward_delay_timer);
  907         }
  908 
  909         callout_stop(&sc->sc_bstpcallout);
  910 
  911         bstp_timer_stop(&sc->sc_topology_change_timer);
  912         bstp_timer_stop(&sc->sc_tcn_timer);
  913         bstp_timer_stop(&sc->sc_hello_timer);
  914 
  915 }
  916 
  917 void
  918 bstp_initialize_port(struct bridge_softc *sc, struct bridge_iflist *bif)
  919 {
  920         bstp_become_designated_port(sc, bif);
  921         bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
  922         bif->bif_topology_change_acknowledge = 0;
  923         bif->bif_config_pending = 0;
  924         bif->bif_change_detection_enabled = 1;
  925         bstp_timer_stop(&bif->bif_message_age_timer);
  926         bstp_timer_stop(&bif->bif_forward_delay_timer);
  927         bstp_timer_stop(&bif->bif_hold_timer);
  928 }
  929 
  930 void
  931 bstp_enable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
  932 {
  933         bstp_initialize_port(sc, bif);
  934         bstp_port_state_selection(sc);
  935 }
  936 
  937 void
  938 bstp_disable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
  939 {
  940         int root;
  941 
  942         BRIDGE_LOCK_ASSERT(sc);
  943 
  944         root = bstp_root_bridge(sc);
  945         bstp_become_designated_port(sc, bif);
  946         bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
  947         bif->bif_topology_change_acknowledge = 0;
  948         bif->bif_config_pending = 0;
  949         bstp_timer_stop(&bif->bif_message_age_timer);
  950         bstp_timer_stop(&bif->bif_forward_delay_timer);
  951         bstp_configuration_update(sc);
  952         bstp_port_state_selection(sc);
  953         bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
  954 
  955         if (bstp_root_bridge(sc) && (root == 0)) {
  956                 sc->sc_max_age = sc->sc_bridge_max_age;
  957                 sc->sc_hello_time = sc->sc_bridge_hello_time;
  958                 sc->sc_forward_delay = sc->sc_bridge_forward_delay;
  959 
  960                 bstp_topology_change_detection(sc);
  961                 bstp_timer_stop(&sc->sc_tcn_timer);
  962                 bstp_config_bpdu_generation(sc);
  963                 bstp_timer_start(&sc->sc_hello_timer, 0);
  964         }
  965 }
  966 
  967 void
  968 bstp_set_bridge_priority(struct bridge_softc *sc, uint64_t new_bridge_id)
  969 {
  970         struct bridge_iflist *bif;
  971         int root;
  972 
  973         BRIDGE_LOCK_ASSERT(sc);
  974 
  975         root = bstp_root_bridge(sc);
  976 
  977         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
  978                 if ((bif->bif_flags & IFBIF_STP) == 0)
  979                         continue;
  980                 if (bstp_designated_port(sc, bif))
  981                         bif->bif_designated_bridge = new_bridge_id;
  982         }
  983 
  984         sc->sc_bridge_id = new_bridge_id;
  985 
  986         bstp_configuration_update(sc);
  987         bstp_port_state_selection(sc);
  988 
  989         if (bstp_root_bridge(sc) && (root == 0)) {
  990                 sc->sc_max_age = sc->sc_bridge_max_age;
  991                 sc->sc_hello_time = sc->sc_bridge_hello_time;
  992                 sc->sc_forward_delay = sc->sc_bridge_forward_delay;
  993 
  994                 bstp_topology_change_detection(sc);
  995                 bstp_timer_stop(&sc->sc_tcn_timer);
  996                 bstp_config_bpdu_generation(sc);
  997                 bstp_timer_start(&sc->sc_hello_timer, 0);
  998         }
  999 }
 1000 
 1001 void
 1002 bstp_set_port_priority(struct bridge_softc *sc, struct bridge_iflist *bif,
 1003     uint16_t new_port_id)
 1004 {
 1005         if (bstp_designated_port(sc, bif))
 1006                 bif->bif_designated_port = new_port_id;
 1007 
 1008         bif->bif_port_id = new_port_id;
 1009 
 1010         if ((sc->sc_bridge_id == bif->bif_designated_bridge) &&
 1011             (bif->bif_port_id < bif->bif_designated_port)) {
 1012                 bstp_become_designated_port(sc, bif);
 1013                 bstp_port_state_selection(sc);
 1014         }
 1015 }
 1016 
 1017 void
 1018 bstp_set_path_cost(struct bridge_softc *sc, struct bridge_iflist *bif,
 1019     uint32_t path_cost)
 1020 {
 1021         bif->bif_path_cost = path_cost;
 1022         bstp_configuration_update(sc);
 1023         bstp_port_state_selection(sc);
 1024 }
 1025 
 1026 void
 1027 bstp_enable_change_detection(struct bridge_iflist *bif)
 1028 {
 1029         bif->bif_change_detection_enabled = 1;
 1030 }
 1031 
 1032 void
 1033 bstp_disable_change_detection(struct bridge_iflist *bif)
 1034 {
 1035         bif->bif_change_detection_enabled = 0;
 1036 }
 1037 
 1038 void
 1039 bstp_linkstate(struct ifnet *ifp, int state)
 1040 {
 1041         struct bridge_softc *sc;
 1042         struct bridge_iflist *bif;
 1043 
 1044         sc = ifp->if_bridge;
 1045         BRIDGE_LOCK(sc);
 1046 
 1047         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
 1048                 if ((bif->bif_flags & IFBIF_STP) == 0)
 1049                         continue;
 1050 
 1051                 if (bif->bif_ifp == ifp) {
 1052                         bstp_ifupdstatus(sc, bif);
 1053                         break;
 1054                 }
 1055         }
 1056 
 1057         BRIDGE_UNLOCK(sc);
 1058 }
 1059 
 1060 void
 1061 bstp_ifupdstatus(struct bridge_softc *sc, struct bridge_iflist *bif)
 1062 {
 1063         struct ifnet *ifp = bif->bif_ifp;
 1064         struct ifmediareq ifmr;
 1065         int error = 0;
 1066 
 1067         BRIDGE_LOCK_ASSERT(sc);
 1068 
 1069         bzero((char *)&ifmr, sizeof(ifmr));
 1070         error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
 1071 
 1072         if ((error == 0) && (ifp->if_flags & IFF_UP)) {
 1073                 if (ifmr.ifm_status & IFM_ACTIVE) {
 1074                         if (bif->bif_state == BSTP_IFSTATE_DISABLED)
 1075                                 bstp_enable_port(sc, bif);
 1076 
 1077                 } else {
 1078                         if (bif->bif_state != BSTP_IFSTATE_DISABLED)
 1079                                 bstp_disable_port(sc, bif);
 1080                 }
 1081                 return;
 1082         }
 1083 
 1084         if (bif->bif_state != BSTP_IFSTATE_DISABLED)
 1085                 bstp_disable_port(sc, bif);
 1086 }
 1087 
 1088 void
 1089 bstp_tick(void *arg)
 1090 {
 1091         struct bridge_softc *sc = arg;
 1092         struct bridge_iflist *bif;
 1093 
 1094         BRIDGE_LOCK_ASSERT(sc);
 1095 
 1096 #if 0
 1097         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
 1098                 if ((bif->bif_flags & IFBIF_STP) == 0)
 1099                         continue;
 1100                 /*
 1101                  * XXX This can cause a lag in "link does away"
 1102                  * XXX and "spanning tree gets updated".  We need
 1103                  * XXX come sort of callback from the link state
 1104                  * XXX update code to kick spanning tree.
 1105                  * XXX --thorpej@NetBSD.org
 1106                  */
 1107                 bstp_ifupdstatus(sc, bif);
 1108         }
 1109 #endif
 1110 
 1111         if (bstp_timer_expired(&sc->sc_hello_timer, sc->sc_hello_time))
 1112                 bstp_hello_timer_expiry(sc);
 1113 
 1114         if (bstp_timer_expired(&sc->sc_tcn_timer, sc->sc_bridge_hello_time))
 1115                 bstp_tcn_timer_expiry(sc);
 1116 
 1117         if (bstp_timer_expired(&sc->sc_topology_change_timer,
 1118             sc->sc_topology_change_time))
 1119                 bstp_topology_change_timer_expiry(sc);
 1120 
 1121         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
 1122                 if ((bif->bif_flags & IFBIF_STP) == 0)
 1123                         continue;
 1124                 if (bstp_timer_expired(&bif->bif_message_age_timer,
 1125                     sc->sc_max_age))
 1126                         bstp_message_age_timer_expiry(sc, bif);
 1127         }
 1128 
 1129         LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
 1130                 if ((bif->bif_flags & IFBIF_STP) == 0)
 1131                         continue;
 1132                 if (bstp_timer_expired(&bif->bif_forward_delay_timer,
 1133                     sc->sc_forward_delay))
 1134                         bstp_forward_delay_timer_expiry(sc, bif);
 1135 
 1136                 if (bstp_timer_expired(&bif->bif_hold_timer,
 1137                     sc->sc_hold_time))
 1138                         bstp_hold_timer_expiry(sc, bif);
 1139         }
 1140 
 1141         if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
 1142                 callout_reset(&sc->sc_bstpcallout, hz, bstp_tick, sc);
 1143 }
 1144 
 1145 void
 1146 bstp_timer_start(struct bridge_timer *t, uint16_t v)
 1147 {
 1148         t->value = v;
 1149         t->active = 1;
 1150 }
 1151 
 1152 void
 1153 bstp_timer_stop(struct bridge_timer *t)
 1154 {
 1155         t->value = 0;
 1156         t->active = 0;
 1157 }
 1158 
 1159 int
 1160 bstp_timer_expired(struct bridge_timer *t, uint16_t v)
 1161 {
 1162         if (t->active == 0)
 1163                 return (0);
 1164         t->value += BSTP_TICK_VAL;
 1165         if (t->value >= v) {
 1166                 bstp_timer_stop(t);
 1167                 return (1);
 1168         }
 1169         return (0);
 1170 
 1171 }

Cache object: ffd3d73bf0f20fb3af23db2f9808c25e


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


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