80211 - Update up to FreeBSD's r287029 (only skipping a few minor changes)
authorImre Vadász <imre@vdsz.com>
Mon, 4 Jan 2016 11:14:51 +0000 (12:14 +0100)
committerImre Vadász <imre@vdsz.com>
Mon, 9 May 2016 18:41:18 +0000 (20:41 +0200)
Taken-From: FreeBSD

55 files changed:
sys/bus/u4b/wlan/if_rum.c
sys/bus/u4b/wlan/if_run.c
sys/bus/u4b/wlan/if_uath.c
sys/bus/u4b/wlan/if_upgt.c
sys/bus/u4b/wlan/if_ural.c
sys/bus/u4b/wlan/if_urtw.c
sys/bus/u4b/wlan/if_urtwn.c
sys/bus/u4b/wlan/if_zyd.c
sys/conf/files
sys/dev/netif/ath/ath/if_ath.c
sys/dev/netif/ath/ath/if_ath_rx.c
sys/dev/netif/ath/ath/if_ath_rx.h
sys/dev/netif/ath/ath/if_athvar.h
sys/dev/netif/bwn/bwn/if_bwn.c
sys/dev/netif/iwi/if_iwi.c
sys/dev/netif/iwm/if_iwm.c
sys/dev/netif/iwn/if_iwn.c
sys/dev/netif/ndis/if_ndis.c
sys/dev/netif/ral/rt2560.c
sys/dev/netif/ral/rt2661.c
sys/dev/netif/ral/rt2860.c
sys/dev/netif/wi/if_wi.c
sys/dev/netif/wi/if_wivar.h
sys/dev/netif/wpi/if_wpi.c
sys/netproto/802_11/ieee80211.h
sys/netproto/802_11/ieee80211_dragonfly.h
sys/netproto/802_11/ieee80211_input.h
sys/netproto/802_11/ieee80211_proto.h
sys/netproto/802_11/ieee80211_scan.h
sys/netproto/802_11/ieee80211_scan_sw.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_tdma.h
sys/netproto/802_11/ieee80211_var.h
sys/netproto/802_11/wlan/Makefile
sys/netproto/802_11/wlan/ieee80211.c
sys/netproto/802_11/wlan/ieee80211_adhoc.c
sys/netproto/802_11/wlan/ieee80211_ddb.c
sys/netproto/802_11/wlan/ieee80211_dfs.c
sys/netproto/802_11/wlan/ieee80211_dragonfly.c
sys/netproto/802_11/wlan/ieee80211_hostap.c
sys/netproto/802_11/wlan/ieee80211_ht.c
sys/netproto/802_11/wlan/ieee80211_input.c
sys/netproto/802_11/wlan/ieee80211_mesh.c
sys/netproto/802_11/wlan/ieee80211_monitor.c
sys/netproto/802_11/wlan/ieee80211_node.c
sys/netproto/802_11/wlan/ieee80211_output.c
sys/netproto/802_11/wlan/ieee80211_power.c
sys/netproto/802_11/wlan/ieee80211_proto.c
sys/netproto/802_11/wlan/ieee80211_radiotap.c
sys/netproto/802_11/wlan/ieee80211_regdomain.c
sys/netproto/802_11/wlan/ieee80211_scan.c
sys/netproto/802_11/wlan/ieee80211_scan_sta.c
sys/netproto/802_11/wlan/ieee80211_scan_sw.c [copied from sys/netproto/802_11/wlan/ieee80211_scan.c with 64% similarity]
sys/netproto/802_11/wlan/ieee80211_sta.c
sys/netproto/802_11/wlan/ieee80211_tdma.c
sys/netproto/802_11/wlan/ieee80211_wds.c

index d586bf8..32e5c92 100644 (file)
@@ -196,8 +196,8 @@ static void         rum_enable_tsf(struct rum_softc *);
 static void            rum_update_slot(struct ifnet *);
 static void            rum_set_bssid(struct rum_softc *, const uint8_t *);
 static void            rum_set_macaddr(struct rum_softc *, const uint8_t *);
-static void            rum_update_mcast(struct ifnet *);
-static void            rum_update_promisc(struct ifnet *);
+static void            rum_update_mcast(struct ieee80211com *);
+static void            rum_update_promisc(struct ieee80211com *);
 static void            rum_setpromisc(struct rum_softc *);
 static const char      *rum_get_rf(int);
 static void            rum_read_eeprom(struct rum_softc *);
@@ -483,6 +483,7 @@ rum_attach(device_t self)
        ifq_set_ready(&ifp->if_snd);
 #endif
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(sc->sc_dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
 
        /* set device capabilities */
@@ -1840,11 +1841,11 @@ rum_setpromisc(struct rum_softc *sc)
 }
 
 static void
-rum_update_promisc(struct ifnet *ifp)
+rum_update_promisc(struct ieee80211com *ic)
 {
-       struct rum_softc *sc = ifp->if_softc;
+       struct rum_softc *sc = ic->ic_softc;
 
-       if ((ifp->if_flags & IFF_RUNNING) == 0)
+       if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
                return;
 
        RUM_LOCK(sc);
@@ -1853,12 +1854,12 @@ rum_update_promisc(struct ifnet *ifp)
 }
 
 static void
-rum_update_mcast(struct ifnet *ifp)
+rum_update_mcast(struct ieee80211com *ic)
 {
        static int warning_printed;
 
        if (warning_printed == 0) {
-               if_printf(ifp, "need to implement %s\n", __func__);
+               ic_printf(ic, "need to implement %s\n", __func__);
                warning_printed = 1;
        }
 }
index 2dd9c14..7b09dd9 100644 (file)
@@ -434,12 +434,12 @@ static void       run_set_basicrates(struct run_softc *);
 static void    run_set_leds(struct run_softc *, uint16_t);
 static void    run_set_bssid(struct run_softc *, const uint8_t *);
 static void    run_set_macaddr(struct run_softc *, const uint8_t *);
-static void    run_updateslot(struct ifnet *);
+static void    run_updateslot(struct ieee80211com *);
 static void    run_updateslot_cb(void *);
-static void    run_update_mcast(struct ifnet *);
+static void    run_update_mcast(struct ieee80211com *);
 static int8_t  run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
-static void    run_update_promisc_locked(struct ifnet *);
-static void    run_update_promisc(struct ifnet *);
+static void    run_update_promisc_locked(struct run_softc *);
+static void    run_update_promisc(struct ieee80211com *);
 static void    run_rt5390_bbp_init(struct run_softc *);
 static int     run_bbp_init(struct run_softc *);
 static int     run_rt3070_rf_init(struct run_softc *);
@@ -775,6 +775,7 @@ run_attach(device_t self)
 #endif
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(sc->sc_dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;        /* default to BSS mode */
 
@@ -2138,7 +2139,7 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
                                RUN_UNLOCK(sc);
                                return (-1);
                        }
-                       run_updateslot(ic->ic_ifp);
+                       run_updateslot(ic);
                        run_enable_mrr(sc);
                        run_set_txpreamble(sc);
                        run_set_basicrates(sc);
@@ -3792,7 +3793,7 @@ run_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                                startall = 1;
                                run_init_locked(sc);
                        } else
