mac80211: remove local->radar_detect_enabled
[cascardo/linux.git] / net / mac80211 / scan.c
index af0d094..b0320bb 100644 (file)
@@ -184,9 +184,21 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
                return;
 
        if (ieee80211_is_probe_resp(mgmt->frame_control)) {
-               /* ignore ProbeResp to foreign address */
-               if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) &&
-                   (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr)))
+               struct cfg80211_scan_request *scan_req;
+               struct cfg80211_sched_scan_request *sched_scan_req;
+
+               scan_req = rcu_dereference(local->scan_req);
+               sched_scan_req = rcu_dereference(local->sched_scan_req);
+
+               /* ignore ProbeResp to foreign address unless scanning
+                * with randomised address
+                */
+               if (!(sdata1 &&
+                     (ether_addr_equal(mgmt->da, sdata1->vif.addr) ||
+                      scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) &&
+                   !(sdata2 &&
+                     (ether_addr_equal(mgmt->da, sdata2->vif.addr) ||
+                      sched_scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)))
                        return;
 
                elements = mgmt->u.probe_resp.variable;
@@ -234,11 +246,14 @@ ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef,
 /* return false if no more work */
 static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
 {
-       struct cfg80211_scan_request *req = local->scan_req;
+       struct cfg80211_scan_request *req;
        struct cfg80211_chan_def chandef;
        u8 bands_used = 0;
        int i, ielen, n_chans;
 
+       req = rcu_dereference_protected(local->scan_req,
+                                       lockdep_is_held(&local->mtx));
+
        if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
                return false;
 
@@ -281,6 +296,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
                                         bands_used, req->rates, &chandef);
        local->hw_scan_req->req.ie_len = ielen;
        local->hw_scan_req->req.no_cck = req->no_cck;
+       ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr);
+       ether_addr_copy(local->hw_scan_req->req.mac_addr_mask,
+                       req->mac_addr_mask);
 
        return true;
 }
@@ -290,6 +308,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        struct ieee80211_local *local = hw_to_local(hw);
        bool hw_scan = local->ops->hw_scan;
        bool was_scanning = local->scanning;
+       struct cfg80211_scan_request *scan_req;
+       struct ieee80211_sub_if_data *scan_sdata;
 
        lockdep_assert_held(&local->mtx);
 
@@ -322,9 +342,15 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        kfree(local->hw_scan_req);
        local->hw_scan_req = NULL;
 
-       if (local->scan_req != local->int_scan_req)
-               cfg80211_scan_done(local->scan_req, aborted);
-       local->scan_req = NULL;
+       scan_req = rcu_dereference_protected(local->scan_req,
+                                            lockdep_is_held(&local->mtx));
+
+       if (scan_req != local->int_scan_req)
+               cfg80211_scan_done(scan_req, aborted);
+       RCU_INIT_POINTER(local->scan_req, NULL);
+
+       scan_sdata = rcu_dereference_protected(local->scan_sdata,
+                                              lockdep_is_held(&local->mtx));
        RCU_INIT_POINTER(local->scan_sdata, NULL);
 
        local->scanning = 0;
@@ -335,7 +361,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
        if (!hw_scan) {
                ieee80211_configure_filter(local);
-               drv_sw_scan_complete(local);
+               drv_sw_scan_complete(local, scan_sdata);
                ieee80211_offchannel_return(local);
        }
 
@@ -361,7 +387,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 }
 EXPORT_SYMBOL(ieee80211_scan_completed);
 
