aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorAndrew Thompson <thompsa@FreeBSD.org>2012-04-20 09:55:50 +0000
committerAndrew Thompson <thompsa@FreeBSD.org>2012-04-20 09:55:50 +0000
commit7702d4013b15419f0391d006a9c20ef652ab2111 (patch)
tree5e720f1f10937bda6108ab3cf3fe0a0b81caa055 /sys/net
parentb50d8083ab595257e0dd4f156bb30b405e38bac9 (diff)
Notes
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bridgestp.c28
-rw-r--r--sys/net/bridgestp.h4
-rw-r--r--sys/net/if.c4
-rw-r--r--sys/net/if_bridge.c59
4 files changed, 60 insertions, 35 deletions
diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c
index 06d7f1518d47..dd2aa095367a 100644
--- a/sys/net/bridgestp.c
+++ b/sys/net/bridgestp.c
@@ -1767,28 +1767,16 @@ bstp_notify_rtage(void *arg, int pending)
}
void
-bstp_linkstate(struct ifnet *ifp, int state)
+bstp_linkstate(struct bstp_port *bp)
{
- struct bstp_state *bs;
- struct bstp_port *bp;
+ struct bstp_state *bs = bp->bp_bs;
- /* search for the stp port */
- mtx_lock(&bstp_list_mtx);
- LIST_FOREACH(bs, &bstp_list, bs_list) {
- BSTP_LOCK(bs);
- LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
- if (bp->bp_ifp == ifp) {
- bstp_ifupdstatus(bs, bp);
- bstp_update_state(bs, bp);
- /* it only exists once so return */
- BSTP_UNLOCK(bs);
- mtx_unlock(&bstp_list_mtx);
- return;
- }
- }
- BSTP_UNLOCK(bs);
+ BSTP_LOCK(bs);
+ if (bp->bp_active) {
+ bstp_ifupdstatus(bs, bp);
+ bstp_update_state(bs, bp);
}
- mtx_unlock(&bstp_list_mtx);
+ BSTP_UNLOCK(bs);
}
static void
@@ -2103,10 +2091,8 @@ bstp_modevent(module_t mod, int type, void *data)
case MOD_LOAD:
mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF);
LIST_INIT(&bstp_list);
- bstp_linkstate_p = bstp_linkstate;
break;
case MOD_UNLOAD:
- bstp_linkstate_p = NULL;
mtx_destroy(&bstp_list_mtx);
break;
default:
diff --git a/sys/net/bridgestp.h b/sys/net/bridgestp.h
index 8cec09c83828..e76cfe9c0510 100644
--- a/sys/net/bridgestp.h
+++ b/sys/net/bridgestp.h
@@ -369,8 +369,6 @@ struct bstp_state {
extern const uint8_t bstp_etheraddr[];
-extern void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
-
void bstp_attach(struct bstp_state *, struct bstp_cb_ops *);
void bstp_detach(struct bstp_state *);
void bstp_init(struct bstp_state *);
@@ -379,7 +377,7 @@ int bstp_create(struct bstp_state *, struct bstp_port *, struct ifnet *);
int bstp_enable(struct bstp_port *);
void bstp_disable(struct bstp_port *);
void bstp_destroy(struct bstp_port *);
-void bstp_linkstate(struct ifnet *, int);
+void bstp_linkstate(struct bstp_port *);
int bstp_set_htime(struct bstp_state *, int);
int bstp_set_fdelay(struct bstp_state *, int);
int bstp_set_maxage(struct bstp_state *, int);
diff --git a/sys/net/if.c b/sys/net/if.c
index 8d2c5f230cb0..bf332db115fd 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -124,7 +124,7 @@ static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions");
static struct sx ifdescr_sx;
SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr");
-void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
+void (*bridge_linkstate_p)(struct ifnet *ifp);
void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
void (*lagg_linkstate_p)(struct ifnet *ifp, int state);
/* These are external hooks for CARP. */
@@ -1910,7 +1910,7 @@ do_link_state_change(void *arg, int pending)
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
if (ifp->if_bridge)
- (*bstp_linkstate_p)(ifp, link_state);
+ (*bridge_linkstate_p)(ifp);
if (ifp->if_lagg)
(*lagg_linkstate_p)(ifp, link_state);
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index a25f648dc791..271ef307228a 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -333,6 +333,9 @@ static int bridge_ip6_checkbasic(struct mbuf **mp);
#endif /* INET6 */
static int bridge_fragment(struct ifnet *, struct mbuf *,
struct ether_header *, int, struct llc *);
+static void bridge_linkstate(struct ifnet *ifp);
+
+extern void (*bridge_linkstate_p)(struct ifnet *ifp);
/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
#define VLANTAGOF(_m) \
@@ -496,6 +499,7 @@ bridge_modevent(module_t mod, int type, void *data)
bridge_input_p = bridge_input;
bridge_output_p = bridge_output;
bridge_dn_p = bridge_dummynet;
+ bridge_linkstate_p = bridge_linkstate;
bridge_detach_cookie = EVENTHANDLER_REGISTER(
ifnet_departure_event, bridge_ifdetach, NULL,
EVENTHANDLER_PRI_ANY);
@@ -508,6 +512,7 @@ bridge_modevent(module_t mod, int type, void *data)
bridge_input_p = NULL;
bridge_output_p = NULL;
bridge_dn_p = NULL;
+ bridge_linkstate_p = NULL;
mtx_destroy(&bridge_list_mtx);
break;
default:
@@ -988,6 +993,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
}
bstp_destroy(&bif->bif_stp); /* prepare to free */
+ bridge_linkstate(ifs);
BRIDGE_LOCK(sc);
free(bif, M_DEVBUF);
}
@@ -1087,17 +1093,17 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
/* Set interface capabilities to the intersection set of all members */
bridge_mutecaps(sc);
+ BRIDGE_UNLOCK(sc);
+ /* Update the linkstate for the bridge */
+ bridge_linkstate(ifs);
+ /* Place the interface into promiscuous mode */
switch (ifs->if_type) {
- case IFT_ETHER:
- case IFT_L2VLAN:
- /*
- * Place the interface into promiscuous mode.
- */
- BRIDGE_UNLOCK(sc);
- error = ifpromisc(ifs, 1);
- BRIDGE_LOCK(sc);
- break;
+ case IFT_ETHER:
+ case IFT_L2VLAN:
+ error = ifpromisc(ifs, 1);
+ break;
}
+ BRIDGE_LOCK(sc);
if (error)
bridge_delete_member(sc, bif, 0);
out:
@@ -3475,3 +3481,38 @@ out:
m_freem(m);
return (error);
}
+
+static void
+bridge_linkstate(struct ifnet *ifp)
+{
+ struct bridge_softc *sc = ifp->if_bridge;
+ struct bridge_iflist *bif, *bif2;
+ int new_link, hasls;
+
+ BRIDGE_LOCK(sc);
+ bif = bridge_lookup_member_if(sc, ifp);
+ if (bif == NULL) {
+ BRIDGE_UNLOCK(sc);
+ return;
+ }
+ new_link = LINK_STATE_DOWN;
+ hasls = 0;
+ /* Our link is considered up if at least one of our ports is active */
+ LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
+ if (bif2->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
+ hasls++;
+ if (bif2->bif_ifp->if_link_state == LINK_STATE_UP) {
+ new_link = LINK_STATE_UP;
+ break;
+ }
+ }
+ if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) {
+ /* If no interfaces support link-state then we default to up */
+ new_link = LINK_STATE_UP;
+ }
+ if_link_state_change(sc->sc_ifp, new_link);
+ BRIDGE_UNLOCK(sc);
+
+ bstp_linkstate(&bif->bif_stp);
+}
+