-                               run_update_promisc_locked(ifp);
+                               run_update_promisc_locked(sc);
                } else {
                        if (ifp->if_flags & IFF_RUNNING &&
                            (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) {
@@ -4908,7 +4909,7 @@ run_update_beacon(struct ieee80211vap *vap, int item)
 
        switch (item) {
        case IEEE80211_BEACON_ERP:
-               run_updateslot(ic->ic_ifp);
+               run_updateslot(ic);
                break;
        case IEEE80211_BEACON_HTINFO:
                run_updateprot(ic);
@@ -5063,33 +5064,32 @@ run_reset_livelock(struct run_softc *sc)
 }
 
 static void
-run_update_promisc_locked(struct ifnet *ifp)
+run_update_promisc_locked(struct run_softc *sc)
 {
-       struct run_softc *sc = ifp->if_softc;
         uint32_t tmp;
 
        run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
 
        tmp |= RT2860_DROP_UC_NOME;
-        if (ifp->if_flags & IFF_PROMISC)
+       if (sc->sc_ifp->if_flags & IFF_PROMISC)
                tmp &= ~RT2860_DROP_UC_NOME;
 
        run_write(sc, RT2860_RX_FILTR_CFG, tmp);
 
-        DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
+       DPRINTF("%s promiscuous mode\n", (sc->sc_ifp->if_flags & IFF_PROMISC) ?
             "entering" : "leaving");
 }
 
 static void
-run_update_promisc(struct ifnet *ifp)
+run_update_promisc(struct ieee80211com *ic)
 {
-       struct run_softc *sc = ifp->if_softc;
+       struct run_softc *sc = ic->ic_softc;
 
-       if ((ifp->if_flags & IFF_RUNNING) == 0)
+       if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
                return;
 
        RUN_LOCK(sc);
-       run_update_promisc_locked(ifp);
+       run_update_promisc_locked(sc);
        RUN_UNLOCK(sc);
 }
 
@@ -5212,16 +5212,15 @@ run_set_macaddr(struct run_softc *sc, const uint8_t *addr)
 }
 
 static void
-run_updateslot(struct ifnet *ifp)
+run_updateslot(struct ieee80211com *ic)
 {
-       struct run_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct run_softc *sc = ic->ic_softc;
        uint32_t i;
 
        i = RUN_CMDQ_GET(&sc->cmdq_store);
        DPRINTF("cmdq_store=%d\n", i);
        sc->cmdq[i].func = run_updateslot_cb;
-       sc->cmdq[i].arg0 = ifp;
+       sc->cmdq[i].arg0 = ic->ic_ifp;
        ieee80211_runtask(ic, &sc->cmdq_task);
 
        return;
@@ -5243,10 +5242,10 @@ run_updateslot_cb(void *arg)
 }
 
 static void
-run_update_mcast(struct ifnet *ifp)
+run_update_mcast(struct ieee80211com *ic)
 {
        /* h/w filter supports getting everything or nothing */
-       ifp->if_flags |= IFF_ALLMULTI;
+       ic->ic_ifp->if_flags |= IFF_ALLMULTI;
 }
 
 static int8_t
index 8194979..5fcf3f6 100644 (file)
@@ -295,8 +295,8 @@ static int  uath_raw_xmit(struct ieee80211_node *, struct mbuf *,
 static void    uath_scan_start(struct ieee80211com *);
 static void    uath_scan_end(struct ieee80211com *);
 static void    uath_set_channel(struct ieee80211com *);
-static void    uath_update_mcast(struct ifnet *);
-static void    uath_update_promisc(struct ifnet *);
+static void    uath_update_mcast(struct ieee80211com *);
+static void    uath_update_promisc(struct ieee80211com *);
 static int     uath_config(struct uath_softc *, uint32_t, uint32_t);
 static int     uath_config_multi(struct uath_softc *, uint32_t, const void *,
                    int);
@@ -443,6 +443,7 @@ uath_attach(device_t dev)
 
        ic = ifp->if_l2com;
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;        /* default to BSS mode */
 
@@ -1921,13 +1922,13 @@ uath_set_rxmulti_filter(struct uath_softc *sc)
        return (0);
 }
 static void
-uath_update_mcast(struct ifnet *ifp)
+uath_update_mcast(struct ieee80211com *ic)
 {
-       struct uath_softc *sc = ifp->if_softc;
+       struct uath_softc *sc = ic->ic_softc;
 
        UATH_LOCK(sc);
        if ((sc->sc_flags & UATH_FLAG_INVALID) ||
-           (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+           (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
                UATH_UNLOCK(sc);
                return;
        }
@@ -1941,13 +1942,13 @@ uath_update_mcast(struct ifnet *ifp)
 }
 
 static void
-uath_update_promisc(struct ifnet *ifp)
+uath_update_promisc(struct ieee80211com *ic)
 {
-       struct uath_softc *sc = ifp->if_softc;
+       struct uath_softc *sc = ic->ic_softc;
 
        UATH_LOCK(sc);
        if ((sc->sc_flags & UATH_FLAG_INVALID) ||
-           (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+           (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
                UATH_UNLOCK(sc);
                return;
        }
index e98a06c..ca60dfb 100644 (file)
@@ -142,7 +142,7 @@ static struct ieee80211vap *upgt_vap_create(struct ieee80211com *,
                    const uint8_t [IEEE80211_ADDR_LEN],
                    const uint8_t [IEEE80211_ADDR_LEN]);
 static void    upgt_vap_delete(struct ieee80211vap *);
-static void    upgt_update_mcast(struct ifnet *);
+static void    upgt_update_mcast(struct ieee80211com *);
 static uint8_t upgt_rx_rate(struct upgt_softc *, const int);
 static void    upgt_set_multi(void *);
 static void    upgt_stop(struct upgt_softc *);
@@ -338,6 +338,7 @@ upgt_attach(device_t dev)
 
        ic = ifp->if_l2com;
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;
        /* set device capabilities */
@@ -1097,9 +1098,9 @@ upgt_vap_delete(struct ieee80211vap *vap)
 }
 
 static void
-upgt_update_mcast(struct ifnet *ifp)
+upgt_update_mcast(struct ieee80211com *ic)
 {
-       struct upgt_softc *sc = ifp->if_softc;
+       struct upgt_softc *sc = ic->ic_softc;
 
        upgt_set_multi(sc);
 }
index b0cce4a..514c360 100644 (file)
@@ -173,7 +173,7 @@ static void         ural_set_basicrates(struct ural_softc *,
                            const struct ieee80211_channel *);
 static void            ural_set_bssid(struct ural_softc *, const uint8_t *);
 static void            ural_set_macaddr(struct ural_softc *, uint8_t *);
-static void            ural_update_promisc(struct ifnet *);
+static void            ural_update_promisc(struct ieee80211com *);
 static void            ural_setpromisc(struct ural_softc *);
 static const char      *ural_get_rf(int);
 static void            ural_read_eeprom(struct ural_softc *);
@@ -470,6 +470,7 @@ ural_attach(device_t self)
        IFQ_SET_READY(&ifp->if_snd);
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
 
        /* set device capabilities */
@@ -1899,11 +1900,11 @@ ural_setpromisc(struct ural_softc *sc)
 }
 
 static void
-ural_update_promisc(struct ifnet *ifp)
+ural_update_promisc(struct ieee80211com *ic)
 {
-       struct ural_softc *sc = ifp->if_softc;
+       struct ural_softc *sc = ic->ic_softc;
 
-       if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+       if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
                return;
 
        RAL_LOCK(sc);
index dde2c9c..ed6c907 100644 (file)
@@ -665,7 +665,7 @@ static int          urtw_raw_xmit(struct ieee80211_node *, struct mbuf *,
 static void            urtw_scan_start(struct ieee80211com *);
 static void            urtw_scan_end(struct ieee80211com *);
 static void            urtw_set_channel(struct ieee80211com *);
-static void            urtw_update_mcast(struct ifnet *);
+static void            urtw_update_mcast(struct ieee80211com *);
 static int             urtw_tx_start(struct urtw_softc *,
                            struct ieee80211_node *, struct mbuf *,
                            struct urtw_data *, int);
@@ -760,7 +760,7 @@ static struct urtw_data *
                        urtw_getbuf(struct urtw_softc *sc);
 static int             urtw_compute_txtime(uint16_t, uint16_t, uint8_t,
                            uint8_t);
-static void            urtw_updateslot(struct ifnet *);
+static void            urtw_updateslot(struct ieee80211com *);
 static void            urtw_updateslottask(void *, int);
 static void            urtw_sysctl_node(struct urtw_softc *);
 
@@ -873,6 +873,7 @@ urtw_attach(device_t dev)
 
        ic = ifp->if_l2com;
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;        /* default to BSS mode */
 
@@ -1630,7 +1631,7 @@ fail:
 }
 
 static void
-urtw_update_mcast(struct ifnet *ifp)
+urtw_update_mcast(struct ieee80211com *ic)
 {
 
        /* XXX do nothing?  */
@@ -4325,10 +4326,9 @@ urtw_compute_txtime(uint16_t framelen, uint16_t rate,
  * slot time based on the current setting.
  */
 static void
-urtw_updateslot(struct ifnet *ifp)
+urtw_updateslot(struct ieee80211com *ic)
 {
-       struct urtw_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct urtw_softc *sc = ic->ic_softc;
 
        ieee80211_runtask(ic, &sc->sc_updateslot_task);
 }
index 83d13dd..a98af33 100644 (file)
@@ -257,7 +257,7 @@ static void         urtwn_set_channel(struct ieee80211com *);
 static void            urtwn_set_chan(struct urtwn_softc *,
                            struct ieee80211_channel *,
                            struct ieee80211_channel *);
-static void            urtwn_update_mcast(struct ifnet *);
+static void            urtwn_update_mcast(struct ieee80211com *);
 static void            urtwn_iq_calib(struct urtwn_softc *);
 static void            urtwn_lc_calib(struct urtwn_softc *);
 static void            urtwn_init(void *);
@@ -434,6 +434,7 @@ urtwn_attach(device_t self)
 #endif
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(sc->sc_dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;        /* default to BSS mode */
 
@@ -3117,7 +3118,7 @@ urtwn_set_channel(struct ieee80211com *ic)
 }
 
 static void
-urtwn_update_mcast(struct ifnet *ifp)
+urtwn_update_mcast(struct ieee80211com *ic)
 {
        /* XXX do nothing?  */
 }
index 741b5e1..8a73e50 100644 (file)
@@ -143,7 +143,7 @@ static int  zyd_set_bssid(struct zyd_softc *, const uint8_t *);
 static int     zyd_switch_radio(struct zyd_softc *, int);
 static int     zyd_set_led(struct zyd_softc *, int, int);
 static void    zyd_set_multi(struct zyd_softc *);
-static void    zyd_update_mcast(struct ifnet *);
+static void    zyd_update_mcast(struct ieee80211com *);
 static int     zyd_set_rxfilter(struct zyd_softc *);
 static void    zyd_set_chan(struct zyd_softc *, struct ieee80211_channel *);
 static int     zyd_set_beacon_interval(struct zyd_softc *, int);
@@ -384,6 +384,7 @@ zyd_attach(device_t dev)
 
        ic = ifp->if_l2com;
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;
 
@@ -2023,11 +2024,11 @@ fail:
 }
 
 static void
-zyd_update_mcast(struct ifnet *ifp)
+zyd_update_mcast(struct ieee80211com *ic)
 {
-       struct zyd_softc *sc = ifp->if_softc;
+       struct zyd_softc *sc = ic->ic_softc;
 
-       if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+       if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
                return;
 
        ZYD_LOCK(sc);
index 62a547d..b52ed02 100644 (file)
@@ -1358,6 +1358,7 @@ netproto/802_11/wlan/ieee80211_regdomain.c  optional wlan
 netproto/802_11/wlan/ieee80211_rssadapt.c   optional wlan_rssadapt
 netproto/802_11/wlan/ieee80211_scan.c       optional wlan
 netproto/802_11/wlan/ieee80211_scan_sta.c   optional wlan
+netproto/802_11/wlan/ieee80211_scan_sw.c    optional wlan
 netproto/802_11/wlan/ieee80211_sta.c        optional wlan
 netproto/802_11/wlan/ieee80211_superg.c     optional wlan ieee80211_support_superg
 netproto/802_11/wlan/ieee80211_tdma.c       optional wlan ieee80211_support_tdma
index 77dee08..40d10ed 100644 (file)
@@ -172,9 +172,9 @@ static void ath_bmiss_proc(void *, int);
 static void    ath_key_update_begin(struct ieee80211vap *);
 static void    ath_key_update_end(struct ieee80211vap *);
 static void    ath_update_mcast_hw(struct ath_softc *);
-static void    ath_update_mcast(struct ifnet *);
-static void    ath_update_promisc(struct ifnet *);
-static void    ath_updateslot(struct ifnet *);
+static void    ath_update_mcast(struct ieee80211com *);
+static void    ath_update_promisc(struct ieee80211com *);
+static void    ath_updateslot(struct ieee80211com *);
 static void    ath_bstuck_proc(void *, int);
 static void    ath_reset_proc(void *, int);
 static int     ath_desc_alloc(struct ath_softc *);
@@ -556,6 +556,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
                goto bad;
        }
        ic = ifp->if_l2com;
+       ic->ic_name = device_get_nameunit(sc->sc_dev);
 
        /* set these up early for if_printf use */
        if_initname(ifp, device_get_name(sc->sc_dev),
@@ -3576,9 +3577,9 @@ ath_key_update_end(struct ieee80211vap *vap)
 }
 
 static void
-ath_update_promisc(struct ifnet *ifp)
+ath_update_promisc(struct ieee80211com *ic)
 {
-       struct ath_softc *sc = ifp->if_softc;
+       struct ath_softc *sc = ic->ic_softc;
        u_int32_t rfilt;
 
        /* configure rx filter */
@@ -3648,9 +3649,9 @@ ath_update_mcast_hw(struct ath_softc *sc)
  * awake before operating.
  */
 static void
-ath_update_mcast(struct ifnet *ifp)
+ath_update_mcast(struct ieee80211com *ic)
 {
-       struct ath_softc *sc = ifp->if_softc;
+       struct ath_softc *sc = ic->ic_softc;
 
        ATH_LOCK(sc);
        ath_power_set_power_state(sc, HAL_PM_AWAKE);
@@ -3736,10 +3737,9 @@ ath_setslottime(struct ath_softc *sc)
  * slot time based on the current setting.
  */
 static void
-ath_updateslot(struct ifnet *ifp)
+ath_updateslot(struct ieee80211com *ic)
 {
-       struct ath_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct ath_softc *sc = ic->ic_softc;
 
        /*
         * When not coordinating the BSS, change the hardware
index 4d2798f..b55c9e4 100644 (file)
@@ -332,7 +332,7 @@ ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
  */
 void
 ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
-       int subtype, int rssi, int nf)
+       int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
@@ -358,7 +358,7 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
         * Call up first so subsequent work can use information
         * potentially stored in the node (e.g. for ibss merge).
         */
-       ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rssi, nf);
+       ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
        switch (subtype) {
        case IEEE80211_FC0_SUBTYPE_BEACON:
                /* update rssi statistics for use by the hal */
index f831148..62be699 100644 (file)
@@ -33,7 +33,8 @@
 
 extern u_int32_t ath_calcrxfilter(struct ath_softc *sc);
 extern void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
-           int subtype, int rssi, int nf);
+           int subtype, const struct ieee80211_rx_stats *rxs,
+           int rssi, int nf);
 
 #define        ath_stoprecv(_sc, _dodelay)             \
            (_sc)->sc_rx.recv_stop((_sc), (_dodelay))
index a95504e..f08306e 100644 (file)
@@ -483,7 +483,8 @@ struct ath_vap {
        struct ath_txq  av_mcastq;      /* buffered mcast s/w queue */
 
        void            (*av_recv_mgmt)(struct ieee80211_node *,
-                               struct mbuf *, int, int, int);
+                               struct mbuf *, int,
+                               const struct ieee80211_rx_stats *, int, int);
        int             (*av_newstate)(struct ieee80211vap *,
                                enum ieee80211_state, int);
        void            (*av_bmiss)(struct ieee80211vap *);
index 1d986d4..2ac0c04 100644 (file)
@@ -183,8 +183,8 @@ static void bwn_addchannels(struct ieee80211_channel [], int, int *,
                    const struct bwn_channelinfo *, int);
 static int     bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
                    const struct ieee80211_bpf_params *);
-static void    bwn_updateslot(struct ifnet *);
-static void    bwn_update_promisc(struct ifnet *);
+static void    bwn_updateslot(struct ieee80211com *);
+static void    bwn_update_promisc(struct ieee80211com *);
 static void    bwn_wme_init(struct bwn_mac *);
 static int     bwn_wme_update(struct ieee80211com *);
 static void    bwn_wme_clear(struct bwn_softc *);
@@ -1032,6 +1032,7 @@ bwn_attach_post(struct bwn_softc *sc)
 
        ic = ifp->if_l2com;
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(sc->sc_dev);
        /* XXX not right but it's not used anywhere important */
        ic->ic_phytype = IEEE80211_T_OFDM;
        ic->ic_opmode = IEEE80211_M_STA;
@@ -1224,7 +1225,7 @@ bwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data,
        switch (cmd) {
        case SIOCSIFFLAGS:
                if (IS_RUNNING(ifp)) {
-                       bwn_update_promisc(ifp);
+                       bwn_update_promisc(ic);
                } else if (ifp->if_flags & IFF_UP) {
                        if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
                                bwn_init(sc);
@@ -2708,13 +2709,12 @@ bwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
  * like slot time and preamble.
  */
 static void
-bwn_updateslot(struct ifnet *ifp)
+bwn_updateslot(struct ieee80211com *ic)
 {
-       struct bwn_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct bwn_softc *sc = ic->ic_softc;
        struct bwn_mac *mac;
 
-       if (ifp->if_flags & IFF_RUNNING) {
+       if (ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) {
                mac = (struct bwn_mac *)sc->sc_curmac;
                bwn_set_slot_time(mac,
                    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
@@ -2729,14 +2729,14 @@ bwn_updateslot(struct ifnet *ifp)
  * mode when operating in hostap mode to do ACS).
  */
 static void
-bwn_update_promisc(struct ifnet *ifp)
+bwn_update_promisc(struct ieee80211com *ic)
 {
-       struct bwn_softc *sc = ifp->if_softc;
+       struct bwn_softc *sc = ic->ic_softc;
        struct bwn_mac *mac = sc->sc_curmac;
 
        mac = sc->sc_curmac;
        if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
-               if (ifp->if_flags & IFF_PROMISC)
+               if (ic->ic_ifp->if_flags & IFF_PROMISC)
                        sc->sc_filters |= BWN_MACCTL_PROMISC;
                else
                        sc->sc_filters &= ~BWN_MACCTL_PROMISC;
index 8135de7..23ea8d6 100644 (file)
@@ -374,6 +374,7 @@ iwi_attach(device_t dev)
 #endif
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_opmode = IEEE80211_M_STA;
        ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
 
index eaf36c2..6b1021d 100644 (file)
@@ -384,7 +384,7 @@ static struct ieee80211vap *
 static void    iwm_vap_delete(struct ieee80211vap *);
 static void    iwm_scan_start(struct ieee80211com *);
 static void    iwm_scan_end(struct ieee80211com *);
-static void    iwm_update_mcast(struct ifnet *);
+static void    iwm_update_mcast(struct ieee80211com *);
 static void    iwm_set_channel(struct ieee80211com *);
 static void    iwm_scan_curchan(struct ieee80211_scan_state *, unsigned long);
 static void    iwm_scan_mindwell(struct ieee80211_scan_state *);
@@ -5303,7 +5303,7 @@ iwm_scan_end(struct ieee80211com *ic)
 }
 
 static void
-iwm_update_mcast(struct ifnet *ifp)
+iwm_update_mcast(struct ieee80211com *ic)
 {
 }
 
index 5c65f2d..095ebff 100644 (file)
@@ -255,7 +255,7 @@ static int  iwn_set_link_quality(struct iwn_softc *,
                    struct ieee80211_node *);
 static int     iwn_add_broadcast_node(struct iwn_softc *, int);
 static int     iwn_updateedca(struct ieee80211com *);
-static void    iwn_update_mcast(struct ifnet *);
+static void    iwn_update_mcast(struct ieee80211com *);
 static void    iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
 static int     iwn_set_critical_temp(struct iwn_softc *);
 static int     iwn_set_timing(struct iwn_softc *, struct ieee80211_node *);
@@ -577,6 +577,7 @@ iwn_attach(device_t dev)
 
        ic = ifp->if_l2com;
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;        /* default to BSS mode */
 
@@ -5490,7 +5491,7 @@ iwn_updateedca(struct ieee80211com *ic)
 }
 
 static void
-iwn_update_mcast(struct ifnet *ifp)
+iwn_update_mcast(struct ieee80211com *ic)
 {
        /* Ignore */
 }
index ab32274..8f99d7a 100644 (file)
@@ -157,8 +157,8 @@ static void ndis_tick               (void *);
 static void ndis_ticktask      (device_object *, void *);
 static int ndis_raw_xmit       (struct ieee80211_node *, struct mbuf *,
        const struct ieee80211_bpf_params *);
-static void ndis_update_mcast  (struct ifnet *ifp);
-static void ndis_update_promisc        (struct ifnet *ifp);
+static void ndis_update_mcast  (struct ieee80211com *ic);
+static void ndis_update_promisc        (struct ieee80211com *ic);
 static void ndis_start         (struct ifnet *, struct ifaltq_subque *);
 static void ndis_starttask     (device_object *, void *);
 static void ndis_resettask     (device_object *, void *);
@@ -739,6 +739,7 @@ ndis_attach(device_t dev)
 
                ifp->if_ioctl = ndis_ioctl_80211;
                ic->ic_ifp = ifp;
+               ic->ic_name = device_get_nameunit(dev);
                ic->ic_opmode = IEEE80211_M_STA;
                ic->ic_phytype = IEEE80211_T_DS;
                ic->ic_caps = IEEE80211_C_8023ENCAP |
@@ -1730,15 +1731,15 @@ ndis_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
 }
 
 static void
-ndis_update_mcast(struct ifnet *ifp)
+ndis_update_mcast(struct ieee80211com *ic)
 {
-       struct ndis_softc       *sc = ifp->if_softc;
+       struct ndis_softc       *sc = ic->ic_softc;
 
        ndis_setmulti(sc);
 }
 
 static void
-ndis_update_promisc(struct ifnet *ifp)
+ndis_update_promisc(struct ieee80211com *ic)
 {
        /* not supported */
 }
@@ -3255,7 +3256,7 @@ done:
                DPRINTF(("scan: bssid %s chan %dMHz (%d/%d) rssi %d\n",
                    kether_ntoa(wb->nwbx_macaddr, ethstr), freq, sp.bchan, chanflag,
                    rssi));
-               ieee80211_add_scan(vap, &sp, &wh, 0, rssi, noise);
+               ieee80211_add_scan(vap, ic->ic_curchan, &sp, &wh, 0, rssi, noise);
                wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
        }
        kfree(bl, M_DEVBUF);
index c4b6626..79ffc8a 100644 (file)
@@ -143,13 +143,13 @@ static void               rt2560_disable_rf_tune(struct rt2560_softc *);
 static void            rt2560_enable_tsf_sync(struct rt2560_softc *);
 static void            rt2560_enable_tsf(struct rt2560_softc *);
 static void            rt2560_update_plcp(struct rt2560_softc *);
-static void            rt2560_update_slot(struct ifnet *);
+static void            rt2560_update_slot(struct ieee80211com *);
 static void            rt2560_set_basicrates(struct rt2560_softc *);
 static void            rt2560_update_led(struct rt2560_softc *, int, int);
 static void            rt2560_set_bssid(struct rt2560_softc *, const uint8_t *);
 static void            rt2560_set_macaddr(struct rt2560_softc *, uint8_t *);
 static void            rt2560_get_macaddr(struct rt2560_softc *, uint8_t *);
-static void            rt2560_update_promisc(struct ifnet *);
+static void            rt2560_update_promisc(struct ieee80211com *);
 static const char      *rt2560_get_rf(int);
 static void            rt2560_read_config(struct rt2560_softc *);
 static int             rt2560_bbp_init(struct rt2560_softc *);
@@ -271,6 +271,7 @@ rt2560_attach(device_t dev, int id)
 #endif
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_opmode = IEEE80211_M_STA;
        ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
 
@@ -1977,7 +1978,7 @@ rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *ucred)
                                rt2560_init_locked(sc);
                                startall = 1;
                        } else
-                               rt2560_update_promisc(ifp);
+                               rt2560_update_promisc(ic);
                } else {
                        if (ifp->if_flags & IFF_RUNNING)
                                rt2560_stop_locked(sc);
@@ -2283,10 +2284,9 @@ rt2560_update_plcp(struct rt2560_softc *sc)
  * IEEE Std 802.11-1999 pp. 85 to know how these values are computed.
  */
 static void
-rt2560_update_slot(struct ifnet *ifp)
+rt2560_update_slot(struct ieee80211com *ic)
 {
-       struct rt2560_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct rt2560_softc *sc = ic->ic_softc;
        uint8_t slottime;
        uint16_t tx_sifs, tx_pifs, tx_difs, eifs;
        uint32_t tmp;
@@ -2408,21 +2408,21 @@ rt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr)
 }
 
 static void
-rt2560_update_promisc(struct ifnet *ifp)
+rt2560_update_promisc(struct ieee80211com *ic)
 {
-       struct rt2560_softc *sc = ifp->if_softc;
+       struct rt2560_softc *sc = ic->ic_softc;
        uint32_t tmp;
 
        tmp = RAL_READ(sc, RT2560_RXCSR0);
 
        tmp &= ~RT2560_DROP_NOT_TO_ME;
-       if (!(ifp->if_flags & IFF_PROMISC))
+       if (!(ic->ic_ifp->if_flags & IFF_PROMISC))
                tmp |= RT2560_DROP_NOT_TO_ME;
 
        RAL_WRITE(sc, RT2560_RXCSR0, tmp);
 
-       DPRINTF(sc, "%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
-           "entering" : "leaving");
+       DPRINTF(sc, "%s promiscuous mode\n",
+           (ic->ic_ifp->if_flags & IFF_PROMISC) ?  "entering" : "leaving");
 }
 
 static const char *
@@ -2629,7 +2629,7 @@ rt2560_init_locked(struct rt2560_softc *sc)
        /* set basic rate set (will be updated later) */
        RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153);
 
-       rt2560_update_slot(ifp);
+       rt2560_update_slot(ic);
        rt2560_update_plcp(sc);
        rt2560_update_led(sc, 0, 0);
 
index 8b9fc54..10e1fbe 100644 (file)
@@ -145,9 +145,9 @@ static void         rt2661_set_bssid(struct rt2661_softc *,
                            const uint8_t *);
 static void            rt2661_set_macaddr(struct rt2661_softc *,
                           const uint8_t *);
-static void            rt2661_update_promisc(struct ifnet *);
+static void            rt2661_update_promisc(struct ieee80211com *);
 static int             rt2661_wme_update(struct ieee80211com *) __unused;
-static void            rt2661_update_slot(struct ifnet *);
+static void            rt2661_update_slot(struct ieee80211com *);
 static const char      *rt2661_get_rf(int);
 static void            rt2661_read_eeprom(struct rt2661_softc *,
                            uint8_t macaddr[IEEE80211_ADDR_LEN]);
@@ -272,6 +272,7 @@ rt2661_attach(device_t dev, int id)
 #endif
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_opmode = IEEE80211_M_STA;
        ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
 
@@ -1711,7 +1712,7 @@ rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *ucred)
                                rt2661_init_locked(sc);
                                startall = 1;
                        } else
-                               rt2661_update_promisc(ifp);
+                               rt2661_update_promisc(ic);
                } else {
                        if (ifp->if_flags & IFF_RUNNING)
                                rt2661_stop_locked(sc);
@@ -2060,21 +2061,21 @@ rt2661_set_macaddr(struct rt2661_softc *sc, const uint8_t *addr)
 }
 
 static void
-rt2661_update_promisc(struct ifnet *ifp)
+rt2661_update_promisc(struct ieee80211com *ic)
 {
-       struct rt2661_softc *sc = ifp->if_softc;
+       struct rt2661_softc *sc = ic->ic_softc;
        uint32_t tmp;
 
        tmp = RAL_READ(sc, RT2661_TXRX_CSR0);
 
        tmp &= ~RT2661_DROP_NOT_TO_ME;
-       if (!(ifp->if_flags & IFF_PROMISC))
+       if (!(ic->ic_ifp->if_flags & IFF_PROMISC))
                tmp |= RT2661_DROP_NOT_TO_ME;
 
        RAL_WRITE(sc, RT2661_TXRX_CSR0, tmp);
 
-       DPRINTF(sc, "%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
-           "entering" : "leaving");
+       DPRINTF(sc, "%s promiscuous mode\n",
+           (ic->ic_ifp->if_flags & IFF_PROMISC) ?  "entering" : "leaving");
 }
 
 /*
@@ -2124,10 +2125,9 @@ rt2661_wme_update(struct ieee80211com *ic)
 }
 
 static void
-rt2661_update_slot(struct ifnet *ifp)
+rt2661_update_slot(struct ieee80211com *ic)
 {
-       struct rt2661_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct rt2661_softc *sc = ic->ic_softc;
        uint8_t slottime;
        uint32_t tmp;
 
index c431bbb..dfd1754 100644 (file)
@@ -148,8 +148,8 @@ static void rt2860_set_leds(struct rt2860_softc *, uint16_t);
 static void    rt2860_set_gp_timer(struct rt2860_softc *, int);
 static void    rt2860_set_bssid(struct rt2860_softc *, const uint8_t *);
 static void    rt2860_set_macaddr(struct rt2860_softc *, const uint8_t *);
-static void    rt2860_update_promisc(struct ifnet *);
-static void    rt2860_updateslot(struct ifnet *);
+static void    rt2860_update_promisc(struct ieee80211com *);
+static void    rt2860_updateslot(struct ieee80211com *);
 static void    rt2860_updateprot(struct ifnet *);
 static int     rt2860_updateedca(struct ieee80211com *);
 #ifdef HW_CRYPTO
@@ -307,6 +307,7 @@ rt2860_attach(device_t dev, int id)
 #endif
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_opmode = IEEE80211_M_STA;
        ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
 
@@ -2024,7 +2025,7 @@ rt2860_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *ucred)
                                rt2860_init_locked(sc);
                                startall = 1;
                        } else
-                               rt2860_update_promisc(ifp);
+                               rt2860_update_promisc(ic);
                } else {
                        if (ifp->if_flags & IFF_RUNNING)
                                rt2860_stop_locked(sc);
@@ -2863,10 +2864,9 @@ rt2860_set_macaddr(struct rt2860_softc *sc, const uint8_t *addr)
 }
 
 static void
-rt2860_updateslot(struct ifnet *ifp)
+rt2860_updateslot(struct ieee80211com *ic)
 {
-       struct rt2860_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct rt2860_softc *sc = ic->ic_softc;
        uint32_t tmp;
 
        tmp = RAL_READ(sc, RT2860_BKOFF_SLOT_CFG);
@@ -2901,14 +2901,14 @@ rt2860_updateprot(struct ifnet *ifp)
 }
 
 static void
-rt2860_update_promisc(struct ifnet *ifp)
+rt2860_update_promisc(struct ieee80211com *ic)
 {
-       struct rt2860_softc *sc = ifp->if_softc;
+       struct rt2860_softc *sc = ic->ic_softc;
        uint32_t tmp;
 
        tmp = RAL_READ(sc, RT2860_RX_FILTR_CFG);
        tmp &= ~RT2860_DROP_NOT_MYBSS;
-       if (!(ifp->if_flags & IFF_PROMISC))
+       if (!(ic->ic_ifp->if_flags & IFF_PROMISC))
                tmp |= RT2860_DROP_NOT_MYBSS;
        RAL_WRITE(sc, RT2860_RX_FILTR_CFG, tmp);
 }
index 8e5f3d1..003a2c6 100644 (file)
@@ -124,7 +124,8 @@ static int  wi_newstate_sta(struct ieee80211vap *, enum ieee80211_state, int);
 static int  wi_newstate_hostap(struct ieee80211vap *, enum ieee80211_state,
                int);
 static void wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
-               int subtype, int rssi, int nf);
+               int subtype, const struct ieee80211_rx_stats *rxs,
+               int rssi, int nf);
 static int  wi_reset(struct wi_softc *);
 static void wi_watchdog_callout(void *);
 static int  wi_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
@@ -139,8 +140,8 @@ static void wi_info_intr(struct wi_softc *);
 static int  wi_write_txrate(struct wi_softc *, struct ieee80211vap *);
 static int  wi_write_wep(struct wi_softc *, struct ieee80211vap *);
 static int  wi_write_multi(struct wi_softc *);
-static void wi_update_mcast(struct ifnet *);
-static void wi_update_promisc(struct ifnet *);
+static void wi_update_mcast(struct ieee80211com *);
+static void wi_update_promisc(struct ieee80211com *);
 static int  wi_alloc_fid(struct wi_softc *, int, int *);
 static void wi_read_nicid(struct wi_softc *);
 static int  wi_write_ssid(struct wi_softc *, int, u_int8_t *, int);
@@ -337,6 +338,7 @@ wi_attach(device_t dev)
 #endif
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_DS;
        ic->ic_opmode = IEEE80211_M_STA;
        ic->ic_caps = IEEE80211_C_STA
@@ -774,7 +776,7 @@ wi_scan_end(struct ieee80211com *ic)
 
 static void
 wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
-       int subtype, int rssi, int nf)
+       int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
 
@@ -785,7 +787,7 @@ wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
                /* NB: filter frames that trigger state changes */
                return;
        }
-       WI_VAP(vap)->wv_recv_mgmt(ni, m, subtype, rssi, nf);
+       WI_VAP(vap)->wv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
 }
 
 static int
@@ -1559,21 +1561,20 @@ allmulti:
 }
 
 static void
-wi_update_mcast(struct ifnet *ifp)
+wi_update_mcast(struct ieee80211com *ic)
 {
-       wi_write_multi(ifp->if_softc);
+       wi_write_multi(ic->ic_softc);
 }
 
 static void
-wi_update_promisc(struct ifnet *ifp)
+wi_update_promisc(struct ieee80211com *ic)
 {
-       struct wi_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = ifp->if_l2com;
+       struct wi_softc *sc = ic->ic_softc;
 
        /* XXX handle WEP special case handling? */
        wi_write_val(sc, WI_RID_PROMISC, 
            (ic->ic_opmode == IEEE80211_M_MONITOR ||
-            (ifp->if_flags & IFF_PROMISC)));
+            (ic->ic_ifp->if_flags & IFF_PROMISC)));
 }
 
 static void
index f5efc6a..ca287b3 100644 (file)
@@ -61,7 +61,7 @@ struct wi_vap {
        struct ieee80211_beacon_offsets wv_bo;
 
        void            (*wv_recv_mgmt)(struct ieee80211_node *, struct mbuf *,
-                           int, int, int);
+                           int, const struct ieee80211_rx_stats *rxs, int, int);
        int             (*wv_newstate)(struct ieee80211vap *,
                            enum ieee80211_state, int);
 };
index 07a698a..4ff29b3 100644 (file)
@@ -634,6 +634,7 @@ wpi_attach(device_t dev)
        ic = ifp->if_l2com;
 
        ic->ic_ifp = ifp;
+       ic->ic_name = device_get_nameunit(dev);
        ic->ic_phytype = IEEE80211_T_OFDM;      /* not only, but not used */
        ic->ic_opmode = IEEE80211_M_STA;        /* default to BSS mode */
 
