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;

Reply via email to