? em_link_state.diff
Index: if_em.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/em/if_em.c,v
retrieving revision 1.39
diff -u -p -r1.39 if_em.c
--- if_em.c	11 Apr 2004 21:01:12 -0000	1.39
+++ if_em.c	7 May 2004 17:53:58 -0000
@@ -158,6 +158,7 @@ static void em_disable_promisc(struct ad
 static void em_set_multi(struct adapter *);
 static void em_print_hw_stats(struct adapter *);
 static void em_print_link_status(struct adapter *);
+static void em_link_state_change(struct adapter *);
 static int  em_get_buf(int i, struct adapter *,
 		       struct mbuf *);
 static void em_enable_vlans(struct adapter *);
@@ -474,6 +475,9 @@ em_attach(device_t dev)
 	em_check_for_link(&adapter->hw);
 
 	/* Print the link status */
+	/*
+	 * XXX: em_check_for_link() does not change adapter->link_active!?
+	 */
 	if (adapter->link_active == 1) {
 		em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, 
 					&adapter->link_duplex);
@@ -483,6 +487,7 @@ em_attach(device_t dev)
 		       adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
 	} else
 		printf("em%d:  Speed:N/A  Duplex:N/A\n", adapter->unit);
+	em_link_state_change(adapter);
 
 	/* Identify 82544 on PCIX */
         em_get_bus_info(&adapter->hw);
@@ -902,6 +907,7 @@ em_poll_locked(struct ifnet *ifp, enum p
                         adapter->hw.get_link_status = 1;
                         em_check_for_link(&adapter->hw);
                         em_print_link_status(adapter);
+			em_link_state_change(adapter);
 			callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
                 }
         }
@@ -969,6 +975,7 @@ em_intr(void *arg)
                 adapter->hw.get_link_status = 1;
                 em_check_for_link(&adapter->hw);
                 em_print_link_status(adapter);
+		em_link_state_change(adapter);
 		callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
         }
 
@@ -1019,6 +1026,7 @@ em_media_status(struct ifnet *ifp, struc
 			adapter->link_active = 0;
 		}
 	}
+	em_link_state_change(adapter);
 
 	ifmr->ifm_status = IFM_AVALID;
 	ifmr->ifm_active = IFM_ETHER;
@@ -1564,6 +1572,7 @@ em_local_timer(void *arg)
 
 	em_check_for_link(&adapter->hw);
 	em_print_link_status(adapter);
+	em_link_state_change(adapter);
 	em_update_stats_counters(adapter);   
 	if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
 		em_print_hw_stats(adapter);
@@ -1576,6 +1585,42 @@ em_local_timer(void *arg)
 	return;
 }
 
+
+/*
+ * The following routine must be called after em_print_link_status() to notify
+ * listeners on routing socket or kqueue of link state changes.
+ */
+extern	void (*vlan_link_state_p)(struct ifnet *, int);	/* XXX: private from if_vlan */
+
+static void
+em_link_state_change(struct adapter *adapter)
+{
+	struct ifnet	*ifp;
+	int klink, link_state, old_link_state;
+	ifp = &adapter->interface_data.ac_if;
+
+	old_link_state = ifp->if_link_state;
+
+	if (adapter->link_active == 0) {
+		link_state = LINK_STATE_DOWN;
+		klink = NOTE_LINKDOWN;
+	} else if (adapter->link_active == 1) {
+		link_state = LINK_STATE_UP;
+		klink = NOTE_LINKUP;
+	} else {
+		link_state = LINK_STATE_UP;
+		klink = NOTE_LINKINV;
+	}
+
+	if (link_state != old_link_state) {
+		ifp->if_link_state = link_state;
+		rt_ifmsg(ifp);
+		KNOTE(&ifp->if_klist, klink);
+		if (ifp->if_nvlans != 0)
+			(*vlan_link_state_p)(ifp, klink);
+	}
+}
+
 static void
 em_print_link_status(struct adapter * adapter)
 {
@@ -1821,6 +1866,7 @@ em_hardware_init(struct adapter * adapte
 		adapter->link_speed = 0;
 		adapter->link_duplex = 0;
 	}
+	em_link_state_change(adapter);
 
 	return(0);
 }
Index: if_em.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/em/if_em.h,v
retrieving revision 1.24
diff -u -p -r1.24 if_em.h
--- if_em.h	14 Nov 2003 18:02:24 -0000	1.24
+++ if_em.h	7 May 2004 17:53:59 -0000
@@ -55,6 +55,7 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <net/bpf.h>
 #include <net/if_types.h>
 #include <net/if_vlan_var.h>
+#include <net/route.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