index 12ccfa5..64d0754 100644 (file)
@@ -173,6 +173,11 @@ struct ieee80211_qosframe_addr4 {
 #define        IEEE80211_FC1_PROTECTED                 0x40
 #define        IEEE80211_FC1_ORDER                     0x80
 
+#define IEEE80211_HAS_SEQ(type, subtype) \
+       ((type) != IEEE80211_FC0_TYPE_CTL && \
+       !((type) == IEEE80211_FC0_TYPE_DATA && \
+        ((subtype) & IEEE80211_FC0_SUBTYPE_QOS_NULL) == \
+                     IEEE80211_FC0_SUBTYPE_QOS_NULL))
 #define        IEEE80211_SEQ_FRAG_MASK                 0x000f
 #define        IEEE80211_SEQ_FRAG_SHIFT                0
 #define        IEEE80211_SEQ_SEQ_MASK                  0xfff0
@@ -811,7 +816,7 @@ struct ieee80211_csa_ie {
 #define        IEEE80211_RATE_BASIC            0x80
 #define        IEEE80211_RATE_VAL              0x7f
 
-/* EPR information element flags */
+/* ERP information element flags */
 #define        IEEE80211_ERP_NON_ERP_PRESENT   0x01
 #define        IEEE80211_ERP_USE_PROTECTION    0x02
 #define        IEEE80211_ERP_LONG_PREAMBLE     0x04
index ab4bf50..6e84b66 100644 (file)
@@ -206,6 +206,9 @@ int ieee80211_add_callback(struct mbuf *m,
                void (*func)(struct ieee80211_node *, void *, int), void *arg);
 void   ieee80211_process_callback(struct ieee80211_node *, struct mbuf *, int);
 
+#define        NET80211_TAG_XMIT_PARAMS        1
+/* See below; this is after the bpf_params definition */
+
 void   get_random_bytes(void *, size_t);
 
 struct ieee80211com;
@@ -245,7 +248,7 @@ wlan_##name##_modevent(module_t mod, int type, void *unused)                \
        case MOD_UNLOAD:                                                \
                error = 0;                                              \
                if (nrefs) {                                            \
-                       kprintf("wlan_##name: still in use (%u "        \
+                       kprintf("wlan_" #name ": still in use (%u "     \
                                "dynamic refs)\n",                      \
                                nrefs);                                 \
                        error = EBUSY;                                  \
@@ -496,6 +499,16 @@ struct ieee80211_bpf_params {
        uint8_t         ibp_rate3;      /* series 4 IEEE tx rate */
 };
 
+#ifdef _KERNEL
+struct ieee80211_tx_params {
+       struct ieee80211_bpf_params params;
+};
+int    ieee80211_add_xmit_params(struct mbuf *m,
+           const struct ieee80211_bpf_params *);
+int    ieee80211_get_xmit_params(struct mbuf *m,
+           struct ieee80211_bpf_params *);
+#endif /* _KERNEL */
+
 /*
  * FreeBSD overrides
  */
index 1f95fe5..f3b304b 100644 (file)
@@ -168,19 +168,22 @@ ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh)
 {
 #define        SEQ_LEQ(a,b)    ((int)((a)-(b)) <= 0)
 #define        SEQ_EQ(a,b)     ((int)((a)-(b)) == 0)
-#define        HAS_SEQ(type)   ((type & 0x4) == 0)
 #define        SEQNO(a)        ((a) >> IEEE80211_SEQ_SEQ_SHIFT)
 #define        FRAGNO(a)       ((a) & IEEE80211_SEQ_FRAG_MASK)
        uint16_t rxseq;
-       uint8_t type;
+       uint8_t type, subtype;
        uint8_t tid;
        struct ieee80211_rx_ampdu *rap;
 
        rxseq = le16toh(*(uint16_t *)wh->i_seq);
        type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+       subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
 
-       /* Types with no sequence number are always treated valid */
-       if (! HAS_SEQ(type))
+       /*
+        * Types with no sequence number (or QoS (+)Null frames)
+        * are always treated valid.
+        */
+       if (! IEEE80211_HAS_SEQ(type, subtype))
                return 1;
 
        tid = ieee80211_gettid(wh);
@@ -235,7 +238,6 @@ ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh)
        return 1;
 #undef SEQ_LEQ
 #undef SEQ_EQ
-#undef HAS_SEQ
 #undef SEQNO
 #undef FRAGNO
 }
@@ -253,6 +255,7 @@ void ieee80211_send_error(struct ieee80211_node *,
                const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg);
 int    ieee80211_alloc_challenge(struct ieee80211_node *);
 int    ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
+               struct ieee80211_channel *,
                struct ieee80211_scanparams *);
 int    ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
 #endif /* _NET80211_IEEE80211_INPUT_H_ */
index caa0634..9ef6217 100644 (file)
@@ -68,6 +68,9 @@ void  ieee80211_syncflag_ext(struct ieee80211vap *, int flag);
 #define        IEEE80211_R_C_RSSI      0x0000010       /* per-chain RSSI value valid */
 #define        IEEE80211_R_C_EVM       0x0000020       /* per-chain EVM valid */
 #define        IEEE80211_R_C_HT40      0x0000040       /* RX'ed packet is 40mhz, pilots 4,5 valid */
+#define        IEEE80211_R_FREQ        0x0000080       /* Freq value populated, MHz */
+#define        IEEE80211_R_IEEE        0x0000100       /* IEEE value populated */
+#define        IEEE80211_R_BAND        0x0000200       /* Frequency band populated */
 
 struct ieee80211_rx_stats {
        uint32_t r_flags;               /* IEEE80211_R_* flags */
@@ -80,6 +83,8 @@ struct ieee80211_rx_stats {
        uint8_t rssi;                   /* global RSSI */
        uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS];
                                        /* per-chain, per-pilot EVM values */
+       uint16_t c_freq;
+       uint8_t c_ieee;
 };
 
 #if defined(__DragonFly__)
@@ -87,7 +92,7 @@ struct route;
 #endif
 
 #define        ieee80211_input(ni, m, rssi, nf) \
-       ((ni)->ni_vap->iv_input(ni, m, rssi, nf))
+       ((ni)->ni_vap->iv_input(ni, m, NULL, rssi, nf))
 int    ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int);
 
 int    ieee80211_input_mimo(struct ieee80211_node *, struct mbuf *,
index 3f13e17..7ece1c2 100644 (file)
@@ -79,6 +79,39 @@ struct ieee80211_scan_ssid {
 };
 #define        IEEE80211_SCAN_MAX_SSID 1               /* max # ssid's to probe */
 
+/*
+ * High-level implementation visible to ieee80211_scan.[ch].
+ *
+ * The default scanner (ieee80211_scan_sw.[ch]) implements a software
+ * driven scanner.  Firmware driven scanning needs a different set of
+ * behaviours.
+ */
+struct ieee80211_scan_methods {
+       void (*sc_attach)(struct ieee80211com *);
+       void (*sc_detach)(struct ieee80211com *);
+       void (*sc_vattach)(struct ieee80211vap *);
+       void (*sc_vdetach)(struct ieee80211vap *);
+       void (*sc_set_scan_duration)(struct ieee80211vap *, u_int);
+       int (*sc_start_scan)(const struct ieee80211_scanner *,
+           struct ieee80211vap *, int, u_int, u_int, u_int, u_int,
+           const struct ieee80211_scan_ssid ssids[]);
+       int (*sc_check_scan)(const struct ieee80211_scanner *,
+           struct ieee80211vap *, int, u_int, u_int, u_int, u_int,
+           const struct ieee80211_scan_ssid ssids[]);
+       int (*sc_bg_scan)(const struct ieee80211_scanner *,
+           struct ieee80211vap *, int);
+       void (*sc_cancel_scan)(struct ieee80211vap *);
+       void (*sc_cancel_anyscan)(struct ieee80211vap *);
+       void (*sc_scan_next)(struct ieee80211vap *);
+       void (*sc_scan_done)(struct ieee80211vap *);
+       void (*sc_scan_probe_curchan)(struct ieee80211vap *, int);
+       void (*sc_add_scan)(struct ieee80211vap *,
+           struct ieee80211_channel *,
+           const struct ieee80211_scanparams *,
+           const struct ieee80211_frame *,
+           int, int, int);
+};
+
 /*
  * Scan state visible to the 802.11 layer.  Scan parameters and
  * results are stored in this data structure.  The ieee80211_scan_state
@@ -148,6 +181,7 @@ struct ieee80211_channel *ieee80211_scan_pickchannel(struct ieee80211com *, int)
 
 struct ieee80211_scanparams;
 void   ieee80211_add_scan(struct ieee80211vap *,
+               struct ieee80211_channel *,
                const struct ieee80211_scanparams *,
                const struct ieee80211_frame *,
                int subtype, int rssi, int noise);
@@ -273,6 +307,7 @@ struct ieee80211_scanner {
                        struct ieee80211_scan_state *, int);
        /* add an entry to the cache */
        int     (*scan_add)(struct ieee80211_scan_state *,
+                       struct ieee80211_channel *,
                        const struct ieee80211_scanparams *,
                        const struct ieee80211_frame *,
                        int subtype, int rssi, int noise);
@@ -299,4 +334,14 @@ void       ieee80211_scanner_unregister(enum ieee80211_opmode,
                const struct ieee80211_scanner *);
 void   ieee80211_scanner_unregister_all(const struct ieee80211_scanner *);
 const struct ieee80211_scanner *ieee80211_scanner_get(enum ieee80211_opmode);
+void    ieee80211_scan_update_locked(struct ieee80211vap *vap,
+               const struct ieee80211_scanner *scan);
+void    ieee80211_scan_copy_ssid(struct ieee80211vap *vap,
+               struct ieee80211_scan_state *ss,
+               int nssid, const struct ieee80211_scan_ssid ssids[]);
+void    ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew,
+               const uint8_t mac[IEEE80211_ADDR_LEN],
+               const struct ieee80211_scanparams *sp, int rssi);
+void    ieee80211_scan_dump(struct ieee80211_scan_state *ss);
+
 #endif /* _NET80211_IEEE80211_SCAN_H_ */
diff --git a/sys/netproto/802_11/ieee80211_scan_sw.h b/sys/netproto/802_11/ieee80211_scan_sw.h
new file mode 100644 (file)
index 0000000..8408933
--- /dev/null
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef        __NET80211_IEEE80211_SCAN_SW_H__
+#define        __NET80211_IEEE80211_SCAN_SW_H__
+
+extern void ieee80211_swscan_attach(struct ieee80211com *ic);
+
+#endif /* __NET80211_IEEE80211_SCAN_SW_H__ */
index 2fe591f..76b9ed1 100644 (file)
@@ -81,7 +81,8 @@ struct ieee80211_tdma_state {
        int     (*tdma_newstate)(struct ieee80211vap *, enum ieee80211_state,
                    int arg);
        void    (*tdma_recv_mgmt)(struct ieee80211_node *,
-                   struct mbuf *, int, int, int);
+                   struct mbuf *, int,
+                   const struct ieee80211_rx_stats *rxs, int, int);
        void    (*tdma_opdetach)(struct ieee80211vap *);
 };
  
index 0e94e07..821c667 100644 (file)
@@ -119,6 +119,8 @@ struct ieee80211_frame;
 
 struct ieee80211com {
        struct ifnet            *ic_ifp;        /* associated device */
+       void                    *ic_softc;      /* driver softc */
+       const char              *ic_name;       /* usually device name */
        ieee80211_com_lock_t    ic_comlock;     /* state update lock */
        ieee80211_tx_lock_t     ic_txlock;      /* ic/vap TX lock */
        TAILQ_HEAD(, ieee80211vap) ic_vaps;     /* list of vap instances */
@@ -194,6 +196,7 @@ struct ieee80211com {
        struct ieee80211_dfs_state ic_dfs;      /* DFS state */
 
        struct ieee80211_scan_state *ic_scan;   /* scan state */
+       struct ieee80211_scan_methods *ic_scan_methods; /* scan methods */
        int                     ic_lastdata;    /* time of last data frame */
        int                     ic_lastscan;    /* time last scan completed */
 
@@ -258,11 +261,11 @@ struct ieee80211com {
                                    struct mbuf *,
                                    const struct ieee80211_bpf_params *);
        /* update device state for 802.11 slot time change */
-       void                    (*ic_updateslot)(struct ifnet *);
+       void                    (*ic_updateslot)(struct ieee80211com *);
        /* handle multicast state changes */
-       void                    (*ic_update_mcast)(struct ifnet *);
+       void                    (*ic_update_mcast)(struct ieee80211com *);
        /* handle promiscuous mode changes */
-       void                    (*ic_update_promisc)(struct ifnet *);
+       void                    (*ic_update_promisc)(struct ieee80211com *);
        /* new station association callback/notification */
        void                    (*ic_newassoc)(struct ieee80211_node *, int);
        /* TDMA update notification */
@@ -468,9 +471,13 @@ struct ieee80211vap {
        void                    (*iv_opdetach)(struct ieee80211vap *);
        /* receive processing */
        int                     (*iv_input)(struct ieee80211_node *,
-                                   struct mbuf *, int, int);
+                                   struct mbuf *,
+                                   const struct ieee80211_rx_stats *,
+                                   int, int);
        void                    (*iv_recv_mgmt)(struct ieee80211_node *,
-                                   struct mbuf *, int, int, int);
+                                   struct mbuf *, int,
+                                   const struct ieee80211_rx_stats *,
+                                   int, int);
        void                    (*iv_recv_ctl)(struct ieee80211_node *,
                                    struct mbuf *, int);
        void                    (*iv_deliver_data)(struct ieee80211vap *,
@@ -677,6 +684,7 @@ MALLOC_DECLARE(M_80211_VAP);
        "\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \
        "\21AMPDU\22AMSDU\23HT\24SMPS\25RIFS"
 
+int    ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3);
 void   ieee80211_ifattach(struct ieee80211com *,
                const uint8_t macaddr[IEEE80211_ADDR_LEN]);
 void   ieee80211_ifdetach(struct ieee80211com *);
@@ -713,10 +721,13 @@ struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *,
                int freq, int flags);
 struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *,
                int ieee, int flags);
+struct ieee80211_channel *ieee80211_lookup_channel_rxstatus(struct ieee80211vap *,
+               const struct ieee80211_rx_stats *);
 int    ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode);
 enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *);
 uint32_t ieee80211_mac_hash(const struct ieee80211com *,
                const uint8_t addr[IEEE80211_ADDR_LEN]);
+char   ieee80211_channel_type_char(const struct ieee80211_channel *c);
 
 void   ieee80211_radiotap_attach(struct ieee80211com *,
            struct ieee80211_radiotap_header *th, int tlen,
index a60379c..7ebe8bc 100644 (file)
@@ -9,8 +9,9 @@ SRCS    += ieee80211_output.c ieee80211_phy.c ieee80211_power.c
 SRCS   += ieee80211_proto.c ieee80211_radiotap.c
 SRCS   += ieee80211_ratectl.c ieee80211_ratectl_none.c
 SRCS   += ieee80211_regdomain.c ieee80211_rssadapt.c
-SRCS   += ieee80211_scan.c ieee80211_scan_sta.c ieee80211_sta.c
-SRCS   += ieee80211_superg.c ieee80211_tdma.c ieee80211_wds.c
+SRCS   += ieee80211_scan.c ieee80211_scan_sta.c  ieee80211_scan_sw.c
+SRCS   += ieee80211_sta.c ieee80211_superg.c ieee80211_tdma.c
+SRCS   += ieee80211_wds.c
 SRCS   += bus_if.h device_if.h opt_inet.h opt_inet6.h opt_wlan.h
 SRCS   += opt_tdma.h opt_ddb.h
 
index 63604ab..681be4d 100644 (file)
@@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/socket.h>
 
+#include <machine/stdarg.h>
+
 #include <net/if.h>
 #include <net/if_var.h>
 #include <net/if_dl.h>
@@ -229,15 +231,15 @@ ieee80211_chan_init(struct ieee80211com *ic)
 }
 
 static void
-null_update_mcast(struct ifnet *ifp)
+null_update_mcast(struct ieee80211com *ic)
 {
-       if_printf(ifp, "need multicast update callback\n");
+       ic_printf(ic, "need multicast update callback\n");
 }
 
 static void
-null_update_promisc(struct ifnet *ifp)
+null_update_promisc(struct ieee80211com *ic)
 {
-       if_printf(ifp, "need promiscuous mode update callback\n");
+       ic_printf(ic, "need promiscuous mode update callback\n");
 }
 
 static int
@@ -287,7 +289,20 @@ static void
 null_update_chw(struct ieee80211com *ic)
 {
 
-       if_printf(ic->ic_ifp, "%s: need callback\n", __func__);
+       ic_printf(ic, "%s: need callback\n", __func__);
+}
+
+int
+ic_printf(struct ieee80211com *ic, const char * fmt, ...)
+{
+       osdep_va_list ap;
+       int retval;
+
+       retval = kprintf("%s: ", ic->ic_name);
+       osdep_va_start(ap, fmt);
+       retval += kvprintf(fmt, ap);
+       osdep_va_end(ap);
+       return (retval);
 }
 
 /*
@@ -304,8 +319,8 @@ ieee80211_ifattach(struct ieee80211com *ic,
 
        KASSERT(ifp->if_type == IFT_IEEE80211, ("if_type %d", ifp->if_type));
 
-       IEEE80211_LOCK_INIT(ic, ifp->if_xname);
-       IEEE80211_TX_LOCK_INIT(ic, ifp->if_xname);
+       IEEE80211_LOCK_INIT(ic, ic->ic_name);
+       IEEE80211_TX_LOCK_INIT(ic, ic->ic_name);
        TAILQ_INIT(&ic->ic_vaps);
 
        /* Create a taskqueue for all state changes */
@@ -313,10 +328,10 @@ ieee80211_ifattach(struct ieee80211com *ic,
            taskqueue_thread_enqueue, &ic->ic_tq);
 #if defined(__DragonFly__)
        taskqueue_start_threads(&ic->ic_tq, 1, TDPRI_KERN_DAEMON, -1,
-                               "%s net80211 taskq", ifp->if_xname);
+                               "%s net80211 taskq", ic->ic_name);
 #else
        taskqueue_start_threads(&ic->ic_tq, 1, PI_NET, "%s net80211 taskq",
-           ifp->if_xname);
+           ic->ic_name);
 #endif
        /*
         * Fill in 802.11 available channel set, mark all
@@ -500,7 +515,7 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
 
        ifp = if_alloc(IFT_ETHER);
        if (ifp == NULL) {
-               if_printf(ic->ic_ifp, "%s: unable to allocate ifnet\n",
+               ic_printf(ic, "%s: unable to allocate ifnet\n",
                    __func__);
                return ENOMEM;
        }
@@ -639,7 +654,7 @@ ieee80211_vap_attach(struct ieee80211vap *vap,
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
            "%s: %s parent %s flags 0x%x flags_ext 0x%x\n",
            __func__, ieee80211_opmode_name[vap->iv_opmode],
-           ic->ic_ifp->if_xname, vap->iv_flags, vap->iv_flags_ext);
+           ic->ic_name, vap->iv_flags, vap->iv_flags_ext);
 
        /*
         * Do late attach work that cannot happen until after
@@ -705,8 +720,7 @@ ieee80211_vap_detach(struct ieee80211vap *vap)
        CURVNET_SET(ifp->if_vnet);
 
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n",
-           __func__, ieee80211_opmode_name[vap->iv_opmode],
-           ic->ic_ifp->if_xname);
+           __func__, ieee80211_opmode_name[vap->iv_opmode], ic->ic_name);
 
        /* NB: bpfdetach is called by ether_ifdetach and claims all taps */
        ether_ifdetach(ifp);
@@ -1000,7 +1014,7 @@ int
 ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
 {
        if (c == NULL) {
-               if_printf(ic->ic_ifp, "invalid channel (NULL)\n");
+               ic_printf(ic, "invalid channel (NULL)\n");
                return 0;               /* XXX */
        }
        return (c == IEEE80211_CHAN_ANYC ?  IEEE80211_CHAN_ANY : c->ic_ieee);
@@ -1091,6 +1105,75 @@ ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags)
        return NULL;
 }
 
+/*
+ * Lookup a channel suitable for the given rx status.
+ *
+ * This is used to find a channel for a frame (eg beacon, probe
+ * response) based purely on the received PHY information.
+ *
+ * For now it tries to do it based on R_FREQ / R_IEEE.
+ * This is enough for 11bg and 11a (and thus 11ng/11na)
+ * but it will not be enough for GSM, PSB channels and the
+ * like.  It also doesn't know about legacy-turbog and
+ * legacy-turbo modes, which some offload NICs actually
+ * support in weird ways.
+ *
+ * Takes the ic and rxstatus; returns the channel or NULL
+ * if not found.
+ *
+ * XXX TODO: Add support for that when the need arises.
+ */
+struct ieee80211_channel *
+ieee80211_lookup_channel_rxstatus(struct ieee80211vap *vap,
+    const struct ieee80211_rx_stats *rxs)
+{
+       struct ieee80211com *ic = vap->iv_ic;
+       uint32_t flags;
+       struct ieee80211_channel *c;
+
+       if (rxs == NULL)
+               return (NULL);
+
+       /*
+        * Strictly speaking we only use freq for now,
+        * however later on we may wish to just store
+        * the ieee for verification.
+        */
+       if ((rxs->r_flags & IEEE80211_R_FREQ) == 0)
+               return (NULL);
+       if ((rxs->r_flags & IEEE80211_R_IEEE) == 0)
+               return (NULL);
+
+       /*
+        * If the rx status contains a valid ieee/freq, then
+        * ensure we populate the correct channel information
+        * in rxchan before passing it up to the scan infrastructure.
+        * Offload NICs will pass up beacons from all channels
+        * during background scans.
+        */
+
+       /* Determine a band */
+       /* XXX should be done by the driver? */
+       if (rxs->c_freq < 3000) {
+               flags = IEEE80211_CHAN_G;
+       } else {
+               flags = IEEE80211_CHAN_A;
+       }
+
+       /* Channel lookup */
+       c = ieee80211_find_channel(ic, rxs->c_freq, flags);
+
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_INPUT,
+           "%s: freq=%d, ieee=%d, flags=0x%08x; c=%p\n",
+           __func__,
+           (int) rxs->c_freq,
+           (int) rxs->c_ieee,
+           flags,
+           c);
+
+       return (c);
+}
+
 static void
 addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
 {
@@ -1269,7 +1352,6 @@ ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *
 void
 ieee80211_announce(struct ieee80211com *ic)
 {
-       struct ifnet *ifp = ic->ic_ifp;
        int i, rate, mword;
        enum ieee80211_phymode mode;
        const struct ieee80211_rateset *rs;
@@ -1278,7 +1360,7 @@ ieee80211_announce(struct ieee80211com *ic)
        for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) {
                if (isclr(ic->ic_modecaps, mode))
                        continue;
-               if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
+               ic_printf(ic, "%s rates: ", ieee80211_phymode_name[mode]);
                rs = &ic->ic_sup_rates[mode];
                for (i = 0; i < rs->rs_nrates; i++) {
                        mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode);
@@ -1847,3 +1929,23 @@ ieee80211_mac_hash(const struct ieee80211com *ic,
        return c;
 }
 #undef mix
+
+char
+ieee80211_channel_type_char(const struct ieee80211_channel *c)
+{
+       if (IEEE80211_IS_CHAN_ST(c))
+               return 'S';
+       if (IEEE80211_IS_CHAN_108A(c))
+               return 'T';
+       if (IEEE80211_IS_CHAN_108G(c))
+               return 'G';
+       if (IEEE80211_IS_CHAN_HT(c))
+               return 'n';
+       if (IEEE80211_IS_CHAN_A(c))
+               return 'a';
+       if (IEEE80211_IS_CHAN_ANYG(c))
+               return 'g';
+       if (IEEE80211_IS_CHAN_B(c))
+               return 'b';
+       return 'f';
+}
index 248499e..807388b 100644 (file)
@@ -70,11 +70,12 @@ __FBSDID("$FreeBSD$");
 
 static void adhoc_vattach(struct ieee80211vap *);
 static int adhoc_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static int adhoc_input(struct ieee80211_node *, struct mbuf *, int, int);
+static int adhoc_input(struct ieee80211_node *, struct mbuf *,
+           const struct ieee80211_rx_stats *, int, int);
 static void adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *,
-       int subtype, int, int);
+       int subtype, const struct ieee80211_rx_stats *, int, int);
 static void ahdemo_recv_mgmt(struct ieee80211_node *, struct mbuf *,
-       int subtype, int, int);
+       int subtype, const struct ieee80211_rx_stats *rxs, int, int);
 static void adhoc_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
 
 void
@@ -229,6 +230,8 @@ adhoc_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
                        }
 #endif
                        break;
+               case IEEE80211_S_RUN:   /* IBSS merge */
+                       break;
                default:
                        goto invalid;
                }
@@ -287,9 +290,9 @@ doprint(struct ieee80211vap *vap, int subtype)
  * by the 802.11 layer.
  */
 static int
-adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
+adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
-#define        HAS_SEQ(type)   ((type & 0x4) == 0)
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
        struct ifnet *ifp = vap->iv_ifp;
@@ -369,7 +372,10 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
                /*
                 * Validate the bssid.
                 */
