summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/mii/mii.c22
-rw-r--r--sys/net/if.h8
-rw-r--r--sys/net/if_var.h1
-rw-r--r--sys/net/if_vlan.c25
4 files changed, 52 insertions, 4 deletions
diff --git a/sys/dev/mii/mii.c b/sys/dev/mii/mii.c
index 4771cc5..a22330b 100644
--- a/sys/dev/mii/mii.c
+++ b/sys/dev/mii/mii.c
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_media.h>
+#include <net/route.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
@@ -230,6 +231,8 @@ miibus_statchg(dev)
return;
}
+void (*vlan_link_state_p)(struct ifnet *, int); /* XXX: private from if_vlan */
+
static void
miibus_linkchg(dev)
device_t dev;
@@ -237,7 +240,7 @@ miibus_linkchg(dev)
struct mii_data *mii;
struct ifnet *ifp;
device_t parent;
- int link;
+ int link, link_state;
parent = device_get_parent(dev);
MIIBUS_LINKCHG(parent);
@@ -249,15 +252,26 @@ miibus_linkchg(dev)
ifp = device_get_softc(parent);
if (mii->mii_media_status & IFM_AVALID) {
- if (mii->mii_media_status & IFM_ACTIVE)
+ if (mii->mii_media_status & IFM_ACTIVE) {
link = NOTE_LINKUP;
- else
+ link_state = LINK_STATE_UP;
+ } else {
link = NOTE_LINKDOWN;
+ link_state = LINK_STATE_DOWN;
+ }
} else {
link = NOTE_LINKINV;
+ link_state = LINK_STATE_UNKNOWN;
}
- KNOTE(&ifp->if_klist, link);
+ /* Notify that the link state has changed. */
+ if (ifp->if_link_state != link_state) {
+ ifp->if_link_state = link_state;
+ rt_ifmsg(ifp);
+ KNOTE(&ifp->if_klist, link);
+ if (ifp->if_nvlans != 0)
+ (*vlan_link_state_p)(ifp, link);
+ }
}
static void
diff --git a/sys/net/if.h b/sys/net/if.h
index 625dfe0..2266fee 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -104,6 +104,7 @@ struct if_data {
u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */
u_char ifi_addrlen; /* media address length */
u_char ifi_hdrlen; /* media header length */
+ u_char ifi_link_state; /* current link state */
u_char ifi_recvquota; /* polling quota for receive intrs */
u_char ifi_xmitquota; /* polling quota for xmit intrs */
u_long ifi_mtu; /* maximum transmission unit */
@@ -155,6 +156,13 @@ struct if_data {
IFF_POLLING)
/*
+ * Values for if_link_state.
+ */
+#define LINK_STATE_UNKNOWN 0 /* link invalid/unknown */
+#define LINK_STATE_DOWN 1 /* link is down */
+#define LINK_STATE_UP 2 /* link is up */
+
+/*
* Some convenience macros used for setting ifi_baudrate.
* XXX 1000 vs. 1024? --thorpej@netbsd.org
*/
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 3d3cad5..541f214 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -197,6 +197,7 @@ typedef void if_init_f_t(void *);
#define if_addrlen if_data.ifi_addrlen
#define if_hdrlen if_data.ifi_hdrlen
#define if_metric if_data.ifi_metric
+#define if_link_state if_data.ifi_link_state
#define if_baudrate if_data.ifi_baudrate
#define if_hwassist if_data.ifi_hwassist
#define if_ipackets if_data.ifi_ipackets
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 87eabb7..25ca790 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -125,6 +125,7 @@ static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
static int vlan_setmulti(struct ifnet *ifp);
static int vlan_unconfig(struct ifnet *ifp);
static int vlan_config(struct ifvlan *ifv, struct ifnet *p);
+static void vlan_link_state(struct ifnet *ifp, int link);
struct if_clone vlan_cloner = IF_CLONE_INITIALIZER(VLANNAME,
vlan_clone_create, vlan_clone_destroy, 0, IF_MAXUNIT);
@@ -209,6 +210,9 @@ vlan_setmulti(struct ifnet *ifp)
*/
extern void (*vlan_input_p)(struct ifnet *, struct mbuf *);
+/* For MII eyes only... */
+extern void (*vlan_link_state_p)(struct ifnet *, int);
+
static int
vlan_modevent(module_t mod, int type, void *data)
{
@@ -218,11 +222,13 @@ vlan_modevent(module_t mod, int type, void *data)
LIST_INIT(&ifv_list);
VLAN_LOCK_INIT();
vlan_input_p = vlan_input;
+ vlan_link_state_p = vlan_link_state;
if_clone_attach(&vlan_cloner);
break;
case MOD_UNLOAD:
if_clone_detach(&vlan_cloner);
vlan_input_p = NULL;
+ vlan_link_state_p = NULL;
while (!LIST_EMPTY(&ifv_list))
vlan_clone_destroy(&LIST_FIRST(&ifv_list)->ifv_if);
VLAN_LOCK_DESTROY();
@@ -532,6 +538,7 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p)
*/
ifv->ifv_if.if_flags = (p->if_flags &
(IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT));
+ ifv->ifv_if.if_link_state = p->if_link_state;
/*
* If the parent interface can do hardware-assisted
@@ -622,6 +629,7 @@ vlan_unconfig(struct ifnet *ifp)
ifv->ifv_p = NULL;
ifv->ifv_if.if_mtu = ETHERMTU; /* XXX why not 0? */
ifv->ifv_flags = 0;
+ ifv->ifv_if.if_link_state = LINK_STATE_UNKNOWN;
/* Clear our MAC address. */
ifa = ifaddr_byindex(ifv->ifv_if.if_index);
@@ -657,6 +665,23 @@ vlan_set_promisc(struct ifnet *ifp)
return (error);
}
+/* Inform all vlans that their parent has changed link state */
+static void
+vlan_link_state(struct ifnet *ifp, int link)
+{
+ struct ifvlan *ifv;
+
+ VLAN_LOCK();
+ LIST_FOREACH(ifv, &ifv_list, ifv_list) {
+ if (ifv->ifv_p == ifp) {
+ ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state;
+ rt_ifmsg(&(ifv->ifv_if));
+ KNOTE(&ifp->if_klist, link);
+ }
+ }
+ VLAN_UNLOCK();
+}
+
static int
vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
OpenPOWER on IntegriCloud