PERFORCE change 127009 for review
Andrew Thompson
thompsa at FreeBSD.org
Sun Sep 30 03:10:12 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=127009
Change 127009 by thompsa at thompsa_heff on 2007/09/30 10:09:51
- Use our own watchdog
- Add WPA support again
- Add more scan hacks and tricks
- Put msdu tx rates back in
Obtained from: sams ipw changes
Affected files ...
.. //depot/projects/wifi/sys/dev/ipw/if_ipw.c#27 edit
.. //depot/projects/wifi/sys/dev/ipw/if_ipwreg.h#7 edit
.. //depot/projects/wifi/sys/dev/ipw/if_ipwvar.h#9 edit
Differences ...
==== //depot/projects/wifi/sys/dev/ipw/if_ipw.c#27 (text+ko) ====
@@ -126,7 +126,7 @@
static int ipw_tx_start(struct ifnet *, struct mbuf *,
struct ieee80211_node *);
static void ipw_start(struct ifnet *);
-static void ipw_watchdog(struct ifnet *);
+static void ipw_watchdog(void *);
static int ipw_ioctl(struct ifnet *, u_long, caddr_t);
static void ipw_stop_master(struct ipw_softc *);
static int ipw_enable(struct ipw_softc *);
@@ -226,6 +226,7 @@
TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc);
TASK_INIT(&sc->sc_scan_task, 0, ipw_scan_task, sc);
TASK_INIT(&sc->sc_assoc_task, 0, ipw_assoc_task, sc);
+ callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0);
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
device_printf(dev, "chip is in D%d power mode "
@@ -279,7 +280,6 @@
ifp->if_init = ipw_init;
ifp->if_ioctl = ipw_ioctl;
ifp->if_start = ipw_start;
- ifp->if_watchdog = ipw_watchdog;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_READY(&ifp->if_snd);
@@ -290,11 +290,12 @@
ic->ic_state = IEEE80211_S_INIT;
/* set device capabilities */
- ic->ic_caps =
- IEEE80211_C_IBSS | /* IBSS mode supported */
- IEEE80211_C_MONITOR | /* monitor mode supported */
- IEEE80211_C_TXPMGT | /* tx power management */
- IEEE80211_C_SHPREAMBLE; /* short preamble supported */
+ ic->ic_caps = IEEE80211_C_IBSS /* IBSS mode supported */
+ | IEEE80211_C_MONITOR /* monitor mode supported */
+ | IEEE80211_C_PMGT /* power save supported */
+ | IEEE80211_C_SHPREAMBLE /* short preamble supported */
+ | IEEE80211_C_WPA /* 802.11i supported */
+ ;
/* read MAC address from EEPROM */
val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0);
@@ -395,6 +396,7 @@
struct ifnet *ifp = ic->ic_ifp;
ipw_stop(sc);
+ callout_drain(&sc->sc_wdtimer);
if (ifp != NULL) {
bpfdetach(ifp);
@@ -966,7 +968,7 @@
cmd = mtod(sbuf->m, struct ipw_cmd *);
- DPRINTFN(4, ("cmd ack'ed %s(%u, %u, %u, %u, %u)\n",
+ DPRINTFN(9, ("cmd ack'ed %s(%u, %u, %u, %u, %u)\n",
ipw_cmdname(le32toh(cmd->type)), le32toh(cmd->type),
le32toh(cmd->subtype), le32toh(cmd->seq), le32toh(cmd->len),
le32toh(cmd->status)));
@@ -1012,11 +1014,23 @@
break;
case IPW_STATE_SCAN_COMPLETE:
+ /*
+ * XXX For some reason scan requests generate scan
+ * started + scan done events before any traffic is
+ * received (e.g. probe response frames). We work
+ * around this by marking the HACK flag and skipping
+ * the first scan complete event.
+ */
+ if (sc->flags & IPW_FLAG_HACK) {
+ sc->flags &= ~IPW_FLAG_HACK;
+ break;
+ }
DPRINTFN(3, ("Scan complete (%s flags 0x%x)\n",
IEEESTATE(ic), sc->flags));
if (sc->flags & IPW_FLAG_SCANNING) {
ieee80211_scan_done(ic);
sc->flags &= ~IPW_FLAG_SCANNING;
+ sc->sc_scan_timer = 0;
}
break;
@@ -1185,7 +1199,7 @@
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
- if (ic->ic_state == IEEE80211_S_SCAN)
+ if (sc->flags & IPW_FLAG_SCANNING)
ipw_fix_channel(sc, m);
wh = mtod(m, struct ieee80211_frame *);
@@ -1407,12 +1421,13 @@
{ IPW_CMD_SET_ESSID, "SET_ESSID" },
{ IPW_CMD_SET_FRAG_THRESHOLD, "SET_FRAG_THRESHOLD" },
{ IPW_CMD_SET_MAC_ADDRESS, "SET_MAC_ADDRESS" },
- { IPW_CMD_SET_MANDATORY_BSSID, "SET_MANDATORY_BSSID" },
+ { IPW_CMD_SET_MANDATORY_BSSID, "SET_MANDATORY_BSSID" },
{ IPW_CMD_SET_MODE, "SET_MODE" },
+ { IPW_CMD_SET_MSDU_TX_RATES, "SET_MSDU_TX_RATES" },
{ IPW_CMD_SET_POWER_MODE, "SET_POWER_MODE" },
{ IPW_CMD_SET_RTS_THRESHOLD, "SET_RTS_THRESHOLD" },
{ IPW_CMD_SET_SCAN_OPTIONS, "SET_SCAN_OPTIONS" },
- { IPW_CMD_SET_SECURITY_INFORMATION, "SET_SECURITY_INFO" },
+ { IPW_CMD_SET_SECURITY_INFO, "SET_SECURITY_INFO" },
{ IPW_CMD_SET_TX_POWER_INDEX, "SET_TX_POWER_INDEX" },
{ IPW_CMD_SET_TX_RATES, "SET_TX_RATES" },
{ IPW_CMD_SET_WEP_FLAGS, "SET_WEP_FLAGS" },
@@ -1478,8 +1493,19 @@
bus_dmamap_sync(sc->cmd_dmat, sc->cmd_map, BUS_DMASYNC_PREWRITE);
bus_dmamap_sync(sc->tbd_dmat, sc->tbd_map, BUS_DMASYNC_PREWRITE);
- DPRINTFN(4, ("sending %s(%u, %u, %u, %u)\n",
- ipw_cmdname(type), type, 0, 0, len));
+#ifdef IPW_DEBUG
+ if (ipw_debug >= 4) {
+ printf("sending %s(%u, %u, %u, %u)", ipw_cmdname(type), type,
+ 0, 0, len);
+ /* Print the data buffer in the higher debug level */
+ if (ipw_debug >= 9 && len > 0) {
+ printf(" data: 0x");
+ for (int i = 1; i <= len; i++)
+ printf("%1D", (char *)data + len - i, "");
+ }
+ printf("\n");
+ }
+#endif
/* kick firmware */
sc->txfree--;
@@ -1703,20 +1729,19 @@
/* start watchdog timer */
sc->sc_tx_timer = 5;
- ifp->if_timer = 1;
}
mtx_unlock(&sc->sc_mtx);
}
static void
-ipw_watchdog(struct ifnet *ifp)
+ipw_watchdog(void *arg)
{
- struct ipw_softc *sc = ifp->if_softc;
+ struct ipw_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
- mtx_lock(&sc->sc_mtx);
-
- ifp->if_timer = 0;
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
@@ -1724,13 +1749,20 @@
ifp->if_oerrors++;
taskqueue_enqueue_fast(taskqueue_fast,
&sc->sc_init_task);
- mtx_unlock(&sc->sc_mtx);
- return;
+ }
+ }
+ if (sc->sc_scan_timer > 0) {
+ if (--sc->sc_scan_timer == 0) {
+ DPRINTFN(3, ("Scan timeout\n"));
+ /* End the scan */
+ if (sc->flags & IPW_FLAG_SCANNING) {
+ ieee80211_scan_done(ic);
+ sc->flags &= ~IPW_FLAG_SCANNING;
+ }
}
- ifp->if_timer = 1;
}
-
- mtx_unlock(&sc->sc_mtx);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ callout_reset(&sc->sc_wdtimer, hz, ipw_watchdog, sc);
}
static int
@@ -1790,7 +1822,8 @@
tmp = CSR_READ_4(sc, IPW_CSR_RST);
CSR_WRITE_4(sc, IPW_CSR_RST, tmp | IPW_RST_PRINCETON_RESET);
- sc->flags &= ~IPW_FLAG_FW_INITED;
+ /* Clear all flags except the following */
+ sc->flags &= IPW_FLAG_HAS_RADIO_SWITCH;
}
static int
@@ -1979,6 +2012,48 @@
}
static int
+ipw_setwepkeys(struct ipw_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ipw_wep_key wepkey;
+ struct ieee80211_key *wk;
+ int error, i;
+
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ wk = &ic->ic_crypto.cs_nw_keys[i];
+
+ if (wk->wk_cipher == NULL ||
+ wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP)
+ continue;
+
+ wepkey.idx = i;
+ wepkey.len = wk->wk_keylen;
+ memset(wepkey.key, 0, sizeof wepkey.key);
+ memcpy(wepkey.key, wk->wk_key, wk->wk_keylen);
+ DPRINTF(("Setting wep key index %u len %u\n", wepkey.idx,
+ wepkey.len));
+ error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY, &wepkey,
+ sizeof wepkey);
+ if (error != 0)
+ return error;
+ }
+ return 0;
+}
+
+static int
+ipw_setwpaie(struct ipw_softc *sc, const void *ie, int ielen)
+{
+ struct ipw_wpa_ie wpaie;
+
+ memset(&wpaie, 0, sizeof(wpaie));
+ wpaie.len = htole32(ielen);
+ /* XXX verify length */
+ memcpy(&wpaie.ie, ie, ielen);
+ DPRINTF(("Setting wpa ie\n"));
+ return ipw_cmd(sc, IPW_CMD_SET_WPA_IE, &wpaie, sizeof(wpaie));
+}
+
+static int
ipw_setbssid(struct ipw_softc *sc, uint8_t *bssid)
{
static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
@@ -2052,7 +2127,10 @@
int error;
DPRINTF(("%s: flags 0x%x\n", __func__, sc->flags));
- sc->flags |= IPW_FLAG_SCANNING;
+
+ if (sc->flags & IPW_FLAG_SCANNING)
+ return (EBUSY);
+ sc->flags |= IPW_FLAG_SCANNING | IPW_FLAG_HACK;
/* NB: IPW_SCAN_DO_NOT_ASSOCIATE does not work (we set it anyway) */
error = ipw_setscanopts(sc, 0x3fff, IPW_SCAN_DO_NOT_ASSOCIATE);
@@ -2073,6 +2151,7 @@
* if so just re-enable it to kick off scanning.
*/
DPRINTF(("Starting scan\n"));
+ sc->sc_scan_timer = 3;
if (sc->flags & IPW_FLAG_ENABLED) {
params = 0; /* XXX? */
error = ipw_cmd(sc, IPW_CMD_BROADCAST_SCAN,
@@ -2082,7 +2161,7 @@
done:
if (error != 0) {
DPRINTF(("Scan failed\n"));
- sc->flags &= ~IPW_FLAG_SCANNING;
+ sc->flags &= ~(IPW_FLAG_SCANNING | IPW_FLAG_HACK);
}
return (error);
}
@@ -2108,11 +2187,9 @@
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
struct ipw_security security;
- struct ieee80211_key *k;
- struct ipw_wep_key wepkey;
struct ipw_configuration config;
uint32_t data;
- int error, i;
+ int error;
error = ipw_disable(sc);
if (error != 0)
@@ -2173,6 +2250,12 @@
if (error != 0)
return error;
+ /* NB: use the same rate set */
+ DPRINTF(("Setting msdu tx rates to 0x%x\n", le32toh(data)));
+ error = ipw_cmd(sc, IPW_CMD_SET_MSDU_TX_RATES, &data, sizeof data);
+ if (error != 0)
+ return error;
+
data = htole32(0xf); /* 1, 2, 5.5, 11 */
DPRINTF(("Setting tx rates to 0x%x\n", le32toh(data)));
error = ipw_cmd(sc, IPW_CMD_SET_TX_RATES, &data, sizeof data);
@@ -2228,35 +2311,25 @@
IPW_AUTH_SHARED : IPW_AUTH_OPEN;
security.ciphers = htole32(IPW_CIPHER_NONE);
DPRINTF(("Setting authmode to %u\n", security.authmode));
- error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFORMATION, &security,
+ error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFO, &security,
sizeof security);
if (error != 0)
return error;
if (ic->ic_flags & IEEE80211_F_PRIVACY) {
- k = ic->ic_crypto.cs_nw_keys;
- for (i = 0; i < IEEE80211_WEP_NKID; i++, k++) {
- if (k->wk_keylen == 0)
- continue;
+ error = ipw_setwepkeys(sc);
+ if (error != 0)
+ return error;
- wepkey.idx = i;
- wepkey.len = k->wk_keylen;
- memset(wepkey.key, 0, sizeof wepkey.key);
- memcpy(wepkey.key, k->wk_key, k->wk_keylen);
- DPRINTF(("Setting wep key index %u len %u\n",
- wepkey.idx, wepkey.len));
- error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY, &wepkey,
- sizeof wepkey);
+ if (ic->ic_crypto.cs_def_txkey != IEEE80211_KEYIX_NONE) {
+ data = htole32(ic->ic_crypto.cs_def_txkey);
+ DPRINTF(("Setting wep tx key index to %u\n",
+ le32toh(data)));
+ error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
+ sizeof data);
if (error != 0)
return error;
}
-
- data = htole32(ic->ic_crypto.cs_def_txkey);
- DPRINTF(("Setting wep tx key index to %u\n", le32toh(data)));
- error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
- sizeof data);
- if (error != 0)
- return error;
}
data = htole32((ic->ic_flags & IEEE80211_F_PRIVACY) ? IPW_WEPON : 0);
@@ -2265,16 +2338,11 @@
if (error != 0)
return error;
-#if 0
- struct ipw_wpa_ie ie;
-
- memset(&ie, 0, sizeof ie);
- ie.len = htole32(sizeof (struct ieee80211_ie_wpa));
- DPRINTF(("Setting wpa ie\n"));
- error = ipw_cmd(sc, IPW_CMD_SET_WPA_IE, &ie, sizeof ie);
- if (error != 0)
- return error;
-#endif
+ if (ic->ic_opt_ie != NULL) {
+ error = ipw_setwpaie(sc, ic->ic_opt_ie, ic->ic_opt_ie_len);
+ if (error != 0)
+ return error;
+ }
if (ic->ic_opmode == IEEE80211_M_IBSS) {
data = htole32(ic->ic_bintval);
@@ -2311,10 +2379,8 @@
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = ic->ic_bss;
struct ipw_security security;
- struct ieee80211_key *k;
- struct ipw_wep_key wepkey;
uint32_t data;
- int error, i;
+ int error;
error = ipw_disable(sc);
if (error != 0)
@@ -2325,35 +2391,25 @@
IPW_AUTH_SHARED : IPW_AUTH_OPEN;
security.ciphers = htole32(IPW_CIPHER_NONE);
DPRINTF(("Setting authmode to %u\n", security.authmode));
- error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFORMATION, &security,
+ error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFO, &security,
sizeof security);
if (error != 0)
return (error);
if (ic->ic_flags & IEEE80211_F_PRIVACY) {
- k = ic->ic_crypto.cs_nw_keys;
- for (i = 0; i < IEEE80211_WEP_NKID; i++, k++) {
- if (k->wk_keylen == 0)
- continue;
+ error = ipw_setwepkeys(sc);
+ if (error != 0)
+ return error;
- wepkey.idx = i;
- wepkey.len = k->wk_keylen;
- memset(wepkey.key, 0, sizeof wepkey.key);
- memcpy(wepkey.key, k->wk_key, k->wk_keylen);
- DPRINTF(("Setting wep key index %u len %u\n",
- wepkey.idx, wepkey.len));
- error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY, &wepkey,
- sizeof wepkey);
+ if (ic->ic_crypto.cs_def_txkey != IEEE80211_KEYIX_NONE) {
+ data = htole32(ic->ic_crypto.cs_def_txkey);
+ DPRINTF(("Setting wep tx key index to %u\n",
+ le32toh(data)));
+ error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
+ sizeof data);
if (error != 0)
return error;
}
-
- data = htole32(ic->ic_crypto.cs_def_txkey);
- DPRINTF(("Setting wep tx key index to %u\n", le32toh(data)));
- error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
- sizeof data);
- if (error != 0)
- return error;
}
data = htole32((ic->ic_flags & IEEE80211_F_PRIVACY) ? IPW_WEPON : 0);
@@ -2370,6 +2426,11 @@
if (error != 0)
return (error);
+ if (ic->ic_opt_ie != NULL) {
+ error = ipw_setwpaie(sc, ic->ic_opt_ie, ic->ic_opt_ie_len);
+ if (error != 0)
+ return error;
+ }
if (ic->ic_opmode == IEEE80211_M_IBSS) {
error = ipw_setchannel(sc, ni->ni_chan);
if (error != 0)
@@ -2557,6 +2618,7 @@
} else
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ callout_reset(&sc->sc_wdtimer, hz, ipw_watchdog, sc);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -2588,6 +2650,7 @@
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+ callout_stop(&sc->sc_wdtimer);
ipw_stop_master(sc);
CSR_WRITE_4(sc, IPW_CSR_RST, IPW_RST_SW_RESET);
@@ -2599,7 +2662,6 @@
ipw_release_sbd(sc, &sc->stbd_list[i]);
sc->sc_tx_timer = 0;
- ifp->if_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
mtx_unlock(&sc->sc_mtx);
==== //depot/projects/wifi/sys/dev/ipw/if_ipwreg.h#7 (text+ko) ====
@@ -88,11 +88,18 @@
#define IPW_IO_LED_OFF 0x00002000
#define IPW_IO_RADIO_DISABLED 0x00010000
+/* state codes sent by fw on IPW_STATUS_CODE_NEWSTATE interrupt */
+#define IPW_STATE_INITIALIZED 0x0001
+#define IPW_STATE_CC_FOUND 0x0002 /* 802.11d cc received */
#define IPW_STATE_ASSOCIATED 0x0004
#define IPW_STATE_ASSOCIATION_LOST 0x0008
+#define IPW_STATE_ASSOCIATION_CHANGED 0x0010 /* assoc params changed? */
#define IPW_STATE_SCAN_COMPLETE 0x0020
+#define IPW_STATE_PS_ENTER 0x0040 /* entered power-save mode */
+#define IPW_STATE_PS_EXIT 0x0080 /* exited power-save mode */
#define IPW_STATE_RADIO_DISABLED 0x0100
#define IPW_STATE_DISABLED 0x0200
+#define IPW_STATE_POWER_DOWN 0x0400 /* ??? */
#define IPW_STATE_SCANNING 0x0800
/* table1 offsets */
@@ -146,7 +153,9 @@
uint8_t flags;
#define IPW_STATUS_FLAG_DECRYPTED 0x01
#define IPW_STATUS_FLAG_WEP_ENCRYPTED 0x02
+#define IPW_STATUS_FLAG_CRC_ERROR 0x04
uint8_t rssi; /* received signal strength indicator */
+#define IPW_RSSI_TO_DBM (-98) /* XXX fixed nf to convert dBm */
} __packed;
/* data header */
@@ -190,9 +199,13 @@
#define IPW_CMD_DISABLE 44
#define IPW_CMD_SET_DESIRED_BSSID 45
#define IPW_CMD_SET_SCAN_OPTIONS 46
+#define IPW_CMD_SET_SCAN_DWELL_TIME 47
+#define IPW_CMD_SET_SHORT_RETRY 51
+#define IPW_CMD_SET_LONG_RETRY 52
#define IPW_CMD_PREPARE_POWER_DOWN 58
#define IPW_CMD_DISABLE_PHY 61
-#define IPW_CMD_SET_SECURITY_INFORMATION 67
+#define IPW_CMD_SET_MSDU_TX_RATES 62
+#define IPW_CMD_SET_SECURITY_INFO 67
#define IPW_CMD_DISASSOCIATE 68
#define IPW_CMD_SET_WPA_IE 69
uint32_t subtype;
@@ -205,7 +218,7 @@
/* possible values for command IPW_CMD_SET_POWER_MODE */
#define IPW_POWER_MODE_CAM 0
-#define IPW_POWER_AUTOMATIC 6
+#define IPW_POWER_MODE_AUTO 6
/* possible values for command IPW_CMD_SET_MODE */
#define IPW_MODE_BSS 0
@@ -242,6 +255,7 @@
struct ipw_scan_options {
uint32_t flags;
#define IPW_SCAN_DO_NOT_ASSOCIATE 0x00000001
+#define IPW_SCAN_MIXED_CELL 0x00000002
#define IPW_SCAN_PASSIVE 0x00000008
uint32_t channels;
} __packed;
==== //depot/projects/wifi/sys/dev/ipw/if_ipwvar.h#9 (text+ko) ====
@@ -87,12 +87,13 @@
struct task sc_init_task;
struct task sc_scan_task;
struct task sc_assoc_task;
+ struct callout sc_wdtimer; /* watchdog timer */
uint32_t flags;
#define IPW_FLAG_FW_INITED (1 << 0)
#define IPW_FLAG_INIT_LOCKED (1 << 1)
#define IPW_FLAG_HAS_RADIO_SWITCH (1 << 2)
-#define IPW_FLAG_FW_WARNED (1 << 3)
+#define IPW_FLAG_HACK (1 << 3)
#define IPW_FLAG_SCANNING (1 << 4)
#define IPW_FLAG_ENABLED (1 << 5)
#define IPW_FLAG_BUSY (1 << 6)
@@ -108,6 +109,7 @@
const struct firmware *sc_firmware;
int sc_tx_timer;
+ int sc_scan_timer;
bus_dma_tag_t tbd_dmat;
bus_dma_tag_t rbd_dmat;
More information about the p4-projects
mailing list