-               if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bss->ni_bssid) &&
+               if (!(type == IEEE80211_FC0_TYPE_MGT &&
+                    (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
+                     subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) &&
+                   !IEEE80211_ADDR_EQ(bssid, vap->iv_bss->ni_bssid) &&
                    !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) {
                        /* not interested in */
                        IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
@@ -409,7 +415,8 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
                }
                IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
                ni->ni_noise = nf;
-               if (HAS_SEQ(type)) {
+               if (IEEE80211_HAS_SEQ(type, subtype) &&
+                   IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
                        uint8_t tid = ieee80211_gettid(wh);
                        if (IEEE80211_QOS_HAS_SEQ(wh) &&
                            TID_TO_WME_AC(tid) >= WME_AC_VI)
@@ -637,7 +644,7 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
                        vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
                        goto out;
                }
-               vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+               vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
                goto out;
 
        case IEEE80211_FC0_TYPE_CTL:
@@ -682,10 +689,11 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
 
 static void
 adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
-       int subtype, int rssi, int nf)
+       int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
+       struct ieee80211_channel *rxchan = ic->ic_curchan;
        struct ieee80211_frame *wh;
        uint8_t *frm, *efrm, *sfrm;
        uint8_t *ssid, *rates, *xrates;
@@ -700,11 +708,17 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
        case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
        case IEEE80211_FC0_SUBTYPE_BEACON: {
                struct ieee80211_scanparams scan;
+               struct ieee80211_channel *c;
                /*
                 * We process beacon/probe response
                 * frames to discover neighbors.
                 */ 
-               if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
+               if (rxs != NULL) {
+                       c = ieee80211_lookup_channel_rxstatus(vap, rxs);
+                       if (c != NULL)
+                               rxchan = c;
+               }
+               if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0)
                        return;
                /*
                 * Count frame now that we know it's to be processed.
@@ -730,7 +744,8 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                                ieee80211_probe_curchan(vap, 1);
                                ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
                        }
-                       ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
+                       ieee80211_add_scan(vap, rxchan, &scan, wh,
+                           subtype, rssi, nf);
                        return;
                }
                if (scan.capinfo & IEEE80211_CAPINFO_IBSS) {
@@ -905,7 +920,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
 
 static void
 ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
-       int subtype, int rssi, int nf)
+       int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
@@ -916,7 +931,7 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
         * a site-survey.
         */
        if (ic->ic_flags & IEEE80211_F_SCAN)
-               adhoc_recv_mgmt(ni, m0, subtype, rssi, nf);
+               adhoc_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);
        else {
                wh = mtod(m0, struct ieee80211_frame *);
                switch (subtype) {
index b343aac..b77c6ba 100644 (file)
@@ -525,6 +525,7 @@ _db_show_com(const struct ieee80211com *ic, int showvaps, int showsta,
                db_printf(" %s(%p)", vap->iv_ifp->if_xname, vap);
        db_printf("\n");
        db_printf("\tifp %p(%s)", ic->ic_ifp, ic->ic_ifp->if_xname);
+       db_printf("\tname %s", ic->ic_name);
        db_printf(" comlock %p", &ic->ic_comlock);
        db_printf("\n");
        db_printf("\theadroom %d", ic->ic_headroom);
index f955276..2d1c4f6 100644 (file)
@@ -251,8 +251,8 @@ dfs_timeout(void *arg)
                                         * msg instead of one for every channel
                                         * table entry.
                                         */
-                                       if_printf(ic->ic_ifp, "radar on channel"
-                                           " %u (%u MHz) cleared after timeout\n",
+                                       ic_printf(ic, "radar on channel %u "
+                                           "(%u MHz) cleared after timeout\n",
                                            c->ic_ieee, c->ic_freq);
                                        /* notify user space */
                                        c->ic_state &=
@@ -271,14 +271,14 @@ dfs_timeout(void *arg)
 }
 
 static void
-announce_radar(struct ifnet *ifp, const struct ieee80211_channel *curchan,
+announce_radar(struct ieee80211com *ic, const struct ieee80211_channel *curchan,
        const struct ieee80211_channel *newchan)
 {
        if (newchan == NULL)
-               if_printf(ifp, "radar detected on channel %u (%u MHz)\n",
+               ic_printf(ic, "radar detected on channel %u (%u MHz)\n",
                    curchan->ic_ieee, curchan->ic_freq);
        else
-               if_printf(ifp, "radar detected on channel %u (%u MHz), "
+               ic_printf(ic, "radar detected on channel %u (%u MHz), "
                    "moving to channel %u (%u MHz)\n",
                    curchan->ic_ieee, curchan->ic_freq,
                    newchan->ic_ieee, newchan->ic_freq);
@@ -308,7 +308,7 @@ ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *ch
         * along merrily.
         */
        if (ieee80211_dfs_debug == DFS_DBG_NOCSANOL) {
-               announce_radar(ic->ic_ifp, chan, chan);
+               announce_radar(ic, chan, chan);
                ieee80211_notify_radar(ic, chan);
                return;
        }
@@ -363,7 +363,7 @@ ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *ch
                else
                        dfs->newchan = chan;
 
-               announce_radar(ic->ic_ifp, chan, dfs->newchan);
+               announce_radar(ic, chan, dfs->newchan);
 
                if (callout_pending(&dfs->cac_timer))
                        callout_schedule_dfly(&dfs->cac_timer, 0, cac_timeout, dfs->cac_timer.c_arg);
@@ -379,7 +379,7 @@ ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *ch
                         * on the NOL to expire.
                         */
                        /*XXX*/
-                       if_printf(ic->ic_ifp, "%s: No free channels; waiting for entry "
+                       ic_printf(ic, "%s: No free channels; waiting for entry "
                            "on NOL to expire\n", __func__);
                }
        } else {
@@ -389,9 +389,9 @@ ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *ch
                if (dfs->lastchan != chan) {
                        dfs->lastchan = chan;
                        dfs->cureps = 0;
-                       announce_radar(ic->ic_ifp, chan, NULL);
+                       announce_radar(ic, chan, NULL);
                } else if (ppsratecheck(&dfs->lastevent, &dfs->cureps, 1)) {
-                       announce_radar(ic->ic_ifp, chan, NULL);
+                       announce_radar(ic, chan, NULL);
                }
        }
 }
@@ -433,6 +433,6 @@ ieee80211_dfs_pickchannel(struct ieee80211com *ic)
                   (c->ic_flags & flags) == flags)
                        return c;
        }
-       if_printf(ic->ic_ifp, "HELP, no channel located to switch to!\n");
+       ic_printf(ic, "HELP, no channel located to switch to!\n");
        return NULL;
 }
index cee47bb..297d3f3 100644 (file)
@@ -372,7 +372,7 @@ static int
 ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS)
 {
        struct ieee80211com *ic = arg1;
-       const char *name = ic->ic_ifp->if_xname;
+       const char *name = ic->ic_name;
 
        return SYSCTL_OUT(req, name, strlen(name));
 }
@@ -669,6 +669,40 @@ ieee80211_add_callback(struct mbuf *m,
        return 1;
 }
 
+int
+ieee80211_add_xmit_params(struct mbuf *m,
+    const struct ieee80211_bpf_params *params)
+{
+       struct m_tag *mtag;
+       struct ieee80211_tx_params *tx;
+
+       mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
+           sizeof(struct ieee80211_tx_params), M_NOWAIT);
+       if (mtag == NULL)
+               return (0);
+
+       tx = (struct ieee80211_tx_params *)(mtag+1);
+       memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params));
+       m_tag_prepend(m, mtag);
+       return (1);
+}
+
+int
+ieee80211_get_xmit_params(struct mbuf *m,
+    struct ieee80211_bpf_params *params)
+{
+       struct m_tag *mtag;
+       struct ieee80211_tx_params *tx;
+
+       mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
+           NULL);
+       if (mtag == NULL)
+               return (-1);
+       tx = (struct ieee80211_tx_params *)(mtag + 1);
+       memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params));
+       return (0);
+}
+
 void
 ieee80211_process_callback(struct ieee80211_node *ni,
        struct mbuf *m, int status)
@@ -821,7 +855,8 @@ void
 ieee80211_notify_csa(struct ieee80211com *ic,
        const struct ieee80211_channel *c, int mode, int count)
 {
-       struct ifnet *ifp = ic->ic_ifp;
+       struct ieee80211vap *vap;
+       struct ifnet *ifp;
        struct ieee80211_csa_event iev;
 
        memset(&iev, 0, sizeof(iev));
@@ -830,36 +865,47 @@ ieee80211_notify_csa(struct ieee80211com *ic,
        iev.iev_ieee = c->ic_ieee;
        iev.iev_mode = mode;
        iev.iev_count = count;
-       rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+               ifp = vap->iv_ifp;
+               rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
+       }
 }
 
 void
 ieee80211_notify_radar(struct ieee80211com *ic,
        const struct ieee80211_channel *c)
 {
-       struct ifnet *ifp = ic->ic_ifp;
        struct ieee80211_radar_event iev;
+       struct ieee80211vap *vap;
+       struct ifnet *ifp;
 
        memset(&iev, 0, sizeof(iev));
        iev.iev_flags = c->ic_flags;
        iev.iev_freq = c->ic_freq;
        iev.iev_ieee = c->ic_ieee;
-       rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+               ifp = vap->iv_ifp;
+               rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
+       }
 }
 
 void
 ieee80211_notify_cac(struct ieee80211com *ic,
        const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type)
 {
-       struct ifnet *ifp = ic->ic_ifp;
        struct ieee80211_cac_event iev;
+       struct ieee80211vap *vap;
+       struct ifnet *ifp;
 
        memset(&iev, 0, sizeof(iev));
        iev.iev_flags = c->ic_flags;
        iev.iev_freq = c->ic_freq;
        iev.iev_ieee = c->ic_ieee;
        iev.iev_type = type;
-       rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+               ifp = vap->iv_ifp;
+               rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
+       }
 }
 
 void
@@ -901,12 +947,16 @@ ieee80211_notify_country(struct ieee80211vap *vap,
 void
 ieee80211_notify_radio(struct ieee80211com *ic, int state)
 {
-       struct ifnet *ifp = ic->ic_ifp;
        struct ieee80211_radio_event iev;
+       struct ieee80211vap *vap;
+       struct ifnet *ifp;
 
        memset(&iev, 0, sizeof(iev));
        iev.iev_state = state;
-       rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+               ifp = vap->iv_ifp;
+               rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
+       }
 }
 
 /* IEEE Std 802.11a-1999, page 9, table 79 */
@@ -1081,18 +1131,9 @@ wlan_modevent(module_t mod, int type, void *unused)
                wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
                                        bpf_track_event, 0,
                                        EVENTHANDLER_PRI_ANY);
-               if (wlan_bpfevent == NULL) {
-                       error = ENOMEM;
-                       break;
-               }
                wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
                                        wlan_iflladdr_event, NULL,
                                        EVENTHANDLER_PRI_ANY);
-               if (wlan_ifllevent == NULL) {
-                       EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
-                       error = ENOMEM;
-                       break;
-               }
                if_clone_attach(&wlan_cloner);
                if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free);
                error = 0;
index 1275d2d..f30c472 100644 (file)
@@ -68,11 +68,12 @@ __FBSDID("$FreeBSD$");
 static void hostap_vattach(struct ieee80211vap *);
 static int hostap_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static int hostap_input(struct ieee80211_node *ni, struct mbuf *m,
+           const struct ieee80211_rx_stats *,
            int rssi, int nf);
 static void hostap_deliver_data(struct ieee80211vap *,
            struct ieee80211_node *, struct mbuf *);
 static void hostap_recv_mgmt(struct ieee80211_node *, struct mbuf *,
-           int subtype, int rssi, int nf);
+           int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf);
 static void hostap_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
 
 void
@@ -481,9 +482,9 @@ doprint(struct ieee80211vap *vap, int subtype)
  * by the 802.11 layer.
  */
 static int
-hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
+hostap_input(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
-#define        HAS_SEQ(type)   ((type & 0x4) == 0)
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
        struct ifnet *ifp = vap->iv_ifp;
@@ -576,7 +577,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 
                IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
                ni->ni_noise = nf;
-               if (HAS_SEQ(type)) {
+               if (IEEE80211_HAS_SEQ(type, subtype)) {
                        uint8_t tid = ieee80211_gettid(wh);
                        if (IEEE80211_QOS_HAS_SEQ(wh) &&
                            TID_TO_WME_AC(tid) >= WME_AC_VI)
@@ -899,7 +900,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
                if (ieee80211_radiotap_active_vap(vap))
                        ieee80211_radiotap_rx(vap, m);
                need_tap = 0;
-               vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+               vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
                goto out;
 
        case IEEE80211_FC0_TYPE_CTL:
@@ -1687,7 +1688,7 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
 
 static void
 hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
-       int subtype, int rssi, int nf)
+       int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
@@ -1715,7 +1716,7 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                        return;
                }
                /* NB: accept off-channel frames */
-               if (ieee80211_parse_beacon(ni, m0, &scan) &~ IEEE80211_BPARSE_OFFCHAN)
+               if (ieee80211_parse_beacon(ni, m0, ic->ic_curchan, &scan) &~ IEEE80211_BPARSE_OFFCHAN)
                        return;
                /*
                 * Count frame now that we know it's to be processed.
@@ -1742,7 +1743,8 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                                ieee80211_probe_curchan(vap, 1);
                                ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
                        }
-                       ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
+                       ieee80211_add_scan(vap, ic->ic_curchan, &scan, wh,
+                           subtype, rssi, nf);
                        return;
                }
                /*
index 0bd75e4..af2a9f0 100644 (file)
@@ -354,7 +354,6 @@ static struct printranges {
 static void
 ht_rateprint(struct ieee80211com *ic, enum ieee80211_phymode mode, int ratetype)
 {
-       struct ifnet *ifp = ic->ic_ifp;
        int minrate, maxrate;
        struct printranges *range;
 
@@ -369,12 +368,12 @@ ht_rateprint(struct ieee80211com *ic, enum ieee80211_phymode mode, int ratetype)
                minrate = ht_getrate(ic, range->minmcs, mode, ratetype);
                maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype);
                if (range->maxmcs) {
-                       if_printf(ifp, "MCS %d-%d: %d%sMbps - %d%sMbps\n",
+                       ic_printf(ic, "MCS %d-%d: %d%sMbps - %d%sMbps\n",
                            range->minmcs, range->maxmcs,
                            minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""),
                            maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : ""));
                } else {
-                       if_printf(ifp, "MCS %d: %d%sMbps\n", range->minmcs,
+                       ic_printf(ic, "MCS %d: %d%sMbps\n", range->minmcs,
                            minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""));
                }
        }
@@ -383,22 +382,21 @@ ht_rateprint(struct ieee80211com *ic, enum ieee80211_phymode mode, int ratetype)
 static void
 ht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode)
 {
-       struct ifnet *ifp = ic->ic_ifp;
        const char *modestr = ieee80211_phymode_name[mode];
 
-       if_printf(ifp, "%s MCS 20MHz\n", modestr);
+       ic_printf(ic, "%s MCS 20MHz\n", modestr);
        ht_rateprint(ic, mode, 0);
        if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) {
-               if_printf(ifp, "%s MCS 20MHz SGI\n", modestr);
+               ic_printf(ic, "%s MCS 20MHz SGI\n", modestr);
                ht_rateprint(ic, mode, 1);
        }
        if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
-               if_printf(ifp, "%s MCS 40MHz:\n", modestr);
+               ic_printf(ic, "%s MCS 40MHz:\n", modestr);
                ht_rateprint(ic, mode, 2);
        }
        if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
            (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) {
-               if_printf(ifp, "%s MCS 40MHz SGI:\n", modestr);
+               ic_printf(ic, "%s MCS 40MHz SGI:\n", modestr);
                ht_rateprint(ic, mode, 3);
        }
 }
@@ -406,11 +404,10 @@ ht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode)
 void
 ieee80211_ht_announce(struct ieee80211com *ic)
 {
-       struct ifnet *ifp = ic->ic_ifp;
 
        if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
            isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
-               if_printf(ifp, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream);
+               ic_printf(ic, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream);
        if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
                ht_announce(ic, IEEE80211_MODE_11NA);
        if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
@@ -1047,6 +1044,7 @@ ieee80211_ht_node_init(struct ieee80211_node *ni)
                tap = &ni->ni_tx_ampdu[tid];
                tap->txa_tid = tid;
                tap->txa_ni = ni;
+               tap->txa_lastsample = ticks;
                /* NB: further initialization deferred */
        }
        ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
@@ -1216,6 +1214,7 @@ ieee80211_ht_wds_init(struct ieee80211_node *ni)
        for (tid = 0; tid < WME_NUM_TID; tid++) {
                tap = &ni->ni_tx_ampdu[tid];
                tap->txa_tid = tid;
+               tap->txa_lastsample = ticks;
        }
        /* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */
        ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
@@ -1691,6 +1690,7 @@ ampdu_tx_setup(struct ieee80211_tx_ampdu *tap)
 {
        callout_init_mp(&tap->txa_timer);
        tap->txa_flags |= IEEE80211_AGGR_SETUP;
+       tap->txa_lastsample = ticks;
 }
 
 static void
@@ -1718,8 +1718,12 @@ ampdu_tx_stop(struct ieee80211_tx_ampdu *tap)
         */
        bar_stop_timer(tap);
 
-       tap->txa_lastsample = 0;
+       /*
+        * Reset packet estimate.
+        */
+       tap->txa_lastsample = ticks;
        tap->txa_avgpps = 0;
+
        /* NB: clearing NAK means we may re-send ADDBA */ 
        tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
 }
@@ -2655,10 +2659,24 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
                        caps |= IEEE80211_HTCAP_CHWIDTH40;
                else
                        caps &= ~IEEE80211_HTCAP_CHWIDTH40;
-               /* use advertised setting (XXX locally constraint) */
+
+               /* Start by using the advertised settings */
                rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
                density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
 
+               /* Cap at VAP rxmax */
+               if (rxmax > vap->iv_ampdu_rxmax)
+                       rxmax = vap->iv_ampdu_rxmax;
+
+               /*
+                * If the VAP ampdu density value greater, use that.
+                *
+                * (Larger density value == larger minimum gap between A-MPDU
+                * subframes.)
+                */
+               if (vap->iv_ampdu_density > density)
+                       density = vap->iv_ampdu_density;
+
                /*
                 * NB: Hardware might support HT40 on some but not all
                 * channels. We can't determine this earlier because only
@@ -2675,9 +2693,12 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
                        caps |= IEEE80211_HTCAP_CHWIDTH40;
                else
                        caps &= ~IEEE80211_HTCAP_CHWIDTH40;
+
+               /* XXX TODO should it start by using advertised settings? */
                rxmax = vap->iv_ampdu_rxmax;
                density = vap->iv_ampdu_density;
        }
+
        /* adjust short GI based on channel and config */
        if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
                caps &= ~IEEE80211_HTCAP_SHORTGI20;
index 0b427c1..fcd10d7 100644 (file)
@@ -88,7 +88,8 @@ ieee80211_input_mimo(struct ieee80211_node *ni, struct mbuf *m,
 {
        /* XXX should assert IEEE80211_R_NF and IEEE80211_R_RSSI are set */
        ieee80211_process_mimo(ni, rx);
-       return ieee80211_input(ni, m, rx->rssi, rx->nf);
+       //return ieee80211_input(ni, m, rx->rssi, rx->nf);
+       return ni->ni_vap->iv_input(ni, m, rx, rx->rssi, rx->nf);
 }
 
 int
@@ -472,7 +473,7 @@ ieee80211_alloc_challenge(struct ieee80211_node *ni)
  */
 int
 ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
-       struct ieee80211_scanparams *scan)
+       struct ieee80211_channel *rxchan, struct ieee80211_scanparams *scan)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
@@ -509,7 +510,7 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
        scan->tstamp  = frm;                            frm += 8;
        scan->bintval = le16toh(*(uint16_t *)frm);      frm += 2;
        scan->capinfo = le16toh(*(uint16_t *)frm);      frm += 2;
-       scan->bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
+       scan->bchan = ieee80211_chan2ieee(ic, rxchan);
        scan->chan = scan->bchan;
        scan->ies = frm;
        scan->ies_len = efrm - frm;
@@ -652,7 +653,8 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
                 */
                IEEE80211_DISCARD(vap,
                    IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
-                   wh, NULL, "for off-channel %u", scan->chan);
+                   wh, NULL, "for off-channel %u (bchan=%u)",
+                   scan->chan, scan->bchan);
                vap->iv_stats.is_rx_chanmismatch++;
                scan->status |= IEEE80211_BPARSE_OFFCHAN;
        }
index 2f2ed17..1923400 100644 (file)
@@ -85,9 +85,10 @@ static void  mesh_transmit_to_gate(struct ieee80211vap *, struct mbuf *,
                    struct ieee80211_mesh_route *);
 static void    mesh_forward(struct ieee80211vap *, struct mbuf *,
                    const struct ieee80211_meshcntl *);
-static int     mesh_input(struct ieee80211_node *, struct mbuf *, int, int);
+static int     mesh_input(struct ieee80211_node *, struct mbuf *,
+                   const struct ieee80211_rx_stats *rxs, int, int);
 static void    mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
-                   int, int);
+                   const struct ieee80211_rx_stats *rxs, int, int);
 static void    mesh_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
 static void    mesh_peer_timeout_setup(struct ieee80211_node *);
 static void    mesh_peer_timeout_backoff(struct ieee80211_node *);
@@ -1525,7 +1526,8 @@ mesh_recv_group_data(struct ieee80211vap *vap, struct mbuf *m,
 }
 
 static int
-mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
+mesh_input(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
 #define        HAS_SEQ(type)   ((type & 0x4) == 0)
 #define        MC01(mc)        ((const struct ieee80211_meshcntl_ae01 *)mc)
@@ -1824,7 +1826,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
                        vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
                        goto out;
                }
-               vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+               vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
                goto out;
        case IEEE80211_FC0_TYPE_CTL:
                vap->iv_stats.is_rx_ctl++;
@@ -1852,11 +1854,12 @@ out:
 
 static void
 mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
-    int rssi, int nf)
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211_mesh_state *ms = vap->iv_mesh;
        struct ieee80211com *ic = ni->ni_ic;
+       struct ieee80211_channel *rxchan = ic->ic_curchan;
        struct ieee80211_frame *wh;
        struct ieee80211_mesh_route *rt;
        uint8_t *frm, *efrm;
@@ -1869,11 +1872,17 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
        case IEEE80211_FC0_SUBTYPE_BEACON:
        {
                struct ieee80211_scanparams scan;
+               struct ieee80211_channel *c;
                /*
                 * We process beacon/probe response
                 * frames to discover neighbors.
                 */
-               if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
+               if (rxs != NULL) {
+                       c = ieee80211_lookup_channel_rxstatus(vap, rxs);
+                       if (c != NULL)
+                               rxchan = c;
+               }
+               if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0)
                        return;
                /*
                 * Count frame now that we know it's to be processed.
@@ -1899,7 +1908,7 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
                                ieee80211_probe_curchan(vap, 1);
                                ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
                        }
-                       ieee80211_add_scan(vap, &scan, wh,
+                       ieee80211_add_scan(vap, rxchan, &scan, wh,
                            subtype, rssi, nf);
                        return;
                }
index a275ef8..db85c23 100644 (file)
@@ -61,7 +61,7 @@ __FBSDID("$FreeBSD$");
 static void monitor_vattach(struct ieee80211vap *);
 static int monitor_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static int monitor_input(struct ieee80211_node *ni, struct mbuf *m,
-       int rssi, int nf);
+       const struct ieee80211_rx_stats *rxs, int rssi, int nf);
 
 void
 ieee80211_monitor_attach(struct ieee80211com *ic)
@@ -125,7 +125,8 @@ monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
  * Process a received frame in monitor mode.
  */
 static int
-monitor_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
+monitor_input(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ifnet *ifp = vap->iv_ifp;
index f61626c..3839099 100644 (file)
@@ -93,6 +93,8 @@ static void node_getmimoinfo(const struct ieee80211_node *,
 
 static void _ieee80211_free_node(struct ieee80211_node *);
 
+static void node_reclaim(struct ieee80211_node_table *nt,
+       struct ieee80211_node *ni);
 static void ieee80211_node_table_init(struct ieee80211com *ic,
        struct ieee80211_node_table *nt, const char *name,
        int inact, int keymaxix);
@@ -719,9 +721,15 @@ ieee80211_sta_join1(struct ieee80211_node *selbs)
                IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr));
        vap->iv_bss = selbs;            /* NB: caller assumed to bump refcnt */
        if (obss != NULL) {
+               struct ieee80211_node_table *nt = obss->ni_table;
+
                copy_bss(selbs, obss);
                ieee80211_node_decref(obss);    /* iv_bss reference */
-               ieee80211_free_node(obss);      /* station table reference */
+
+               IEEE80211_NODE_LOCK(nt);
+               node_reclaim(nt, obss); /* station table reference */
+               IEEE80211_NODE_UNLOCK(nt);
+
                obss = NULL;            /* NB: guard against later use */
        }
 
@@ -871,7 +879,7 @@ ieee80211_sta_leave(struct ieee80211_node *ni)
 void
 ieee80211_node_deauth(struct ieee80211_node *ni, int reason)
 {
-       /* NB: bump the refcnt to be sure temporay nodes are not reclaimed */
+       /* NB: bump the refcnt to be sure temporary nodes are not reclaimed */
        ieee80211_ref_node(ni);
        if (ni->ni_associd != 0)
                IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
@@ -1749,6 +1757,28 @@ _ieee80211_free_node(struct ieee80211_node *ni)
        ni->ni_ic->ic_node_free(ni);
 }
 
+/*
+ * Clear any entry in the unicast key mapping table.
+ */
+static int
+node_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
+{
+       ieee80211_keyix keyix;
+
+       keyix = ni->ni_ucastkey.wk_rxkeyix;
+       if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
+           nt->nt_keyixmap[keyix] == ni) {
+               IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
+                   "%s: %p<%s> clear key map entry %u\n",
+                   __func__, ni, ether_sprintf(ni->ni_macaddr), keyix);
+                   nt->nt_keyixmap[keyix] = NULL;
+                   ieee80211_node_decref(ni);
+                   return 1;
+       }
+
+       return 0;
+}
+
 void
 #ifdef IEEE80211_DEBUG_REFCNT
 ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line)
@@ -1770,24 +1800,9 @@ ieee80211_free_node(struct ieee80211_node *ni)
                         * Last reference, reclaim state.
                         */
                        _ieee80211_free_node(ni);