-static int ieee80211_start_sw_scan(struct ieee80211_local *local)
+static int ieee80211_start_sw_scan(struct ieee80211_local *local,
+                                  struct ieee80211_sub_if_data *sdata)
 {
        /* Software scan is not supported in multi-channel cases */
        if (local->use_chanctx)
@@ -380,7 +407,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
         * nullfunc frames and probe requests will be dropped in
         * ieee80211_tx_h_check_assoc().
         */
-       drv_sw_scan_start(local);
+       drv_sw_scan_start(local, sdata, local->scan_addr);
 
        local->leave_oper_channel_time = jiffies;
        local->next_scan_state = SCAN_DECISION;
@@ -389,7 +416,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        ieee80211_offchannel_stop_vifs(local);
 
        /* ensure nullfunc is transmitted before leaving operating channel */
-       ieee80211_flush_queues(local, NULL);
+       ieee80211_flush_queues(local, NULL, false);
 
        ieee80211_configure_filter(local);
 
@@ -405,7 +432,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 static bool ieee80211_can_scan(struct ieee80211_local *local,
                               struct ieee80211_sub_if_data *sdata)
 {
-       if (local->radar_detect_enabled)
+       if (ieee80211_is_radar_required(local))
                return false;
 
        if (!list_empty(&local->roc_list))
@@ -440,23 +467,26 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
 {
        int i;
        struct ieee80211_sub_if_data *sdata;
+       struct cfg80211_scan_request *scan_req;
        enum ieee80211_band band = local->hw.conf.chandef.chan->band;
        u32 tx_flags;
 
+       scan_req = rcu_dereference_protected(local->scan_req,
+                                            lockdep_is_held(&local->mtx));
+
        tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
-       if (local->scan_req->no_cck)
+       if (scan_req->no_cck)
                tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
 
        sdata = rcu_dereference_protected(local->scan_sdata,
                                          lockdep_is_held(&local->mtx));
 
-       for (i = 0; i < local->scan_req->n_ssids; i++)
+       for (i = 0; i < scan_req->n_ssids; i++)
                ieee80211_send_probe_req(
-                       sdata, NULL,
-                       local->scan_req->ssids[i].ssid,
-                       local->scan_req->ssids[i].ssid_len,
-                       local->scan_req->ie, local->scan_req->ie_len,
-                       local->scan_req->rates[band], false,
+                       sdata, local->scan_addr, NULL,
+                       scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len,
+                       scan_req->ie, scan_req->ie_len,
+                       scan_req->rates[band], false,
                        tx_flags, local->hw.conf.chandef.chan, true);
 
        /*
@@ -480,7 +510,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
        if (!ieee80211_can_scan(local, sdata)) {
                /* wait for the work to finish/time out */
-               local->scan_req = req;
+               rcu_assign_pointer(local->scan_req, req);
                rcu_assign_pointer(local->scan_sdata, sdata);
                return 0;
        }
@@ -530,9 +560,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                 */
        }
 
-       local->scan_req = req;
+       rcu_assign_pointer(local->scan_req, req);
        rcu_assign_pointer(local->scan_sdata, sdata);
 
+       if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
+               get_random_mask_addr(local->scan_addr,
+                                    req->mac_addr,
+                                    req->mac_addr_mask);
+       else
+               memcpy(local->scan_addr, sdata->vif.addr, ETH_ALEN);
+
        if (local->ops->hw_scan) {
                __set_bit(SCAN_HW_SCANNING, &local->scanning);
        } else if ((req->n_channels == 1) &&
@@ -549,7 +586,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
                /* Notify driver scan is starting, keep order of operations
                 * same as normal software scan, in case that matters. */
-               drv_sw_scan_start(local);
+               drv_sw_scan_start(local, sdata, local->scan_addr);
 
                ieee80211_configure_filter(local); /* accept probe-responses */
 
@@ -558,7 +595,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
                if ((req->channels[0]->flags &
                     IEEE80211_CHAN_NO_IR) ||
-                   !local->scan_req->n_ssids) {
+                   !req->n_ssids) {
                        next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                } else {
                        ieee80211_scan_state_send_probe(local, &next_delay);
@@ -579,8 +616,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        if (local->ops->hw_scan) {
                WARN_ON(!ieee80211_prep_hw_scan(local));
                rc = drv_hw_scan(local, sdata, local->hw_scan_req);
-       } else
-               rc = ieee80211_start_sw_scan(local);
+       } else {
+               rc = ieee80211_start_sw_scan(local, sdata);
+       }
 
        if (rc) {
                kfree(local->hw_scan_req);
@@ -617,6 +655,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_channel *next_chan;
        enum mac80211_scan_state next_scan_state;
+       struct cfg80211_scan_request *scan_req;
 
        /*
         * check if at least one STA interface is associated,
@@ -641,7 +680,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
        }
        mutex_unlock(&local->iflist_mtx);
 
-       next_chan = local->scan_req->channels[local->scan_channel_idx];
+       scan_req = rcu_dereference_protected(local->scan_req,
+                                            lockdep_is_held(&local->mtx));
+
+       next_chan = scan_req->channels[local->scan_channel_idx];
 
        /*
         * we're currently scanning a different channel, let's
@@ -656,7 +698,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
                                 local->leave_oper_channel_time + HZ / 8);
 
        if (associated && !tx_empty) {
-               if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
+               if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
                        next_scan_state = SCAN_ABORT;
                else
                        next_scan_state = SCAN_SUSPEND;
@@ -677,14 +719,18 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
        int skip;
        struct ieee80211_channel *chan;
        enum nl80211_bss_scan_width oper_scan_width;
+       struct cfg80211_scan_request *scan_req;
+
+       scan_req = rcu_dereference_protected(local->scan_req,
+                                            lockdep_is_held(&local->mtx));
 
        skip = 0;
-       chan = local->scan_req->channels[local->scan_channel_idx];
+       chan = scan_req->channels[local->scan_channel_idx];
 
        local->scan_chandef.chan = chan;
        local->scan_chandef.center_freq1 = chan->center_freq;
        local->scan_chandef.center_freq2 = 0;
-       switch (local->scan_req->scan_width) {
+       switch (scan_req->scan_width) {
        case NL80211_BSS_CHAN_WIDTH_5:
                local->scan_chandef.width = NL80211_CHAN_WIDTH_5;
                break;
@@ -698,7 +744,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
                oper_scan_width = cfg80211_chandef_to_scan_width(
                                        &local->_oper_chandef);
                if (chan == local->_oper_chandef.chan &&
-                   oper_scan_width == local->scan_req->scan_width)
+                   oper_scan_width == scan_req->scan_width)
                        local->scan_chandef = local->_oper_chandef;
                else
                        local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -727,8 +773,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
         *
         * In any case, it is not necessary for a passive scan.
         */
-       if (chan->flags & IEEE80211_CHAN_NO_IR ||
-           !local->scan_req->n_ssids) {
+       if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) {
                *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                local->next_scan_state = SCAN_DECISION;
                return;
@@ -760,7 +805,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
        ieee80211_offchannel_stop_vifs(local);
 
        if (local->ops->flush) {
-               ieee80211_flush_queues(local, NULL);
+               ieee80211_flush_queues(local, NULL, false);
                *next_delay = 0;
        } else
                *next_delay = HZ / 10;
@@ -777,6 +822,7 @@ void ieee80211_scan_work(struct work_struct *work)
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, scan_work.work);
        struct ieee80211_sub_if_data *sdata;
+       struct cfg80211_scan_request *scan_req;
        unsigned long next_delay = 0;
        bool aborted;
 
@@ -784,6 +830,8 @@ void ieee80211_scan_work(struct work_struct *work)
 
        sdata = rcu_dereference_protected(local->scan_sdata,
                                          lockdep_is_held(&local->mtx));
+       scan_req = rcu_dereference_protected(local->scan_req,
+                                            lockdep_is_held(&local->mtx));
 
        /* When scanning on-channel, the first-callback means completed. */
        if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
@@ -796,20 +844,19 @@ void ieee80211_scan_work(struct work_struct *work)
                goto out_complete;
        }
 
-       if (!sdata || !local->scan_req)
+       if (!sdata || !scan_req)
                goto out;
 
-       if (local->scan_req && !local->scanning) {
-               struct cfg80211_scan_request *req = local->scan_req;
+       if (!local->scanning) {
                int rc;
 
-               local->scan_req = NULL;
+               RCU_INIT_POINTER(local->scan_req, NULL);
                RCU_INIT_POINTER(local->scan_sdata, NULL);
 
-               rc = __ieee80211_start_scan(sdata, req);
+               rc = __ieee80211_start_scan(sdata, scan_req);
                if (rc) {
                        /* need to complete scan in cfg80211 */
-                       local->scan_req = req;
+                       rcu_assign_pointer(local->scan_req, scan_req);
                        aborted = true;
                        goto out_complete;
                } else
@@ -829,7 +876,7 @@ void ieee80211_scan_work(struct work_struct *work)
                switch (local->next_scan_state) {
                case SCAN_DECISION:
                        /* if no more bands/channels left, complete scan */
-                       if (local->scan_channel_idx >= local->scan_req->n_channels) {
+                       if (local->scan_channel_idx >= scan_req->n_channels) {
                                aborted = false;
                                goto out_complete;
                        }
@@ -1043,7 +1090,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
        ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
        if (ret == 0) {
                rcu_assign_pointer(local->sched_scan_sdata, sdata);
-               local->sched_scan_req = req;
+               rcu_assign_pointer(local->sched_scan_req, req);
        }
 
        kfree(ie);
@@ -1052,7 +1099,7 @@ out:
        if (ret) {
                /* Clean in case of failure after HW restart or upon resume. */
                RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
-               local->sched_scan_req = NULL;
+               RCU_INIT_POINTER(local->sched_scan_req, NULL);
        }
 
        return ret;
@@ -1090,7 +1137,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
        }
 
        /* We don't want to restart sched scan anymore. */
-       local->sched_scan_req = NULL;
+       RCU_INIT_POINTER(local->sched_scan_req, NULL);
 
        if (rcu_access_pointer(local->sched_scan_sdata)) {
                ret = drv_sched_scan_stop(local, sdata);
@@ -1125,7 +1172,7 @@ void ieee80211_sched_scan_end(struct ieee80211_local *local)
        RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
 
        /* If sched scan was aborted by the driver. */
-       local->sched_scan_req = NULL;
+       RCU_INIT_POINTER(local->sched_scan_req, NULL);
 
        mutex_unlock(&local->mtx);