Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Mar 2008 23:08:12 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 138681 for review
Message-ID:  <200803262308.m2QN8CIn006648@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=138681

Change 138681 by sam@sam_ebb on 2008/03/26 23:07:56

	checkpoint; can associate and pass traffic with a netgear ma401
	but my intersil cards lock up after sending auth

Affected files ...

.. //depot/projects/vap/sys/dev/wi/if_wi.c#13 edit
.. //depot/projects/vap/sys/dev/wi/if_wi_pci.c#6 edit
.. //depot/projects/vap/sys/dev/wi/if_wivar.h#10 edit

Differences ...

==== //depot/projects/vap/sys/dev/wi/if_wi.c#13 (text+ko) ====

@@ -114,6 +114,7 @@
 		const uint8_t bssid[IEEE80211_ADDR_LEN],
 		const uint8_t mac[IEEE80211_ADDR_LEN]);
 static void wi_vap_delete(struct ieee80211vap *vap);
+static void wi_stop_locked(struct wi_softc *sc, int disable);
 static void wi_start_locked(struct ifnet *);
 static void wi_start(struct ifnet *);
 static int  wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr,
@@ -122,7 +123,7 @@
 		const struct ieee80211_bpf_params *);
 static void wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
 		int subtype, int rssi, int noise, u_int32_t rstamp);
-static int  wi_reset(struct ifnet *);
+static int  wi_reset(struct wi_softc *);
 static void wi_watchdog(void *);
 static int  wi_ioctl(struct ifnet *, u_long, caddr_t);
 static void wi_media_status(struct ifnet *, struct ifmediareq *);
@@ -271,7 +272,7 @@
 	sc->sc_firmware_type = WI_NOTYPE;
 	sc->wi_cmd_count = 500;
 	/* Reset the NIC. */
-	if (wi_reset(ifp) != 0) {
+	if (wi_reset(sc) != 0) {
 		wi_free(dev);
 		return ENXIO;		/* XXX */
 	}
@@ -436,8 +437,7 @@
 
 	sc->sc_max_datalen = 2304;
 	sc->sc_system_scale = 1;
-	sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN;
-	sc->sc_roaming_mode = 1;
+	sc->sc_roaming_mode = 2;	/* NB: host decides */
 	sc->sc_portnum = WI_DEFAULT_PORT;
 	sc->sc_authtype = WI_DEFAULT_AUTHTYPE;
 
@@ -489,7 +489,7 @@
 	/* check if device was removed */
 	sc->wi_gone |= !bus_child_present(dev);
 
-	wi_stop(ifp, 0);
+	wi_stop_locked(sc, 0);
 	WI_UNLOCK(sc);
 #if NBPFILTER > 0
 	bpfdetach(ifp);
@@ -577,7 +577,7 @@
 {
 	struct wi_softc *sc = device_get_softc(dev);
 
-	wi_stop(sc->sc_ifp, 1);
+	wi_stop(sc, 1);
 }
 
 void
@@ -620,31 +620,26 @@
 	return;
 }
 
-void
-wi_init(void *arg)
+static void
+wi_enable(struct wi_softc *sc)
+{
+	/* enable port */
+	wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
+	sc->sc_enabled = 1;
+}
+
+static int
+wi_init_locked(struct wi_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN])
 {
-	struct wi_softc *sc = arg;
-	struct ifnet *ifp = sc->sc_ifp;
-	struct ieee80211com *ic = &sc->sc_ic;
 	int i;
-	int error = 0, wasenabled;
 
-	if (sc->wi_gone) 
-		return;
-
-	if ((wasenabled = sc->sc_enabled))
-		wi_stop(ifp, 1);
+	wi_reset(sc);
 
-	WI_LOCK(sc);
-	wi_reset(ifp);
-
 	wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_porttype);
-	wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
+	wi_write_val(sc, WI_RID_CREATE_IBSS, 3);	/* join only, don't create */
 	wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen);
-#if 0
 	/* NB: for IEEE80211_BPF_NOACK */
 	wi_write_val(sc, WI_RID_ALT_RETRY_CNT, 0);
-#endif
 	if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)
 		wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale);
 	if (sc->sc_flags & WI_FLAGS_HAS_ROAMING)
@@ -652,30 +647,52 @@
 	if (sc->sc_flags & WI_FLAGS_HAS_MOR)
 		wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven);
 