-               } else if (ieee80211_node_refcnt(ni) == 1 &&
-                   nt->nt_keyixmap != NULL) {
-                       ieee80211_keyix keyix;
-                       /*
-                        * Check for a last reference in the key mapping table.
-                        */
-                       keyix = ni->ni_ucastkey.wk_rxkeyix;
-                       if (keyix < nt->nt_keyixmax &&
-                           nt->nt_keyixmap[keyix] == ni) {
-                               IEEE80211_DPRINTF(ni->ni_vap,
-                                   IEEE80211_MSG_NODE,
-                                   "%s: %p<%s> clear key map entry", __func__,
-                                   ni, ether_sprintf(ni->ni_macaddr));
-                               nt->nt_keyixmap[keyix] = NULL;
-                               ieee80211_node_decref(ni); /* XXX needed? */
+               } else if (ieee80211_node_refcnt(ni) == 1)
+                       if (node_clear_keyixmap(nt, ni))
                                _ieee80211_free_node(ni);
-                       }
-               }
                IEEE80211_NODE_UNLOCK(nt);
        } else {
                if (ieee80211_node_dectestref(ni))
@@ -1855,7 +1870,6 @@ ieee80211_node_delucastkey(struct ieee80211_node *ni)
 static void
 node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
 {
-       ieee80211_keyix keyix;
 
        IEEE80211_NODE_LOCK_ASSERT(nt);
 
@@ -1870,15 +1884,7 @@ node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
         * table.  We cannot depend on the mapping table entry
         * being cleared because the node may not be free'd.
         */
-       keyix = ni->ni_ucastkey.wk_rxkeyix;
-       if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
-           nt->nt_keyixmap[keyix] == ni) {
-               IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
-                       "%s: %p<%s> clear key map entry %u\n",
-                       __func__, ni, ether_sprintf(ni->ni_macaddr), keyix);
-               nt->nt_keyixmap[keyix] = NULL;
-               ieee80211_node_decref(ni);      /* NB: don't need free */
-       }
+       (void)node_clear_keyixmap(nt, ni);
        if (!ieee80211_node_dectestref(ni)) {
                /*
                 * Other references are present, just remove the
@@ -1902,11 +1908,10 @@ ieee80211_node_table_init(struct ieee80211com *ic,
        struct ieee80211_node_table *nt,
        const char *name, int inact, int keyixmax)
 {
-       struct ifnet *ifp = ic->ic_ifp;
 
        nt->nt_ic = ic;
-       IEEE80211_NODE_LOCK_INIT(nt, ifp->if_xname);
-       IEEE80211_NODE_ITERATE_LOCK_INIT(nt, ifp->if_xname);
+       IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name);
+       IEEE80211_NODE_ITERATE_LOCK_INIT(nt, ic->ic_name);
        TAILQ_INIT(&nt->nt_node);
        nt->nt_name = name;
        nt->nt_scangen = 1;
@@ -1917,7 +1922,7 @@ ieee80211_node_table_init(struct ieee80211com *ic,
                        keyixmax * sizeof(struct ieee80211_node *),
                        M_80211_NODE, M_INTWAIT | M_ZERO);
                if (nt->nt_keyixmap == NULL)
-                       if_printf(ic->ic_ifp,
+                       ic_printf(ic,
                            "Cannot allocate key index map with %u entries\n",
                            keyixmax);
        } else
@@ -2250,8 +2255,8 @@ ieee80211_iterate_nt(struct ieee80211_node_table *nt,
        TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
                if (i >= max_aid) {
                        ret = E2BIG;
-                       if_printf(nt->nt_ic->ic_ifp,
-                           "Node array overflow: max=%u", max_aid);
+                       ic_printf(nt->nt_ic, "Node array overflow: max=%u",
+                           max_aid);
                        break;
                }
                ni_arr[i] = ieee80211_ref_node(ni);
index 020171c..371d79a 100644 (file)
@@ -136,7 +136,7 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ifnet *ifp = vap->iv_ifp;
-       int error;
+       int error, len, mcast;
 
        if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
            (m->m_flags & M_PWR_SAV) == 0) {
@@ -146,7 +146,8 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
                 * the frame back when the time is right.
                 * XXX lose WDS vap linkage?
                 */
-               (void) ieee80211_pwrsave(ni, m);
+               if (ieee80211_pwrsave(ni, m) != 0)
+                       IFNET_STAT_INC(ifp, oerrors, 1);
                ieee80211_free_node(ni);
 
                /*
@@ -175,6 +176,8 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
         * interface it (might have been) received on.
         */
        m->m_pkthdr.rcvif = (void *)ni;
+       mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0;
+       len = m->m_pkthdr.len;
 
        BPF_MTAP(ifp, m);               /* 802.3 tx */
 
@@ -240,7 +243,7 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
                        /* NB: stat+msg handled in ieee80211_encap */
                        IEEE80211_TX_UNLOCK(ic);
                        ieee80211_free_node(ni);
-                       /* XXX better status? */
+                       IFNET_STAT_INC(ifp, oerrors, 1);
                        return (ENOBUFS);
                }
        }
@@ -254,8 +257,11 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
        if (error != 0) {
                /* NB: IFQ_HANDOFF reclaims mbuf */
                ieee80211_free_node(ni);
+               IFNET_STAT_INC(ifp, oerrors, 1);
        } else {
                IFNET_STAT_INC(ifp, opackets, 1);
+               IFNET_STAT_INC(ifp, omcasts, mcast);
+               IFNET_STAT_INC(ifp, obytes, len);
        }
        ic->ic_lastdata = ticks;
 
@@ -320,6 +326,7 @@ ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m)
                        vap->iv_stats.is_dwds_mcast++;
                        m_freem(m);
                        /* XXX better status? */
+                       IFNET_STAT_INC(ifp, oerrors, 1);
                        return (ENOBUFS);
                }
                if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
@@ -401,7 +408,8 @@ ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m)
                 * for transmit.
                 */
                ic->ic_lastdata = ticks;
-               (void) ieee80211_pwrsave(ni, m);
+               if (ieee80211_pwrsave(ni, m) != 0)
+                       IFNET_STAT_INC(ifp, oerrors, 1);
                ieee80211_free_node(ni);
                ieee80211_new_state(vap, IEEE80211_S_RUN, 0);
                return (0);
@@ -511,9 +519,9 @@ ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m)
                IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
                    "%s: ignore queue, parent %s not up+running\n",
                    __func__, parent->if_xname);
-               /* XXX stat */
                m_freem(m);
-               return (EINVAL);
+               IFNET_STAT_INC(ifp, oerrors, 1);
+               return (ENETDOWN);
        }
 
        /*
@@ -535,7 +543,8 @@ ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m)
                        IEEE80211_UNLOCK(ic);
                        ifp->if_drv_flags |= IFF_DRV_OACTIVE;
                        m_freem(m);
-                       return (EINVAL);
+                       IFNET_STAT_INC(ifp, oerrors, 1);
+                       return (ENETDOWN);
                }
                IEEE80211_UNLOCK(ic);
        }
@@ -583,6 +592,26 @@ ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni,
 {
        struct ieee80211com *ic = vap->iv_ic;
 
+       /*
+        * Set node - the caller has taken a reference, so ensure
+        * that the mbuf has the same node value that
+        * it would if it were going via the normal path.
+        */
+       m->m_pkthdr.rcvif = (void *)ni;
+
+       /*
+        * Attempt to add bpf transmit parameters.
+        *
+        * For now it's ok to fail; the raw_xmit api still takes
+        * them as an option.
+        *
+        * Later on when ic_raw_xmit() has params removed,
+        * they'll have to be added - so fail the transmit if
+        * they can't be.
+        */
+       if (params)
+               (void) ieee80211_add_xmit_params(m, params);
+
        return (ic->ic_raw_xmit(ni, m, params));
 }
 
@@ -826,7 +855,11 @@ ieee80211_send_setup(
        if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap))
                m->m_flags |= M_AMPDU_MPDU;
        else {
-               seqno = ni->ni_txseqs[tid]++;
+               if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK,
+                                     type & IEEE80211_FC0_SUBTYPE_MASK))
+                       seqno = ni->ni_txseqs[tid]++;
+               else
+                       seqno = 0;
                *(uint16_t *)&wh->i_seq[0] =
                    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
                M_SEQNO_SET(m, seqno);
@@ -2431,18 +2464,33 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
                            ic->ic_curchan);
                        frm = ieee80211_add_supportedchannels(frm, ic);
                }
+
+               /*
+                * Check the channel - we may be using an 11n NIC with an
+                * 11n capable station, but we're configured to be an 11b
+                * channel.
+                */
                if ((vap->iv_flags_ht & IEEE80211_FHT_HT) &&
+                   IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
                    ni->ni_ies.htcap_ie != NULL &&
-                   ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP)
+                   ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) {
                        frm = ieee80211_add_htcap(frm, ni);
+               }
                frm = ieee80211_add_wpa(frm, vap);
                if ((ic->ic_flags & IEEE80211_F_WME) &&
                    ni->ni_ies.wme_ie != NULL)
                        frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
+
+               /*
+                * Same deal - only send HT info if we're on an 11n
+                * capable channel.
+                */
                if ((vap->iv_flags_ht & IEEE80211_FHT_HT) &&
+                   IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
                    ni->ni_ies.htcap_ie != NULL &&
-                   ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR)
+                   ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) {
                        frm = ieee80211_add_htcap_vendor(frm, ni);
+               }
 #ifdef IEEE80211_SUPPORT_SUPERG
                if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) {
                        frm = ieee80211_add_ath(frm, 
index 3009e54..749de29 100644 (file)
@@ -560,10 +560,15 @@ ieee80211_sta_pwrsave(struct ieee80211vap *vap, int enable)
  * Handle being notified that we have data available for us in a TIM/ATIM.
  *
  * This may schedule a transition from _SLEEP -> _RUN if it's appropriate.
+ *
+ * In STA mode, we may have put to sleep during scan and need to be dragged
+ * back out of powersave mode.
  */
 void
 ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set)
 {
+       struct ieee80211com *ic = vap->iv_ic;
+
        /*
         * Schedule the driver state change.  It'll happen at some point soon.
         * Since the hardware shouldn't know that we're running just yet
@@ -574,10 +579,24 @@ ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set)
         * XXX TODO: verify that the transition to RUN will wake up the
         * BSS node!
         */
-       IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, "%s: TIM=%d\n", __func__, set);
        IEEE80211_LOCK(vap->iv_ic);
        if (set == 1 && vap->iv_state == IEEE80211_S_SLEEP) {
                ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0);
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
+                   "%s: TIM=%d; wakeup\n", __func__, set);
+       } else if ((set == 1) && (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN)) {
+               /*
+                * XXX only do this if we're in RUN state?
+                */
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
+                   "%s: wake up from bgscan vap sleep\n",
+                   __func__);
+               /*
+                * We may be in BGSCAN mode - this means the VAP is is in STA
+                * mode powersave.  If it is, we need to wake it up so we
+                * can process outbound traffic.
+                */
+               vap->iv_sta_ps(vap, 0);
        }
        IEEE80211_UNLOCK(vap->iv_ic);
 }
index b382ee7..643b820 100644 (file)
@@ -117,9 +117,8 @@ static int
 null_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
        const struct ieee80211_bpf_params *params)
 {
-       struct ifnet *ifp = ni->ni_ic->ic_ifp;
 
-       if_printf(ifp, "missing ic_raw_xmit callback, drop frame\n");
+       ic_printf(ni->ni_ic, "missing ic_raw_xmit callback, drop frame\n");
        m_freem(m);
        return ENETDOWN;
 }
@@ -656,7 +655,7 @@ ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff)
                ic->ic_flags &= ~IEEE80211_F_SHSLOT;
        /* notify driver */
        if (ic->ic_updateslot != NULL)
-               ic->ic_updateslot(ic->ic_ifp);
+               ic->ic_updateslot(ic);
 }
 
 /*
@@ -1178,18 +1177,16 @@ static void
 update_mcast(void *arg, int npending)
 {
        struct ieee80211com *ic = arg;
-       struct ifnet *parent = ic->ic_ifp;
 
-       ic->ic_update_mcast(parent);
+       ic->ic_update_mcast(ic);
 }
 
 static void
 update_promisc(void *arg, int npending)
 {
        struct ieee80211com *ic = arg;
-       struct ifnet *parent = ic->ic_ifp;
 
-       ic->ic_update_promisc(parent);
+       ic->ic_update_promisc(ic);
 }
 
 static void
@@ -1230,6 +1227,41 @@ ieee80211_waitfor_parent(struct ieee80211com *ic)
        taskqueue_unblock(ic->ic_tq);
 }
 
+/*
+ * Check to see whether the current channel needs reset.
+ *
+ * Some devices don't handle being given an invalid channel
+ * in their operating mode very well (eg wpi(4) will throw a
+ * firmware exception.)
+ *
+ * Return 0 if we're ok, 1 if the channel needs to be reset.
+ *
+ * See PR kern/202502.
+ */
+static int
+ieee80211_start_check_reset_chan(struct ieee80211vap *vap)
+{
+       struct ieee80211com *ic = vap->iv_ic;
+
+       if ((vap->iv_opmode == IEEE80211_M_IBSS &&
+            IEEE80211_IS_CHAN_NOADHOC(ic->ic_curchan)) ||
+           (vap->iv_opmode == IEEE80211_M_HOSTAP &&
+            IEEE80211_IS_CHAN_NOHOSTAP(ic->ic_curchan)))
+               return (1);
+       return (0);
+}
+
+/*
+ * Reset the curchan to a known good state.
+ */
+static void
+ieee80211_start_reset_chan(struct ieee80211vap *vap)
+{
+       struct ieee80211com *ic = vap->iv_ic;
+
+       ic->ic_curchan = &ic->ic_channels[0];
+}
+
 /*
  * Start a vap running.  If this is the first vap to be
  * set running on the underlying device then we
@@ -1264,6 +1296,11 @@ ieee80211_start_locked(struct ieee80211vap *vap)
                 */
                if (ic->ic_nrunning++ == 0 &&
                    (parent->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+
+                       /* reset the channel to a known good channel */
+                       if (ieee80211_start_check_reset_chan(vap))
+                               ieee80211_start_reset_chan(vap);
+
                        IEEE80211_DPRINTF(vap,
                            IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
                            "%s: up parent %s\n", __func__, parent->if_xname);
index 4cd8c3d..1467f0c 100644 (file)
@@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$");
 #include <net/bpf.h>
 #include <net/if.h>
 #include <net/if_var.h>
-#include <net/if_llc.h>
 #include <net/if_media.h>
 #include <net/ethernet.h>
 
@@ -90,8 +89,8 @@ ieee80211_radiotap_attachv(struct ieee80211com *ic,
        else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
                off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL);
        if (off == -1) {
-               if_printf(ic->ic_ifp, "%s: no tx channel, radiotap 0x%x\n",
-                   __func__, tx_radiotap);
+               ic_printf(ic, "%s: no tx channel, radiotap 0x%x\n", __func__,
+                   tx_radiotap);
                /* NB: we handle this case but data will have no chan spec */
        } else
                ic->ic_txchan = ((uint8_t *) th) + off;
@@ -106,8 +105,8 @@ ieee80211_radiotap_attachv(struct ieee80211com *ic,
        else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
                off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL);
        if (off == -1) {
-               if_printf(ic->ic_ifp, "%s: no rx channel, radiotap 0x%x\n",
-                   __func__, rx_radiotap);
+               ic_printf(ic, "%s: no rx channel, radiotap 0x%x\n", __func__,
+                   rx_radiotap);
                /* NB: we handle this case but data will have no chan spec */
        } else
                ic->ic_rxchan = ((uint8_t *) rh) + off;
index f07e514..5bea7a1 100644 (file)
@@ -304,16 +304,16 @@ ieee80211_alloc_countryie(struct ieee80211com *ic)
        aie = kmalloc(IEEE80211_COUNTRY_MAX_SIZE, M_80211_NODE_IE,
            M_INTWAIT | M_ZERO);
        if (aie == NULL) {
-               if_printf(ic->ic_ifp,
-                   "%s: unable to allocate memory for country ie\n", __func__);
+               ic_printf(ic, "%s: unable to allocate memory for country ie\n",
+                   __func__);
                /* XXX stat */
                return NULL;
        }
        ie = (struct ieee80211_country_ie *) aie->ie_data;
        ie->ie = IEEE80211_ELEMID_COUNTRY;
        if (rd->isocc[0] == '\0') {
-               if_printf(ic->ic_ifp, "no ISO country string for cc %d; "
-                       "using blanks\n", rd->country);
+               ic_printf(ic, "no ISO country string for cc %d; using blanks\n",
+                   rd->country);
                ie->cc[0] = ie->cc[1] = ' ';
        } else {
                ie->cc[0] = rd->isocc[0];
@@ -350,7 +350,7 @@ ieee80211_alloc_countryie(struct ieee80211com *ic)
                if (c->ic_ieee != nextchan ||
                    c->ic_maxregpower != frm[-1]) {     /* new run */
                        if (nruns == IEEE80211_COUNTRY_MAX_BANDS) {
-                               if_printf(ic->ic_ifp, "%s: country ie too big, "
+                               ic_printf(ic, "%s: country ie too big, "
                                    "runs > max %d, truncating\n",
                                    __func__, IEEE80211_COUNTRY_MAX_BANDS);
                                /* XXX stat? fail? */
index fb49bdb..37313fa 100644 (file)
@@ -46,35 +46,10 @@ __FBSDID("$FreeBSD$");
 
 #include <netproto/802_11/ieee80211_var.h>
 
-#include <net/bpf.h>
-
-struct scan_state {
-       struct ieee80211_scan_state base;       /* public state */
-
-       u_int           ss_iflags;              /* flags used internally */
-#define        ISCAN_MINDWELL  0x0001          /* min dwell time reached */
-#define        ISCAN_DISCARD   0x0002          /* discard rx'd frames */
-#define        ISCAN_CANCEL    0x0004          /* cancel current scan */
-#define        ISCAN_ABORT     0x0008          /* end the scan immediately */
-       unsigned long   ss_chanmindwell;        /* min dwell on curchan */
-       unsigned long   ss_scanend;             /* time scan must stop */
-       u_int           ss_duration;            /* duration for next scan */
-       struct task     ss_scan_task;           /* scan execution */
-       struct cv       ss_scan_cv;             /* scan signal */
-       struct callout  ss_scan_timer;          /* scan timer */
-};
-#define        SCAN_PRIVATE(ss)        ((struct scan_state *) ss)
+/* XXX until it's implemented as attach ops */
+#include <netproto/802_11/ieee80211_scan_sw.h>
 
-/*
- * Amount of time to go off-channel during a background
- * scan.  This value should be large enough to catch most
- * ap's but short enough that we can return on-channel
- * before our listen interval expires.
- *
- * XXX tunable
- * XXX check against configured listen interval
- */
-#define        IEEE80211_SCAN_OFFCHANNEL       msecs_to_ticks(150)
+#include <net/bpf.h>
 
 /*
  * Roaming-related defaults.  RSSI thresholds are as returned by the
@@ -93,55 +68,31 @@ struct scan_state {
 #define        ROAM_RATE_QUARTER_DEFAULT       2*3     /* quarter-width 11a/g bss */
 #define        ROAM_MCS_11N_DEFAULT            (1 | IEEE80211_RATE_MCS) /* 11n bss */
 
-static void scan_curchan(struct ieee80211_scan_state *, unsigned long);
-static void scan_mindwell(struct ieee80211_scan_state *);
-static void scan_signal(void *);
-static void scan_task(void *, int);
-
-MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
-
 void
 ieee80211_scan_attach(struct ieee80211com *ic)
 {
-       struct scan_state *ss;
 
-       ss = (struct scan_state *) kmalloc(sizeof(struct scan_state),
-               M_80211_SCAN, M_INTWAIT | M_ZERO);
-       if (ss == NULL) {
-               ic->ic_scan = NULL;
-               return;
-       }
-       callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0);
-       cv_init(&ss->ss_scan_cv, "scan");
-       TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss);
-       ic->ic_scan = &ss->base;
-       ss->base.ss_ic = ic;
-
-       ic->ic_scan_curchan = scan_curchan;
-       ic->ic_scan_mindwell = scan_mindwell;
+       /*
+        * If there's no scan method pointer, attach the
+        * swscan set as a default.
+        */
+       if (ic->ic_scan_methods == NULL)
+               ieee80211_swscan_attach(ic);
+       else
+               ic->ic_scan_methods->sc_attach(ic);
 }
 
 void
 ieee80211_scan_detach(struct ieee80211com *ic)
 {
-       struct ieee80211_scan_state *ss = ic->ic_scan;
 
-       if (ss != NULL) {
-               IEEE80211_LOCK(ic);
-               SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT;
-               scan_signal(ss);
-               IEEE80211_UNLOCK(ic);
-               ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
-               callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer);
-               KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0,
-                   ("scan still running"));
-               if (ss->ss_ops != NULL) {
-                       ss->ss_ops->scan_detach(ss);
-                       ss->ss_ops = NULL;
-               }
-               ic->ic_scan = NULL;
-               kfree(SCAN_PRIVATE(ss), M_80211_SCAN);
-       }
+       /*
+        * Ideally we'd do the ss_ops detach call here;
+        * but then sc_detach() would need to be split in two.
+        *
+        * I'll do that later.
+        */
+       ic->ic_scan_methods->sc_detach(ic);
 }
 
 static const struct ieee80211_roamparam defroam[IEEE80211_MODE_MAX] = {
@@ -170,12 +121,15 @@ static const struct ieee80211_roamparam defroam[IEEE80211_MODE_MAX] = {
 void
 ieee80211_scan_vattach(struct ieee80211vap *vap)
 {
+       struct ieee80211com *ic = vap->iv_ic;
        vap->iv_bgscanidle = (IEEE80211_BGSCAN_IDLE_DEFAULT*1000)/hz;
        vap->iv_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT*hz;
        vap->iv_scanvalid = IEEE80211_SCAN_VALID_DEFAULT*hz;
 
        vap->iv_roaming = IEEE80211_ROAMING_AUTO;
        memcpy(vap->iv_roamparms, defroam, sizeof(defroam));
+
+       ic->ic_scan_methods->sc_vattach(vap);
 }
 
 void
@@ -186,11 +140,10 @@ ieee80211_scan_vdetach(struct ieee80211vap *vap)
 
        IEEE80211_LOCK(ic);
        ss = ic->ic_scan;
+
+       ic->ic_scan_methods->sc_vdetach(vap);
+
        if (ss != NULL && ss->ss_vap == vap) {
-               if (ic->ic_flags & IEEE80211_F_SCAN) {
-                       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT;
-                       scan_signal(ss);
-               }
                if (ss->ss_ops != NULL) {
                        ss->ss_ops->scan_detach(ss);
                        ss->ss_ops = NULL;
@@ -261,8 +214,8 @@ ieee80211_scanner_unregister_all(const struct ieee80211_scanner *scan)
  * ensure later callbacks find ss_ops set to properly
  * reflect current operating mode.
  */
-static void
-scan_update_locked(struct ieee80211vap *vap,
+void
+ieee80211_scan_update_locked(struct ieee80211vap *vap,
        const struct ieee80211_scanner *scan)
 {
        struct ieee80211com *ic = vap->iv_ic;
@@ -307,26 +260,6 @@ scan_update_locked(struct ieee80211vap *vap,
        }
 }
 
-static char
-channel_type(const struct ieee80211_channel *c)
-{
-       if (IEEE80211_IS_CHAN_ST(c))
-               return 'S';
-       if (IEEE80211_IS_CHAN_108A(c))
-               return 'T';
-       if (IEEE80211_IS_CHAN_108G(c))
-               return 'G';
-       if (IEEE80211_IS_CHAN_HT(c))
-               return 'n';
-       if (IEEE80211_IS_CHAN_A(c))
-               return 'a';
-       if (IEEE80211_IS_CHAN_ANYG(c))
-               return 'g';
-       if (IEEE80211_IS_CHAN_B(c))
-               return 'b';
-       return 'f';
-}
-
 void
 ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss)
 {
@@ -339,14 +272,14 @@ ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss)
                const struct ieee80211_channel *c = ss->ss_chans[i];
 
                kprintf("%s%u%c", sep, ieee80211_chan2ieee(ic, c),
-                       channel_type(c));
+                   ieee80211_channel_type_char(c));
                sep = ", ";
        }
 }
 
 #ifdef IEEE80211_DEBUG
-static void
-scan_dump(struct ieee80211_scan_state *ss)
+void
+ieee80211_scan_dump(struct ieee80211_scan_state *ss)
 {
        struct ieee80211vap *vap = ss->ss_vap;
 
@@ -357,8 +290,8 @@ scan_dump(struct ieee80211_scan_state *ss)
 }
 #endif /* IEEE80211_DEBUG */
 
-static void
-copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss,
+void
+ieee80211_scan_copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss,
        int nssid, const struct ieee80211_scan_ssid ssids[])
 {
        if (nssid > IEEE80211_SCAN_MAX_SSID) {
@@ -372,78 +305,6 @@ copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss,
        ss->ss_nssid = nssid;
 }
 
-/*
- * Start a scan unless one is already going.
- */
-static int
-start_scan_locked(const struct ieee80211_scanner *scan,
-       struct ieee80211vap *vap, int flags, u_int duration,
-       u_int mindwell, u_int maxdwell,
-       u_int nssid, const struct ieee80211_scan_ssid ssids[])
-{
-       struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_state *ss = ic->ic_scan;
-
-       IEEE80211_LOCK_ASSERT(ic);
-
-       if (ic->ic_flags & IEEE80211_F_CSAPENDING) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: scan inhibited by pending channel change\n", __func__);
-       } else if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: %s scan, duration %u mindwell %u maxdwell %u, desired mode %s, %s%s%s%s%s%s\n"
-                   , __func__
-                   , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
-                   , duration, mindwell, maxdwell
-                   , ieee80211_phymode_name[vap->iv_des_mode]
-                   , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
-                   , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
-                   , flags & IEEE80211_SCAN_NOJOIN ? ", nojoin" : ""
-                   , flags & IEEE80211_SCAN_NOBCAST ? ", nobcast" : ""
-                   , flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
-                   , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
-               );
-
-               scan_update_locked(vap, scan);
-               if (ss->ss_ops != NULL) {
-                       if ((flags & IEEE80211_SCAN_NOSSID) == 0)
-                               copy_ssid(vap, ss, nssid, ssids);
-
-                       /* NB: top 4 bits for internal use */
-                       ss->ss_flags = flags & 0xfff;
-                       if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
-                               vap->iv_stats.is_scan_active++;
-                       else
-                               vap->iv_stats.is_scan_passive++;
-                       if (flags & IEEE80211_SCAN_FLUSH)
-                               ss->ss_ops->scan_flush(ss);
-                       if (flags & IEEE80211_SCAN_BGSCAN)
-                               ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
-
-                       /* NB: flush frames rx'd before 1st channel change */
-                       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
-                       SCAN_PRIVATE(ss)->ss_duration = duration;
-                       ss->ss_next = 0;
-                       ss->ss_mindwell = mindwell;
-                       ss->ss_maxdwell = maxdwell;
-                       /* NB: scan_start must be before the scan runtask */
-                       ss->ss_ops->scan_start(ss, vap);
-#ifdef IEEE80211_DEBUG
-                       if (ieee80211_msg_scan(vap))
-                               scan_dump(ss);
-#endif /* IEEE80211_DEBUG */
-                       ic->ic_flags |= IEEE80211_F_SCAN;
-                       ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
-               }
-               return 1;
-       } else {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: %s scan already in progress\n", __func__,
-                   ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
-       }
-       return 0;
-}
-
 /*
  * Start a scan unless one is already going.
  */
