/* This happens while joining an IBSS */ if (!update_data) return;
elems = ieee802_11_parse_elems(ies->data, ies->len, false, NULL); if (!elems) return;
rx_status = update_data->rx_status;
if (update_data->beacon)
bss->device_ts_beacon = rx_status->device_timestamp; else
bss->device_ts_presp = rx_status->device_timestamp;
if (elems->parse_error) { if (update_data->beacon)
bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; else
bss->corrupt_data |= IEEE80211_BSS_CORRUPT_PROBE_RESP;
} else { if (update_data->beacon)
bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON; else
bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP;
}
/* save the ERP value so that it is available at association time */ if (elems->erp_info && (!elems->parse_error ||
!(bss->valid_data & IEEE80211_BSS_VALID_ERP))) {
bss->erp_value = elems->erp_info[0];
bss->has_erp_value = true; if (!elems->parse_error)
bss->valid_data |= IEEE80211_BSS_VALID_ERP;
}
/* replace old supported rates if we get new values */ if (!elems->parse_error ||
!(bss->valid_data & IEEE80211_BSS_VALID_RATES)) {
srlen = 0; if (elems->supp_rates) {
clen = IEEE80211_MAX_SUPP_RATES; if (clen > elems->supp_rates_len)
clen = elems->supp_rates_len;
memcpy(bss->supp_rates, elems->supp_rates, clen);
srlen += clen;
} if (elems->ext_supp_rates) {
clen = IEEE80211_MAX_SUPP_RATES - srlen; if (clen > elems->ext_supp_rates_len)
clen = elems->ext_supp_rates_len;
memcpy(bss->supp_rates + srlen, elems->ext_supp_rates,
clen);
srlen += clen;
} if (srlen) {
bss->supp_rates_len = srlen; if (!elems->parse_error)
bss->valid_data |= IEEE80211_BSS_VALID_RATES;
}
}
/* for an MLO connection, set the TSF data only in case we have * an indication on which of the links the frame was received
*/ if (ieee80211_vif_is_mld(&scan_sdata->vif)) { if (rx_status->link_valid) {
s8 link_id = rx_status->link_id;
/* In case the signal is invalid update the status */
signal_valid = channel == cbss->channel; if (!signal_valid)
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
if (test_and_clear_bit(SCAN_BEACON_WAIT, &local->scanning)) { /* * we were passive scanning because of radar/no-IR, but * the beacon/proberesp rx gives us an opportunity to upgrade * to active scan
*/
set_bit(SCAN_BEACON_DONE, &local->scanning);
wiphy_delayed_work_queue(local->hw.wiphy, &local->scan_work, 0);
}
for (i = 0; i < req->n_channels; i++) { if (req->channels[i]->band !=
local->hw_scan_band) continue;
local->hw_scan_req->req.channels[(*n_chans)++] =
req->channels[i];
bands_used |= BIT(req->channels[i]->band);
}
local->hw_scan_band++;
} while (!*n_chans);
}
ieee80211_prepare_scan_chandef(&chandef);
if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
/* * It's ok to abort a not-yet-running scan (that * we have one at all will be verified by checking * local->scan_req next), but not to complete it * successfully.
*/ if (WARN_ON(!local->scanning && !aborted))
aborted = true;
/* HW scan failed and is going to be reported as aborted, * so clear old scan info.
*/
memset(&local->scan_info, 0, sizeof(local->scan_info));
aborted = true;
}
/* Requeue all the work that might have been ignored while * the scan was in progress; if there was none this will * just be a no-op for the particular interface.
*/
list_for_each_entry(sdata, &local->interfaces, list) { if (ieee80211_sdata_running(sdata))
wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
}
if (was_scanning)
ieee80211_start_next_roc(local);
}
staticint 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->emulate_chanctx) return -EOPNOTSUPP;
/* * Hardware/driver doesn't support hw_scan, so use software * scanning instead. First send a nullfunc frame with power save * bit on so that AP will buffer the frames for us while we are not * listening, then send probe requests to each channel and wait for * the responses. After all channels are scanned, tune back to the * original channel and send a nullfunc frame with power save bit * off to trigger the AP to send us all the buffered frames. * * Note that while local->sw_scanning is true everything else but * nullfunc frames and probe requests will be dropped in * ieee80211_tx_h_check_assoc().
*/
drv_sw_scan_start(local, sdata, local->scan_addr);
/* For an MLO connection, if a link ID was specified, validate that it * is indeed active.
*/ if (ieee80211_vif_is_mld(&sdata->vif) && req->tsf_report_link_id >= 0 &&
!(sdata->vif.active_links & BIT(req->tsf_report_link_id))) return -EINVAL;
if (!__ieee80211_can_leave_ch(sdata, req)) return -EBUSY;
if (!ieee80211_can_scan(local, sdata, req)) { /* wait for the work to finish/time out */
rcu_assign_pointer(local->scan_req, req);
rcu_assign_pointer(local->scan_sdata, sdata); return 0;
}
if (ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS)) { int i, n_bands = 0;
u8 bands_counted = 0;
for (i = 0; i < req->n_channels; i++) { if (bands_counted & BIT(req->channels[i]->band)) continue;
bands_counted |= BIT(req->channels[i]->band);
n_bands++;
}
local->hw_scan_req->req.ssids = req->ssids;
local->hw_scan_req->req.n_ssids = req->n_ssids; /* None of the channels are actually set * up but let UBSAN know the boundaries.
*/
local->hw_scan_req->req.n_channels = req->n_channels;
/* * After allocating local->hw_scan_req, we must * go through until ieee80211_prep_hw_scan(), so * anything that might be changed here and leave * this function early must not go after this * allocation.
*/
}
if (hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning);
} elseif ((req->n_channels == 1) &&
(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
*/ unsignedlong next_delay;
/* Notify driver scan is starting, keep order of operations
* same as normal software scan, in case that matters. */
drv_sw_scan_start(local, sdata, local->scan_addr);
/* Now, just wait a bit and we are all done! */
wiphy_delayed_work_queue(local->hw.wiphy, &local->scan_work,
next_delay); return 0;
} else { /* Do normal software scan */
__set_bit(SCAN_SW_SCANNING, &local->scanning);
}
if (hw_scan && rc == 1) { /* * we can't fall back to software for P2P-GO * as it must update NoA etc.
*/ if (ieee80211_vif_type_p2p(&sdata->vif) ==
NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP;
hw_scan = false; goto again;
}
return rc;
}
staticunsignedlong
ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
{ /* * TODO: channel switching also consumes quite some time, * add that delay as well to get a better estimation
*/ if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) return IEEE80211_PASSIVE_CHANNEL_TIME; return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
}
/* * check if at least one STA interface is associated, * check if at least one STA interface has pending tx frames * and grab the lowest used beacon interval
*/
list_for_each_entry(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.associated) {
associated = true;
/* * we're currently scanning a different channel, let's * see if we can scan another channel without interfering * with the current traffic situation. * * Keep good latency, do not stay off-channel more than 125 ms.
*/
/* For scanning on the S1G band, detect the channel width according to * the channel being scanned.
*/ if (chan->band == NL80211_BAND_S1GHZ) {
local->scan_chandef.width = ieee80211_s1g_channel_width(chan); goto set_channel;
}
/* If scanning on oper channel, use whatever channel-type * is currently in use.
*/ 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_conf_chan(local))
skip = 1;
/* advance state machine to next channel/band */
local->scan_channel_idx++;
if (skip) { /* if we skip this channel return to the decision state */
local->next_scan_state = SCAN_DECISION; return;
}
/* * Probe delay is used to update the NAV, cf. 11.1.3.2.2 * (which unfortunately doesn't say _why_ step a) is done, * but it waits for the probe delay or until a frame is * received - and the received frame would update the NAV). * For now, we do not support waiting until a frame is * received. * * In any case, it is not necessary for a passive scan.
*/ if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ||
!scan_req->n_ssids) {
*next_delay = max(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); return;
}
/* When scanning on-channel, the first-callback means completed. */ if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); goto out_complete;
}
rc = __ieee80211_start_scan(sdata, scan_req); if (!rc) return; /* need to complete scan in cfg80211 */
rcu_assign_pointer(local->scan_req, scan_req);
aborted = true; goto out_complete;
}
clear_bit(SCAN_BEACON_WAIT, &local->scanning);
/* * as long as no delay is required advance immediately * without scheduling a new work
*/ do { if (!ieee80211_sdata_running(sdata)) {
aborted = true; goto out_complete;
}
if (test_and_clear_bit(SCAN_BEACON_DONE, &local->scanning) &&
local->next_scan_state == SCAN_DECISION)
local->next_scan_state = SCAN_SEND_PROBE;
switch (local->next_scan_state) { case SCAN_DECISION: /* if no more bands/channels left, complete scan */ if (local->scan_channel_idx >= scan_req->n_channels) {
aborted = false; goto out_complete;
}
ieee80211_scan_state_decision(local, &next_delay); break; case SCAN_SET_CHANNEL:
ieee80211_scan_state_set_channel(local, &next_delay); break; case SCAN_SEND_PROBE:
ieee80211_scan_state_send_probe(local, &next_delay); break; case SCAN_SUSPEND:
ieee80211_scan_state_suspend(local, &next_delay); break; case SCAN_RESUME:
ieee80211_scan_state_resume(local, &next_delay); break; case SCAN_ABORT:
aborted = true; goto out_complete;
}
} while (next_delay == 0);
void ieee80211_scan_cancel(struct ieee80211_local *local)
{ /* ensure a new scan cannot be queued */
lockdep_assert_wiphy(local->hw.wiphy);
/* * We are canceling software scan, or deferred scan that was not * yet really started (see __ieee80211_start_scan ). * * Regarding hardware scan: * - we can not call __ieee80211_scan_completed() as when * SCAN_HW_SCANNING bit is set this function change * local->hw_scan_req to operate on 5G band, what race with * driver which can use local->hw_scan_req * * - we can not cancel scan_work since driver can schedule it * by ieee80211_scan_completed(..., true) to finish scan * * Hence we only call the cancel_hw_scan() callback, but the low-level * driver is still responsible for calling ieee80211_scan_completed() * after the scan was completed/aborted.
*/
if (!local->scan_req) return;
/* * We have a scan running and the driver already reported completion, * but the worker hasn't run yet or is stuck on the mutex - mark it as * cancelled.
*/ if (test_bit(SCAN_HW_SCANNING, &local->scanning) &&
test_bit(SCAN_COMPLETED, &local->scanning)) {
set_bit(SCAN_HW_CANCELLED, &local->scanning); return;
}
if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { /* * Make sure that __ieee80211_scan_completed doesn't trigger a * scan on another band.
*/
set_bit(SCAN_HW_CANCELLED, &local->scanning); if (local->ops->cancel_hw_scan)
drv_cancel_hw_scan(local,
rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->hw.wiphy->mtx))); return;
}
wiphy_delayed_work_cancel(local->hw.wiphy, &local->scan_work); /* and clean up */
memset(&local->scan_info, 0, sizeof(local->scan_info));
__ieee80211_scan_completed(&local->hw, true);
}
if (!local->ops->sched_scan_start) return -EOPNOTSUPP;
for (i = 0; i < NUM_NL80211_BANDS; i++) { if (local->hw.wiphy->bands[i]) {
bands_used |= BIT(i);
rate_masks[i] = (u32) -1;
num_bands++;
}
}
if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
ie = kcalloc(iebufsz, num_bands, GFP_KERNEL); if (!ie) {
ret = -ENOMEM; goto out;
}
ieee80211_prepare_scan_chandef(&chandef);
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) {
rcu_assign_pointer(local->sched_scan_sdata, 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. */
RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
RCU_INIT_POINTER(local->sched_scan_req, NULL);
}
/* * this shouldn't really happen, so for simplicity * simply ignore it, and let mac80211 reconfigure * the sched scan later on.
*/ if (local->in_reconfig) return;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.19Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.