diff options
-rw-r--r-- | sys/dev/mii/mii.c | 22 | ||||
-rw-r--r-- | sys/net/if.h | 8 | ||||
-rw-r--r-- | sys/net/if_var.h | 1 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 25 |
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) { |