@@ -452,9 +313,8 @@ ieee80211_start_scan(struct ieee80211vap *vap, int flags,
        u_int duration, u_int mindwell, u_int maxdwell,
        u_int nssid, const struct ieee80211_scan_ssid ssids[])
 {
-       struct ieee80211com *ic = vap->iv_ic;
        const struct ieee80211_scanner *scan;
-       int result;
+       struct ieee80211com *ic = vap->iv_ic;
 
        scan = ieee80211_scanner_get(vap->iv_opmode);
        if (scan == NULL) {
@@ -465,12 +325,8 @@ ieee80211_start_scan(struct ieee80211vap *vap, int flags,
                return 0;
        }
 
-       IEEE80211_LOCK(ic);
-       result = start_scan_locked(scan, vap, flags, duration,
+       return ic->ic_scan_methods->sc_start_scan(scan, vap, flags, duration,
            mindwell, maxdwell, nssid, ssids);
-       IEEE80211_UNLOCK(ic);
-
-       return result;
 }
 
 /*
@@ -517,49 +373,18 @@ ieee80211_check_scan(struct ieee80211vap *vap, int flags,
                /* XXX re-use cache contents? e.g. adhoc<->sta */
                flags |= IEEE80211_SCAN_FLUSH;
        }
-       scan_update_locked(vap, scan);
-       if (ss->ss_ops != NULL) {
-               /* XXX verify ss_ops matches vap->iv_opmode */
-               if ((flags & IEEE80211_SCAN_NOSSID) == 0) {
-                       /*
-                        * Update the ssid list and mark flags so if
-                        * we call start_scan it doesn't duplicate work.
-                        */
-                       copy_ssid(vap, ss, nssid, ssids);
-                       flags |= IEEE80211_SCAN_NOSSID;
-               }
-               if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
-                   (flags & IEEE80211_SCAN_FLUSH) == 0 &&
-                   time_before(ticks, ic->ic_lastscan + vap->iv_scanvalid)) {
-                       /*
-                        * We're not currently scanning and the cache is
-                        * deemed hot enough to consult.  Lock out others
-                        * by marking IEEE80211_F_SCAN while we decide if
-                        * something is already in the scan cache we can
-                        * use.  Also discard any frames that might come
-                        * in while temporarily marked as scanning.
-                        */
-                       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
-                       ic->ic_flags |= IEEE80211_F_SCAN;
-
-                       /* NB: need to use supplied flags in check */
-                       ss->ss_flags = flags & 0xff;
-                       result = ss->ss_ops->scan_end(ss, vap);
-
-                       ic->ic_flags &= ~IEEE80211_F_SCAN;
-                       SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD;
-                       if (result) {
-                               ieee80211_notify_scan_done(vap);
-                               IEEE80211_UNLOCK(ic);
-                               return 1;
-                       }
-               }
-       }
-       result = start_scan_locked(scan, vap, flags, duration,
+
+       /*
+        * XXX TODO: separate things out a bit better.
+        */
+       ieee80211_scan_update_locked(vap, scan);
+
+       result = ic->ic_scan_methods->sc_check_scan(scan, vap, flags, duration,
            mindwell, maxdwell, nssid, ssids);
+
        IEEE80211_UNLOCK(ic);
 
-       return result;
+       return (result);
 }
 
 /*
@@ -583,9 +408,10 @@ int
 ieee80211_bg_scan(struct ieee80211vap *vap, int flags)
 {
        struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_state *ss = ic->ic_scan;
        const struct ieee80211_scanner *scan;
 
+       // IEEE80211_UNLOCK_ASSERT(sc);
+
        scan = ieee80211_scanner_get(vap->iv_opmode);
        if (scan == NULL) {
                IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
@@ -595,84 +421,12 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags)
                return 0;
        }
 
-       IEEE80211_LOCK(ic);
-       if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
-               u_int duration;
-               /*
-                * Go off-channel for a fixed interval that is large
-                * enough to catch most ap's but short enough that
-                * we can return on-channel before our listen interval
-                * expires.
-                */
-               duration = IEEE80211_SCAN_OFFCHANNEL;
-
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: %s scan, ticks %u duration %u\n", __func__,
-                   ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",
-                   ticks, duration);
-
-               scan_update_locked(vap, scan);
-               if (ss->ss_ops != NULL) {
-                       ss->ss_vap = vap;
-                       /*
-                        * A background scan does not select a new sta; it
-                        * just refreshes the scan cache.  Also, indicate
-                        * the scan logic should follow the beacon schedule:
-                        * we go off-channel and scan for a while, then
-                        * return to the bss channel to receive a beacon,
-                        * then go off-channel again.  All during this time
-                        * we notify the ap we're in power save mode.  When
-                        * the scan is complete we leave power save mode.
-                        * If any beacon indicates there are frames pending
-                        * for us then we drop out of power save mode
-                        * (and background scan) automatically by way of the
-                        * usual sta power save logic.
-                        */
-                       ss->ss_flags |= IEEE80211_SCAN_NOPICK
-                                    |  IEEE80211_SCAN_BGSCAN
-                                    |  flags
-                                    ;
-                       /* if previous scan completed, restart */
-                       if (ss->ss_next >= ss->ss_last) {
-                               if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
-                                       vap->iv_stats.is_scan_active++;
-                               else
-                                       vap->iv_stats.is_scan_passive++;
-                               /*
-                                * NB: beware of the scan cache being flushed;
-                                *     if the channel list is empty use the
-                                *     scan_start method to populate it.
-                                */
-                               ss->ss_next = 0;
-                               if (ss->ss_last != 0)
-                                       ss->ss_ops->scan_restart(ss, vap);
-                               else {
-                                       ss->ss_ops->scan_start(ss, vap);
-#ifdef IEEE80211_DEBUG
-                                       if (ieee80211_msg_scan(vap))
-                                               scan_dump(ss);
-#endif /* IEEE80211_DEBUG */
-                               }
-                       }
-                       /* NB: flush frames rx'd before 1st channel change */
-                       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
-                       SCAN_PRIVATE(ss)->ss_duration = duration;
-                       ss->ss_maxdwell = duration;
-                       ic->ic_flags |= IEEE80211_F_SCAN;
-                       ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
-                       ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
-               } else {
-                       /* XXX msg+stat */
-               }
-       } else {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: %s scan already in progress\n", __func__,
-                   ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
-       }
-       IEEE80211_UNLOCK(ic);
-
-       /* NB: racey, does it matter? */
-       return (ic->ic_flags & IEEE80211_F_SCAN);
+       /*
+        * XXX TODO: pull apart the bgscan logic into whatever
+        * belongs here and whatever belongs in the software
+        * scanner.
+        */
+       return (ic->ic_scan_methods->sc_bg_scan(scan, vap, flags));
 }
 
 /*
@@ -682,24 +436,8 @@ void
 ieee80211_cancel_scan(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_state *ss = ic->ic_scan;
 
-       IEEE80211_LOCK(ic);
-       if ((ic->ic_flags & IEEE80211_F_SCAN) &&
-           ss->ss_vap == vap &&
-           (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: cancel %s scan\n", __func__,
-                   ss->ss_flags & IEEE80211_SCAN_ACTIVE ?
-                       "active" : "passive");
-
-               /* clear bg scan NOPICK and mark cancel request */
-               ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
-               SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
-               /* wake up the scan task */
-               scan_signal(ss);
-       }
-       IEEE80211_UNLOCK(ic);
+       ic->ic_scan_methods->sc_cancel_scan(vap);
 }
 
 /*
@@ -709,23 +447,8 @@ void
 ieee80211_cancel_anyscan(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_state *ss = ic->ic_scan;
 
-       IEEE80211_LOCK(ic);
-       if ((ic->ic_flags & IEEE80211_F_SCAN) &&
-           (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: cancel %s scan\n", __func__,
-                   ss->ss_flags & IEEE80211_SCAN_ACTIVE ?
-                       "active" : "passive");
-
-               /* clear bg scan NOPICK and mark cancel request */
-               ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
-               SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
-               /* wake up the scan task */
-               scan_signal(ss);
-       }
-       IEEE80211_UNLOCK(ic);
+       ic->ic_scan_methods->sc_cancel_anyscan(vap);
 }
 
 /*
@@ -736,12 +459,8 @@ void
 ieee80211_scan_next(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_state *ss = ic->ic_scan;
 
-       /* wake up the scan task */
-       IEEE80211_LOCK(ic);
-       scan_signal(ss);
-       IEEE80211_UNLOCK(ic);
+       ic->ic_scan_methods->sc_scan_next(vap);
 }
 
 /*
@@ -754,10 +473,14 @@ ieee80211_scan_done(struct ieee80211vap *vap)
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss;
 
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__);
+
        IEEE80211_LOCK(ic);
        ss = ic->ic_scan;
        ss->ss_next = ss->ss_last; /* all channels are complete */
-       scan_signal(ss);
+
+       ic->ic_scan_methods->sc_scan_done(vap);
+
        IEEE80211_UNLOCK(ic);
 }
 
@@ -772,293 +495,13 @@ void
 ieee80211_probe_curchan(struct ieee80211vap *vap, int force)
 {
        struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_state *ss = ic->ic_scan;
-       struct ifnet *ifp = vap->iv_ifp;
-       int i;
 
        if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) && !force) {
                ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN;
                return;
        }
-       /*
-        * Send directed probe requests followed by any
-        * broadcast probe request.
-        * XXX remove dependence on ic/vap->iv_bss
-        */
-       for (i = 0; i < ss->ss_nssid; i++)
-               ieee80211_send_probereq(vap->iv_bss,
-                       vap->iv_myaddr, ifp->if_broadcastaddr,
-                       ifp->if_broadcastaddr,
-                       ss->ss_ssid[i].ssid, ss->ss_ssid[i].len);
-       if ((ss->ss_flags & IEEE80211_SCAN_NOBCAST) == 0)
-               ieee80211_send_probereq(vap->iv_bss,
-                       vap->iv_myaddr, ifp->if_broadcastaddr,
-                       ifp->if_broadcastaddr,
-                       "", 0);
-}
-
-/*
- * Scan curchan.  If this is an active scan and the channel
- * is not marked passive then send probe request frame(s).
- * Arrange for the channel change after maxdwell ticks.
- */
-static void
-scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
-{
-       struct ieee80211vap *vap  = ss->ss_vap;
-
-       IEEE80211_LOCK(vap->iv_ic);
-       if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
-               ieee80211_probe_curchan(vap, 0);
-       callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
-           maxdwell, scan_signal, ss);
-       IEEE80211_UNLOCK(vap->iv_ic);
-}
-
-static void
-scan_signal(void *arg)
-{
-       struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
-
-       IEEE80211_LOCK_ASSERT(ss->ss_ic);
 
-       cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv);
-}
-
-/*
- * Handle mindwell requirements completed; initiate a channel
- * change to the next channel asap.
- */
-static void
-scan_mindwell(struct ieee80211_scan_state *ss)
-{
-       struct ieee80211com *ic = ss->ss_ic;
-
-       IEEE80211_LOCK(ic);
-       scan_signal(ss);
-       IEEE80211_UNLOCK(ic);
-}
-
-static void
-scan_task(void *arg, int pending)
-{
-#define        ISCAN_REP       (ISCAN_MINDWELL | ISCAN_DISCARD)
-       struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
-       struct ieee80211vap *vap = ss->ss_vap;
-       struct ieee80211com *ic = ss->ss_ic;
-       struct ieee80211_channel *chan;
-       unsigned long maxdwell, scanend;
-       int scandone = 0;
-
-       IEEE80211_LOCK(ic);
-       if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
-           (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) {
-               /* Cancelled before we started */
-               goto done;
-       }
-
-       if (ss->ss_next == ss->ss_last) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                       "%s: no channels to scan\n", __func__);
-               scandone = 1;
-               goto done;
-       }
-
-       if (vap->iv_opmode == IEEE80211_M_STA &&
-           vap->iv_state == IEEE80211_S_RUN) {
-               if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
-                       /* Enable station power save mode */
-                       vap->iv_sta_ps(vap, 1);
-                       /*
-                        * Use an 1ms delay so the null data frame has a chance
-                        * to go out.
-                        * XXX Should use M_TXCB mechanism to eliminate this.
-                        */
-                       cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv,
-                           IEEE80211_LOCK_OBJ(ic), hz / 1000);
-                       if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)
-                               goto done;
-               }
-       }
-
-       scanend = ticks + SCAN_PRIVATE(ss)->ss_duration;
-       IEEE80211_UNLOCK(ic);
-       ic->ic_scan_start(ic);          /* notify driver */
-       IEEE80211_LOCK(ic);
-
-       for (;;) {
-               scandone = (ss->ss_next >= ss->ss_last) ||
-                   (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0;
-               if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) ||
-                   (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) ||
-                    time_after(ticks + ss->ss_mindwell, scanend))
-                       break;
-
-               chan = ss->ss_chans[ss->ss_next++];
-
-               /*
-                * Watch for truncation due to the scan end time.
-                */
-               if (time_after(ticks + ss->ss_maxdwell, scanend))
-                       maxdwell = scanend - ticks;
-               else
-                       maxdwell = ss->ss_maxdwell;
-
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n",
-                   __func__,
-                   ieee80211_chan2ieee(ic, ic->ic_curchan),
-                       channel_type(ic->ic_curchan),
-                   ieee80211_chan2ieee(ic, chan), channel_type(chan),
-                   (ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
-                       (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ?
-                       "active" : "passive",
-                   ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell));
-
-               /*
-                * Potentially change channel and phy mode.
-                */
-               ic->ic_curchan = chan;
-               ic->ic_rt = ieee80211_get_ratetable(chan);
-               IEEE80211_UNLOCK(ic);
-               /*
-                * Perform the channel change and scan unlocked so the driver
-                * may sleep. Once set_channel returns the hardware has
-                * completed the channel change.
-                */
-               ic->ic_set_channel(ic);
-               ieee80211_radiotap_chan_change(ic);
-
-               /*
-                * Scan curchan.  Drivers for "intelligent hardware"
-                * override ic_scan_curchan to tell the device to do
-                * the work.  Otherwise we manage the work outselves;
-                * sending a probe request (as needed), and arming the
-                * timeout to switch channels after maxdwell ticks.
-                *
-                * scan_curchan should only pause for the time required to
-                * prepare/initiate the hardware for the scan (if at all), the
-                * below condvar is used to sleep for the channels dwell time
-                * and allows it to be signalled for abort.
-                */
-               ic->ic_scan_curchan(ss, maxdwell);
-               IEEE80211_LOCK(ic);
-
-               SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell;
-               /* clear mindwell lock and initial channel change flush */
-               SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
-
-               if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT)))
-                       continue;
-
-               /* Wait to be signalled to scan the next channel */
-               cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv, IEEE80211_LOCK_OBJ(ic));
-       }
-       if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)
-               goto done;
-
-       IEEE80211_UNLOCK(ic);
-       ic->ic_scan_end(ic);            /* notify driver */
-       IEEE80211_LOCK(ic);
-
-       /*
-        * Since a cancellation may have occured during one of the
-        * driver calls (whilst unlocked), update scandone.
-        */
-       if (scandone == 0 &&
-           ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) {
-               /* XXX printf? */
-               if_printf(vap->iv_ifp,
-                   "%s: OOPS! scan cancelled during driver call!\n",
-                   __func__);
-       }
-       scandone |= ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0);
-
-       /*
-        * Record scan complete time.  Note that we also do
-        * this when canceled so any background scan will
-        * not be restarted for a while.
-        */
-       if (scandone)
-               ic->ic_lastscan = ticks;
-       /* return to the bss channel */
-       if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
-           ic->ic_curchan != ic->ic_bsschan) {
-               ieee80211_setupcurchan(ic, ic->ic_bsschan);
-               IEEE80211_UNLOCK(ic);
-               ic->ic_set_channel(ic);
-               ieee80211_radiotap_chan_change(ic);
-               IEEE80211_LOCK(ic);
-       }
-       /* clear internal flags and any indication of a pick */
-       SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
-       ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK;
-
-       /*
-        * If not canceled and scan completed, do post-processing.
-        * If the callback function returns 0, then it wants to
-        * continue/restart scanning.  Unfortunately we needed to
-        * notify the driver to end the scan above to avoid having
-        * rx frames alter the scan candidate list.
-        */
-       if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 &&
-           !ss->ss_ops->scan_end(ss, vap) &&
-           (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
-           time_before(ticks + ss->ss_mindwell, scanend)) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: done, restart "
-                   "[ticks %u, dwell min %lu scanend %lu]\n",
-                   __func__,
-                   ticks, ss->ss_mindwell, scanend);
-               ss->ss_next = 0;        /* reset to begining */
-               if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
-                       vap->iv_stats.is_scan_active++;
-               else
-                       vap->iv_stats.is_scan_passive++;
-
-               ss->ss_ops->scan_restart(ss, vap);      /* XXX? */
-               ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
-               IEEE80211_UNLOCK(ic);
-               return;
-       }
-
-       /* past here, scandone is ``true'' if not in bg mode */
-       if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
-               scandone = 1;
-
-       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-           "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n",
-           __func__, scandone ? "done" : "stopped",
-           ticks, ss->ss_mindwell, scanend);
-
-       /*
-        * Clear the SCAN bit first in case frames are
-        * pending on the station power save queue.  If
-        * we defer this then the dispatch of the frames
-        * may generate a request to cancel scanning.
-        */
-done:
-       ic->ic_flags &= ~IEEE80211_F_SCAN;
-       /*
-        * Drop out of power save mode when a scan has
-        * completed.  If this scan was prematurely terminated
-        * because it is a background scan then don't notify
-        * the ap; we'll either return to scanning after we
-        * receive the beacon frame or we'll drop out of power
-        * save mode because the beacon indicates we have frames
-        * waiting for us.
-        */
-       if (scandone) {
-               vap->iv_sta_ps(vap, 0);
-               if (ss->ss_next >= ss->ss_last) {
-                       ieee80211_notify_scan_done(vap);
-                       ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
-               }
-       }
-       SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT);
-       ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
-       IEEE80211_UNLOCK(ic);
-#undef ISCAN_REP
+       ic->ic_scan_methods->sc_scan_probe_curchan(vap, force);
 }
 
 #ifdef IEEE80211_DEBUG
@@ -1087,8 +530,8 @@ dump_country(const uint8_t *ie)
        kprintf("]");
 }
 
-static void
-dump_probe_beacon(uint8_t subtype, int isnew,
+void
+ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew,
        const uint8_t mac[IEEE80211_ADDR_LEN],
        const struct ieee80211_scanparams *sp, int rssi)
 {
@@ -1115,49 +558,15 @@ dump_probe_beacon(uint8_t subtype, int isnew,
  */
 void
 ieee80211_add_scan(struct ieee80211vap *vap,
+       struct ieee80211_channel *curchan,
        const struct ieee80211_scanparams *sp,
        const struct ieee80211_frame *wh,
        int subtype, int rssi, int noise)
 {
        struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_state *ss = ic->ic_scan;
 
-       /* XXX locking */
-       /*
-        * Frames received during startup are discarded to avoid
-        * using scan state setup on the initial entry to the timer
-        * callback.  This can occur because the device may enable
-        * rx prior to our doing the initial channel change in the
-        * timer routine.
-        */
-       if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_DISCARD)
-               return;
-#ifdef IEEE80211_DEBUG
-       if (ieee80211_msg_scan(vap) && (ic->ic_flags & IEEE80211_F_SCAN))
-               dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi);
-#endif
-       if (ss->ss_ops != NULL &&
-           ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise)) {
-               /*
-                * If we've reached the min dwell time terminate
-                * the timer so we'll switch to the next channel.
-                */
-               if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 &&
-                   time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) {
-                       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                           "%s: chan %3d%c min dwell met (%u > %lu)\n",
-                           __func__,
-                           ieee80211_chan2ieee(ic, ic->ic_curchan),
-                               channel_type(ic->ic_curchan),
-                           ticks, SCAN_PRIVATE(ss)->ss_chanmindwell);
-                       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL;
-                       /*
-                        * NB: trigger at next clock tick or wait for the
-                        * hardware.
-                        */
-                       ic->ic_scan_mindwell(ss);
-               }
-       }
+       return (ic->ic_scan_methods->sc_add_scan(vap, curchan, sp, wh, subtype,
+           rssi, noise));
 }
 
 /*
index 74eef50..10177ce 100644 (file)
@@ -228,6 +228,7 @@ sta_flush_table(struct sta_table *st)
  */
 static int
 sta_add(struct ieee80211_scan_state *ss, 
+       struct ieee80211_channel *curchan,
        const struct ieee80211_scanparams *sp,
        const struct ieee80211_frame *wh,
        int subtype, int rssi, int noise)
