/* exclude the given vif */ if (vif == data->current_vif) return;
/* TODO: CDB check the band of the GO */ if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO &&
iwl_mld_vif_from_mac80211(vif)->ap_ibss_active)
data->p2p_go = true;
}
/* A scanning AP interface probably wants to generate a survey to do * ACS (automatic channel selection). * Force a non-fragmented scan in that case.
*/ if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP) return IWL_SCAN_TYPE_WILD;
if (!data->active_vif) return IWL_SCAN_TYPE_UNASSOC;
/* In case of DCM with P2P GO set all scan requests as * fast-balance scan
*/ if (vif->type == NL80211_IFTYPE_STATION &&
data->is_dcm_with_p2p_go) return IWL_SCAN_TYPE_FAST_BALANCE;
if (load >= IWL_MLD_TRAFFIC_MEDIUM || data->global_low_latency) return IWL_SCAN_TYPE_MILD;
staticint
iwl_mld_scan_uid_by_status(struct iwl_mld *mld, int status)
{ for (int i = 0; i < ARRAY_SIZE(mld->scan.uid_status); i++) if (mld->scan.uid_status[i] == status) return i;
return -ENOENT;
}
staticconstchar *
iwl_mld_scan_ebs_status_str(enum iwl_scan_ebs_status status)
{ switch (status) { case IWL_SCAN_EBS_SUCCESS: return"successful"; case IWL_SCAN_EBS_INACTIVE: return"inactive"; case IWL_SCAN_EBS_FAILED: case IWL_SCAN_EBS_CHAN_NOT_FOUND: default: return"failed";
}
}
staticint
iwl_mld_scan_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
{ for (int i = 0; i < PROBE_OPTION_MAX; i++) { if (!ssid_list[i].len) return -1; if (ssid_list[i].len == ssid_len &&
!memcmp(ssid_list[i].ssid, ssid, ssid_len)) return i;
}
/* If no direct SSIDs are provided perform a passive scan. Otherwise, * if there is a single SSID which is not the broadcast SSID, assume * that the scan is intended for roaming purposes and thus enable Rx on * all chains to improve chances of hearing the beacons/probe responses.
*/ if (params->n_ssids == 0)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE; elseif (params->n_ssids == 1 && params->ssids[0].ssid_len)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS;
if (params->pass_all)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL; else
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_MATCH;
if (iwl_mld_scan_is_fragmented(params->type))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1;
if (!iwl_mld_scan_is_regular(params))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC;
if (params->iter_notif ||
mld->scan.pass_all_sched_res == SCHED_SCAN_PASS_ALL_STATE_ENABLED)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE;
if (params->scan_6ghz)
flags |= IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_DONT_TOGGLE_ANT;
/* For AP interfaces, request survey data for regular scans and if * it is supported. For non-AP interfaces, EBS will be enabled and * the results may be missing information for some channels.
*/ if (scan_status == IWL_MLD_SCAN_REGULAR &&
ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP &&
gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE &&
iwl_fw_lookup_notif_ver(mld->fw, SCAN_GROUP,
CHANNEL_SURVEY_NOTIF, 0) >= 1)
flags |= IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS;
/* If the number of iterations of the last scan plan is set to zero, * it should run infinitely. However, this is not always the case. * For example, when regular scan is requested the driver sets one scan * plan with one iteration.
*/ if (!schedule[params->n_scan_plans - 1].iter_count)
schedule[params->n_scan_plans - 1].iter_count = 0xff;
*delay = cpu_to_le16(params->delay);
return 0;
}
/* We insert the SSIDs in an inverted order, because the FW will * invert it back.
*/ staticvoid
iwl_mld_scan_cmd_build_ssids(struct iwl_mld_scan_params *params, struct iwl_ssid_ie *ssids, u32 *ssid_bitmap)
{ int i, j; int index;
u32 tmp_bitmap = 0;
/* copy SSIDs from match list. iwl_config_sched_scan_profiles() * uses the order of these ssids to config match list.
*/ for (i = 0, j = params->n_match_sets - 1;
j >= 0 && i < PROBE_OPTION_MAX;
i++, j--) { /* skip empty SSID match_sets */ if (!params->match_sets[j].ssid.ssid_len) continue;
/* Populate the arrays of the short SSIDs and the BSSIDs using the 6GHz * collocated parameters. This might not be optimal, as this processing * does not (yet) correspond to the actual channels, so it is possible * that some entries would be left out.
*/ for (j = 0; j < params->n_6ghz_params; j++) { int k;
/* First, try to place the short SSID */ if (scan_6ghz_params[j].short_ssid_valid) { for (k = 0; k < idex_s; k++) { if (pp->short_ssid[k] ==
cpu_to_le32(scan_6ghz_params[j].short_ssid)) break;
}
/* try to place BSSID for the same entry */ for (k = 0; k < idex_b; k++) { if (!memcmp(&pp->bssid_array[k],
scan_6ghz_params[j].bssid, ETH_ALEN)) break;
}
if (k == idex_b && idex_b < SCAN_BSSID_MAX_SIZE &&
!WARN_ONCE(!is_valid_ether_addr(scan_6ghz_params[j].bssid), "scan: invalid BSSID at index %u, index_b=%u\n",
j, idex_b)) {
memcpy(&pp->bssid_array[idex_b++],
scan_6ghz_params[j].bssid, ETH_ALEN);
}
}
/* We can only use EBS if: * 1. the feature is supported. * 2. the last EBS was successful. * 3. it's not a p2p find operation. * 4. we are not in low latency mode, * or if fragmented ebs is supported by the FW * 5. the VIF is not an AP interface (scan wants survey results)
*/ return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
!mld->scan.last_ebs_failed &&
vif->type != NL80211_IFTYPE_P2P_DEVICE &&
(!low_latency || fw_has_api(capa, IWL_UCODE_TLV_API_FRAG_EBS)) &&
ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_AP);
}
/* set fragmented ebs for fragmented scan */ if (iwl_mld_scan_is_fragmented(params->type))
flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG;
/* Force EBS in case the scan is a fragmented and there is a need * to take P2P GO operation into consideration during scan operation.
*/ /* TODO: CDB */ if (iwl_mld_scan_is_fragmented(params->type) &&
params->respect_p2p_go) {
IWL_DEBUG_SCAN(mld, "Respect P2P GO. Force EBS\n");
flags |= IWL_SCAN_CHANNEL_FLAG_FORCE_EBS;
}
if (band == NL80211_BAND_6GHZ) { /* 6 GHz channels should only appear in a scan request * that has scan_6ghz set. The only exception is MLO * scan, which has to be passive.
*/
WARN_ON_ONCE(cfg->flags != 0);
cfg->flags =
cpu_to_le32(IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE);
}
/* Avoid performing passive scan on non PSC channels unless the * scan is specifically a passive scan, i.e., no SSIDs * configured in the scan command.
*/ if (!cfg80211_channel_is_psc(params->channels[i]) &&
!params->n_6ghz_params && params->n_ssids) continue;
/* Use the highest PSD value allowed as advertised by * APs for this channel
*/
tmp_psd_20 = scan_6ghz_params[j].psd_20; if (tmp_psd_20 !=
IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED &&
(psd_20 ==
IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED ||
psd_20 < tmp_psd_20))
psd_20 = tmp_psd_20;
/* In the following cases apply passive scan: * 1. Non fragmented scan: * - PSC channel with NO_LISTEN_FLAG on should be treated * like non PSC channel * - Non PSC channel with more than 3 short SSIDs or more * than 9 BSSIDs. * - Non PSC Channel with unsolicited probe response and * more than 2 short SSIDs or more than 6 BSSIDs. * - PSC channel with more than 2 short SSIDs or more than * 6 BSSIDs. * 2. Fragmented scan: * - PSC channel with more than 1 SSID or 3 BSSIDs. * - Non PSC channel with more than 2 SSIDs or 6 BSSIDs. * - Non PSC channel with unsolicited probe response and * more than 1 SSID or more than 3 BSSIDs.
*/ if (!iwl_mld_scan_is_fragmented(params->type)) { if (!cfg80211_channel_is_psc(params->channels[i]) ||
psc_no_listen) { if (unsolicited_probe_on_chan) {
max_s_ssids = 2;
max_bssids = 6;
} else {
max_s_ssids = 3;
max_bssids = 9;
}
} else {
max_s_ssids = 2;
max_bssids = 6;
}
} elseif (cfg80211_channel_is_psc(params->channels[i])) {
max_s_ssids = 1;
max_bssids = 3;
} else { if (unsolicited_probe_on_chan) {
max_s_ssids = 1;
max_bssids = 3;
} else {
max_s_ssids = 2;
max_bssids = 6;
}
}
/* To optimize the scan time, i.e., reduce the scan dwell time * on each channel, the below logic tries to set 3 direct BSSID * probe requests for each broadcast probe request with a short * SSID.
*/ for (u32 j = 0; j < params->n_6ghz_params; j++) { if (!(scan_6ghz_params[j].channel_idx == i)) continue;
found = false;
for (k = 0;
k < pp->short_ssid_num && n_s_ssids < max_s_ssids;
k++) { if (!scan_6ghz_params[j].unsolicited_probe &&
le32_to_cpu(pp->short_ssid[k]) ==
scan_6ghz_params[j].short_ssid) { /* Relevant short SSID bit set */ if (s_ssid_bitmap & BIT(k)) {
found = true; break;
}
/* Prefer creating BSSID entries unless * the short SSID probe can be done in * the same channel dwell iteration. * * We also need to create a short SSID * entry for any hidden AP.
*/ if (3 * n_s_ssids > n_bssids &&
!pp->direct_scan[k].len) break;
/* Hidden AP, cannot do passive scan */ if (pp->direct_scan[k].len)
allow_passive = false;
s_ssid_bitmap |= BIT(k);
n_s_ssids++;
found = true; break;
}
}
if (found) continue;
for (k = 0; k < pp->bssid_num; k++) { if (memcmp(&pp->bssid_array[k],
scan_6ghz_params[j].bssid,
ETH_ALEN)) continue;
staticint
iwl_mld_sched_scan_handle_non_psc_channels(struct iwl_mld_scan_params *params, bool *non_psc_included)
{ int i, j;
*non_psc_included = false; /* for 6 GHZ band only PSC channels need to be added */ for (i = 0; i < params->n_channels; i++) { struct ieee80211_channel *channel = params->channels[i];
/* 6 GHz passive scan may be enabled in the first 2.4 GHz/5 GHz scan * phase to discover geo location if no AP's are found. Skip it when * we're in the 6 GHz scan phase.
*/ if (params->scan_6ghz) return;
/* 6 GHz passive scan allowed only on station interface */ if (vif->type != NL80211_IFTYPE_STATION) {
IWL_DEBUG_SCAN(mld, "6GHz passive scan: not station interface\n"); return;
}
/* 6 GHz passive scan is allowed in a defined time interval following * HW reset or resume flow, or while not associated and a large * interval has passed since the last 6 GHz passive scan.
*/ if ((vif->cfg.assoc ||
time_after(mld->scan.last_6ghz_passive_jiffies +
(IWL_MLD_6GHZ_PASSIVE_SCAN_TIMEOUT * HZ), jiffies)) &&
(time_before(mld->scan.last_start_time_jiffies +
(IWL_MLD_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT * HZ),
jiffies))) {
IWL_DEBUG_SCAN(mld, "6GHz passive scan: %s\n",
vif->cfg.assoc ? "associated" : "timeout did not expire"); return;
}
/* not enough channels in the regular scan request */ if (params->n_channels < IWL_MLD_6GHZ_PASSIVE_SCAN_MIN_CHANS) {
IWL_DEBUG_SCAN(mld, "6GHz passive scan: not enough channels %d\n",
params->n_channels); return;
}
for (i = 0; i < params->n_ssids; i++) { if (!params->ssids[i].ssid_len) break;
}
/* not a wildcard scan, so cannot enable passive 6 GHz scan */ if (i == params->n_ssids) {
IWL_DEBUG_SCAN(mld, "6GHz passive scan: no wildcard SSID\n"); return;
}
if (!sband || !sband->n_channels) {
IWL_DEBUG_SCAN(mld, "6GHz passive scan: no 6GHz channels\n"); return;
}
for (i = 0, n_disabled = 0; i < sband->n_channels; i++) { if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED))
n_disabled++;
}
/* Not all the 6 GHz channels are disabled, so no need for 6 GHz * passive scan
*/ if (n_disabled != sband->n_channels) {
IWL_DEBUG_SCAN(mld, "6GHz passive scan: 6GHz channels enabled\n"); return;
}
/* all conditions to enable 6 GHz passive scan are satisfied */
IWL_DEBUG_SCAN(mld, "6GHz passive scan: can be enabled\n");
params->enable_6ghz_passive = true;
}
if (tsf_report_link_id < 0) { if (vif->active_links)
tsf_report_link_id = __ffs(vif->active_links); else
tsf_report_link_id = 0;
}
link = iwl_mld_link_dereference_check(mld_vif, tsf_report_link_id); if (!WARN_ON(!link)) {
params->fw_link_id = link->fw_id; /* we to store fw_link_id only for regular scan, * and use it in scan complete notif
*/ if (scan_status == IWL_MLD_SCAN_REGULAR)
mld->scan.fw_link_id = link->fw_id;
} else {
mld->scan.fw_link_id = IWL_MLD_INVALID_FW_ID;
params->fw_link_id = IWL_MLD_INVALID_FW_ID;
}
}
/* We don't need to wait to scan complete in the following cases: * 1. Driver failed to send the scan abort cmd. * 2. The FW is no longer familiar with the scan that needs to be * stopped. It is expected that the scan complete notification was * already received but not yet processed. * * In both cases the flow should continue similar to the case that the * scan was really aborted.
*/ if (ret || status == IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND)
*wait = false;
return ret;
}
staticint
iwl_mld_scan_stop_wait(struct iwl_mld *mld, int type, int uid)
{ struct iwl_notification_wait wait_scan_done; staticconst u16 scan_comp_notif[] = { SCAN_COMPLETE_UMAC }; bool wait = true; int ret;
out: if (non_psc_included)
kfree(params.channels); return ret;
}
int iwl_mld_scan_stop(struct iwl_mld *mld, int type, bool notify)
{ int uid, ret;
IWL_DEBUG_SCAN(mld, "Request to stop scan: type=0x%x, status=0x%x\n",
type, mld->scan.status);
if (!(mld->scan.status & type)) return 0;
uid = iwl_mld_scan_uid_by_status(mld, type); /* must be valid, we just checked it's running */ if (WARN_ON_ONCE(uid < 0)) return uid;
ret = iwl_mld_scan_stop_wait(mld, type, uid); if (ret)
IWL_DEBUG_SCAN(mld, "Failed to stop scan\n");
/* Clear the scan status so the next scan requests will * succeed and mark the scan as stopping, so that the Rx * handler doesn't do anything, as the scan was stopped from * above. Also remove the handler to not notify mac80211 * erroneously after a new scan starts, for example.
*/
mld->scan.status &= ~type;
mld->scan.uid_status[uid] = IWL_MLD_SCAN_NONE;
iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_SCAN,
uid);
if (type == IWL_MLD_SCAN_REGULAR) { if (notify) { struct cfg80211_scan_info info = {
.aborted = true,
};
int iwl_mld_regular_scan_start(struct iwl_mld *mld, struct ieee80211_vif *vif, struct cfg80211_scan_request *req, struct ieee80211_scan_ies *ies)
{ /* Clear survey data when starting the first part of a regular scan */ if (req->first_part && mld->channel_survey)
memset(mld->channel_survey->channels, 0, sizeof(mld->channel_survey->channels[0]) *
mld->channel_survey->n_channels);
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
iwl_mld_emlsr_block_tmp_non_bss(mld);
if (mld->scan.status & IWL_MLD_SCAN_INT_MLO) {
IWL_DEBUG_SCAN(mld, "Internal MLO scan is already running\n"); return;
}
if (mld_vif->last_link_activation_time > ktime_get_boottime_seconds() -
IWL_MLD_MLO_SCAN_BLOCKOUT_TIME) { /* timing doesn't matter much, so use the blockout time */
wiphy_delayed_work_queue(mld->wiphy,
&mld_vif->mlo_scan_start_wk,
IWL_MLD_MLO_SCAN_BLOCKOUT_TIME); return;
}
if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status), "FW reports scan UID %d we didn't trigger\n", uid)) return;
/* if the scan is already stopping, we don't need to notify mac80211 */ if (mld->scan.uid_status[uid] == IWL_MLD_SCAN_REGULAR) { struct cfg80211_scan_info info = {
.aborted = aborted,
.scan_start_tsf = mld->scan.start_tsf,
}; int fw_link_id = mld->scan.fw_link_id; struct ieee80211_bss_conf *link_conf = NULL;
if (fw_link_id != IWL_MLD_INVALID_FW_ID)
link_conf =
wiphy_dereference(mld->wiphy,
mld->fw_id_to_bss_conf[fw_link_id]);
/* It is possible that by the time the scan is complete the * link was already removed and is not valid.
*/ if (link_conf)
ether_addr_copy(info.tsf_bssid, link_conf->bssid); else
IWL_DEBUG_SCAN(mld, "Scan link is no longer valid\n");
ieee80211_scan_completed(mld->hw, &info);
/* Scan is over, we can check again the tpt counters */
iwl_mld_stop_ignoring_tpt_updates(mld);
} elseif (mld->scan.uid_status[uid] == IWL_MLD_SCAN_SCHED) {
ieee80211_sched_scan_stopped(mld->hw);
mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_DISABLED;
} elseif (mld->scan.uid_status[uid] == IWL_MLD_SCAN_INT_MLO) {
IWL_DEBUG_SCAN(mld, "Internal MLO scan completed\n");
/* * We limit link selection to internal MLO scans as otherwise * we do not know whether all channels were covered.
*/
iwl_mld_select_links(mld);
}
mld->scan.status &= ~mld->scan.uid_status[uid];
IWL_DEBUG_SCAN(mld, "Scan completed: after update: scan_status=0x%x\n",
mld->scan.status);
/* This function is used in nic restart flow, to inform mac80211 about scans * that were aborted by restart flow or by an assert.
*/ void iwl_mld_report_scan_aborted(struct iwl_mld *mld)
{ int uid;
uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_REGULAR); if (uid >= 0) { struct cfg80211_scan_info info = {
.aborted = true,
};
/* sched scan will be restarted by mac80211 in reconfig. * report to mac80211 that sched scan stopped only if we won't * restart the firmware.
*/ if (!iwlwifi_mod_params.fw_restart)
ieee80211_sched_scan_stopped(mld->hw);
}
band = iwl_mld_phy_band_to_nl80211(le32_to_cpu(notif->band));
chan_idx = iwl_mld_chanidx_from_phy(mld, band,
le32_to_cpu(notif->channel)); if (WARN_ON_ONCE(chan_idx < 0)) return;
IWL_DEBUG_SCAN(mld, "channel survey received for freq %d\n",
mld->wiphy->bands[band]->channels[chan_idx].center_freq);
info = &mld->channel_survey->bands[band][chan_idx];
/* Times are all in ms */
info->time = le32_to_cpu(notif->active_time);
info->time_busy = le32_to_cpu(notif->busy_time);
info->noise =
iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise));
}
int iwl_mld_mac80211_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
{ struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); int curr_idx = 0;
if (!mld->channel_survey) return -ENOENT;
/* Iterate bands/channels to find the requested index. * Logically this returns the entry with index "idx" from a flattened * survey result array that only contains channels with information. * The current index into this flattened array is tracked in curr_idx.
*/ for (enum nl80211_band band = 0; band < NUM_NL80211_BANDS; band++) { struct ieee80211_supported_band *sband =
mld->wiphy->bands[band];
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.