On Tue, Sep 09, 2014 at 12:38:04PM +0200, Fabian Raetz wrote: > Hi, > > below is a patch for iwn(4) which hopefully fixes a problem where iwn(4) > does not return from a scan, if the interface is up.
here's an updated version which does not set hdr->max_svc / hdr->pause_svc. Cristoph Zimmermann noticed that scan requests return no APs on his device (thanks for testing). iwn0 at pci2 dev 0 function 0 "Intel WiFi Link 5100" rev 0x00: msi, MIMO 1T2R, MoW, address 00:21:6b:a3:70:7a As Piotr and Mike tested the patch from Piotr which does not set this values either and it still works on my card, this should the way to go for now. Index: if_iwn.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v retrieving revision 1.133 diff -u -p -r1.133 if_iwn.c --- if_iwn.c 22 Jul 2014 13:12:11 -0000 1.133 +++ if_iwn.c 9 Sep 2014 14:57:34 -0000 @@ -220,6 +220,9 @@ int iwn_send_btcoex(struct iwn_softc *) int iwn_send_advanced_btcoex(struct iwn_softc *); int iwn5000_runtime_calib(struct iwn_softc *); int iwn_config(struct iwn_softc *); +uint16_t iwn_get_active_dwell_time(struct iwn_softc *, uint16_t, uint8_t); +uint16_t iwn_limit_dwell(struct iwn_softc *, uint16_t); +uint16_t iwn_get_passive_dwell_time(struct iwn_softc *, uint16_t); int iwn_scan(struct iwn_softc *, uint16_t); int iwn_auth(struct iwn_softc *); int iwn_run(struct iwn_softc *); @@ -4424,6 +4427,66 @@ iwn_config(struct iwn_softc *sc) return 0; } +uint16_t +iwn_get_active_dwell_time(struct iwn_softc *sc, + uint16_t flags, uint8_t n_probes) +{ + /* No channel? Default to 2GHz settings */ + if (flags & IEEE80211_CHAN_2GHZ) { + return (IWN_ACTIVE_DWELL_TIME_2GHZ + + IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1)); + } + + /* 5GHz dwell time */ + return (IWN_ACTIVE_DWELL_TIME_5GHZ + + IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1)); +} + +/* + * Limit the total dwell time to 85% of the beacon interval. + * + * Returns the dwell time in milliseconds. + */ +uint16_t +iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = ic->ic_bss; + int bintval = 0; + + /* bintval is in TU (1.024mS) */ + if (ni != NULL) + bintval = ni->ni_intval; + + /* + * If it's non-zero, we should calculate the minimum of + * it and the DWELL_BASE. + * + * XXX Yes, the math should take into account that bintval + * is 1.024mS, not 1mS.. + */ + if (bintval > 0) { + return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100))); + } + + /* No association context? Default */ + return (IWN_PASSIVE_DWELL_BASE); +} + +uint16_t +iwn_get_passive_dwell_time(struct iwn_softc *sc, uint16_t flags) +{ + uint16_t passive; + if (flags & IEEE80211_CHAN_2GHZ) { + passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ; + } else { + passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ; + } + + /* Clamp to the beacon interval if we're associated */ + return (iwn_limit_dwell(sc, passive)); +} + int iwn_scan(struct iwn_softc *sc, uint16_t flags) { @@ -4436,9 +4499,9 @@ iwn_scan(struct iwn_softc *sc, uint16_t struct ieee80211_rateset *rs; struct ieee80211_channel *c; uint8_t *buf, *frm; - uint16_t rxchain; + uint16_t rxchain, dwell_active, dwell_passive; uint8_t txant; - int buflen, error; + int buflen, error, is_active; buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); if (buf == NULL) { @@ -4474,7 +4537,6 @@ iwn_scan(struct iwn_softc *sc, uint16_t tx->lifetime = htole32(IWN_LIFETIME_INFINITE); if (flags & IEEE80211_CHAN_5GHZ) { - hdr->crc_threshold = 0xffff; /* Send probe requests at 6Mbps. */ tx->plcp = iwn_rates[IWN_RIDX_OFDM6].plcp; rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; @@ -4488,12 +4550,23 @@ iwn_scan(struct iwn_softc *sc, uint16_t /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); tx->rflags |= IWN_RFLAG_ANT(txant); + + /* + * Only do active scanning if we're announcing a probe request + * for a given SSID (or more, if we ever add it to the driver.) + */ + is_active = 0; + /* + * If we're scanning for a specific SSID, add it to the command. + */ essid = (struct iwn_scan_essid *)(tx + 1); if (ic->ic_des_esslen != 0) { essid[0].id = IEEE80211_ELEMID_SSID; essid[0].len = ic->ic_des_esslen; memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen); + + is_active = 1; } /* * Build a probe request frame. Most of the following code is a @@ -4522,6 +4595,41 @@ iwn_scan(struct iwn_softc *sc, uint16_t /* Set length of probe request. */ tx->len = htole16(frm - (uint8_t *)wh); + /* + * If active scanning is requested but a certain channel is + * marked passive, we can do active scanning if we detect + * transmissions. + * + * There is an issue with some firmware versions that triggers + * a sysassert on a "good CRC threshold" of zero (== disabled), + * on a radar channel even though this means that we should NOT + * send probes. + * + * The "good CRC threshold" is the number of frames that we + * need to receive during our dwell time on a channel before + * sending out probes -- setting this to a huge value will + * mean we never reach it, but at the same time work around + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER + * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. + */ + + /* + * If we're doing active scanning, set the crc_threshold + * to a suitable value. This is different to active veruss + * passive scanning depending upon the channel flags; the + * firmware will obey that particular check for us. + */ + if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN) + hdr->crc_threshold = is_active ? + IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED; + else + hdr->crc_threshold = is_active ? + IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER; + chan = (struct iwn_scan_chan *)frm; for (c = &ic->ic_channels[1]; c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) { @@ -4531,19 +4639,33 @@ iwn_scan(struct iwn_softc *sc, uint16_t chan->chan = htole16(ieee80211_chan2ieee(ic, c)); DPRINTFN(2, ("adding channel %d\n", chan->chan)); chan->flags = 0; - if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) - chan->flags |= htole32(IWN_CHAN_ACTIVE); if (ic->ic_des_esslen != 0) chan->flags |= htole32(IWN_CHAN_NPBREQS(1)); + + if (c->ic_flags & IEEE80211_CHAN_PASSIVE) + chan->flags |= htole32(IWN_CHAN_PASSIVE); + else + chan->flags |= htole32(IWN_CHAN_ACTIVE); + + /* + * Calculate the active/passive dwell times. + */ + + dwell_active = iwn_get_active_dwell_time(sc, flags, is_active); + dwell_passive = iwn_get_passive_dwell_time(sc, flags); + + /* Make sure they're valid */ + if (dwell_passive <= dwell_active) + dwell_passive = dwell_active + 1; + + chan->active = htole16(dwell_active); + chan->passive = htole16(dwell_passive); + chan->dsp_gain = 0x6e; if (IEEE80211_IS_CHAN_5GHZ(c)) { chan->rf_gain = 0x3b; - chan->active = htole16(24); - chan->passive = htole16(110); } else { chan->rf_gain = 0x28; - chan->active = htole16(36); - chan->passive = htole16(120); } hdr->nchan++; chan++; @@ -5580,6 +5702,14 @@ iwn_read_firmware_tlv(struct iwn_softc * sc->reset_noise_gain = letoh32(*ptr); sc->noise_gain = letoh32(*ptr) + 1; } + break; + case IWN_FW_TLV_FLAGS: + if (len < sizeof(uint32_t)) + break; + if (len % sizeof(uint32_t)) + break; + sc->tlv_feature_flags = letoh32(*ptr); + DPRINTF(("feature: 0x%08x\n", sc->tlv_feature_flags)); break; default: DPRINTF(("TLV type %d not handled\n", Index: if_iwnreg.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwnreg.h,v retrieving revision 1.47 diff -u -p -r1.47 if_iwnreg.h --- if_iwnreg.h 11 Feb 2014 19:30:10 -0000 1.47 +++ if_iwnreg.h 9 Sep 2014 14:57:34 -0000 @@ -799,6 +799,7 @@ struct iwn_scan_hdr { struct iwn_scan_chan { uint32_t flags; +#define IWN_CHAN_PASSIVE (0 << 0) #define IWN_CHAN_ACTIVE (1 << 0) #define IWN_CHAN_NPBREQS(x) (((1 << (x)) - 1) << 1) @@ -812,6 +813,51 @@ struct iwn_scan_chan { /* Maximum size of a scan command. */ #define IWN_SCAN_MAXSZ (MCLBYTES - 4) +/* + * For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after + * sending probe req. This should be set long enough to hear probe responses + * from more than one AP. + */ +#define IWN_ACTIVE_DWELL_TIME_2GHZ (30) /* all times in msec */ +#define IWN_ACTIVE_DWELL_TIME_5GHZ (20) +#define IWN_ACTIVE_DWELL_FACTOR_2GHZ (3) +#define IWN_ACTIVE_DWELL_FACTOR_5GHZ (2) + +/* + * For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. + * Must be set longer than active dwell time. + * For the most reliable scan, set > AP beacon interval (typically 100msec). + */ +#define IWN_PASSIVE_DWELL_TIME_2GHZ (20) /* all times in msec */ +#define IWN_PASSIVE_DWELL_TIME_5GHZ (10) +#define IWN_PASSIVE_DWELL_BASE (100) +#define IWN_CHANNEL_TUNE_TIME (5) + +/* + * If active scanning is requested but a certain channel is + * marked passive, we can do active scanning if we detect + * transmissions. + * + * There is an issue with some firmware versions that triggers + * a sysassert on a "good CRC threshold" of zero (== disabled), + * on a radar channel even though this means that we should NOT + * send probes. + * + * The "good CRC threshold" is the number of frames that we + * need to receive during our dwell time on a channel before + * sending out probes -- setting this to a huge value will + * mean we never reach it, but at the same time work around + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER + * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. + */ +#define IWN_GOOD_CRC_TH_DISABLED 0 +#define IWN_GOOD_CRC_TH_DEFAULT htole16(1) +#define IWN_GOOD_CRC_TH_NEVER htole16(0xffff) + /* Structure for command IWN_CMD_TXPOWER (4965AGN only.) */ #define IWN_RIDX_MAX 32 struct iwn4965_cmd_txpower { @@ -1407,6 +1453,7 @@ struct iwn_fw_tlv { #define IWN_FW_TLV_PBREQ_MAXLEN 6 #define IWN_FW_TLV_ENH_SENS 14 #define IWN_FW_TLV_PHY_CALIB 15 +#define IWN_FW_TLV_FLAGS 18 uint16_t alt; uint32_t len; @@ -1419,6 +1466,60 @@ struct iwn_fw_tlv { #define IWN_FW_BOOT_TEXT_MAXSZ 1024 #define IWN4965_FWSZ (IWN4965_FW_TEXT_MAXSZ + IWN4965_FW_DATA_MAXSZ) #define IWN5000_FWSZ IWN5000_FW_TEXT_MAXSZ + +/* + * Microcode flags TLV (18.) + */ + +/** + * enum iwn_ucode_tlv_flag - ucode API flags + * @IWN_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously + * was a separate TLV but moved here to save space. + * @IWN_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, + * treats good CRC threshold as a boolean + * @IWN_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + * @IWN_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. + * @IWN_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS + * @IWN_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD + * @IWN_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan + * offload profile config command. + * @IWN_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api + * @IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. + * @IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six + * (rather than two) IPv6 addresses + * @IWN_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API + * @IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element + * from the probe request template. + * @IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping + * connection when going back to D0 + * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) + * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) + * @IWN_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. + * @IWN_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API + * @IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command + * containing CAM (Continuous Active Mode) indication. + */ +enum iwn_ucode_tlv_flag { + IWN_UCODE_TLV_FLAGS_PAN = (1 << 0), + IWN_UCODE_TLV_FLAGS_NEWSCAN = (1 << 1), + IWN_UCODE_TLV_FLAGS_MFP = (1 << 2), + IWN_UCODE_TLV_FLAGS_P2P = (1 << 3), + IWN_UCODE_TLV_FLAGS_DW_BC_TABLE = (1 << 4), + IWN_UCODE_TLV_FLAGS_NEWBT_COEX = (1 << 5), + IWN_UCODE_TLV_FLAGS_UAPSD = (1 << 6), + IWN_UCODE_TLV_FLAGS_SHORT_BL = (1 << 7), + IWN_UCODE_TLV_FLAGS_RX_ENERGY_API = (1 << 8), + IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = (1 << 9), + IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = (1 << 10), + IWN_UCODE_TLV_FLAGS_BF_UPDATED = (1 << 11), + IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID = (1 << 12), + IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API = (1 << 14), + IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = (1 << 15), + IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = (1 << 16), + IWN_UCODE_TLV_FLAGS_SCHED_SCAN = (1 << 17), + IWN_UCODE_TLV_FLAGS_STA_KEY_CMD = (1 << 19), + IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD = (1 << 20), +}; /* * Offsets into EEPROM. Index: if_iwnvar.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwnvar.h,v retrieving revision 1.27 diff -u -p -r1.27 if_iwnvar.h --- if_iwnvar.h 10 Feb 2014 19:08:58 -0000 1.27 +++ if_iwnvar.h 9 Sep 2014 14:57:34 -0000 @@ -284,6 +284,8 @@ struct iwn_softc { uint8_t reset_noise_gain; uint8_t noise_gain; + uint32_t tlv_feature_flags; + int32_t temp_off; uint32_t int_mask; uint8_t ntxchains; > > This patch was backported from this FreeBSD commit > https://svnweb.freebsd.org/base?view=revision&revision=258829 > --------- > Overhaul the iwn(4) scan infrastructure to be slightly more "correct" > for these chipsets. > > * Correctly set the active/passive flag in the scan request - this is > NOT a "is the channel active|passive"; it's to do with whether we > have an SSID to actively scan for or not. The firmware takes care > of the active/passive setup of the channel. > > * Calculate the active/passive dwell time based on the beacon interval > and the channel mode, rather than using a hard coded value. > > * For now, hardcode the scan service_time. It's defined as: > > 31:22 - number of beacon intervals to come back onto the home channel > for; > 0:21 - time (microseconds) to come back onto the home channel for. > > When doing an active scan when the NIC is active (whether we're associated > or not - it only matters if we've setup the NIC to a destination or not) > this determines how much time to stay on the home channel for when > scanning. We can tune this based on the amount of active traffic. > > For now it's 4 beacon intervals and 100 microseconds. > > * Fix the "good crc threshold" setting. It differs based on the NIC > firmware. Some older firmware required a workaround; the later > firmware instead treats the field as a flag. > > * Enforce that we are not sending a scan command if one is already > pending. Any time this is done is a bug and it absolutely needs > to be fixed - so be very loud. > > * Add the SCAN flag to a few debug messages that are scan related but > only occuring under STATE. > > Now, this does get noisy when you're scanning in an actively busy 2GHz > network as the firmware (for reason I don't quite yet understand) seems > hell bent on staying on some passive channels longer than it should. > However, it should eventually recover and complete the scan. > ---------- > > Marcin Piotr Pawlowski came up with the same diff (without comments) and > send it to me in a private mail. Thanks! > > I kept all comments to reduce the diff to FreeBSD's iwn(4). > In iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time), the > dwell_time is unused, so there could probably some code be removed. > > > Devices tested so far: > > Inter WiFi Link 5100 (Marcin Piotr Pawlowski) > Intel Centrino Advanced-N 6205 (Mike Burns, who also reported the > problem on misc@, thanks!) > Intel Centrino Wireless-N 2230 (Fabian Raetz) > > > More tests are much appreciated :) > > > Regards, > Fabian > > > Index: if_iwn.c > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v > retrieving revision 1.133 > diff -u -p -r1.133 if_iwn.c > --- if_iwn.c 22 Jul 2014 13:12:11 -0000 1.133 > +++ if_iwn.c 9 Sep 2014 09:47:48 -0000 > @@ -220,6 +220,9 @@ int iwn_send_btcoex(struct iwn_softc *) > int iwn_send_advanced_btcoex(struct iwn_softc *); > int iwn5000_runtime_calib(struct iwn_softc *); > int iwn_config(struct iwn_softc *); > +uint16_t iwn_get_active_dwell_time(struct iwn_softc *, uint16_t, > uint8_t); > +uint16_t iwn_limit_dwell(struct iwn_softc *, uint16_t); > +uint16_t iwn_get_passive_dwell_time(struct iwn_softc *, uint16_t); > int iwn_scan(struct iwn_softc *, uint16_t); > int iwn_auth(struct iwn_softc *); > int iwn_run(struct iwn_softc *); > @@ -4424,6 +4427,66 @@ iwn_config(struct iwn_softc *sc) > return 0; > } > > +uint16_t > +iwn_get_active_dwell_time(struct iwn_softc *sc, > + uint16_t flags, uint8_t n_probes) > +{ > + /* No channel? Default to 2GHz settings */ > + if (flags & IEEE80211_CHAN_2GHZ) { > + return (IWN_ACTIVE_DWELL_TIME_2GHZ + > + IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1)); > + } > + > + /* 5GHz dwell time */ > + return (IWN_ACTIVE_DWELL_TIME_5GHZ + > + IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1)); > +} > + > +/* > + * Limit the total dwell time to 85% of the beacon interval. > + * > + * Returns the dwell time in milliseconds. > + */ > +uint16_t > +iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) > +{ > + struct ieee80211com *ic = &sc->sc_ic; > + struct ieee80211_node *ni = ic->ic_bss; > + int bintval = 0; > + > + /* bintval is in TU (1.024mS) */ > + if (ni != NULL) > + bintval = ni->ni_intval; > + > + /* > + * If it's non-zero, we should calculate the minimum of > + * it and the DWELL_BASE. > + * > + * XXX Yes, the math should take into account that bintval > + * is 1.024mS, not 1mS.. > + */ > + if (bintval > 0) { > + return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100))); > + } > + > + /* No association context? Default */ > + return (IWN_PASSIVE_DWELL_BASE); > +} > + > +uint16_t > +iwn_get_passive_dwell_time(struct iwn_softc *sc, uint16_t flags) > +{ > + uint16_t passive; > + if (flags & IEEE80211_CHAN_2GHZ) { > + passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ; > + } else { > + passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ; > + } > + > + /* Clamp to the beacon interval if we're associated */ > + return (iwn_limit_dwell(sc, passive)); > +} > + > int > iwn_scan(struct iwn_softc *sc, uint16_t flags) > { > @@ -4436,9 +4499,10 @@ iwn_scan(struct iwn_softc *sc, uint16_t > struct ieee80211_rateset *rs; > struct ieee80211_channel *c; > uint8_t *buf, *frm; > - uint16_t rxchain; > + uint32_t scan_service_time; > + uint16_t rxchain, dwell_active, dwell_passive; > uint8_t txant; > - int buflen, error; > + int buflen, error, is_active; > > buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); > if (buf == NULL) { > @@ -4453,6 +4517,21 @@ iwn_scan(struct iwn_softc *sc, uint16_t > */ > hdr->quiet_time = htole16(10); /* timeout in milliseconds */ > hdr->quiet_threshold = htole16(1); /* min # of packets */ > + /* > + * Max needs to be greater than active and passive and quiet! > + * It's also in microseconds! > + */ > + hdr->max_svc = htole32(250 * 1024); > + > + > + /* > + * Reset scan: interval=100 > + * Normal scan: interval=beacon interval > + * suspend_time: 100 (TU) > + * > + */ > + scan_service_time = (4 << 22) | (100 * 1024); /* Hardcode for now! */ > + hdr->pause_svc = htole32(scan_service_time); > > /* Select antennas for scanning. */ > rxchain = > @@ -4474,7 +4553,6 @@ iwn_scan(struct iwn_softc *sc, uint16_t > tx->lifetime = htole32(IWN_LIFETIME_INFINITE); > > if (flags & IEEE80211_CHAN_5GHZ) { > - hdr->crc_threshold = 0xffff; > /* Send probe requests at 6Mbps. */ > tx->plcp = iwn_rates[IWN_RIDX_OFDM6].plcp; > rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; > @@ -4488,12 +4566,23 @@ iwn_scan(struct iwn_softc *sc, uint16_t > /* Use the first valid TX antenna. */ > txant = IWN_LSB(sc->txchainmask); > tx->rflags |= IWN_RFLAG_ANT(txant); > + > + /* > + * Only do active scanning if we're announcing a probe request > + * for a given SSID (or more, if we ever add it to the driver.) > + */ > + is_active = 0; > > + /* > + * If we're scanning for a specific SSID, add it to the command. > + */ > essid = (struct iwn_scan_essid *)(tx + 1); > if (ic->ic_des_esslen != 0) { > essid[0].id = IEEE80211_ELEMID_SSID; > essid[0].len = ic->ic_des_esslen; > memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen); > + > + is_active = 1; > } > /* > * Build a probe request frame. Most of the following code is a > @@ -4522,6 +4611,41 @@ iwn_scan(struct iwn_softc *sc, uint16_t > /* Set length of probe request. */ > tx->len = htole16(frm - (uint8_t *)wh); > > + /* > + * If active scanning is requested but a certain channel is > + * marked passive, we can do active scanning if we detect > + * transmissions. > + * > + * There is an issue with some firmware versions that triggers > + * a sysassert on a "good CRC threshold" of zero (== disabled), > + * on a radar channel even though this means that we should NOT > + * send probes. > + * > + * The "good CRC threshold" is the number of frames that we > + * need to receive during our dwell time on a channel before > + * sending out probes -- setting this to a huge value will > + * mean we never reach it, but at the same time work around > + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER > + * here instead of IWL_GOOD_CRC_TH_DISABLED. > + * > + * This was fixed in later versions along with some other > + * scan changes, and the threshold behaves as a flag in those > + * versions. > + */ > + > + /* > + * If we're doing active scanning, set the crc_threshold > + * to a suitable value. This is different to active veruss > + * passive scanning depending upon the channel flags; the > + * firmware will obey that particular check for us. > + */ > + if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN) > + hdr->crc_threshold = is_active ? > + IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED; > + else > + hdr->crc_threshold = is_active ? > + IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER; > + > chan = (struct iwn_scan_chan *)frm; > for (c = &ic->ic_channels[1]; > c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) { > @@ -4531,19 +4655,33 @@ iwn_scan(struct iwn_softc *sc, uint16_t > chan->chan = htole16(ieee80211_chan2ieee(ic, c)); > DPRINTFN(2, ("adding channel %d\n", chan->chan)); > chan->flags = 0; > - if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) > - chan->flags |= htole32(IWN_CHAN_ACTIVE); > if (ic->ic_des_esslen != 0) > chan->flags |= htole32(IWN_CHAN_NPBREQS(1)); > + > + if (c->ic_flags & IEEE80211_CHAN_PASSIVE) > + chan->flags |= htole32(IWN_CHAN_PASSIVE); > + else > + chan->flags |= htole32(IWN_CHAN_ACTIVE); > + > + /* > + * Calculate the active/passive dwell times. > + */ > + > + dwell_active = iwn_get_active_dwell_time(sc, flags, is_active); > + dwell_passive = iwn_get_passive_dwell_time(sc, flags); > + > + /* Make sure they're valid */ > + if (dwell_passive <= dwell_active) > + dwell_passive = dwell_active + 1; > + > + chan->active = htole16(dwell_active); > + chan->passive = htole16(dwell_passive); > + > chan->dsp_gain = 0x6e; > if (IEEE80211_IS_CHAN_5GHZ(c)) { > chan->rf_gain = 0x3b; > - chan->active = htole16(24); > - chan->passive = htole16(110); > } else { > chan->rf_gain = 0x28; > - chan->active = htole16(36); > - chan->passive = htole16(120); > } > hdr->nchan++; > chan++; > @@ -5580,6 +5718,14 @@ iwn_read_firmware_tlv(struct iwn_softc * > sc->reset_noise_gain = letoh32(*ptr); > sc->noise_gain = letoh32(*ptr) + 1; > } > + break; > + case IWN_FW_TLV_FLAGS: > + if (len < sizeof(uint32_t)) > + break; > + if (len % sizeof(uint32_t)) > + break; > + sc->tlv_feature_flags = letoh32(*ptr); > + DPRINTF(("feature: 0x%08x\n", sc->tlv_feature_flags)); > break; > default: > DPRINTF(("TLV type %d not handled\n", > Index: if_iwnreg.h > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_iwnreg.h,v > retrieving revision 1.47 > diff -u -p -r1.47 if_iwnreg.h > --- if_iwnreg.h 11 Feb 2014 19:30:10 -0000 1.47 > +++ if_iwnreg.h 9 Sep 2014 09:47:48 -0000 > @@ -799,6 +799,7 @@ struct iwn_scan_hdr { > > struct iwn_scan_chan { > uint32_t flags; > +#define IWN_CHAN_PASSIVE (0 << 0) > #define IWN_CHAN_ACTIVE (1 << 0) > #define IWN_CHAN_NPBREQS(x) (((1 << (x)) - 1) << 1) > > @@ -812,6 +813,51 @@ struct iwn_scan_chan { > /* Maximum size of a scan command. */ > #define IWN_SCAN_MAXSZ (MCLBYTES - 4) > > +/* > + * For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after > + * sending probe req. This should be set long enough to hear probe responses > + * from more than one AP. > + */ > +#define IWN_ACTIVE_DWELL_TIME_2GHZ (30) /* all times in msec */ > +#define IWN_ACTIVE_DWELL_TIME_5GHZ (20) > +#define IWN_ACTIVE_DWELL_FACTOR_2GHZ (3) > +#define IWN_ACTIVE_DWELL_FACTOR_5GHZ (2) > + > +/* > + * For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. > + * Must be set longer than active dwell time. > + * For the most reliable scan, set > AP beacon interval (typically 100msec). > + */ > +#define IWN_PASSIVE_DWELL_TIME_2GHZ (20) /* all times in msec */ > +#define IWN_PASSIVE_DWELL_TIME_5GHZ (10) > +#define IWN_PASSIVE_DWELL_BASE (100) > +#define IWN_CHANNEL_TUNE_TIME (5) > + > +/* > + * If active scanning is requested but a certain channel is > + * marked passive, we can do active scanning if we detect > + * transmissions. > + * > + * There is an issue with some firmware versions that triggers > + * a sysassert on a "good CRC threshold" of zero (== disabled), > + * on a radar channel even though this means that we should NOT > + * send probes. > + * > + * The "good CRC threshold" is the number of frames that we > + * need to receive during our dwell time on a channel before > + * sending out probes -- setting this to a huge value will > + * mean we never reach it, but at the same time work around > + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER > + * here instead of IWL_GOOD_CRC_TH_DISABLED. > + * > + * This was fixed in later versions along with some other > + * scan changes, and the threshold behaves as a flag in those > + * versions. > + */ > +#define IWN_GOOD_CRC_TH_DISABLED 0 > +#define IWN_GOOD_CRC_TH_DEFAULT htole16(1) > +#define IWN_GOOD_CRC_TH_NEVER htole16(0xffff) > + > /* Structure for command IWN_CMD_TXPOWER (4965AGN only.) */ > #define IWN_RIDX_MAX 32 > struct iwn4965_cmd_txpower { > @@ -1407,6 +1453,7 @@ struct iwn_fw_tlv { > #define IWN_FW_TLV_PBREQ_MAXLEN 6 > #define IWN_FW_TLV_ENH_SENS 14 > #define IWN_FW_TLV_PHY_CALIB 15 > +#define IWN_FW_TLV_FLAGS 18 > > uint16_t alt; > uint32_t len; > @@ -1419,6 +1466,60 @@ struct iwn_fw_tlv { > #define IWN_FW_BOOT_TEXT_MAXSZ 1024 > #define IWN4965_FWSZ (IWN4965_FW_TEXT_MAXSZ + IWN4965_FW_DATA_MAXSZ) > #define IWN5000_FWSZ IWN5000_FW_TEXT_MAXSZ > + > +/* > + * Microcode flags TLV (18.) > + */ > + > +/** > + * enum iwn_ucode_tlv_flag - ucode API flags > + * @IWN_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously > + * was a separate TLV but moved here to save space. > + * @IWN_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, > + * treats good CRC threshold as a boolean > + * @IWN_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). > + * @IWN_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. > + * @IWN_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS > + * @IWN_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD > + * @IWN_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in > scan > + * offload profile config command. > + * @IWN_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api > + * @IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. > + * @IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six > + * (rather than two) IPv6 addresses > + * @IWN_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API > + * @IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID > element > + * from the probe request template. > + * @IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping > + * connection when going back to D0 > + * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) > + * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) > + * @IWN_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. > + * @IWN_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API > + * @IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command > + * containing CAM (Continuous Active Mode) indication. > + */ > +enum iwn_ucode_tlv_flag { > + IWN_UCODE_TLV_FLAGS_PAN = (1 << 0), > + IWN_UCODE_TLV_FLAGS_NEWSCAN = (1 << 1), > + IWN_UCODE_TLV_FLAGS_MFP = (1 << 2), > + IWN_UCODE_TLV_FLAGS_P2P = (1 << 3), > + IWN_UCODE_TLV_FLAGS_DW_BC_TABLE = (1 << 4), > + IWN_UCODE_TLV_FLAGS_NEWBT_COEX = (1 << 5), > + IWN_UCODE_TLV_FLAGS_UAPSD = (1 << 6), > + IWN_UCODE_TLV_FLAGS_SHORT_BL = (1 << 7), > + IWN_UCODE_TLV_FLAGS_RX_ENERGY_API = (1 << 8), > + IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = (1 << 9), > + IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = (1 << 10), > + IWN_UCODE_TLV_FLAGS_BF_UPDATED = (1 << 11), > + IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID = (1 << 12), > + IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API = (1 << 14), > + IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = (1 << 15), > + IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = (1 << 16), > + IWN_UCODE_TLV_FLAGS_SCHED_SCAN = (1 << 17), > + IWN_UCODE_TLV_FLAGS_STA_KEY_CMD = (1 << 19), > + IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD = (1 << 20), > +}; > > /* > * Offsets into EEPROM. > Index: if_iwnvar.h > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_iwnvar.h,v > retrieving revision 1.27 > diff -u -p -r1.27 if_iwnvar.h > --- if_iwnvar.h 10 Feb 2014 19:08:58 -0000 1.27 > +++ if_iwnvar.h 9 Sep 2014 09:47:48 -0000 > @@ -284,6 +284,8 @@ struct iwn_softc { > uint8_t reset_noise_gain; > uint8_t noise_gain; > > + uint32_t tlv_feature_flags; > + > int32_t temp_off; > uint32_t int_mask; > uint8_t ntxchains;