Stefan Sperling(s...@stsp.name) on 2017.12.13 17:17:41 +0100:
> Since nobody is reporting problems with iwm(4), I took some time to write the
> corresponding diff for iwn(4) as well. I hope this increases test coverage :)
> 
> Works for me on:
> iwn0 at pci3 dev 0 function 0 "Intel Centrino Advanced-N 6200" rev 0x35: msi, 
> MIMO 2T2R, MoW

works on my 

iwn0 at pci2 dev 0 function 0 "Intel Centrino Advanced-N 6205" rev 0x34: msi, 
MIMO 2T2R, MoW

/Benno


> 
> Index: if_iwn.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
> retrieving revision 1.194
> diff -u -p -r1.194 if_iwn.c
> --- if_iwn.c  26 Oct 2017 15:00:28 -0000      1.194
> +++ if_iwn.c  13 Dec 2017 16:07:07 -0000
> @@ -222,7 +222,9 @@ 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_scan(struct iwn_softc *, uint16_t, int);
> +void         iwn_scan_abort(struct iwn_softc *);
> +int          iwn_bgscan(struct ieee80211com *);
>  int          iwn_auth(struct iwn_softc *, int);
>  int          iwn_run(struct iwn_softc *);
>  int          iwn_set_key(struct ieee80211com *, struct ieee80211_node *,
> @@ -516,6 +518,7 @@ iwn_attach(struct device *parent, struct
>       if_attach(ifp);
>       ieee80211_ifattach(ifp);
>       ic->ic_node_alloc = iwn_node_alloc;
> +     ic->ic_bgscan_start = iwn_bgscan;
>       ic->ic_newassoc = iwn_newassoc;
>       ic->ic_updateedca = iwn_updateedca;
>       ic->ic_set_key = iwn_set_key;
> @@ -1761,18 +1764,20 @@ iwn_newstate(struct ieee80211com *ic, en
>       struct iwn_node *wn = (void *)ni;
>       int error;
>  
> -     timeout_del(&sc->calib_to);
> -
> -     if (ic->ic_state == IEEE80211_S_RUN &&
> -         (ni->ni_flags & IEEE80211_NODE_HT))
> +     if (ic->ic_state == IEEE80211_S_RUN) {
>               ieee80211_mira_cancel_timeouts(&wn->mn);
> +             timeout_del(&sc->calib_to);
> +             sc->calib.state = IWN_CALIB_STATE_INIT;
> +             if (sc->sc_flags & IWN_FLAG_BGSCAN)
> +                     iwn_scan_abort(sc);
> +     }
>  
>       switch (nstate) {
>       case IEEE80211_S_SCAN:
>               /* Make the link LED blink while we're scanning. */
>               iwn_set_led(sc, IWN_LED_LINK, 10, 10);
>  
> -             if ((error = iwn_scan(sc, IEEE80211_CHAN_2GHZ)) != 0) {
> +             if ((error = iwn_scan(sc, IEEE80211_CHAN_2GHZ, 0)) != 0) {
>                       printf("%s: could not initiate scan\n",
>                           sc->sc_dev.dv_xname);
>                       return error;
> @@ -1971,11 +1976,13 @@ iwn_rx_done(struct iwn_softc *sc, struct
>       struct ieee80211_frame *wh;
>       struct ieee80211_rxinfo rxi;
>       struct ieee80211_node *ni;
> +     struct ieee80211_channel *bss_chan = NULL;
>       struct mbuf *m, *m1;
>       struct iwn_rx_stat *stat;
>       caddr_t head;
>       uint32_t flags;
>       int error, len, rssi;
> +     uint8_t chan;
>  
>       if (desc->type == IWN_MPDU_RX_DONE) {
>               /* Check for prior RX_PHY notification. */
> @@ -2131,6 +2138,16 @@ iwn_rx_done(struct iwn_softc *sc, struct
>  
>       rssi = ops->get_rssi(stat);
>  
> +     chan = stat->chan;
> +     if (chan > IEEE80211_CHAN_MAX)
> +             chan = IEEE80211_CHAN_MAX;
> +
> +     if (ni == ic->ic_bss) {
> +             bss_chan = ni->ni_chan;
> +             /* Fix current channel. */
> +             ni->ni_chan = &ic->ic_channels[chan];
> +     }
> +
>  #if NBPFILTER > 0
>       if (sc->sc_drvbpf != NULL) {
>               struct mbuf mb;
> @@ -2140,9 +2157,8 @@ iwn_rx_done(struct iwn_softc *sc, struct
>               tap->wr_flags = 0;
>               if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE))
>                       tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
> -             tap->wr_chan_freq =
> -                 htole16(ic->ic_channels[stat->chan].ic_freq);
> -             chan_flags = ic->ic_channels[stat->chan].ic_flags;
> +             tap->wr_chan_freq = htole16(ic->ic_channels[chan].ic_freq);
> +             chan_flags = ic->ic_channels[chan].ic_flags;
>               if (ic->ic_curmode != IEEE80211_MODE_11N)
>                       chan_flags &= ~IEEE80211_CHAN_HT;
>               tap->wr_chan_flags = htole16(chan_flags);
> @@ -2187,6 +2203,10 @@ iwn_rx_done(struct iwn_softc *sc, struct
>       rxi.rxi_tstamp = 0;     /* unused */
>       ieee80211_input(ifp, m, ni, &rxi);
>  
> +     /* Restore BSS channel. */
> +     if (ni == ic->ic_bss)
> +             ni->ni_chan = bss_chan;
> +
>       /* Node is no longer needed. */
>       ieee80211_release_node(ic, ni);
>  }
> @@ -2586,6 +2606,9 @@ iwn_notif_intr(struct iwn_softc *sc)
>                       DPRINTFN(2, ("scanning channel %d status %x\n",
>                           scan->chan, letoh32(scan->status)));
>  
> +                     if (sc->sc_flags & IWN_FLAG_BGSCAN)
> +                             break;
> +
>                       /* Fix current channel. */
>                       ic->ic_bss->ni_chan = &ic->ic_channels[scan->chan];
>                       break;
> @@ -2602,14 +2625,18 @@ iwn_notif_intr(struct iwn_softc *sc)
>  
>                       if (scan->status == 1 && scan->chan <= 14 &&
>                           (sc->sc_flags & IWN_FLAG_HAS_5GHZ)) {
> +                             int error;
>                               /*
>                                * We just finished scanning 2GHz channels,
>                                * start scanning 5GHz ones.
>                                */
> -                             if (iwn_scan(sc, IEEE80211_CHAN_5GHZ) == 0)
> +                             error = iwn_scan(sc, IEEE80211_CHAN_5GHZ,
> +                                 (sc->sc_flags & IWN_FLAG_BGSCAN) ? 1 : 0);
> +                             if (error == 0)
>                                       break;
>                       }
>                       ieee80211_end_scan(ifp);
> +                     sc->sc_flags &= ~IWN_FLAG_BGSCAN;
>                       break;
>               }
>               case IWN5000_CALIBRATION_RESULT:
> @@ -4642,9 +4669,8 @@ iwn_limit_dwell(struct iwn_softc *sc, ui
>        * XXX Yes, the math should take into account that bintval
>        * is 1.024mS, not 1mS..
>        */
> -     if (bintval > 0) {
> +     if (ic->ic_state == IEEE80211_S_RUN && bintval > 0)
>               return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100)));
> -     }
>  
>       /* No association context? Default */
>       return (IWN_PASSIVE_DWELL_BASE);
> @@ -4665,7 +4691,7 @@ iwn_get_passive_dwell_time(struct iwn_so
>  }
>  
>  int
> -iwn_scan(struct iwn_softc *sc, uint16_t flags)
> +iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgscan)
>  {
>       struct ieee80211com *ic = &sc->sc_ic;
>       struct iwn_scan_hdr *hdr;
> @@ -4695,6 +4721,18 @@ iwn_scan(struct iwn_softc *sc, uint16_t 
>       hdr->quiet_time = htole16(10);          /* timeout in milliseconds */
>       hdr->quiet_threshold = htole16(1);      /* min # of packets */
>  
> +     if (bgscan) {
> +             int bintval;
> +
> +             /* Set maximum off-channel time. */
> +             hdr->max_out = htole32(200 * 1024);
> +
> +             /* Configure scan pauses which service on-channel traffic. */
> +             bintval = ic->ic_bss->ni_intval ? ic->ic_bss->ni_intval : 100;
> +             hdr->pause_scan = htole32(((100 / bintval) << 22) |
> +                 ((100 % bintval) * 1024));
> +     }
> +
>       /* Select antennas for scanning. */
>       rxchain =
>           IWN_RXCHAIN_VALID(sc->rxchainmask) |
> @@ -4852,11 +4890,39 @@ iwn_scan(struct iwn_softc *sc, uint16_t 
>       hdr->len = htole16(buflen);
>  
>       DPRINTF(("sending scan command nchan=%d\n", hdr->nchan));
> +     if (bgscan)
> +             sc->sc_flags |= IWN_FLAG_BGSCAN;
>       error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1);
> +     if (bgscan && error)
> +             sc->sc_flags &= ~IWN_FLAG_BGSCAN;
>       free(buf, M_DEVBUF, IWN_SCAN_MAXSZ);
>       return error;
>  }
>  
> +void
> +iwn_scan_abort(struct iwn_softc *sc)
> +{
> +     iwn_cmd(sc, IWN_CMD_SCAN_ABORT, NULL, 0, 1);
> +
> +     /* XXX Cannot wait for status response in interrupt context. */
> +     DELAY(100);
> +
> +     sc->sc_flags &= ~IWN_FLAG_BGSCAN;
> +}
> +
> +int
> +iwn_bgscan(struct ieee80211com *ic) 
> +{
> +     struct iwn_softc *sc = ic->ic_softc;
> +     int error; 
> +
> +     error = iwn_scan(sc, IEEE80211_CHAN_2GHZ, 1);
> +     if (error)
> +             printf("%s: could not initiate background scan\n",
> +                 sc->sc_dev.dv_xname);
> +     return error;
> +}
> +
>  int
>  iwn_auth(struct iwn_softc *sc, int arg)
>  {
> @@ -4864,6 +4930,9 @@ iwn_auth(struct iwn_softc *sc, int arg)
>       struct ieee80211com *ic = &sc->sc_ic;
>       struct ieee80211_node *ni = ic->ic_bss;
>       int error, ridx;
> +     int bss_switch = 
> +         (!IEEE80211_ADDR_EQ(sc->bss_node_addr, etheranyaddr) &&
> +         !IEEE80211_ADDR_EQ(sc->bss_node_addr, ni->ni_macaddr));
>  
>       /* Update adapter configuration. */
>       IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid);
> @@ -4878,8 +4947,12 @@ iwn_auth(struct iwn_softc *sc, int arg)
>       }
>       if (ic->ic_flags & IEEE80211_F_SHSLOT)
>               sc->rxon.flags |= htole32(IWN_RXON_SHSLOT);
> +     else
> +             sc->rxon.flags &= ~htole32(IWN_RXON_SHSLOT);
>       if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
>               sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE);
> +     else
> +             sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE);
>       switch (ic->ic_curmode) {
>       case IEEE80211_MODE_11A:
>               sc->rxon.cck_mask  = 0;
> @@ -4923,12 +4996,19 @@ iwn_auth(struct iwn_softc *sc, int arg)
>        * Make sure the firmware gets to see a beacon before we send
>        * the auth request. Otherwise the Tx attempt can fail due to
>        * the firmware's built-in regulatory domain enforcement.
> +      * Delaying here for every incoming deauth frame can result in a DoS.
>        * Don't delay if we're here because of an incoming frame (arg != -1)
>        * or if we're already waiting for a response (ic_mgt_timer != 0).
> +      * If we are switching APs after a background scan then net80211 has
> +      * just faked the reception of a deauth frame from our old AP, so it
> +      * is safe to delay in that case.
>        */
> -     if (arg == -1 && ic->ic_mgt_timer == 0)
> +     if ((arg == -1 || bss_switch) && ic->ic_mgt_timer == 0)
>               DELAY(ni->ni_intval * 3 * IEEE80211_DUR_TU);
>  
> +     /* We can now clear the cached address of our previous AP. */
> +     memset(sc->bss_node_addr, 0, sizeof(sc->bss_node_addr));
> +
>       return 0;
>  }
>  
> @@ -4938,6 +5018,7 @@ iwn_run(struct iwn_softc *sc)
>       struct iwn_ops *ops = &sc->ops;
>       struct ieee80211com *ic = &sc->sc_ic;
>       struct ieee80211_node *ni = ic->ic_bss;
> +     struct iwn_node *wn = (void *)ni;
>       struct iwn_node_info node;
>       int error;
>  
> @@ -5028,6 +5109,10 @@ iwn_run(struct iwn_softc *sc)
>               printf("%s: could not add BSS node\n", sc->sc_dev.dv_xname);
>               return error;
>       }
> +
> +     /* Cache address of AP in case it changes after a background scan. */
> +     IEEE80211_ADDR_COPY(sc->bss_node_addr, ni->ni_macaddr);
> +
>       DPRINTF(("setting link quality for node %d\n", node.id));
>       if ((error = iwn_set_link_quality(sc, ni)) != 0) {
>               printf("%s: could not setup link quality for node %d\n",
> @@ -5045,10 +5130,7 @@ iwn_run(struct iwn_softc *sc)
>       sc->calib_cnt = 0;
>       timeout_add_msec(&sc->calib_to, 500);
>  
> -     if (ni->ni_flags & IEEE80211_NODE_HT) {
> -             struct iwn_node *wn = (void *)ni;
> -             ieee80211_mira_node_init(&wn->mn);
> -     }
> +     ieee80211_mira_node_init(&wn->mn);
>  
>       /* Link LED always on while associated. */
>       iwn_set_led(sc, IWN_LED_LINK, 0, 1);
> @@ -6443,6 +6525,8 @@ iwn_init(struct ifnet *ifp)
>       struct iwn_softc *sc = ifp->if_softc;
>       struct ieee80211com *ic = &sc->sc_ic;
>       int error;
> +
> +     memset(sc->bss_node_addr, 0, sizeof(sc->bss_node_addr));
>  
>       if ((error = iwn_hw_prepare(sc)) != 0) {
>               printf("%s: hardware not ready\n", sc->sc_dev.dv_xname);
> Index: if_iwnreg.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwnreg.h,v
> retrieving revision 1.54
> diff -u -p -r1.54 if_iwnreg.h
> --- if_iwnreg.h       12 Aug 2017 09:13:06 -0000      1.54
> +++ if_iwnreg.h       13 Dec 2017 15:58:45 -0000
> @@ -437,6 +437,7 @@ struct iwn_tx_cmd {
>  #define IWN5000_CMD_CALIB_CONFIG     101
>  #define IWN_CMD_SET_POWER_MODE               119
>  #define IWN_CMD_SCAN                 128
> +#define IWN_CMD_SCAN_ABORT           129
>  #define IWN_CMD_TXPOWER_DBM          149
>  #define IWN_CMD_TXPOWER                      151
>  #define IWN5000_CMD_TX_ANT_CONFIG    152
> @@ -823,8 +824,8 @@ struct iwn_scan_hdr {
>       uint16_t        quiet_threshold;
>       uint16_t        crc_threshold;
>       uint16_t        rxchain;
> -     uint32_t        max_svc;        /* background scans */
> -     uint32_t        pause_svc;      /* background scans */
> +     uint32_t        max_out;        /* (in usec) background scans */
> +     uint32_t        pause_scan;     /* (in usec) background scans */
>       uint32_t        flags;
>       uint32_t        filter;
>  
> Index: if_iwnvar.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwnvar.h,v
> retrieving revision 1.32
> diff -u -p -r1.32 if_iwnvar.h
> --- if_iwnvar.h       7 Dec 2016 15:48:44 -0000       1.32
> +++ if_iwnvar.h       13 Dec 2017 13:09:32 -0000
> @@ -202,6 +202,7 @@ struct iwn_softc {
>  #define IWN_FLAG_HAS_11N     (1 << 6)
>  #define IWN_FLAG_ENH_SENS    (1 << 7)
>  #define IWN_FLAG_ADV_BT_COEX (1 << 8)
> +#define IWN_FLAG_BGSCAN              (1 << 9)
>  
>       uint8_t                 hw_type;
>  
> @@ -256,6 +257,8 @@ struct iwn_softc {
>       struct iwn_fw_info      fw;
>       struct iwn_calib_info   calibcmd[5];
>       uint32_t                errptr;
> +
> +     uint8_t                 bss_node_addr[IEEE80211_ADDR_LEN];
>  
>       struct iwn_rx_stat      last_rx_stat;
>       int                     last_rx_valid;
> 

Reply via email to