-	IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
-	wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
+	wi_write_rid(sc, WI_RID_MAC_NODE, mac, IEEE80211_ADDR_LEN);
 
 	/* Allocate fids for the card */
-	if (!wasenabled) {
-		sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame);
-		for (i = 0; i < sc->sc_ntxbuf; i++) {
-			error = wi_alloc_fid(sc, sc->sc_buflen,
-			    &sc->sc_txd[i].d_fid);
-			if (error) {
-				device_printf(sc->sc_dev,
-				    "tx buffer allocation failed (error %u)\n",
-				    error);
-				goto out;
-			}
-			sc->sc_txd[i].d_len = 0;
+	sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame);
+	for (i = 0; i < sc->sc_ntxbuf; i++) {
+		int error = wi_alloc_fid(sc, sc->sc_buflen,
+		    &sc->sc_txd[i].d_fid);
+		if (error) {
+			device_printf(sc->sc_dev,
+			    "tx buffer allocation failed (error %u)\n",
+			    error);
+			return error;
 		}
+		sc->sc_txd[i].d_len = 0;
 	}
 	sc->sc_txcur = sc->sc_txnext = 0;
 
-	/* Enable desired port */
-	wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
+	return 0;
+}
+
+void
+wi_init(void *arg)
+{
+	struct wi_softc *sc = arg;
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211com *ic = &sc->sc_ic;
+	int wasenabled;
+
+	WI_LOCK(sc);
+	if (sc->wi_gone) {
+		WI_UNLOCK(sc);
+		return;
+	}
+	wasenabled = sc->sc_enabled;
+	if (wasenabled)
+		wi_stop_locked(sc, 1);
+
+	IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
+	if (wi_init_locked(sc, ic->ic_myaddr) != 0) {
+		if_printf(ifp, "interface not running\n");
+		wi_stop_locked(sc, 1);
+		WI_UNLOCK(sc);
+		return;
+	}
+	wi_enable(sc);			/* Enable desired port */
 
-	sc->sc_enabled = 1;
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
@@ -686,23 +703,15 @@
 	ieee80211_start_all(ic);
 
 	callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc);
-	return;
-out:
-	if (error) {
-		if_printf(ifp, "interface not running\n");
-		wi_stop(ifp, 1);
-	}
-	WI_UNLOCK(sc);
-	DPRINTF(("wi_init: return %d\n", error));
-	return;
 }
 
-void
-wi_stop(struct ifnet *ifp, int disable)
+static void
+wi_stop_locked(struct wi_softc *sc, int disable)
 {
-	struct wi_softc *sc = ifp->if_softc;
+	struct ifnet *ifp = sc->sc_ifp;
+
+	WI_LOCK_ASSERT(sc);
 
-	WI_LOCK(sc);
 	if (sc->sc_enabled && !sc->wi_gone) {
 		CSR_WRITE_2(sc, WI_INT_EN, 0);
 		wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
@@ -716,7 +725,13 @@
 	sc->sc_false_syns = 0;
 
 	ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING);
+}
 
+void
+wi_stop(struct wi_softc *sc, int disable)
+{
+	WI_LOCK(sc);
+	wi_stop_locked(sc, disable);
 	WI_UNLOCK(sc);
 }
 
@@ -726,24 +741,25 @@
 	struct ifnet *ifp = ic->ic_ifp;
 	struct wi_softc *sc = ifp->if_softc;
 
+	DPRINTF(("%s: channel %d, %sscanning\n", __func__,
+	    ieee80211_chan2ieee(ic, ic->ic_curchan),
+	    ic->ic_flags & IEEE80211_F_SCAN ? "" : "!"));
+
 	WI_LOCK(sc);
+	/*
+	 * Don't force the channel if we're not scanning; we may
+	 * be called back on entering the AUTH and/or RUN state
+	 * but the firmware gets unhappy as it's join primitive
+	 * handles the channel change.
+	 */
 	wi_write_val(sc, WI_RID_OWN_CHNL,
 	    ieee80211_chan2ieee(ic, ic->ic_curchan));
-
 #if NBPFILTER > 0
 	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
 		htole16(ic->ic_curchan->ic_freq);
 	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
 		htole16(ic->ic_curchan->ic_flags);
 #endif
-
-	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
-	    ic->ic_opmode == IEEE80211_M_HOSTAP &&
-	    sc->sc_firmware_type == WI_INTERSIL) {
-		/* XXX: some cards need to be re-enabled */
-		wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
-		wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
-	}
 	WI_UNLOCK(sc);
 }
 
