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