diff -r 9d42302b182d sys/dev/netif/em/if_em.c
--- a/sys/dev/netif/em/if_em.c	Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/dev/netif/em/if_em.c	Thu Mar 15 20:05:40 2007 +0200
@@ -1788,6 +1788,9 @@ static void
 static void
 em_update_link_status(struct adapter *adapter)
 {
+	struct ifnet *ifp;
+	ifp = &adapter->interface_data.ac_if;
+
 	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
 		if (adapter->link_active == 0) {
 			em_get_speed_and_duplex(&adapter->hw, 
@@ -1812,16 +1815,13 @@ em_update_link_status(struct adapter *ad
 			}
 			adapter->link_active = 1;
 			adapter->smartspeed = 0;
-#ifdef notyet
 			ifp->if_baudrate = adapter->link_speed * 1000000;
-			if_link_state_change(ifp, LINK_STATE_UP);
-#endif
+			ifp->if_link_state = LINK_STATE_UP;
+			if_link_state_change(ifp);
 		}
 	} else {
 		if (adapter->link_active == 1) {
-#ifdef notyet
 			ifp->if_baudrate = 0;
-#endif
 			adapter->link_speed = 0;
 			adapter->link_duplex = 0;
 			if (bootverbose) {
@@ -1829,9 +1829,8 @@ em_update_link_status(struct adapter *ad
 					  "Link is Down\n");
 			}
 			adapter->link_active = 0;
-#ifdef notyet
-			if_link_state_change(ifp, LINK_STATE_DOWN);
-#endif
+			ifp->if_link_state = LINK_STATE_DOWN;
+			if_link_state_change(ifp);
 		}
 	}
 }
diff -r 9d42302b182d sys/dev/netif/mii_layer/mii_physubr.c
--- a/sys/dev/netif/mii_layer/mii_physubr.c	Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/dev/netif/mii_layer/mii_physubr.c	Thu Mar 15 20:10:03 2007 +0200
@@ -500,42 +500,61 @@ mii_phy_tick(struct mii_softc *sc)
 	return (0);
 }
 
-#ifdef notyet
-static void
+static int
 mii_phy_statusmsg(struct mii_softc *sc)
 {
 	struct mii_data *mii = sc->mii_pdata;
 	struct ifnet *ifp = mii->mii_ifp;
-	int s;
-
-	crit_enter();
+	int baudrate, link_state, announce = 0;
+
 	if (mii->mii_media_status & IFM_AVALID) {
 		if (mii->mii_media_status & IFM_ACTIVE)
-			if_link_state_change(ifp, LINK_STATE_UP);
+			link_state = LINK_STATE_UP;
 		else
-			if_link_state_change(ifp, LINK_STATE_DOWN);
+			link_state = LINK_STATE_DOWN;
 	} else
-		if_link_state_change(ifp, LINK_STATE_UNKNOWN);
-	crit_exit();
-
-	ifp->if_baudrate = ifmedia_baudrate(mii->mii_media_active);
-}
-#endif
+		link_state = LINK_STATE_UNKNOWN;
+
+	baudrate = ifmedia_baudrate(mii->mii_media_active);
+
+	if (link_state != ifp->if_link_state) {
+		ifp->if_link_state = link_state;
+		/*
+		 * XXX Right here we'd like to notify protocols
+		 * XXX that the link status has changed, so that
+		 * XXX e.g. Duplicate Address Detection can restart.
+		 */
+		announce = 1;
+	}
+
+	if (baudrate != ifp->if_baudrate) {
+		ifp->if_baudrate = baudrate;
+		announce = 1;
+	}
+
+	return (announce);
+}
 
 void
 mii_phy_update(struct mii_softc *sc, int cmd)
 {
 	struct mii_data *mii = sc->mii_pdata;
+	struct ifnet *ifp = mii->mii_ifp;
+	int announce;
 
 	if (sc->mii_media_active != mii->mii_media_active ||
 	    sc->mii_media_status != mii->mii_media_status ||
 	    cmd == MII_MEDIACHG) {
-#ifdef notyet
-		mii_phy_statusmsg(sc);
-#endif
+		announce = mii_phy_statusmsg(sc);
 		MIIBUS_STATCHG(sc->mii_dev);
 		sc->mii_media_active = mii->mii_media_active;
 		sc->mii_media_status = mii->mii_media_status;
+
+		if (announce) {
+			crit_enter();
+			if_link_state_change(ifp);
+			crit_exit();
+		}
 	}
 }
 
diff -r 9d42302b182d sys/net/if.c
--- a/sys/net/if.c	Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if.c	Fri Mar 16 06:58:52 2007 +0200
@@ -975,6 +975,16 @@ if_up(struct ifnet *ifp)
 {
 
 	if_route(ifp, IFF_UP, AF_UNSPEC);
+}
+
+/*
+ * Process a link state change.
+ * NOTE: must be called at splsoftnet or equivalent.
+ */
+void
+if_link_state_change(struct ifnet *ifp)
+{
+	rt_ifmsg(ifp);
 }
 
 /*
diff -r 9d42302b182d sys/net/if.h
--- a/sys/net/if.h	Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if.h	Thu Mar 15 20:08:58 2007 +0200
@@ -56,6 +56,13 @@
 
 #endif
 
+/*
+ * 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 */
+
 struct ifnet;
 
 /*
@@ -111,6 +118,7 @@ struct if_data {
 	u_char	ifi_xmitquota;		/* polling quota for xmit intrs */
 	u_long	ifi_mtu;		/* maximum transmission unit */
 	u_long	ifi_metric;		/* routing metric (external only) */