@@ -310,15 +311,15 @@ found:
                 * IEEE80211_BPARSE_OFFCHAN.
                 */
                c = ieee80211_find_channel_byieee(ic, sp->chan,
-                   ic->ic_curchan->ic_flags);
+                   curchan->ic_flags);
                if (c != NULL) {
                        ise->se_chan = c;
                } else if (ise->se_chan == NULL) {
                        /* should not happen, pick something */
-                       ise->se_chan = ic->ic_curchan;
+                       ise->se_chan = curchan;
                }
        } else
-               ise->se_chan = ic->ic_curchan;
+               ise->se_chan = curchan;
        if (IEEE80211_IS_CHAN_HT(ise->se_chan) && sp->htcap == NULL) {
                /* Demote legacy networks to a non-HT channel. */
                c = ieee80211_find_channel(ic, ise->se_chan->ic_freq,
@@ -600,10 +601,12 @@ makescanlist(struct ieee80211_scan_state *ss, struct ieee80211vap *vap,
                                 * so if the desired mode is 11g, then use
                                 * the 11b channel list but upgrade the mode.
                                 */
-                               if (vap->iv_des_mode != IEEE80211_MODE_11G ||
-                                   mode != IEEE80211_MODE_11B)
-                                       continue;
-                               mode = IEEE80211_MODE_11G;      /* upgrade */
+                               if (vap->iv_des_mode == IEEE80211_MODE_11G) {
+                                       if (mode == IEEE80211_MODE_11G) /* Skip the G check */
+                                               continue;
+                                       else if (mode == IEEE80211_MODE_11B)
+                                               mode = IEEE80211_MODE_11G;      /* upgrade */
+                               }
                        }
                } else {
                        /*
@@ -32,7 +32,7 @@ __FBSDID("$FreeBSD$");
 #include "opt_wlan.h"
 
 #include <sys/param.h>
-#include <sys/systm.h> 
+#include <sys/systm.h>
 #include <sys/proc.h>
 #include <sys/kernel.h>
 #include <sys/condvar.h>
@@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$");
 
 #include <netproto/802_11/ieee80211_var.h>
 
+#include <netproto/802_11/ieee80211_scan_sw.h>
+
 #include <net/bpf.h>
 
 struct scan_state {
@@ -100,29 +102,8 @@ static     void scan_task(void *, int);
 
 MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
 
-void
-ieee80211_scan_attach(struct ieee80211com *ic)
-{
-       struct scan_state *ss;
-
-       ss = (struct scan_state *) kmalloc(sizeof(struct scan_state),
-               M_80211_SCAN, M_INTWAIT | M_ZERO);
-       if (ss == NULL) {
-               ic->ic_scan = NULL;
-               return;
-       }
-       callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0);
-       cv_init(&ss->ss_scan_cv, "scan");
-       TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss);
-       ic->ic_scan = &ss->base;
-       ss->base.ss_ic = ic;
-
-       ic->ic_scan_curchan = scan_curchan;
-       ic->ic_scan_mindwell = scan_mindwell;
-}
-
-void
-ieee80211_scan_detach(struct ieee80211com *ic)
+static void
+ieee80211_swscan_detach(struct ieee80211com *ic)
 {
        struct ieee80211_scan_state *ss = ic->ic_scan;
 
@@ -135,6 +116,14 @@ ieee80211_scan_detach(struct ieee80211com *ic)
                callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer);
                KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0,
                    ("scan still running"));
+
+               /*
+                * For now, do the ss_ops detach here rather
+                * than ieee80211_scan_detach().
+                *
+                * I'll figure out how to cleanly split things up
+                * at a later date.
+                */
                if (ss->ss_ops != NULL) {
                        ss->ss_ops->scan_detach(ss);
                        ss->ss_ops = NULL;
@@ -144,242 +133,53 @@ ieee80211_scan_detach(struct ieee80211com *ic)
        }
 }
 
-static const struct ieee80211_roamparam defroam[IEEE80211_MODE_MAX] = {
-       [IEEE80211_MODE_11A]    = { .rssi = ROAM_RSSI_11A_DEFAULT,
-                                   .rate = ROAM_RATE_11A_DEFAULT },
-       [IEEE80211_MODE_11G]    = { .rssi = ROAM_RSSI_11B_DEFAULT,
-                                   .rate = ROAM_RATE_11B_DEFAULT },
-       [IEEE80211_MODE_11B]    = { .rssi = ROAM_RSSI_11BONLY_DEFAULT,
-                                   .rate = ROAM_RATE_11BONLY_DEFAULT },
-       [IEEE80211_MODE_TURBO_A]= { .rssi = ROAM_RSSI_11A_DEFAULT,
-                                   .rate = ROAM_RATE_11A_DEFAULT },
-       [IEEE80211_MODE_TURBO_G]= { .rssi = ROAM_RSSI_11A_DEFAULT,
-                                   .rate = ROAM_RATE_11A_DEFAULT },
-       [IEEE80211_MODE_STURBO_A]={ .rssi = ROAM_RSSI_11A_DEFAULT,
-                                   .rate = ROAM_RATE_11A_DEFAULT },
-       [IEEE80211_MODE_HALF]   = { .rssi = ROAM_RSSI_11A_DEFAULT,
-                                   .rate = ROAM_RATE_HALF_DEFAULT },
-       [IEEE80211_MODE_QUARTER]= { .rssi = ROAM_RSSI_11A_DEFAULT,
-                                   .rate = ROAM_RATE_QUARTER_DEFAULT },
-       [IEEE80211_MODE_11NA]   = { .rssi = ROAM_RSSI_11A_DEFAULT,
-                                   .rate = ROAM_MCS_11N_DEFAULT },
-       [IEEE80211_MODE_11NG]   = { .rssi = ROAM_RSSI_11B_DEFAULT,
-                                   .rate = ROAM_MCS_11N_DEFAULT },
-};
-
-void
-ieee80211_scan_vattach(struct ieee80211vap *vap)
+static void
+ieee80211_swscan_vattach(struct ieee80211vap *vap)
 {
-       vap->iv_bgscanidle = (IEEE80211_BGSCAN_IDLE_DEFAULT*1000)/hz;
-       vap->iv_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT*hz;
-       vap->iv_scanvalid = IEEE80211_SCAN_VALID_DEFAULT*hz;
+       /* nothing to do for now */
+       /*
+        * TODO: all of the vap scan calls should be methods!
+        */
 
-       vap->iv_roaming = IEEE80211_ROAMING_AUTO;
-       memcpy(vap->iv_roamparms, defroam, sizeof(defroam));
 }
 
-void
-ieee80211_scan_vdetach(struct ieee80211vap *vap)
+static void
+ieee80211_swscan_vdetach(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss;
 
-       IEEE80211_LOCK(ic);
+       IEEE80211_LOCK_ASSERT(ic);
        ss = ic->ic_scan;
        if (ss != NULL && ss->ss_vap == vap) {
                if (ic->ic_flags & IEEE80211_F_SCAN) {
                        SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT;
                        scan_signal(ss);
                }
-               if (ss->ss_ops != NULL) {
-                       ss->ss_ops->scan_detach(ss);
-                       ss->ss_ops = NULL;
-               }
-               ss->ss_vap = NULL;
        }
-       IEEE80211_UNLOCK(ic);
-}
-
-/*
- * Simple-minded scanner module support.
- */
-static const char *scan_modnames[IEEE80211_OPMODE_MAX] = {
-       "wlan_scan_sta",        /* IEEE80211_M_IBSS */
-       "wlan_scan_sta",        /* IEEE80211_M_STA */
-       "wlan_scan_wds",        /* IEEE80211_M_WDS */
-       "wlan_scan_sta",        /* IEEE80211_M_AHDEMO */
-       "wlan_scan_ap",         /* IEEE80211_M_HOSTAP */
-       "wlan_scan_monitor",    /* IEEE80211_M_MONITOR */
-       "wlan_scan_sta",        /* IEEE80211_M_MBSS */
-};
-static const struct ieee80211_scanner *scanners[IEEE80211_OPMODE_MAX];
-
-const struct ieee80211_scanner *
-ieee80211_scanner_get(enum ieee80211_opmode mode)
-{
-       if (mode >= IEEE80211_OPMODE_MAX)
-               return NULL;
-       if (scanners[mode] == NULL)
-               ieee80211_load_module(scan_modnames[mode]);
-       return scanners[mode];
 }
 
-void
-ieee80211_scanner_register(enum ieee80211_opmode mode,
-       const struct ieee80211_scanner *scan)
-{
-       if (mode >= IEEE80211_OPMODE_MAX)
-               return;
-       scanners[mode] = scan;
-}
-
-void
-ieee80211_scanner_unregister(enum ieee80211_opmode mode,
-       const struct ieee80211_scanner *scan)
-{
-       if (mode >= IEEE80211_OPMODE_MAX)
-               return;
-       if (scanners[mode] == scan)
-               scanners[mode] = NULL;
-}
-
-void
-ieee80211_scanner_unregister_all(const struct ieee80211_scanner *scan)
-{
-       int m;
-
-       for (m = 0; m < IEEE80211_OPMODE_MAX; m++)
-               if (scanners[m] == scan)
-                       scanners[m] = NULL;
-}
-
-/*
- * Update common scanner state to reflect the current
- * operating mode.  This is called when the state machine
- * is transitioned to RUN state w/o scanning--e.g. when
- * operating in monitor mode.  The purpose of this is to
- * ensure later callbacks find ss_ops set to properly
- * reflect current operating mode.
- */
 static void
-scan_update_locked(struct ieee80211vap *vap,
-       const struct ieee80211_scanner *scan)
+ieee80211_swscan_set_scan_duration(struct ieee80211vap *vap, u_int duration)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
 
        IEEE80211_LOCK_ASSERT(ic);
 
-#ifdef IEEE80211_DEBUG
-       if (ss->ss_vap != vap || ss->ss_ops != scan) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: current scanner is <%s:%s>, switch to <%s:%s>\n",
-                   __func__,
-                   ss->ss_vap != NULL ?
-                       ss->ss_vap->iv_ifp->if_xname : "none",
-                   ss->ss_vap != NULL ?
-                       ieee80211_opmode_name[ss->ss_vap->iv_opmode] : "none",
-                   vap->iv_ifp->if_xname,
-                   ieee80211_opmode_name[vap->iv_opmode]);
-       }
-#endif
-       ss->ss_vap = vap;
-       if (ss->ss_ops != scan) {
-               /*
-                * Switch scanners; detach old, attach new.  Special
-                * case where a single scan module implements multiple
-                * policies by using different scan ops but a common
-                * core.  We assume if the old and new attach methods
-                * are identical then it's ok to just change ss_ops
-                * and not flush the internal state of the module.
-                */
-               if (scan == NULL || ss->ss_ops == NULL ||
-                   ss->ss_ops->scan_attach != scan->scan_attach) {
-                       if (ss->ss_ops != NULL)
-                               ss->ss_ops->scan_detach(ss);
-                       if (scan != NULL && !scan->scan_attach(ss)) {
-                               /* XXX attach failure */
-                               /* XXX stat+msg */
-                               scan = NULL;
-                       }
-               }
-               ss->ss_ops = scan;
-       }
-}
-
-static char
-channel_type(const struct ieee80211_channel *c)
-{
-       if (IEEE80211_IS_CHAN_ST(c))
-               return 'S';
-       if (IEEE80211_IS_CHAN_108A(c))
-               return 'T';
-       if (IEEE80211_IS_CHAN_108G(c))
-               return 'G';
-       if (IEEE80211_IS_CHAN_HT(c))
-               return 'n';
-       if (IEEE80211_IS_CHAN_A(c))
-               return 'a';
-       if (IEEE80211_IS_CHAN_ANYG(c))
-               return 'g';
-       if (IEEE80211_IS_CHAN_B(c))
-               return 'b';
-       return 'f';
-}
-
-void
-ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss)
-{
-       struct ieee80211com *ic = ss->ss_ic;
-       const char *sep;
-       int i;
-
-       sep = "";
-       for (i = ss->ss_next; i < ss->ss_last; i++) {
-               const struct ieee80211_channel *c = ss->ss_chans[i];
-
-               kprintf("%s%u%c", sep, ieee80211_chan2ieee(ic, c),
-                       channel_type(c));
-               sep = ", ";
-       }
-}
-
-#ifdef IEEE80211_DEBUG
-static void
-scan_dump(struct ieee80211_scan_state *ss)
-{
-       struct ieee80211vap *vap = ss->ss_vap;
-
-       if_printf(vap->iv_ifp, "scan set ");
-       ieee80211_scan_dump_channels(ss);
-       kprintf(" dwell min %lums max %lums\n",
-           ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(ss->ss_maxdwell));
-}
-#endif /* IEEE80211_DEBUG */
-
-static void
-copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss,
-       int nssid, const struct ieee80211_scan_ssid ssids[])
-{
-       if (nssid > IEEE80211_SCAN_MAX_SSID) {
-               /* XXX printf */
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: too many ssid %d, ignoring all of them\n",
-                   __func__, nssid);
-               return;
-       }
-       memcpy(ss->ss_ssid, ssids, nssid * sizeof(ssids[0]));
-       ss->ss_nssid = nssid;
+       /* NB: flush frames rx'd before 1st channel change */
+       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
+       SCAN_PRIVATE(ss)->ss_duration = duration;
 }
 
 /*
  * Start a scan unless one is already going.
  */
 static int
-start_scan_locked(const struct ieee80211_scanner *scan,
-       struct ieee80211vap *vap, int flags, u_int duration,
-       u_int mindwell, u_int maxdwell,
-       u_int nssid, const struct ieee80211_scan_ssid ssids[])
+ieee80211_swscan_start_scan_locked(const struct ieee80211_scanner *scan,
+    struct ieee80211vap *vap, int flags, u_int duration,
+    u_int mindwell, u_int maxdwell,
+    u_int nssid, const struct ieee80211_scan_ssid ssids[])
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
@@ -404,10 +204,10 @@ start_scan_locked(const struct ieee80211_scanner *scan,
                    , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
                );
 
-               scan_update_locked(vap, scan);
+               ieee80211_scan_update_locked(vap, scan);
                if (ss->ss_ops != NULL) {
                        if ((flags & IEEE80211_SCAN_NOSSID) == 0)
-                               copy_ssid(vap, ss, nssid, ssids);
+                               ieee80211_scan_copy_ssid(vap, ss, nssid, ssids);
 
                        /* NB: top 4 bits for internal use */
                        ss->ss_flags = flags & 0xfff;
@@ -420,9 +220,9 @@ start_scan_locked(const struct ieee80211_scanner *scan,
                        if (flags & IEEE80211_SCAN_BGSCAN)
                                ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
 
-                       /* NB: flush frames rx'd before 1st channel change */
-                       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
-                       SCAN_PRIVATE(ss)->ss_duration = duration;
+                       /* Set duration for this particular scan */
+                       ieee80211_swscan_set_scan_duration(vap, duration);
+
                        ss->ss_next = 0;
                        ss->ss_mindwell = mindwell;
                        ss->ss_maxdwell = maxdwell;
@@ -430,9 +230,11 @@ start_scan_locked(const struct ieee80211_scanner *scan,
                        ss->ss_ops->scan_start(ss, vap);
 #ifdef IEEE80211_DEBUG
                        if (ieee80211_msg_scan(vap))
-                               scan_dump(ss);
+                               ieee80211_scan_dump(ss);
 #endif /* IEEE80211_DEBUG */
                        ic->ic_flags |= IEEE80211_F_SCAN;
+
+                       /* Start scan task */
                        ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
                }
                return 1;
@@ -446,27 +248,23 @@ start_scan_locked(const struct ieee80211_scanner *scan,
 
 /*
  * Start a scan unless one is already going.
+ *
+ * Called without the comlock held; grab the comlock as appropriate.
  */
-int
-ieee80211_start_scan(struct ieee80211vap *vap, int flags,
-       u_int duration, u_int mindwell, u_int maxdwell,
-       u_int nssid, const struct ieee80211_scan_ssid ssids[])
+static int
+ieee80211_swscan_start_scan(const struct ieee80211_scanner *scan,
+    struct ieee80211vap *vap, int flags,
+    u_int duration, u_int mindwell, u_int maxdwell,
+    u_int nssid, const struct ieee80211_scan_ssid ssids[])
 {
        struct ieee80211com *ic = vap->iv_ic;
-       const struct ieee80211_scanner *scan;
        int result;
 
-       scan = ieee80211_scanner_get(vap->iv_opmode);
-       if (scan == NULL) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: no scanner support for %s mode\n",
-                   __func__, ieee80211_opmode_name[vap->iv_opmode]);
-               /* XXX stat */
-               return 0;
-       }
+       /* XXX Missing on DragonFly */
+       // IEEE80211_UNLOCK_ASSERT(ic);
 
        IEEE80211_LOCK(ic);
-       result = start_scan_locked(scan, vap, flags, duration,
+       result = ieee80211_swscan_start_scan_locked(scan, vap, flags, duration,
            mindwell, maxdwell, nssid, ssids);
        IEEE80211_UNLOCK(ic);
 
@@ -476,48 +274,23 @@ ieee80211_start_scan(struct ieee80211vap *vap, int flags,
 /*
  * Check the scan cache for an ap/channel to use; if that
  * fails then kick off a new scan.
+ *
+ * Called with the comlock held.
+ *
+ * XXX TODO: split out!
  */
-int
-ieee80211_check_scan(struct ieee80211vap *vap, int flags,
-       u_int duration, u_int mindwell, u_int maxdwell,
-       u_int nssid, const struct ieee80211_scan_ssid ssids[])
+static int
+ieee80211_swscan_check_scan(const struct ieee80211_scanner *scan,
+    struct ieee80211vap *vap, int flags,
+    u_int duration, u_int mindwell, u_int maxdwell,
+    u_int nssid, const struct ieee80211_scan_ssid ssids[])
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
-       const struct ieee80211_scanner *scan;
        int result;
 
-       scan = ieee80211_scanner_get(vap->iv_opmode);
-       if (scan == NULL) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: no scanner support for %d mode\n",
-                   __func__, vap->iv_opmode);
-               /* XXX stat */
-               return 0;
-       }
-
-       /*
-        * Check if there's a list of scan candidates already.
-        * XXX want more than the ap we're currently associated with
-        */
+       IEEE80211_LOCK_ASSERT(ic);
 
-       IEEE80211_LOCK(ic);
-       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-           "%s: %s scan, %s%s%s%s%s\n"
-           , __func__
-           , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
-           , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
-           , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
-           , flags & IEEE80211_SCAN_NOJOIN ? ", nojoin" : ""
-           , flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
-           , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
-       );
-
-       if (ss->ss_ops != scan) {
-               /* XXX re-use cache contents? e.g. adhoc<->sta */
-               flags |= IEEE80211_SCAN_FLUSH;
-       }
-       scan_update_locked(vap, scan);
        if (ss->ss_ops != NULL) {
                /* XXX verify ss_ops matches vap->iv_opmode */
                if ((flags & IEEE80211_SCAN_NOSSID) == 0) {
@@ -525,7 +298,7 @@ ieee80211_check_scan(struct ieee80211vap *vap, int flags,
                         * Update the ssid list and mark flags so if
                         * we call start_scan it doesn't duplicate work.
                         */
-                       copy_ssid(vap, ss, nssid, ssids);
+                       ieee80211_scan_copy_ssid(vap, ss, nssid, ssids);
                        flags |= IEEE80211_SCAN_NOSSID;
                }
                if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
@@ -550,50 +323,29 @@ ieee80211_check_scan(struct ieee80211vap *vap, int flags,
                        SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD;
                        if (result) {
                                ieee80211_notify_scan_done(vap);
-                               IEEE80211_UNLOCK(ic);
                                return 1;
                        }
                }
        }
-       result = start_scan_locked(scan, vap, flags, duration,
+       result = ieee80211_swscan_start_scan_locked(scan, vap, flags, duration,
            mindwell, maxdwell, nssid, ssids);
-       IEEE80211_UNLOCK(ic);
 
        return result;
 }
 
-/*
- * Check the scan cache for an ap/channel to use; if that fails
- * then kick off a scan using the current settings.
- */
-int
-ieee80211_check_scan_current(struct ieee80211vap *vap)
-{
-       return ieee80211_check_scan(vap,
-           IEEE80211_SCAN_ACTIVE,
-           IEEE80211_SCAN_FOREVER, 0, 0,
-           vap->iv_des_nssid, vap->iv_des_ssid);
-}
-
 /*
  * Restart a previous scan.  If the previous scan completed
  * then we start again using the existing channel list.
  */
-int
-ieee80211_bg_scan(struct ieee80211vap *vap, int flags)
+static int
+ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan,
+    struct ieee80211vap *vap, int flags)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
-       const struct ieee80211_scanner *scan;
 
-       scan = ieee80211_scanner_get(vap->iv_opmode);
-       if (scan == NULL) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-                   "%s: no scanner support for %d mode\n",
-                   __func__, vap->iv_opmode);
-               /* XXX stat */
-               return 0;
-       }
+       /* XXX assert unlocked? */
+       // IEEE80211_UNLOCK_ASSERT(ic);
 
        IEEE80211_LOCK(ic);
        if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
@@ -611,7 +363,7 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags)
                    ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",
                    ticks, duration);
 
-               scan_update_locked(vap, scan);
+               ieee80211_scan_update_locked(vap, scan);
                if (ss->ss_ops != NULL) {
                        ss->ss_vap = vap;
                        /*
@@ -650,13 +402,11 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags)
                                        ss->ss_ops->scan_start(ss, vap);
 #ifdef IEEE80211_DEBUG
                                        if (ieee80211_msg_scan(vap))
-                                               scan_dump(ss);
+                                               ieee80211_scan_dump(ss);
 #endif /* IEEE80211_DEBUG */
                                }
                        }
-                       /* NB: flush frames rx'd before 1st channel change */
-                       SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
-                       SCAN_PRIVATE(ss)->ss_duration = duration;
+                       ieee80211_swscan_set_scan_duration(vap, duration);
                        ss->ss_maxdwell = duration;
                        ic->ic_flags |= IEEE80211_F_SCAN;
                        ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
@@ -678,8 +428,8 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags)
 /*
  * Cancel any scan currently going on for the specified vap.
  */
-void
-ieee80211_cancel_scan(struct ieee80211vap *vap)
+static void
+ieee80211_swscan_cancel_scan(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
@@ -698,6 +448,13 @@ ieee80211_cancel_scan(struct ieee80211vap *vap)
                SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
                /* wake up the scan task */
                scan_signal(ss);
+       } else {
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+                   "%s: called; F_SCAN=%d, vap=%s, CANCEL=%d\n",
+                       __func__,
+                       !! (ic->ic_flags & IEEE80211_F_SCAN),
+                       (ss->ss_vap == vap ? "match" : "nomatch"),
+                       !! (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL));
        }
        IEEE80211_UNLOCK(ic);
 }
@@ -705,8 +462,8 @@ ieee80211_cancel_scan(struct ieee80211vap *vap)
 /*
  * Cancel any scan currently going on.
  */
