Index: sys/dev/iwi/if_iwivar.h =================================================================== --- sys/dev/iwi/if_iwivar.h (revision 213522) +++ sys/dev/iwi/if_iwivar.h (working copy) @@ -193,6 +193,7 @@ struct iwi_softc { struct task sc_scanaborttask; /* cancel active scan */ struct task sc_restarttask; /* restart adapter processing */ struct task sc_opstask; /* scan / auth processing */ + struct task sc_monitortask; unsigned int sc_softled : 1, /* enable LED gpio status */ sc_ledstate: 1, /* LED on/off state */ Index: sys/dev/iwi/if_iwi.c =================================================================== --- sys/dev/iwi/if_iwi.c (revision 213522) +++ sys/dev/iwi/if_iwi.c (working copy) @@ -163,6 +163,7 @@ static void iwi_release_fw_dma(struct iwi_softc *s static int iwi_config(struct iwi_softc *); static int iwi_get_firmware(struct iwi_softc *); static void iwi_put_firmware(struct iwi_softc *); +static void iwi_monitor_scan(void *, int); static int iwi_scanchan(struct iwi_softc *, unsigned long, int); static void iwi_scan_start(struct ieee80211com *); static void iwi_scan_end(struct ieee80211com *); @@ -291,6 +292,7 @@ iwi_attach(device_t dev) TASK_INIT(&sc->sc_restarttask, 0, iwi_restart, sc); TASK_INIT(&sc->sc_opstask, 0, iwi_ops, sc); TASK_INIT(&sc->sc_scanaborttask, 0, iwi_scanabort, sc); + TASK_INIT(&sc->sc_monitortask, 0, iwi_monitor_scan, sc); callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0); if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { @@ -978,7 +980,8 @@ iwi_newstate(struct ieee80211com *ic, enum ieee802 */ if (ic->ic_state == IEEE80211_S_SCAN) iwi_assoc(ic); - } + } else if (ic->ic_opmode == IEEE80211_M_MONITOR) + taskqueue_enqueue(sc->sc_tq, &sc->sc_monitortask); break; case IEEE80211_S_INIT: /* @@ -1411,6 +1414,18 @@ iwi_notification_intr(struct iwi_softc *sc, struct IWI_STATE_END(sc, IWI_FW_SCANNING); + /* + * Monitor mode works by doing a passive scan to set + * the channel and enable rx. Because we don't want + * to abort a scan lest the firmware crash we scan + * for a short period of time and automatically restart + * the scan when notified the sweep has completed. + */ + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + taskqueue_enqueue(sc->sc_tq, &sc->sc_monitortask); + break; + } + if (scan->status == IWI_SCAN_COMPLETED) ieee80211_scan_next(ic); @@ -2595,6 +2610,11 @@ iwi_config(struct iwi_softc *sc) config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; config.disable_unicast_decryption = 1; config.disable_multicast_decryption = 1; + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + config.allow_invalid_frames = 1; + config.allow_beacon_and_probe_resp = 1; + config.allow_mgt = 1; + } DPRINTF(("Configuring adapter\n")); error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config); if (error != 0) @@ -2717,6 +2737,18 @@ scan_band(const struct ieee80211_channel *c) return IEEE80211_IS_CHAN_5GHZ(c) ? IWI_CHAN_5GHZ : IWI_CHAN_2GHZ; } +static void +iwi_monitor_scan(void *arg, int npending) +{ + struct ieee80211com *ic = arg; + struct iwi_softc *sc = ic->ic_ifp->if_softc; + IWI_LOCK_DECL; + + IWI_LOCK(sc); + (void) iwi_scanchan(sc, 2000, 0); + IWI_UNLOCK(sc); +} + /* * Start a scan on the current channel or all channels. */