diff options
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r-- | net/mac80211/scan.c | 90 |
1 files changed, 57 insertions, 33 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 645355e5f1bc..0429e59ba387 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -9,7 +9,7 @@ * Copyright 2007, Michael Wu <[email protected]> * Copyright 2013-2015 Intel Mobile Communications GmbH * Copyright 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/if_arp.h> @@ -237,14 +237,18 @@ ieee80211_bss_info_update(struct ieee80211_local *local, } static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, u32 scan_flags, const u8 *da) { if (!sdata) return false; - /* accept broadcast for OCE */ - if (scan_flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP && - is_broadcast_ether_addr(da)) + + /* accept broadcast on 6 GHz and for OCE */ + if (is_broadcast_ether_addr(da) && + (channel->band == NL80211_BAND_6GHZ || + scan_flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP)) return true; + if (scan_flags & NL80211_SCAN_FLAG_RANDOM_ADDR) return true; return ether_addr_equal(da, sdata->vif.addr); @@ -253,7 +257,6 @@ static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_sub_if_data *sdata1, *sdata2; struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_bss *bss; struct ieee80211_channel *channel; @@ -277,12 +280,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) if (skb->len < min_hdr_len) return; - sdata1 = rcu_dereference(local->scan_sdata); - sdata2 = rcu_dereference(local->sched_scan_sdata); - - if (likely(!sdata1 && !sdata2)) - return; - if (test_and_clear_bit(SCAN_BEACON_WAIT, &local->scanning)) { /* * we were passive scanning because of radar/no-IR, but @@ -293,11 +290,24 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) wiphy_delayed_work_queue(local->hw.wiphy, &local->scan_work, 0); } + channel = ieee80211_get_channel_khz(local->hw.wiphy, + ieee80211_rx_status_to_khz(rx_status)); + + if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) + return; + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + struct ieee80211_sub_if_data *sdata1, *sdata2; struct cfg80211_scan_request *scan_req; struct cfg80211_sched_scan_request *sched_scan_req; u32 scan_req_flags = 0, sched_scan_req_flags = 0; + sdata1 = rcu_dereference(local->scan_sdata); + sdata2 = rcu_dereference(local->sched_scan_sdata); + + if (likely(!sdata1 && !sdata2)) + return; + scan_req = rcu_dereference(local->scan_req); sched_scan_req = rcu_dereference(local->sched_scan_req); @@ -310,17 +320,21 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) /* ignore ProbeResp to foreign address or non-bcast (OCE) * unless scanning with randomised address */ - if (!ieee80211_scan_accept_presp(sdata1, scan_req_flags, + if (!ieee80211_scan_accept_presp(sdata1, channel, + scan_req_flags, mgmt->da) && - !ieee80211_scan_accept_presp(sdata2, sched_scan_req_flags, + !ieee80211_scan_accept_presp(sdata2, channel, + sched_scan_req_flags, mgmt->da)) return; + } else { + /* Beacons are expected only with broadcast address */ + if (!is_broadcast_ether_addr(mgmt->da)) + return; } - channel = ieee80211_get_channel_khz(local->hw.wiphy, - ieee80211_rx_status_to_khz(rx_status)); - - if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) + /* Do not update the BSS table in case of only monitor interfaces */ + if (local->open_count == local->monitors) return; bss = ieee80211_bss_info_update(local, rx_status, @@ -394,6 +408,8 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_sub_if_data *sdata) req->ie, req->ie_len, bands_used, req->rates, &chandef, flags); + if (ielen < 0) + return false; 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); @@ -470,7 +486,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) } /* Set power back to normal operating levels. */ - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); if (!hw_scan && was_scanning) { ieee80211_configure_filter(local); @@ -517,7 +533,7 @@ 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) + if (!local->emulate_chanctx) return -EOPNOTSUPP; /* @@ -547,7 +563,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local, ieee80211_configure_filter(local); /* We need to set power level at maximum rate for scanning. */ - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); wiphy_delayed_work_queue(local->hw.wiphy, &local->scan_work, 0); @@ -671,7 +687,10 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, * After sending probe requests, wait for probe responses * on the channel. */ - *next_delay = IEEE80211_CHANNEL_TIME; + *next_delay = msecs_to_jiffies(scan_req->duration) > + IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME ? + msecs_to_jiffies(scan_req->duration) - IEEE80211_PROBE_DELAY : + IEEE80211_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; } @@ -781,7 +800,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); } else if ((req->n_channels == 1) && - (req->channels[0] == local->_oper_chandef.chan)) { + (req->channels[0] == local->hw.conf.chandef.chan)) { /* * If we are scanning only on the operating channel * then we do not need to stop normal activities @@ -799,7 +818,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_configure_filter(local); /* accept probe-responses */ /* We need to ensure power level is at max for scanning. */ - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) || @@ -964,13 +983,13 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, /* If scanning on oper channel, use whatever channel-type * is currently in use. */ - if (chan == local->_oper_chandef.chan) - local->scan_chandef = local->_oper_chandef; + if (chan == local->hw.conf.chandef.chan) + local->scan_chandef = local->hw.conf.chandef; else local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; set_channel: - if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) + if (ieee80211_hw_conf_chan(local)) skip = 1; /* advance state machine to next channel/band */ @@ -994,7 +1013,10 @@ set_channel: */ if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) || !scan_req->n_ssids) { - *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + *next_delay = msecs_to_jiffies(scan_req->duration) > + IEEE80211_PASSIVE_CHANNEL_TIME ? + msecs_to_jiffies(scan_req->duration) : + IEEE80211_PASSIVE_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; if (scan_req->n_ssids) set_bit(SCAN_BEACON_WAIT, &local->scanning); @@ -1011,7 +1033,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, { /* switch back to the operating channel */ local->scan_chandef.chan = NULL; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + ieee80211_hw_conf_chan(local); /* disable PS */ ieee80211_offchannel_return(local); @@ -1310,10 +1332,12 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, ieee80211_prepare_scan_chandef(&chandef); - ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz, - &sched_scan_ies, req->ie, - req->ie_len, bands_used, rate_masks, &chandef, - flags); + ret = ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz, + &sched_scan_ies, req->ie, + req->ie_len, bands_used, rate_masks, + &chandef, flags); + if (ret < 0) + goto error; ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); if (ret == 0) { @@ -1321,8 +1345,8 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, rcu_assign_pointer(local->sched_scan_req, req); } +error: kfree(ie); - out: if (ret) { /* Clean in case of failure after HW restart or upon resume. */ |