-void
-ieee80211_cancel_anyscan(struct ieee80211vap *vap)
+static void
+ieee80211_swscan_cancel_anyscan(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
@@ -724,6 +481,13 @@ ieee80211_cancel_anyscan(struct ieee80211vap *vap)
                SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
                /* wake up the scan task */
                scan_signal(ss);
+       } else {
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+                   "%s: called; F_SCAN=%d, vap=%s, CANCEL=%d\n",
+                       __func__,
+                       !! (ic->ic_flags & IEEE80211_F_SCAN),
+                       (ss->ss_vap == vap ? "match" : "nomatch"),
+                       !! (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL));
        }
        IEEE80211_UNLOCK(ic);
 }
@@ -732,12 +496,14 @@ ieee80211_cancel_anyscan(struct ieee80211vap *vap)
  * Public access to scan_next for drivers that manage
  * scanning themselves (e.g. for firmware-based devices).
  */
-void
-ieee80211_scan_next(struct ieee80211vap *vap)
+static void
+ieee80211_swscan_scan_next(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
 
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__);
+
        /* wake up the scan task */
        IEEE80211_LOCK(ic);
        scan_signal(ss);
@@ -748,17 +514,16 @@ ieee80211_scan_next(struct ieee80211vap *vap)
  * Public access to scan_next for drivers that are not able to scan single
  * channels (e.g. for firmware-based devices).
  */
-void
-ieee80211_scan_done(struct ieee80211vap *vap)
+static void
+ieee80211_swscan_scan_done(struct ieee80211vap *vap)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss;
 
-       IEEE80211_LOCK(ic);
+       IEEE80211_LOCK_ASSERT(ic);
+
        ss = ic->ic_scan;
-       ss->ss_next = ss->ss_last; /* all channels are complete */
        scan_signal(ss);
-       IEEE80211_UNLOCK(ic);
 }
 
 /*
@@ -768,18 +533,14 @@ ieee80211_scan_done(struct ieee80211vap *vap)
  * listen for beacons on the channel; if we receive something
  * then we'll transmit a probe request.
  */
-void
-ieee80211_probe_curchan(struct ieee80211vap *vap, int force)
+static void
+ieee80211_swscan_probe_curchan(struct ieee80211vap *vap, int force)
 {
        struct ieee80211com *ic = vap->iv_ic;
        struct ieee80211_scan_state *ss = ic->ic_scan;
        struct ifnet *ifp = vap->iv_ifp;
        int i;
 
-       if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) && !force) {
-               ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN;
-               return;
-       }
        /*
         * Send directed probe requests followed by any
         * broadcast probe request.
@@ -807,6 +568,10 @@ scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
 {
        struct ieee80211vap *vap  = ss->ss_vap;
 
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+           "%s: calling; maxdwell=%lu\n",
+           __func__,
+           maxdwell);
        IEEE80211_LOCK(vap->iv_ic);
        if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
                ieee80211_probe_curchan(vap, 0);
@@ -821,7 +586,6 @@ scan_signal(void *arg)
        struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
 
        IEEE80211_LOCK_ASSERT(ss->ss_ic);
-
        cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv);
 }
 
@@ -834,6 +598,9 @@ scan_mindwell(struct ieee80211_scan_state *ss)
 {
        struct ieee80211com *ic = ss->ss_ic;
 
+       IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN, "%s: called\n",
+           __func__);
+
        IEEE80211_LOCK(ic);
        scan_signal(ss);
        IEEE80211_UNLOCK(ic);
@@ -882,13 +649,23 @@ scan_task(void *arg, int pending)
        }
 
        scanend = ticks + SCAN_PRIVATE(ss)->ss_duration;
+
+       /* XXX scan state can change! Re-validate scan state! */
+
        IEEE80211_UNLOCK(ic);
        ic->ic_scan_start(ic);          /* notify driver */
        IEEE80211_LOCK(ic);
 
        for (;;) {
+
                scandone = (ss->ss_next >= ss->ss_last) ||
                    (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0;
+
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+                   "%s: loop start; scandone=%d\n",
+                   __func__,
+                   scandone);
+
                if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) ||
                    (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) ||
                     time_after(ticks + ss->ss_mindwell, scanend))
@@ -908,8 +685,9 @@ scan_task(void *arg, int pending)
                    "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n",
                    __func__,
                    ieee80211_chan2ieee(ic, ic->ic_curchan),
-                       channel_type(ic->ic_curchan),
-                   ieee80211_chan2ieee(ic, chan), channel_type(chan),
+                   ieee80211_channel_type_char(ic->ic_curchan),
+                   ieee80211_chan2ieee(ic, chan),
+                   ieee80211_channel_type_char(chan),
                    (ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
                        (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ?
                        "active" : "passive",
@@ -944,6 +722,8 @@ scan_task(void *arg, int pending)
                ic->ic_scan_curchan(ss, maxdwell);
                IEEE80211_LOCK(ic);
 
+               /* XXX scan state can change! Re-validate scan state! */
+
                SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell;
                /* clear mindwell lock and initial channel change flush */
                SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
@@ -951,15 +731,20 @@ scan_task(void *arg, int pending)
                if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT)))
                        continue;
 
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: waiting\n", __func__);
                /* Wait to be signalled to scan the next channel */
                cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv, IEEE80211_LOCK_OBJ(ic));
        }
+
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: out\n", __func__);
+
        if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)
                goto done;
 
        IEEE80211_UNLOCK(ic);
        ic->ic_scan_end(ic);            /* notify driver */
        IEEE80211_LOCK(ic);
+       /* XXX scan state can change! Re-validate scan state! */
 
        /*
         * Since a cancellation may have occured during one of the
@@ -969,10 +754,10 @@ scan_task(void *arg, int pending)
            ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) {
                /* XXX printf? */
                if_printf(vap->iv_ifp,
-                   "%s: OOPS! scan cancelled during driver call!\n",
+                   "%s: OOPS! scan cancelled during driver call (1)!\n",
                    __func__);
+               scandone = 1;
        }
-       scandone |= ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0);
 
        /*
         * Record scan complete time.  Note that we also do
@@ -1031,6 +816,19 @@ scan_task(void *arg, int pending)
            __func__, scandone ? "done" : "stopped",
            ticks, ss->ss_mindwell, scanend);
 
+       /*
+        * Since a cancellation may have occured during one of the
+        * driver calls (whilst unlocked), update scandone.
+        */
+       if (scandone == 0 &&
+           ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) {
+               /* XXX printf? */
+               if_printf(vap->iv_ifp,
+                   "%s: OOPS! scan cancelled during driver call (2)!\n",
+                   __func__);
+               scandone = 1;
+       }
+
        /*
         * Clear the SCAN bit first in case frames are
         * pending on the station power save queue.  If
@@ -1061,60 +859,12 @@ done:
 #undef ISCAN_REP
 }
 
-#ifdef IEEE80211_DEBUG
-static void
-dump_country(const uint8_t *ie)
-{
-       const struct ieee80211_country_ie *cie =
-          (const struct ieee80211_country_ie *) ie;
-       int i, nbands, schan, nchan;
-
-       if (cie->len < 3) {
-               kprintf(" <bogus country ie, len %d>", cie->len);
-               return;
-       }
-       kprintf(" country [%c%c%c", cie->cc[0], cie->cc[1], cie->cc[2]);
-       nbands = (cie->len - 3) / sizeof(cie->band[0]);
-       for (i = 0; i < nbands; i++) {
-               schan = cie->band[i].schan;
-               nchan = cie->band[i].nchan;
-               if (nchan != 1)
-                       kprintf(" %u-%u,%u", schan, schan + nchan-1,
-                           cie->band[i].maxtxpwr);
-               else
-                       kprintf(" %u,%u", schan, cie->band[i].maxtxpwr);
-       }
-       kprintf("]");
-}
-
-static void
-dump_probe_beacon(uint8_t subtype, int isnew,
-       const uint8_t mac[IEEE80211_ADDR_LEN],
-       const struct ieee80211_scanparams *sp, int rssi)
-{
-
-       kprintf("[%s] %s%s on chan %u (bss chan %u) ",
-           ether_sprintf(mac), isnew ? "new " : "",
-           ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
-           sp->chan, sp->bchan);
-       ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]);
-       kprintf(" rssi %d\n", rssi);
-
-       if (isnew) {
-               kprintf("[%s] caps 0x%x bintval %u erp 0x%x",
-                       ether_sprintf(mac), sp->capinfo, sp->bintval, sp->erp);
-               if (sp->country != NULL)
-                       dump_country(sp->country);
-               kprintf("\n");
-       }
-}
-#endif /* IEEE80211_DEBUG */
-
 /*
  * Process a beacon or probe response frame.
  */
-void
-ieee80211_add_scan(struct ieee80211vap *vap,
+static void
+ieee80211_swscan_add_scan(struct ieee80211vap *vap,
+       struct ieee80211_channel *curchan,
        const struct ieee80211_scanparams *sp,
        const struct ieee80211_frame *wh,
        int subtype, int rssi, int noise)
@@ -1134,10 +884,10 @@ ieee80211_add_scan(struct ieee80211vap *vap,
                return;
 #ifdef IEEE80211_DEBUG
        if (ieee80211_msg_scan(vap) && (ic->ic_flags & IEEE80211_F_SCAN))
-               dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi);
+               ieee80211_scan_dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi);
 #endif
        if (ss->ss_ops != NULL &&
-           ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise)) {
+           ss->ss_ops->scan_add(ss, curchan, sp, wh, subtype, rssi, noise)) {
                /*
                 * If we've reached the min dwell time terminate
                 * the timer so we'll switch to the next channel.
@@ -1148,7 +898,7 @@ ieee80211_add_scan(struct ieee80211vap *vap,
                            "%s: chan %3d%c min dwell met (%u > %lu)\n",
                            __func__,
                            ieee80211_chan2ieee(ic, ic->ic_curchan),
-                               channel_type(ic->ic_curchan),
+                           ieee80211_channel_type_char(ic->ic_curchan),
                            ticks, SCAN_PRIVATE(ss)->ss_chanmindwell);
                        SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL;
                        /*
@@ -1160,97 +910,50 @@ ieee80211_add_scan(struct ieee80211vap *vap,
        }
 }
 
-/*
- * Timeout/age scan cache entries; called from sta timeout
- * timer (XXX should be self-contained).
- */
-void
-ieee80211_scan_timeout(struct ieee80211com *ic)
-{
-       struct ieee80211_scan_state *ss = ic->ic_scan;
-
-       if (ss->ss_ops != NULL)
-               ss->ss_ops->scan_age(ss);
-}
-
-/*
- * Mark a scan cache entry after a successful associate.
- */
-void
-ieee80211_scan_assoc_success(struct ieee80211vap *vap, const uint8_t mac[])
-{
-       struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan;
-
-       if (ss->ss_ops != NULL) {
-               IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_SCAN,
-                       mac, "%s",  __func__);
-               ss->ss_ops->scan_assoc_success(ss, mac);
-       }
-}
-
-/*
- * Demerit a scan cache entry after failing to associate.
- */
-void
-ieee80211_scan_assoc_fail(struct ieee80211vap *vap,
-       const uint8_t mac[], int reason)
-{
-       struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan;
-
-       if (ss->ss_ops != NULL) {
-               IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_SCAN, mac,
-                       "%s: reason %u", __func__, reason);
-               ss->ss_ops->scan_assoc_fail(ss, mac, reason);
-       }
-}
+static struct ieee80211_scan_methods swscan_methods = {
+       .sc_attach = ieee80211_swscan_attach,
+       .sc_detach = ieee80211_swscan_detach,
+       .sc_vattach = ieee80211_swscan_vattach,
+       .sc_vdetach = ieee80211_swscan_vdetach,
+       .sc_set_scan_duration = ieee80211_swscan_set_scan_duration,
+       .sc_start_scan = ieee80211_swscan_start_scan,
+       .sc_check_scan = ieee80211_swscan_check_scan,
+       .sc_bg_scan = ieee80211_swscan_bg_scan,
+       .sc_cancel_scan = ieee80211_swscan_cancel_scan,
+       .sc_cancel_anyscan = ieee80211_swscan_cancel_anyscan,
+       .sc_scan_next = ieee80211_swscan_scan_next,
+       .sc_scan_done = ieee80211_swscan_scan_done,
+       .sc_scan_probe_curchan = ieee80211_swscan_probe_curchan,
+       .sc_add_scan = ieee80211_swscan_add_scan
+};
 
 /*
- * Iterate over the contents of the scan cache.
+ * Default scan attach method.
  */
 void
-ieee80211_scan_iterate(struct ieee80211vap *vap,
-       ieee80211_scan_iter_func *f, void *arg)
+ieee80211_swscan_attach(struct ieee80211com *ic)
 {
-       struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan;
-
-       if (ss->ss_ops != NULL)
-               ss->ss_ops->scan_iterate(ss, f, arg);
-}
+       struct scan_state *ss;
 
-/*
- * Flush the contents of the scan cache.
- */
-void
-ieee80211_scan_flush(struct ieee80211vap *vap)
-{
-       struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan;
+       /*
+        * Setup the default methods
+        */
+       ic->ic_scan_methods = &swscan_methods;
 
-       if (ss->ss_ops != NULL && ss->ss_vap == vap) {
-               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n",  __func__);
-               ss->ss_ops->scan_flush(ss);
+       /* Allocate initial scan state */
+       ss = (struct scan_state *) kmalloc(sizeof(struct scan_state),
+               M_80211_SCAN, M_INTWAIT | M_ZERO);
+       if (ss == NULL) {
+               ic->ic_scan = NULL;
+               return;
        }
-}
-
-/*
- * Check the scan cache for an ap/channel to use; if that
- * fails then kick off a new scan.
- */
-struct ieee80211_channel *
-ieee80211_scan_pickchannel(struct ieee80211com *ic, int flags)
-{
-       struct ieee80211_scan_state *ss = ic->ic_scan;
+       callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0);
+       cv_init(&ss->ss_scan_cv, "scan");
+       TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss);
 
-       IEEE80211_LOCK_ASSERT(ic);
+       ic->ic_scan = &ss->base;
+       ss->base.ss_ic = ic;
 
-       if (ss == NULL || ss->ss_ops == NULL || ss->ss_vap == NULL) {
-               /* XXX printf? */
-               return NULL;
-       }
-       if (ss->ss_ops->scan_pickchan == NULL) {
-               IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN,
-                   "%s: scan module does not support picking a channel, "
-                   "opmode %d\n", __func__, ss->ss_vap->iv_opmode);
-               return NULL;
-       }
-       return ss->ss_ops->scan_pickchan(ss, flags);
+       ic->ic_scan_curchan = scan_curchan;
+       ic->ic_scan_mindwell = scan_mindwell;
 }
index 81dbd75..83c700c 100644 (file)
@@ -70,9 +70,10 @@ __FBSDID("$FreeBSD$");
 static void sta_vattach(struct ieee80211vap *);
 static void sta_beacon_miss(struct ieee80211vap *);
 static int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static int sta_input(struct ieee80211_node *, struct mbuf *, int, int);
+static int sta_input(struct ieee80211_node *, struct mbuf *,
+           const struct ieee80211_rx_stats *, int, int);
 static void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *,
-           int subtype, int rssi, int nf);
+           int subtype, const struct ieee80211_rx_stats *, int rssi, int nf);
 static void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
 
 void
@@ -525,9 +526,9 @@ doprint(struct ieee80211vap *vap, int subtype)
  * by the 802.11 layer.
  */
 static int
-sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
+sta_input(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
-#define        HAS_SEQ(type)   ((type & 0x4) == 0)
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
        struct ifnet *ifp = vap->iv_ifp;
@@ -624,7 +625,8 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 
                IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
                ni->ni_noise = nf;
-               if (HAS_SEQ(type) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+               if ( IEEE80211_HAS_SEQ(type, subtype) &&
+                   !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
                        uint8_t tid = ieee80211_gettid(wh);
                        if (IEEE80211_QOS_HAS_SEQ(wh) &&
                            TID_TO_WME_AC(tid) >= WME_AC_VI)
@@ -923,7 +925,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
                        wh = mtod(m, struct ieee80211_frame *);
                        wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
                }
-               vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+               vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
                goto out;
 
        case IEEE80211_FC0_TYPE_CTL:
@@ -1286,13 +1288,15 @@ startbgscan(struct ieee80211vap *vap)
 }
 
 static void
-sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
-       int subtype, int rssi, int nf)
+sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
+    const struct ieee80211_rx_stats *rxs,
+    int rssi, int nf)
 {
 #define        ISPROBE(_st)    ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
 #define        ISREASSOC(_st)  ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
+       struct ieee80211_channel *rxchan = ic->ic_curchan;
        struct ieee80211_frame *wh;
        uint8_t *frm, *efrm;
        uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
@@ -1306,6 +1310,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
        case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
        case IEEE80211_FC0_SUBTYPE_BEACON: {
                struct ieee80211_scanparams scan;
+               struct ieee80211_channel *c;
                /*
                 * We process beacon/probe response frames:
                 *    o when scanning, or
@@ -1317,8 +1322,14 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                        vap->iv_stats.is_rx_mgtdiscard++;
                        return;
                }
+               /* Override RX channel as appropriate */
+               if (rxs != NULL) {
+                       c = ieee80211_lookup_channel_rxstatus(vap, rxs);
+                       if (c != NULL)
+                               rxchan = c;
+               }
                /* XXX probe response in sta mode when !scanning? */
-               if (ieee80211_parse_beacon(ni, m0, &scan) != 0) {
+               if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0) {
                        if (! (ic->ic_flags & IEEE80211_F_SCAN))
                                vap->iv_stats.is_beacon_bad++;
                        return;
@@ -1406,6 +1417,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                                int ix = aid / NBBY;
                                int min = tim->tim_bitctl &~ 1;
                                int max = tim->tim_len + min - 4;
+                               int tim_ucast = 0, tim_mcast = 0;
 
                                /*
                                 * Only do this for unicast traffic in the TIM
@@ -1415,20 +1427,42 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                                 */
                                if (min <= ix && ix <= max &&
                                     isset(tim->tim_bitmap - min, aid)) {
-                                       ieee80211_sta_tim_notify(vap, 1);
-                                       ic->ic_lastdata = ticks;
+                                       tim_ucast = 1;
                                }
 
                                /*
-                                * XXX TODO: do a separate notification
+                                * Do a separate notification
                                 * for the multicast bit being set.
                                 */
-#if 0
                                if (tim->tim_bitctl & 1) {
+                                       tim_mcast = 1;
+                               }
+
+                               /*
+                                * If the TIM indicates there's traffic for
+                                * us then get us out of STA mode powersave.
+                                */
+                               if (tim_ucast == 1) {
+
+                                       /*
+                                        * Wake us out of SLEEP state if we're
+                                        * in it; and if we're doing bgscan
+                                        * then wake us out of STA powersave.
+                                        */
                                        ieee80211_sta_tim_notify(vap, 1);
+
+                                       /*
+                                        * This is preventing us from
+                                        * continuing a bgscan; because it
+                                        * tricks the contbgscan()
+                                        * routine to think there's always
+                                        * traffic for us.
+                                        *
+                                        * I think we need both an RX and
+                                        * TX ic_lastdata field.
+                                        */
                                        ic->ic_lastdata = ticks;
                                }
-#endif
 
                                ni->ni_dtim_count = tim->tim_count;
                                ni->ni_dtim_period = tim->tim_period;
@@ -1462,8 +1496,8 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                         * our ap.
                         */
                        if (ic->ic_flags & IEEE80211_F_SCAN) {
-                               ieee80211_add_scan(vap, &scan, wh,
-                                       subtype, rssi, nf);
+                               ieee80211_add_scan(vap, rxchan,
+                                   &scan, wh, subtype, rssi, nf);
                        } else if (contbgscan(vap)) {
                                ieee80211_bg_scan(vap, 0);
                        } else if (startbgscan(vap)) {
@@ -1507,7 +1541,8 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                                ieee80211_probe_curchan(vap, 1);
                                ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
                        }
-                       ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf);
+                       ieee80211_add_scan(vap, rxchan, &scan, wh,
+                           subtype, rssi, nf);
                        return;
                }
                break;
index 918f7bf..0b64279 100644 (file)
@@ -115,7 +115,7 @@ static void tdma_vdetach(struct ieee80211vap *vap);
 static int tdma_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void tdma_beacon_miss(struct ieee80211vap *vap);
 static void tdma_recv_mgmt(struct ieee80211_node *, struct mbuf *,
-       int subtype, int rssi, int nf);
+       int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf);
 static int tdma_update(struct ieee80211vap *vap,
        const struct ieee80211_tdma_param *tdma, struct ieee80211_node *ni,
        int pickslot);
@@ -320,7 +320,7 @@ tdma_beacon_miss(struct ieee80211vap *vap)
 
 static void
 tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
-       int subtype, int rssi, int nf)
+       int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211com *ic = ni->ni_ic;
        struct ieee80211vap *vap = ni->ni_vap;
@@ -331,7 +331,8 @@ tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
                struct ieee80211_scanparams scan;
 
-               if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
+               /* XXX TODO: use rxstatus to determine off-channel beacons */
+               if (ieee80211_parse_beacon(ni, m0, ic->ic_curchan, &scan) != 0)
                        return;
                if (scan.tdma == NULL) {
                        /*
@@ -391,7 +392,7 @@ tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
                 *     2x parsing of the frame but should happen infrequently
                 */
        }
-       ts->tdma_recv_mgmt(ni, m0, subtype, rssi, nf);
+       ts->tdma_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);
 }
 
 /*
index 8bfa719..21a1582 100644 (file)
@@ -64,9 +64,10 @@ __FBSDID("$FreeBSD$");
 
 static void wds_vattach(struct ieee80211vap *);
 static int wds_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static int wds_input(struct ieee80211_node *ni, struct mbuf *m, int, int);
-static void wds_recv_mgmt(struct ieee80211_node *, struct mbuf *,
-           int subtype, int, int);
+static int wds_input(struct ieee80211_node *ni, struct mbuf *m,
+           const struct ieee80211_rx_stats *rxs, int, int);
+static void wds_recv_mgmt(struct ieee80211_node *, struct mbuf *, int subtype,
+       const struct ieee80211_rx_stats *, int, int);
 
 void
 ieee80211_wds_attach(struct ieee80211com *ic)
@@ -301,8 +302,11 @@ ieee80211_dwds_mcast(struct ieee80211vap *vap0, struct mbuf *m)
                        /* NB: IFQ_HANDOFF reclaims mbuf */
                        IFNET_STAT_INC(ifp, oerrors, 1);
                        ieee80211_free_node(ni);
-               } else
+               } else {
                        IFNET_STAT_INC(ifp, opackets, 1);
+                       IFNET_STAT_INC(ifp, omcasts, 1);
+                       IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
+               }
        }
 }
 
@@ -404,9 +408,9 @@ wds_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
  * by the 802.11 layer.
  */
 static int
-wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
+wds_input(struct ieee80211_node *ni, struct mbuf *m,
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
-#define        HAS_SEQ(type)   ((type & 0x4) == 0)
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;
        struct ifnet *ifp = vap->iv_ifp;
@@ -488,7 +492,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
        }
        IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
        ni->ni_noise = nf;
-       if (HAS_SEQ(type)) {
+       if (IEEE80211_HAS_SEQ(type, subtype)) {
                uint8_t tid = ieee80211_gettid(wh);
                if (IEEE80211_QOS_HAS_SEQ(wh) &&
                    TID_TO_WME_AC(tid) >= WME_AC_VI)
@@ -715,7 +719,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
                        vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
                        goto out;
                }
-               vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+               vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
                goto out;
 
        case IEEE80211_FC0_TYPE_CTL:
@@ -741,8 +745,8 @@ out:
 }
 
 static void
-wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
-       int subtype, int rssi, int nf)
+wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
+    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
 {
        struct ieee80211vap *vap = ni->ni_vap;
        struct ieee80211com *ic = ni->ni_ic;