On Tue, Sep 9, 2014 at 5:29 PM, Fabian Raetz <fabian.ra...@gmail.com> wrote: > 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.
Little inaccuracy: While comments talk about IWL_GOOD_CRC_TH_NEVER, IWL_GOOD_CRC_TH_DISABLED, these are IWN_GOOD_CRC_TH_NEVER, IWN_GOOD_CRC_TH_DISABLED in the code, so comments should be amended accordingly... Ciao! David > > 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;