> Date: Tue, 9 Sep 2014 17:29:35 +0200
> From: Fabian Raetz <[email protected]>
>
> 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.
Looks (almost) ok to me; there are some spaces vs. tabs issues with
some of the added #defines. Tested on:
iwn0 at pci2 dev 0 function 0 "Intel Centrino Advanced-N 6205" rev 0x34
So with some minor fixes: ok kettenis@
> 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;