+	u_long  ifi_link_state;		/* current link state */
 	u_long	ifi_baudrate;		/* linespeed */
 	/* volatile statistics */
 	u_long	ifi_ipackets;		/* packets received on interface */
diff -r 9d42302b182d sys/net/if_media.c
--- a/sys/net/if_media.c	Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if_media.c	Thu Mar 15 13:57:11 2007 +0200
@@ -360,6 +360,24 @@ ifmedia_match(struct ifmedia *ifm, int t
 	return match;
 }
 
+struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
+    IFM_BAUDRATE_DESCRIPTIONS;
+
+int
+ifmedia_baudrate(int mword)
+{
+	int i;
+
+	for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
+		if ((mword & (IFM_NMASK|IFM_TMASK)) ==
+		    ifmedia_baudrate_descriptions[i].ifmb_word)
+			return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
+	}
+
+	/* Not known. */
+	return (0);
+}
+
 #ifdef IFMEDIA_DEBUG
 struct ifmedia_description ifm_type_descriptions[] =
     IFM_TYPE_DESCRIPTIONS;
diff -r 9d42302b182d sys/net/if_media.h
--- a/sys/net/if_media.h	Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if_media.h	Fri Mar 16 06:56:20 2007 +0200
@@ -115,6 +115,8 @@ int	ifmedia_ioctl(struct ifnet *ifp, str
 int	ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr,
 	    struct ifmedia *ifm, u_long cmd);
 
+/* Compute baudrate for a given media. */
+int	ifmedia_baudrate(int);
 #endif /*_KERNEL */
 
 /*
@@ -541,4 +543,57 @@ struct ifmedia_description {
 	{ 0, NULL },							\
 }
 
+/*
+ * Baudrate descriptions for the various media types.
+ */
+struct ifmedia_baudrate {
+	int	ifmb_word;		/* media word */
+	int	ifmb_baudrate;		/* corresponding baudrate */
+};
+
+#define IFM_BAUDRATE_DESCRIPTIONS {					\
+	{ IFM_ETHER|IFM_10_T,		IF_Mbps(10) },			\
+	{ IFM_ETHER|IFM_10_2,		IF_Mbps(10) },			\
+	{ IFM_ETHER|IFM_10_5,		IF_Mbps(10) },			\
+	{ IFM_ETHER|IFM_100_TX,		IF_Mbps(100) },			\
+	{ IFM_ETHER|IFM_100_FX,		IF_Mbps(100) },			\
+	{ IFM_ETHER|IFM_100_T4,		IF_Mbps(100) },			\
+	{ IFM_ETHER|IFM_100_VG,		IF_Mbps(100) },			\
+	{ IFM_ETHER|IFM_100_T2,		IF_Mbps(100) },			\
+	{ IFM_ETHER|IFM_1000_SX,	IF_Mbps(1000) },		\
+	{ IFM_ETHER|IFM_10_STP,		IF_Mbps(10) },			\
+	{ IFM_ETHER|IFM_10_FL,		IF_Mbps(10) },			\
+	{ IFM_ETHER|IFM_1000_LX,	IF_Mbps(1000) },		\
+	{ IFM_ETHER|IFM_1000_CX,	IF_Mbps(1000) },		\
+	{ IFM_ETHER|IFM_1000_T,		IF_Mbps(1000) },		\
+	{ IFM_ETHER|IFM_HPNA_1,		IF_Mbps(1) },			\
+									\
+	{ IFM_TOKEN|IFM_TOK_STP4,	IF_Mbps(4) },			\
+	{ IFM_TOKEN|IFM_TOK_STP16,	IF_Mbps(16) },			\
+	{ IFM_TOKEN|IFM_TOK_UTP4,	IF_Mbps(4) },			\
+	{ IFM_TOKEN|IFM_TOK_UTP16,	IF_Mbps(16) },			\
+									\
+	{ IFM_FDDI|IFM_FDDI_SMF,	IF_Mbps(100) },			\
+	{ IFM_FDDI|IFM_FDDI_MMF,	IF_Mbps(100) },			\
+	{ IFM_FDDI|IFM_FDDI_UTP,	IF_Mbps(100) },			\
+									\
+	{ IFM_IEEE80211|IFM_IEEE80211_FH1, IF_Mbps(1) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_FH2, IF_Mbps(2) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_DS1, IF_Mbps(1) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_DS2, IF_Mbps(2) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_DS5, IF_Mbps(5) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_DS11, IF_Mbps(11) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_DS22, IF_Mbps(22) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM6, IF_Mbps(6) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM9, IF_Mbps(9) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM12, IF_Mbps(12) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM18, IF_Mbps(18) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM24, IF_Mbps(24) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM36, IF_Mbps(36) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM48, IF_Mbps(48) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM54, IF_Mbps(54) },		\
+	{ IFM_IEEE80211|IFM_IEEE80211_OFDM72, IF_Mbps(72) },		\
+									\
+	{ 0, 0 },							\
+}
 #endif	/* _NET_IF_MEDIA_H_ */
diff -r 9d42302b182d sys/net/if_var.h
--- a/sys/net/if_var.h	Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if_var.h	Thu Mar 15 14:18:56 2007 +0200
@@ -228,6 +228,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
@@ -462,6 +463,7 @@ int	if_delmulti(struct ifnet *, struct s
 int	if_delmulti(struct ifnet *, struct sockaddr *);
 void	if_detach(struct ifnet *);
 void	if_down(struct ifnet *);
+void	if_link_state_change(struct ifnet *);
 void	if_initname(struct ifnet *, const char *, int);
 int	if_printf(struct ifnet *, const char *, ...) __printflike(2, 3);
 void	if_route(struct ifnet *, int flag, int fam);