@@ -754,6 +770,8 @@
 	struct wi_softc *sc = ifp->if_softc;
 	struct ieee80211_scan_state *ss = ic->ic_scan;
 
+	DPRINTF(("%s\n", __func__));
+
 	WI_LOCK(sc);
 	/*
 	 * Switch device to monitor mode.
@@ -766,9 +784,12 @@
 		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_APSILENT);
 		break;
 	}
-	wi_cmd(sc, WI_CMD_DEBUG | (WI_TEST_MONITOR << 8), 0, 0, 0);
-
-	ss->ss_mindwell = ss->ss_maxdwell = msecs_to_ticks(400); /* 400ms */
+	if (sc->sc_firmware_type == WI_INTERSIL) {
+		wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
+		wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
+	}
+	/* force full dwell time to compensate for firmware overhead */
+	ss->ss_mindwell = ss->ss_maxdwell = msecs_to_ticks(400);
 	WI_UNLOCK(sc);
 
 }
@@ -779,9 +800,14 @@
 	struct ifnet *ifp = ic->ic_ifp;
 	struct wi_softc *sc = ifp->if_softc;
 
+	DPRINTF(("%s: restore port type %d\n", __func__, sc->sc_porttype));
+
 	WI_LOCK(sc);
-	wi_cmd(sc, WI_CMD_DEBUG, 0, 0, 0);
 	wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_porttype);
+	if (sc->sc_firmware_type == WI_INTERSIL) {
+		wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
+		wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
+	}
 	WI_UNLOCK(sc);
 }
 
@@ -816,8 +842,30 @@
 	if (nstate == IEEE80211_S_AUTH) {
 		struct ieee80211_node *bss = vap->iv_bss;
 
-		wi_write_ssid(sc, WI_RID_DESIRED_SSID,
-		    bss->ni_essid, bss->ni_esslen);
+		wi_init_locked(sc, vap->iv_myaddr);
+
+		if (vap->iv_flags & IEEE80211_F_PMGTON) {
+			wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
+			wi_write_val(sc, WI_RID_PM_ENABLED, 1);
+		}
+		wi_write_val(sc, WI_RID_RTS_THRESH, vap->iv_rtsthreshold);
+		if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
+			wi_write_val(sc, WI_RID_FRAG_THRESH,
+			    vap->iv_fragthreshold);
+		wi_write_txrate(sc, vap);
+
+		/* Configure WEP. */
+		if (ic->ic_caps & IEEE80211_C_WEP)
+			wi_write_wep(sc, vap);
+		else
+			sc->sc_encryption = 0;
+
+		wi_write_ssid(sc, WI_RID_DESIRED_SSID, bss->ni_essid, bss->ni_esslen);
+		wi_write_val(sc, WI_RID_OWN_CHNL,
+		    ieee80211_chan2ieee(ic, bss->ni_chan));
+
+		wi_enable(sc);		/* enable port */
+
 		/* Lucent firmware does not support the JOIN RID. */
 		if (sc->sc_firmware_type == WI_INTERSIL) {
 			struct wi_joinreq join;
@@ -827,8 +875,6 @@
 			join.wi_chan = htole16(
 			    ieee80211_chan2ieee(ic, bss->ni_chan));
 			wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join));
-		} else {
-			wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
 		}
 		/* NB: don't go through 802.11 layer, it'll send auth frame */
 		vap->iv_state = nstate;
@@ -840,32 +886,29 @@
 	if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) {
 		if (vap->iv_opmode == IEEE80211_M_MONITOR)
 			wi_cmd(sc, WI_CMD_DEBUG | (WI_TEST_MONITOR << 8), 0, 0, 0);
-		wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
-		if (ic->ic_caps & IEEE80211_C_PMGT)
-			wi_write_val(sc, WI_RID_PM_ENABLED,
-			    (vap->iv_flags & IEEE80211_F_PMGTON) ? 1 : 0);
-		wi_write_val(sc, WI_RID_RTS_THRESH, vap->iv_rtsthreshold);
-		if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
-			wi_write_val(sc, WI_RID_FRAG_THRESH,
-			    vap->iv_fragthreshold);
-		wi_write_txrate(sc, vap);
+		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+			wi_write_val(sc, WI_RID_RTS_THRESH, vap->iv_rtsthreshold);
+			if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
+				wi_write_val(sc, WI_RID_FRAG_THRESH,
+				    vap->iv_fragthreshold);
+			wi_write_txrate(sc, vap);
 
-		/* Configure WEP. */
-		if (ic->ic_caps & IEEE80211_C_WEP) {
-			sc->sc_cnfauthmode = vap->iv_bss->ni_authmode;
-			wi_write_wep(sc, vap);
-		} else
-			sc->sc_encryption = 0;
+			/* Configure WEP. */
+			if (ic->ic_caps & IEEE80211_C_WEP) {
+				sc->sc_cnfauthmode = vap->iv_bss->ni_authmode;
+				wi_write_wep(sc, vap);
+			} else
+				sc->sc_encryption = 0;
 
-		if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
-		    sc->sc_firmware_type == WI_INTERSIL) {
+			/* NB: only Intersil supports HOSTAP so this works for now */
 			wi_write_ssid(sc, WI_RID_OWN_SSID,
 			    vap->iv_des_ssid[0].ssid, vap->iv_des_ssid[0].len);
 			wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_bintval);
 			wi_write_val(sc, WI_RID_BASIC_RATE, 0x03);   /* 1, 2 */
 			wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
 			wi_write_val(sc, WI_RID_DTIM_PERIOD, vap->iv_dtim_period);
-			/* XXX: some card need to be re-enabled for hostap */
+
+			/* XXX: some cards need to be re-enabled for hostap */
 			wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
 			wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
 		}
@@ -1066,21 +1109,20 @@
 }
 
 static int
-wi_reset(struct ifnet *ifp)
+wi_reset(struct wi_softc *sc)
 {
 #define WI_INIT_TRIES 3
-	struct wi_softc *sc = ifp->if_softc;
-	int i;
-	int error = 0;
+	int i, error = 0;
 
 	for (i = 0; i < WI_INIT_TRIES; i++) {
-		if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
+		error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0);
+		if (error == 0)
 			break;
 		DELAY(WI_DELAY * 1000);
 	}
 	sc->sc_reset = 1;
 	if (i == WI_INIT_TRIES) {
-		if_printf(ifp, "init failed\n");
+		if_printf(sc->sc_ifp, "reset failed\n");
 		return error;
 	}
 
@@ -1142,7 +1184,7 @@
 				wi_init(sc);
 		} else {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-				wi_stop(ifp, 1);
+				wi_stop_locked(sc, 1);
 			sc->wi_gone = 0;
 		}
 		sc->sc_if_flags = ifp->if_flags;
@@ -1462,11 +1504,11 @@
 			IEEE80211_UNLOCK(ic);
 			break;
 		case WI_INFO_LINK_STAT_AP_INR:
+		case WI_INFO_LINK_STAT_DISCONNECTED:
 			break;
 		case WI_INFO_LINK_STAT_AP_OOR:
 			ieee80211_beacon_miss(ic);
 			break;
-		case WI_INFO_LINK_STAT_DISCONNECTED:
 		case WI_INFO_LINK_STAT_ASSOC_FAILED:
 			if (vap->iv_opmode == IEEE80211_M_STA)
 				ieee80211_new_state(vap, IEEE80211_S_SCAN,
@@ -1748,7 +1790,7 @@
 				wi_write_val(sc, WI_RID_PROMISC, 1);
 			}
 			wi_write_val(sc, WI_RID_CNFAUTHMODE,
-			    sc->sc_cnfauthmode);
+			    vap->iv_bss->ni_authmode);
 			/* XXX should honor IEEE80211_F_DROPUNENC */
 			val = PRIVACY_INVOKED | EXCLUDE_UNENCRYPTED;
 			/*

==== //depot/projects/vap/sys/dev/wi/if_wi_pci.c#6 (text+ko) ====

@@ -246,10 +246,8 @@
 wi_pci_suspend(device_t dev)
 {
 	struct wi_softc	*sc = device_get_softc(dev);
-	struct ieee80211com *ic = &sc->sc_ic;
-	struct ifnet *ifp = ic->ic_ifp;
 
-	wi_stop(ifp, 1);
+	wi_stop(sc, 1);
 	
 	return (0);
 }

==== //depot/projects/vap/sys/dev/wi/if_wivar.h#10 (text+ko) ====

@@ -194,4 +194,4 @@
 void	wi_init(void *);
 void	wi_intr(void *);
 int	wi_mgmt_xmit(struct wi_softc *, caddr_t, int);
-void	wi_stop(struct ifnet *, int);
+void	wi_stop(struct wi_softc *, int);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200803262308.m2QN8CIn006648>