Path: blob/main/sys/contrib/dev/iwlwifi/mld/scan.c
48287 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2024-2025 Intel Corporation3*/4#include <linux/crc32.h>56#include "iwl-utils.h"78#include "mld.h"9#include "scan.h"10#include "hcmd.h"11#include "iface.h"12#include "phy.h"13#include "mlo.h"1415#include "fw/api/scan.h"16#include "fw/dbg.h"1718#define IWL_SCAN_DWELL_ACTIVE 1019#define IWL_SCAN_DWELL_PASSIVE 11020#define IWL_SCAN_NUM_OF_FRAGS 32122/* adaptive dwell max budget time [TU] for full scan */23#define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 3002425/* adaptive dwell max budget time [TU] for directed scan */26#define IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 1002728/* adaptive dwell default high band APs number */29#define IWL_SCAN_ADWELL_DEFAULT_HB_N_APS 83031/* adaptive dwell default low band APs number */32#define IWL_SCAN_ADWELL_DEFAULT_LB_N_APS 23334/* adaptive dwell default APs number for P2P social channels (1, 6, 11) */35#define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 103637/* adaptive dwell number of APs override for P2P friendly GO channels */38#define IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY 103940/* adaptive dwell number of APs override for P2P social channels */41#define IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS 24243/* adaptive dwell number of APs override mask for p2p friendly GO */44#define IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY_BIT BIT(20)4546/* adaptive dwell number of APs override mask for social channels */47#define IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT BIT(21)4849#define SCAN_TIMEOUT_MSEC (30000 * HZ)5051/* minimal number of 2GHz and 5GHz channels in the regular scan request */52#define IWL_MLD_6GHZ_PASSIVE_SCAN_MIN_CHANS 45354enum iwl_mld_scan_type {55IWL_SCAN_TYPE_NOT_SET,56IWL_SCAN_TYPE_UNASSOC,57IWL_SCAN_TYPE_WILD,58IWL_SCAN_TYPE_MILD,59IWL_SCAN_TYPE_FRAGMENTED,60IWL_SCAN_TYPE_FAST_BALANCE,61};6263struct iwl_mld_scan_timing_params {64u32 suspend_time;65u32 max_out_time;66};6768static const struct iwl_mld_scan_timing_params scan_timing[] = {69[IWL_SCAN_TYPE_UNASSOC] = {70.suspend_time = 0,71.max_out_time = 0,72},73[IWL_SCAN_TYPE_WILD] = {74.suspend_time = 30,75.max_out_time = 120,76},77[IWL_SCAN_TYPE_MILD] = {78.suspend_time = 120,79.max_out_time = 120,80},81[IWL_SCAN_TYPE_FRAGMENTED] = {82.suspend_time = 95,83.max_out_time = 44,84},85[IWL_SCAN_TYPE_FAST_BALANCE] = {86.suspend_time = 30,87.max_out_time = 37,88},89};9091struct iwl_mld_scan_params {92enum iwl_mld_scan_type type;93u32 n_channels;94u16 delay;95int n_ssids;96struct cfg80211_ssid *ssids;97struct ieee80211_channel **channels;98u32 flags;99u8 *mac_addr;100u8 *mac_addr_mask;101bool no_cck;102bool pass_all;103int n_match_sets;104struct iwl_scan_probe_req preq;105struct cfg80211_match_set *match_sets;106int n_scan_plans;107struct cfg80211_sched_scan_plan *scan_plans;108bool iter_notif;109bool respect_p2p_go;110u8 fw_link_id;111struct cfg80211_scan_6ghz_params *scan_6ghz_params;112u32 n_6ghz_params;113bool scan_6ghz;114bool enable_6ghz_passive;115u8 bssid[ETH_ALEN] __aligned(2);116};117118struct iwl_mld_scan_respect_p2p_go_iter_data {119struct ieee80211_vif *current_vif;120bool p2p_go;121};122123static void iwl_mld_scan_respect_p2p_go_iter(void *_data, u8 *mac,124struct ieee80211_vif *vif)125{126struct iwl_mld_scan_respect_p2p_go_iter_data *data = _data;127128/* exclude the given vif */129if (vif == data->current_vif)130return;131132/* TODO: CDB check the band of the GO */133if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO &&134iwl_mld_vif_from_mac80211(vif)->ap_ibss_active)135data->p2p_go = true;136}137138static bool iwl_mld_get_respect_p2p_go(struct iwl_mld *mld,139struct ieee80211_vif *vif,140bool low_latency)141{142struct iwl_mld_scan_respect_p2p_go_iter_data data = {143.current_vif = vif,144.p2p_go = false,145};146147if (!low_latency)148return false;149150ieee80211_iterate_active_interfaces_mtx(mld->hw,151IEEE80211_IFACE_ITER_NORMAL,152iwl_mld_scan_respect_p2p_go_iter,153&data);154155return data.p2p_go;156}157158struct iwl_mld_scan_iter_data {159struct ieee80211_vif *current_vif;160bool active_vif;161bool is_dcm_with_p2p_go;162bool global_low_latency;163};164165static void iwl_mld_scan_iterator(void *_data, u8 *mac,166struct ieee80211_vif *vif)167{168struct iwl_mld_scan_iter_data *data = _data;169struct ieee80211_vif *curr_vif = data->current_vif;170struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);171struct iwl_mld_vif *curr_mld_vif;172unsigned long curr_vif_active_links;173u16 link_id;174175data->global_low_latency |= iwl_mld_vif_low_latency(mld_vif);176177if ((ieee80211_vif_is_mld(vif) && vif->active_links) ||178(vif->type != NL80211_IFTYPE_P2P_DEVICE &&179mld_vif->deflink.active))180data->active_vif = true;181182if (vif == curr_vif)183return;184185if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_P2P_GO)186return;187188/* Currently P2P GO can't be AP MLD so the logic below assumes that */189WARN_ON_ONCE(ieee80211_vif_is_mld(vif));190191curr_vif_active_links =192ieee80211_vif_is_mld(curr_vif) ? curr_vif->active_links : 1;193194curr_mld_vif = iwl_mld_vif_from_mac80211(curr_vif);195196for_each_set_bit(link_id, &curr_vif_active_links,197IEEE80211_MLD_MAX_NUM_LINKS) {198struct iwl_mld_link *curr_mld_link =199iwl_mld_link_dereference_check(curr_mld_vif, link_id);200201if (WARN_ON(!curr_mld_link))202return;203204if (rcu_access_pointer(curr_mld_link->chan_ctx) &&205rcu_access_pointer(mld_vif->deflink.chan_ctx) !=206rcu_access_pointer(curr_mld_link->chan_ctx)) {207data->is_dcm_with_p2p_go = true;208return;209}210}211}212213static enum214iwl_mld_scan_type iwl_mld_get_scan_type(struct iwl_mld *mld,215struct ieee80211_vif *vif,216struct iwl_mld_scan_iter_data *data)217{218enum iwl_mld_traffic_load load = mld->scan.traffic_load.status;219220/* A scanning AP interface probably wants to generate a survey to do221* ACS (automatic channel selection).222* Force a non-fragmented scan in that case.223*/224if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP)225return IWL_SCAN_TYPE_WILD;226227if (!data->active_vif)228return IWL_SCAN_TYPE_UNASSOC;229230if ((load == IWL_MLD_TRAFFIC_HIGH || data->global_low_latency) &&231vif->type != NL80211_IFTYPE_P2P_DEVICE)232return IWL_SCAN_TYPE_FRAGMENTED;233234/* In case of DCM with P2P GO set all scan requests as235* fast-balance scan236*/237if (vif->type == NL80211_IFTYPE_STATION &&238data->is_dcm_with_p2p_go)239return IWL_SCAN_TYPE_FAST_BALANCE;240241if (load >= IWL_MLD_TRAFFIC_MEDIUM || data->global_low_latency)242return IWL_SCAN_TYPE_MILD;243244return IWL_SCAN_TYPE_WILD;245}246247static u8 *248iwl_mld_scan_add_2ghz_elems(struct iwl_mld *mld, const u8 *ies,249size_t len, u8 *const pos)250{251static const u8 before_ds_params[] = {252WLAN_EID_SSID,253WLAN_EID_SUPP_RATES,254WLAN_EID_REQUEST,255WLAN_EID_EXT_SUPP_RATES,256};257size_t offs;258u8 *newpos = pos;259260offs = ieee80211_ie_split(ies, len,261before_ds_params,262ARRAY_SIZE(before_ds_params),2630);264265memcpy(newpos, ies, offs);266newpos += offs;267268/* Add a placeholder for DS Parameter Set element */269*newpos++ = WLAN_EID_DS_PARAMS;270*newpos++ = 1;271*newpos++ = 0;272273memcpy(newpos, ies + offs, len - offs);274newpos += len - offs;275276return newpos;277}278279static void280iwl_mld_scan_add_tpc_report_elem(u8 *pos)281{282pos[0] = WLAN_EID_VENDOR_SPECIFIC;283pos[1] = WFA_TPC_IE_LEN - 2;284pos[2] = (WLAN_OUI_MICROSOFT >> 16) & 0xff;285pos[3] = (WLAN_OUI_MICROSOFT >> 8) & 0xff;286pos[4] = WLAN_OUI_MICROSOFT & 0xff;287pos[5] = WLAN_OUI_TYPE_MICROSOFT_TPC;288pos[6] = 0;289/* pos[7] - tx power will be inserted by the FW */290pos[7] = 0;291pos[8] = 0;292}293294static u32295iwl_mld_scan_ooc_priority(enum iwl_mld_scan_status scan_status)296{297if (scan_status == IWL_MLD_SCAN_REGULAR)298return IWL_SCAN_PRIORITY_EXT_6;299if (scan_status == IWL_MLD_SCAN_INT_MLO)300return IWL_SCAN_PRIORITY_EXT_4;301302return IWL_SCAN_PRIORITY_EXT_2;303}304305static bool306iwl_mld_scan_is_regular(struct iwl_mld_scan_params *params)307{308return params->n_scan_plans == 1 &&309params->scan_plans[0].iterations == 1;310}311312static bool313iwl_mld_scan_is_fragmented(enum iwl_mld_scan_type type)314{315return (type == IWL_SCAN_TYPE_FRAGMENTED ||316type == IWL_SCAN_TYPE_FAST_BALANCE);317}318319static int320iwl_mld_scan_uid_by_status(struct iwl_mld *mld, int status)321{322for (int i = 0; i < ARRAY_SIZE(mld->scan.uid_status); i++)323if (mld->scan.uid_status[i] == status)324return i;325326return -ENOENT;327}328329static const char *330iwl_mld_scan_ebs_status_str(enum iwl_scan_ebs_status status)331{332switch (status) {333case IWL_SCAN_EBS_SUCCESS:334return "successful";335case IWL_SCAN_EBS_INACTIVE:336return "inactive";337case IWL_SCAN_EBS_FAILED:338case IWL_SCAN_EBS_CHAN_NOT_FOUND:339default:340return "failed";341}342}343344static int345iwl_mld_scan_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)346{347for (int i = 0; i < PROBE_OPTION_MAX; i++) {348if (!ssid_list[i].len)349return -1;350if (ssid_list[i].len == ssid_len &&351!memcmp(ssid_list[i].ssid, ssid, ssid_len))352return i;353}354355return -1;356}357358static bool359iwl_mld_scan_fits(struct iwl_mld *mld, int n_ssids,360struct ieee80211_scan_ies *ies, int n_channels)361{362return ((n_ssids <= PROBE_OPTION_MAX) &&363(n_channels <= mld->fw->ucode_capa.n_scan_channels) &&364(ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +365ies->len[NL80211_BAND_5GHZ] + ies->len[NL80211_BAND_6GHZ] <=366iwl_mld_scan_max_template_size()));367}368369static void370iwl_mld_scan_build_probe_req(struct iwl_mld *mld, struct ieee80211_vif *vif,371struct ieee80211_scan_ies *ies,372struct iwl_mld_scan_params *params)373{374struct ieee80211_mgmt *frame = (void *)params->preq.buf;375u8 *pos, *newpos;376const u8 *mac_addr = params->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?377params->mac_addr : NULL;378379if (mac_addr)380get_random_mask_addr(frame->sa, mac_addr,381params->mac_addr_mask);382else383memcpy(frame->sa, vif->addr, ETH_ALEN);384385frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);386eth_broadcast_addr(frame->da);387ether_addr_copy(frame->bssid, params->bssid);388frame->seq_ctrl = 0;389390pos = frame->u.probe_req.variable;391*pos++ = WLAN_EID_SSID;392*pos++ = 0;393394params->preq.mac_header.offset = 0;395params->preq.mac_header.len = cpu_to_le16(24 + 2);396397/* Insert DS parameter set element on 2.4 GHz band */398newpos = iwl_mld_scan_add_2ghz_elems(mld,399ies->ies[NL80211_BAND_2GHZ],400ies->len[NL80211_BAND_2GHZ],401pos);402params->preq.band_data[0].offset = cpu_to_le16(pos - params->preq.buf);403params->preq.band_data[0].len = cpu_to_le16(newpos - pos);404pos = newpos;405406memcpy(pos, ies->ies[NL80211_BAND_5GHZ],407ies->len[NL80211_BAND_5GHZ]);408params->preq.band_data[1].offset = cpu_to_le16(pos - params->preq.buf);409params->preq.band_data[1].len =410cpu_to_le16(ies->len[NL80211_BAND_5GHZ]);411pos += ies->len[NL80211_BAND_5GHZ];412413memcpy(pos, ies->ies[NL80211_BAND_6GHZ],414ies->len[NL80211_BAND_6GHZ]);415params->preq.band_data[2].offset = cpu_to_le16(pos - params->preq.buf);416params->preq.band_data[2].len =417cpu_to_le16(ies->len[NL80211_BAND_6GHZ]);418pos += ies->len[NL80211_BAND_6GHZ];419420memcpy(pos, ies->common_ies, ies->common_ie_len);421params->preq.common_data.offset = cpu_to_le16(pos - params->preq.buf);422423iwl_mld_scan_add_tpc_report_elem(pos + ies->common_ie_len);424params->preq.common_data.len = cpu_to_le16(ies->common_ie_len +425WFA_TPC_IE_LEN);426}427428static u16429iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld,430struct iwl_mld_scan_params *params,431struct ieee80211_vif *vif,432enum iwl_mld_scan_status scan_status)433{434u16 flags = 0;435436/* If no direct SSIDs are provided perform a passive scan. Otherwise,437* if there is a single SSID which is not the broadcast SSID, assume438* that the scan is intended for roaming purposes and thus enable Rx on439* all chains to improve chances of hearing the beacons/probe responses.440*/441if (params->n_ssids == 0)442flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE;443else if (params->n_ssids == 1 && params->ssids[0].ssid_len)444flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS;445446if (params->pass_all)447flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL;448else449flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_MATCH;450451if (iwl_mld_scan_is_fragmented(params->type))452flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1;453454if (!iwl_mld_scan_is_regular(params))455flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC;456457if (params->iter_notif ||458mld->scan.pass_all_sched_res == SCHED_SCAN_PASS_ALL_STATE_ENABLED)459flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE;460461if (scan_status == IWL_MLD_SCAN_SCHED ||462scan_status == IWL_MLD_SCAN_NETDETECT)463flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE;464465if (params->flags & (NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP |466NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE |467NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME))468flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_OCE;469470if ((scan_status == IWL_MLD_SCAN_SCHED ||471scan_status == IWL_MLD_SCAN_NETDETECT) &&472params->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ)473flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN;474475if (params->enable_6ghz_passive)476flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN;477478flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL;479480return flags;481}482483static u8484iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld,485struct iwl_mld_scan_params *params,486struct ieee80211_vif *vif,487enum iwl_mld_scan_status scan_status,488u16 gen_flags)489{490u8 flags = 0;491492/* TODO: CDB */493if (params->respect_p2p_go)494flags |= IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_LB |495IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_HB;496497if (params->scan_6ghz)498flags |= IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_DONT_TOGGLE_ANT;499500/* For AP interfaces, request survey data for regular scans and if501* it is supported. For non-AP interfaces, EBS will be enabled and502* the results may be missing information for some channels.503*/504if (scan_status == IWL_MLD_SCAN_REGULAR &&505ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP &&506gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE &&507iwl_fw_lookup_notif_ver(mld->fw, SCAN_GROUP,508CHANNEL_SURVEY_NOTIF, 0) >= 1)509flags |= IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS;510511return flags;512}513514static void515iwl_mld_scan_cmd_set_dwell(struct iwl_mld *mld,516struct iwl_scan_general_params_v11 *gp,517struct iwl_mld_scan_params *params)518{519const struct iwl_mld_scan_timing_params *timing =520&scan_timing[params->type];521522gp->adwell_default_social_chn =523IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL;524gp->adwell_default_2g = IWL_SCAN_ADWELL_DEFAULT_LB_N_APS;525gp->adwell_default_5g = IWL_SCAN_ADWELL_DEFAULT_HB_N_APS;526527if (params->n_ssids && params->ssids[0].ssid_len)528gp->adwell_max_budget =529cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN);530else531gp->adwell_max_budget =532cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN);533534gp->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);535536gp->max_out_of_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->max_out_time);537gp->suspend_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->suspend_time);538539gp->active_dwell[SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE;540gp->passive_dwell[SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE;541gp->active_dwell[SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE;542gp->passive_dwell[SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE;543544IWL_DEBUG_SCAN(mld,545"Scan: adwell_max_budget=%d max_out_of_time=%d suspend_time=%d\n",546gp->adwell_max_budget,547gp->max_out_of_time[SCAN_LB_LMAC_IDX],548gp->suspend_time[SCAN_LB_LMAC_IDX]);549}550551static void552iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld,553struct iwl_mld_scan_params *params,554struct ieee80211_vif *vif,555struct iwl_scan_general_params_v11 *gp,556enum iwl_mld_scan_status scan_status)557{558u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif,559scan_status);560u8 gen_flags2 = iwl_mld_scan_get_cmd_gen_flags2(mld, params, vif,561scan_status,562gen_flags);563564IWL_DEBUG_SCAN(mld, "General: flags=0x%x, flags2=0x%x\n",565gen_flags, gen_flags2);566567gp->flags = cpu_to_le16(gen_flags);568gp->flags2 = gen_flags2;569570iwl_mld_scan_cmd_set_dwell(mld, gp, params);571572if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1)573gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS;574575if (params->fw_link_id != IWL_MLD_INVALID_FW_ID)576gp->scan_start_mac_or_link_id = params->fw_link_id;577}578579static int580iwl_mld_scan_cmd_set_sched_params(struct iwl_mld_scan_params *params,581struct iwl_scan_umac_schedule *schedule,582__le16 *delay)583{584if (WARN_ON(!params->n_scan_plans ||585params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))586return -EINVAL;587588for (int i = 0; i < params->n_scan_plans; i++) {589struct cfg80211_sched_scan_plan *scan_plan =590¶ms->scan_plans[i];591592schedule[i].iter_count = scan_plan->iterations;593schedule[i].interval =594cpu_to_le16(scan_plan->interval);595}596597/* If the number of iterations of the last scan plan is set to zero,598* it should run infinitely. However, this is not always the case.599* For example, when regular scan is requested the driver sets one scan600* plan with one iteration.601*/602if (!schedule[params->n_scan_plans - 1].iter_count)603schedule[params->n_scan_plans - 1].iter_count = 0xff;604605*delay = cpu_to_le16(params->delay);606607return 0;608}609610/* We insert the SSIDs in an inverted order, because the FW will611* invert it back.612*/613static void614iwl_mld_scan_cmd_build_ssids(struct iwl_mld_scan_params *params,615struct iwl_ssid_ie *ssids, u32 *ssid_bitmap)616{617int i, j;618int index;619u32 tmp_bitmap = 0;620621/* copy SSIDs from match list. iwl_config_sched_scan_profiles()622* uses the order of these ssids to config match list.623*/624for (i = 0, j = params->n_match_sets - 1;625j >= 0 && i < PROBE_OPTION_MAX;626i++, j--) {627/* skip empty SSID match_sets */628if (!params->match_sets[j].ssid.ssid_len)629continue;630631ssids[i].id = WLAN_EID_SSID;632ssids[i].len = params->match_sets[j].ssid.ssid_len;633memcpy(ssids[i].ssid, params->match_sets[j].ssid.ssid,634ssids[i].len);635}636637/* add SSIDs from scan SSID list */638for (j = params->n_ssids - 1;639j >= 0 && i < PROBE_OPTION_MAX;640i++, j--) {641index = iwl_mld_scan_ssid_exist(params->ssids[j].ssid,642params->ssids[j].ssid_len,643ssids);644if (index < 0) {645ssids[i].id = WLAN_EID_SSID;646ssids[i].len = params->ssids[j].ssid_len;647memcpy(ssids[i].ssid, params->ssids[j].ssid,648ssids[i].len);649tmp_bitmap |= BIT(i);650} else {651tmp_bitmap |= BIT(index);652}653}654655if (ssid_bitmap)656*ssid_bitmap = tmp_bitmap;657}658659static void660iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params,661struct iwl_scan_probe_params_v4 *pp)662{663int j, idex_s = 0, idex_b = 0;664struct cfg80211_scan_6ghz_params *scan_6ghz_params =665params->scan_6ghz_params;666667for (j = 0;668j < params->n_ssids && idex_s < SCAN_SHORT_SSID_MAX_SIZE;669j++) {670if (!params->ssids[j].ssid_len)671continue;672673pp->short_ssid[idex_s] =674cpu_to_le32(~crc32_le(~0, params->ssids[j].ssid,675params->ssids[j].ssid_len));676677/* hidden 6ghz scan */678pp->direct_scan[idex_s].id = WLAN_EID_SSID;679pp->direct_scan[idex_s].len = params->ssids[j].ssid_len;680memcpy(pp->direct_scan[idex_s].ssid, params->ssids[j].ssid,681params->ssids[j].ssid_len);682idex_s++;683}684685/* Populate the arrays of the short SSIDs and the BSSIDs using the 6GHz686* collocated parameters. This might not be optimal, as this processing687* does not (yet) correspond to the actual channels, so it is possible688* that some entries would be left out.689*/690for (j = 0; j < params->n_6ghz_params; j++) {691int k;692693/* First, try to place the short SSID */694if (scan_6ghz_params[j].short_ssid_valid) {695for (k = 0; k < idex_s; k++) {696if (pp->short_ssid[k] ==697cpu_to_le32(scan_6ghz_params[j].short_ssid))698break;699}700701if (k == idex_s && idex_s < SCAN_SHORT_SSID_MAX_SIZE) {702pp->short_ssid[idex_s++] =703cpu_to_le32(scan_6ghz_params[j].short_ssid);704}705}706707/* try to place BSSID for the same entry */708for (k = 0; k < idex_b; k++) {709if (!memcmp(&pp->bssid_array[k],710scan_6ghz_params[j].bssid, ETH_ALEN))711break;712}713714if (k == idex_b && idex_b < SCAN_BSSID_MAX_SIZE &&715!WARN_ONCE(!is_valid_ether_addr(scan_6ghz_params[j].bssid),716"scan: invalid BSSID at index %u, index_b=%u\n",717j, idex_b)) {718memcpy(&pp->bssid_array[idex_b++],719scan_6ghz_params[j].bssid, ETH_ALEN);720}721}722723pp->short_ssid_num = idex_s;724pp->bssid_num = idex_b;725}726727static void728iwl_mld_scan_cmd_set_probe_params(struct iwl_mld_scan_params *params,729struct iwl_scan_probe_params_v4 *pp,730u32 *bitmap_ssid)731{732pp->preq = params->preq;733734if (params->scan_6ghz) {735iwl_mld_scan_fill_6g_chan_list(params, pp);736return;737}738739/* relevant only for 2.4 GHz /5 GHz scan */740iwl_mld_scan_cmd_build_ssids(params, pp->direct_scan, bitmap_ssid);741}742743static bool744iwl_mld_scan_use_ebs(struct iwl_mld *mld, struct ieee80211_vif *vif,745bool low_latency)746{747const struct iwl_ucode_capabilities *capa = &mld->fw->ucode_capa;748749/* We can only use EBS if:750* 1. the feature is supported.751* 2. the last EBS was successful.752* 3. it's not a p2p find operation.753* 4. we are not in low latency mode,754* or if fragmented ebs is supported by the FW755* 5. the VIF is not an AP interface (scan wants survey results)756*/757return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) &&758!mld->scan.last_ebs_failed &&759vif->type != NL80211_IFTYPE_P2P_DEVICE &&760(!low_latency || fw_has_api(capa, IWL_UCODE_TLV_API_FRAG_EBS)) &&761ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_AP);762}763764static u8765iwl_mld_scan_cmd_set_chan_flags(struct iwl_mld *mld,766struct iwl_mld_scan_params *params,767struct ieee80211_vif *vif,768bool low_latency)769{770u8 flags = 0;771772flags |= IWL_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER;773774if (iwl_mld_scan_use_ebs(mld, vif, low_latency))775flags |= IWL_SCAN_CHANNEL_FLAG_EBS |776IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |777IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;778779/* set fragmented ebs for fragmented scan */780if (iwl_mld_scan_is_fragmented(params->type))781flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG;782783/* Force EBS in case the scan is a fragmented and there is a need784* to take P2P GO operation into consideration during scan operation.785*/786/* TODO: CDB */787if (iwl_mld_scan_is_fragmented(params->type) &&788params->respect_p2p_go) {789IWL_DEBUG_SCAN(mld, "Respect P2P GO. Force EBS\n");790flags |= IWL_SCAN_CHANNEL_FLAG_FORCE_EBS;791}792793return flags;794}795796static const u8 p2p_go_friendly_chs[] = {79736, 40, 44, 48, 149, 153, 157, 161, 165,798};799800static const u8 social_chs[] = {8011, 6, 11802};803804static u32 iwl_mld_scan_ch_n_aps_flag(enum nl80211_iftype vif_type, u8 ch_id)805{806if (vif_type != NL80211_IFTYPE_P2P_DEVICE)807return 0;808809for (int i = 0; i < ARRAY_SIZE(p2p_go_friendly_chs); i++) {810if (ch_id == p2p_go_friendly_chs[i])811return IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY_BIT;812}813814for (int i = 0; i < ARRAY_SIZE(social_chs); i++) {815if (ch_id == social_chs[i])816return IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT;817}818819return 0;820}821822static void823iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld,824struct ieee80211_channel **channels,825struct iwl_scan_channel_params_v7 *cp,826int n_channels, u32 flags,827enum nl80211_iftype vif_type)828{829for (int i = 0; i < n_channels; i++) {830enum nl80211_band band = channels[i]->band;831struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i];832u8 iwl_band = iwl_mld_nl80211_band_to_fw(band);833u32 n_aps_flag =834iwl_mld_scan_ch_n_aps_flag(vif_type,835channels[i]->hw_value);836837if (IWL_MLD_ADAPTIVE_DWELL_NUM_APS_OVERRIDE)838n_aps_flag = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY_BIT;839840cfg->flags = cpu_to_le32(flags | n_aps_flag);841cfg->channel_num = channels[i]->hw_value;842if (cfg80211_channel_is_psc(channels[i]))843cfg->flags = 0;844845if (band == NL80211_BAND_6GHZ) {846/* 6 GHz channels should only appear in a scan request847* that has scan_6ghz set. The only exception is MLO848* scan, which has to be passive.849*/850WARN_ON_ONCE(cfg->flags != 0);851cfg->flags =852cpu_to_le32(IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE);853}854855cfg->v2.iter_count = 1;856cfg->v2.iter_interval = 0;857cfg->flags |= cpu_to_le32(iwl_band <<858IWL_CHAN_CFG_FLAGS_BAND_POS);859}860}861862static u8863iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld,864struct iwl_mld_scan_params *params,865u32 n_channels,866struct iwl_scan_probe_params_v4 *pp,867struct iwl_scan_channel_params_v7 *cp,868enum nl80211_iftype vif_type)869{870struct cfg80211_scan_6ghz_params *scan_6ghz_params =871params->scan_6ghz_params;872u32 i;873u8 ch_cnt;874875for (i = 0, ch_cnt = 0; i < params->n_channels; i++) {876struct iwl_scan_channel_cfg_umac *cfg =877&cp->channel_config[ch_cnt];878879u32 s_ssid_bitmap = 0, bssid_bitmap = 0, flags = 0;880u8 k, n_s_ssids = 0, n_bssids = 0;881u8 max_s_ssids, max_bssids;882bool force_passive = false, found = false, allow_passive = true,883unsolicited_probe_on_chan = false, psc_no_listen = false;884s8 psd_20 = IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED;885886/* Avoid performing passive scan on non PSC channels unless the887* scan is specifically a passive scan, i.e., no SSIDs888* configured in the scan command.889*/890if (!cfg80211_channel_is_psc(params->channels[i]) &&891!params->n_6ghz_params && params->n_ssids)892continue;893894cfg->channel_num = params->channels[i]->hw_value;895cfg->flags |=896cpu_to_le32(PHY_BAND_6 << IWL_CHAN_CFG_FLAGS_BAND_POS);897898cfg->v5.iter_count = 1;899cfg->v5.iter_interval = 0;900901for (u32 j = 0; j < params->n_6ghz_params; j++) {902s8 tmp_psd_20;903904if (!(scan_6ghz_params[j].channel_idx == i))905continue;906907unsolicited_probe_on_chan |=908scan_6ghz_params[j].unsolicited_probe;909910/* Use the highest PSD value allowed as advertised by911* APs for this channel912*/913tmp_psd_20 = scan_6ghz_params[j].psd_20;914if (tmp_psd_20 !=915IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED &&916(psd_20 ==917IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED ||918psd_20 < tmp_psd_20))919psd_20 = tmp_psd_20;920921psc_no_listen |= scan_6ghz_params[j].psc_no_listen;922}923924/* In the following cases apply passive scan:925* 1. Non fragmented scan:926* - PSC channel with NO_LISTEN_FLAG on should be treated927* like non PSC channel928* - Non PSC channel with more than 3 short SSIDs or more929* than 9 BSSIDs.930* - Non PSC Channel with unsolicited probe response and931* more than 2 short SSIDs or more than 6 BSSIDs.932* - PSC channel with more than 2 short SSIDs or more than933* 6 BSSIDs.934* 2. Fragmented scan:935* - PSC channel with more than 1 SSID or 3 BSSIDs.936* - Non PSC channel with more than 2 SSIDs or 6 BSSIDs.937* - Non PSC channel with unsolicited probe response and938* more than 1 SSID or more than 3 BSSIDs.939*/940if (!iwl_mld_scan_is_fragmented(params->type)) {941if (!cfg80211_channel_is_psc(params->channels[i]) ||942psc_no_listen) {943if (unsolicited_probe_on_chan) {944max_s_ssids = 2;945max_bssids = 6;946} else {947max_s_ssids = 3;948max_bssids = 9;949}950} else {951max_s_ssids = 2;952max_bssids = 6;953}954} else if (cfg80211_channel_is_psc(params->channels[i])) {955max_s_ssids = 1;956max_bssids = 3;957} else {958if (unsolicited_probe_on_chan) {959max_s_ssids = 1;960max_bssids = 3;961} else {962max_s_ssids = 2;963max_bssids = 6;964}965}966967/* To optimize the scan time, i.e., reduce the scan dwell time968* on each channel, the below logic tries to set 3 direct BSSID969* probe requests for each broadcast probe request with a short970* SSID.971*/972for (u32 j = 0; j < params->n_6ghz_params; j++) {973if (!(scan_6ghz_params[j].channel_idx == i))974continue;975976found = false;977978for (k = 0;979k < pp->short_ssid_num && n_s_ssids < max_s_ssids;980k++) {981if (!scan_6ghz_params[j].unsolicited_probe &&982le32_to_cpu(pp->short_ssid[k]) ==983scan_6ghz_params[j].short_ssid) {984/* Relevant short SSID bit set */985if (s_ssid_bitmap & BIT(k)) {986found = true;987break;988}989990/* Prefer creating BSSID entries unless991* the short SSID probe can be done in992* the same channel dwell iteration.993*994* We also need to create a short SSID995* entry for any hidden AP.996*/997if (3 * n_s_ssids > n_bssids &&998!pp->direct_scan[k].len)999break;10001001/* Hidden AP, cannot do passive scan */1002if (pp->direct_scan[k].len)1003allow_passive = false;10041005s_ssid_bitmap |= BIT(k);1006n_s_ssids++;1007found = true;1008break;1009}1010}10111012if (found)1013continue;10141015for (k = 0; k < pp->bssid_num; k++) {1016if (memcmp(&pp->bssid_array[k],1017scan_6ghz_params[j].bssid,1018ETH_ALEN))1019continue;10201021if (bssid_bitmap & BIT(k))1022break;10231024if (n_bssids < max_bssids) {1025bssid_bitmap |= BIT(k);1026n_bssids++;1027} else {1028force_passive = TRUE;1029}10301031break;1032}1033}10341035if (cfg80211_channel_is_psc(params->channels[i]) &&1036psc_no_listen)1037flags |= IWL_UHB_CHAN_CFG_FLAG_PSC_CHAN_NO_LISTEN;10381039if (unsolicited_probe_on_chan)1040flags |= IWL_UHB_CHAN_CFG_FLAG_UNSOLICITED_PROBE_RES;10411042if ((allow_passive && force_passive) ||1043(!(bssid_bitmap | s_ssid_bitmap) &&1044!cfg80211_channel_is_psc(params->channels[i])))1045flags |= IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE;1046else1047flags |= bssid_bitmap | (s_ssid_bitmap << 16);10481049cfg->flags |= cpu_to_le32(flags);1050cfg->v5.psd_20 = psd_20;10511052ch_cnt++;1053}10541055if (params->n_channels > ch_cnt)1056IWL_DEBUG_SCAN(mld,1057"6GHz: reducing number channels: (%u->%u)\n",1058params->n_channels, ch_cnt);10591060return ch_cnt;1061}10621063static int1064iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld,1065struct iwl_mld_scan_params *params,1066struct ieee80211_vif *vif,1067struct iwl_scan_req_params_v17 *scan_p,1068enum iwl_mld_scan_status scan_status)1069{1070struct iwl_scan_channel_params_v7 *chan_p = &scan_p->channel_params;1071struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params;10721073chan_p->flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif,1074scan_status);1075chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params,1076params->n_channels,1077probe_p, chan_p,1078vif->type);1079if (!chan_p->count)1080return -EINVAL;10811082if (!params->n_ssids ||1083(params->n_ssids == 1 && !params->ssids[0].ssid_len))1084chan_p->flags |= IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER;10851086return 0;1087}10881089static int1090iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,1091struct iwl_mld_scan_params *params,1092struct ieee80211_vif *vif,1093struct iwl_scan_req_params_v17 *scan_p,1094bool low_latency,1095enum iwl_mld_scan_status scan_status,1096u32 channel_cfg_flags)1097{1098struct iwl_scan_channel_params_v7 *cp = &scan_p->channel_params;1099struct ieee80211_supported_band *sband =1100&mld->nvm_data->bands[NL80211_BAND_6GHZ];11011102cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY;1103cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS;11041105if (IWL_MLD_ADAPTIVE_DWELL_NUM_APS_OVERRIDE)1106cp->n_aps_override[0] = IWL_MLD_ADAPTIVE_DWELL_NUM_APS_OVERRIDE;11071108if (params->scan_6ghz)1109return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params,1110vif, scan_p,1111scan_status);11121113/* relevant only for 2.4 GHz/5 GHz scan */1114cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif,1115low_latency);1116cp->count = params->n_channels;11171118iwl_mld_scan_cmd_set_channels(mld, params->channels, cp,1119params->n_channels, channel_cfg_flags,1120vif->type);11211122if (!params->enable_6ghz_passive)1123return 0;11241125/* fill 6 GHz passive scan cfg */1126for (int i = 0; i < sband->n_channels; i++) {1127struct ieee80211_channel *channel =1128&sband->channels[i];1129struct iwl_scan_channel_cfg_umac *cfg =1130&cp->channel_config[cp->count];11311132if (!cfg80211_channel_is_psc(channel))1133continue;11341135cfg->channel_num = channel->hw_value;1136cfg->v5.iter_count = 1;1137cfg->v5.iter_interval = 0;1138cfg->v5.psd_20 =1139IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED;1140cfg->flags = cpu_to_le32(PHY_BAND_6 <<1141IWL_CHAN_CFG_FLAGS_BAND_POS);1142cp->count++;1143}11441145return 0;1146}11471148static int1149iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif,1150struct iwl_mld_scan_params *params,1151enum iwl_mld_scan_status scan_status,1152bool low_latency)1153{1154struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd;1155struct iwl_scan_req_params_v17 *scan_p = &cmd->scan_params;1156u32 bitmap_ssid = 0;1157int uid, ret;11581159memset(mld->scan.cmd, 0, mld->scan.cmd_size);11601161/* find a free UID entry */1162uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE);1163if (uid < 0)1164return uid;11651166cmd->uid = cpu_to_le32(uid);1167cmd->ooc_priority =1168cpu_to_le32(iwl_mld_scan_ooc_priority(scan_status));11691170iwl_mld_scan_cmd_set_gen_params(mld, params, vif,1171&scan_p->general_params, scan_status);11721173ret = iwl_mld_scan_cmd_set_sched_params(params,1174scan_p->periodic_params.schedule,1175&scan_p->periodic_params.delay);1176if (ret)1177return ret;11781179iwl_mld_scan_cmd_set_probe_params(params, &scan_p->probe_params,1180&bitmap_ssid);11811182ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, scan_p,1183low_latency, scan_status,1184bitmap_ssid);1185if (ret)1186return ret;11871188return uid;1189}11901191static bool1192iwl_mld_scan_pass_all(struct iwl_mld *mld,1193struct cfg80211_sched_scan_request *req)1194{1195if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) {1196IWL_DEBUG_SCAN(mld,1197"Sending scheduled scan with filtering, n_match_sets %d\n",1198req->n_match_sets);1199mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_DISABLED;1200return false;1201}12021203IWL_DEBUG_SCAN(mld, "Sending Scheduled scan without filtering\n");1204mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_ENABLED;12051206return true;1207}12081209static int1210iwl_mld_config_sched_scan_profiles(struct iwl_mld *mld,1211struct cfg80211_sched_scan_request *req)1212{1213struct iwl_host_cmd hcmd = {1214.id = SCAN_OFFLOAD_UPDATE_PROFILES_CMD,1215.dataflags[0] = IWL_HCMD_DFL_NOCOPY,1216};1217struct iwl_scan_offload_profile *profile;1218struct iwl_scan_offload_profile_cfg_data *cfg_data;1219struct iwl_scan_offload_profile_cfg *profile_cfg;1220struct iwl_scan_offload_blocklist *blocklist;1221u32 blocklist_size = IWL_SCAN_MAX_BLACKLIST_LEN * sizeof(*blocklist);1222u32 cmd_size = blocklist_size + sizeof(*profile_cfg);1223u8 *cmd;1224int ret;12251226if (WARN_ON(req->n_match_sets > IWL_SCAN_MAX_PROFILES_V2))1227return -EIO;12281229cmd = kzalloc(cmd_size, GFP_KERNEL);1230if (!cmd)1231return -ENOMEM;12321233hcmd.data[0] = cmd;1234hcmd.len[0] = cmd_size;12351236blocklist = (struct iwl_scan_offload_blocklist *)cmd;1237profile_cfg = (struct iwl_scan_offload_profile_cfg *)(cmd + blocklist_size);12381239/* No blocklist configuration */1240cfg_data = &profile_cfg->data;1241cfg_data->num_profiles = req->n_match_sets;1242cfg_data->active_clients = SCAN_CLIENT_SCHED_SCAN;1243cfg_data->pass_match = SCAN_CLIENT_SCHED_SCAN;1244cfg_data->match_notify = SCAN_CLIENT_SCHED_SCAN;12451246if (!req->n_match_sets || !req->match_sets[0].ssid.ssid_len)1247cfg_data->any_beacon_notify = SCAN_CLIENT_SCHED_SCAN;12481249for (int i = 0; i < req->n_match_sets; i++) {1250profile = &profile_cfg->profiles[i];12511252/* Support any cipher and auth algorithm */1253profile->unicast_cipher = 0xff;1254profile->auth_alg = IWL_AUTH_ALGO_UNSUPPORTED |1255IWL_AUTH_ALGO_NONE | IWL_AUTH_ALGO_PSK |1256IWL_AUTH_ALGO_8021X | IWL_AUTH_ALGO_SAE |1257IWL_AUTH_ALGO_8021X_SHA384 | IWL_AUTH_ALGO_OWE;1258profile->network_type = IWL_NETWORK_TYPE_ANY;1259profile->band_selection = IWL_SCAN_OFFLOAD_SELECT_ANY;1260profile->client_bitmap = SCAN_CLIENT_SCHED_SCAN;1261profile->ssid_index = i;1262}12631264IWL_DEBUG_SCAN(mld,1265"Sending scheduled scan profile config (n_match_sets=%u)\n",1266req->n_match_sets);12671268ret = iwl_mld_send_cmd(mld, &hcmd);12691270kfree(cmd);12711272return ret;1273}12741275static int1276iwl_mld_sched_scan_handle_non_psc_channels(struct iwl_mld_scan_params *params,1277bool *non_psc_included)1278{1279int i, j;12801281*non_psc_included = false;1282/* for 6 GHZ band only PSC channels need to be added */1283for (i = 0; i < params->n_channels; i++) {1284struct ieee80211_channel *channel = params->channels[i];12851286if (channel->band == NL80211_BAND_6GHZ &&1287!cfg80211_channel_is_psc(channel)) {1288*non_psc_included = true;1289break;1290}1291}12921293if (!*non_psc_included)1294return 0;12951296params->channels =1297kmemdup(params->channels,1298sizeof(params->channels[0]) * params->n_channels,1299GFP_KERNEL);1300if (!params->channels)1301return -ENOMEM;13021303for (i = j = 0; i < params->n_channels; i++) {1304if (params->channels[i]->band == NL80211_BAND_6GHZ &&1305!cfg80211_channel_is_psc(params->channels[i]))1306continue;1307params->channels[j++] = params->channels[i];1308}13091310params->n_channels = j;13111312return 0;1313}13141315static void1316iwl_mld_scan_6ghz_passive_scan(struct iwl_mld *mld,1317struct iwl_mld_scan_params *params,1318struct ieee80211_vif *vif)1319{1320struct ieee80211_supported_band *sband =1321&mld->nvm_data->bands[NL80211_BAND_6GHZ];1322u32 n_disabled, i;13231324params->enable_6ghz_passive = false;13251326/* 6 GHz passive scan may be enabled in the first 2.4 GHz/5 GHz scan1327* phase to discover geo location if no AP's are found. Skip it when1328* we're in the 6 GHz scan phase.1329*/1330if (params->scan_6ghz)1331return;13321333/* 6 GHz passive scan allowed only on station interface */1334if (vif->type != NL80211_IFTYPE_STATION) {1335IWL_DEBUG_SCAN(mld,1336"6GHz passive scan: not station interface\n");1337return;1338}13391340/* 6 GHz passive scan is allowed in a defined time interval following1341* HW reset or resume flow, or while not associated and a large1342* interval has passed since the last 6 GHz passive scan.1343*/1344if ((vif->cfg.assoc ||1345time_after(mld->scan.last_6ghz_passive_jiffies +1346(IWL_MLD_6GHZ_PASSIVE_SCAN_TIMEOUT * HZ), jiffies)) &&1347(time_before(mld->scan.last_start_time_jiffies +1348(IWL_MLD_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT * HZ),1349jiffies))) {1350IWL_DEBUG_SCAN(mld, "6GHz passive scan: %s\n",1351vif->cfg.assoc ? "associated" :1352"timeout did not expire");1353return;1354}13551356/* not enough channels in the regular scan request */1357if (params->n_channels < IWL_MLD_6GHZ_PASSIVE_SCAN_MIN_CHANS) {1358IWL_DEBUG_SCAN(mld,1359"6GHz passive scan: not enough channels %d\n",1360params->n_channels);1361return;1362}13631364for (i = 0; i < params->n_ssids; i++) {1365if (!params->ssids[i].ssid_len)1366break;1367}13681369/* not a wildcard scan, so cannot enable passive 6 GHz scan */1370if (i == params->n_ssids) {1371IWL_DEBUG_SCAN(mld,1372"6GHz passive scan: no wildcard SSID\n");1373return;1374}13751376if (!sband || !sband->n_channels) {1377IWL_DEBUG_SCAN(mld,1378"6GHz passive scan: no 6GHz channels\n");1379return;1380}13811382for (i = 0, n_disabled = 0; i < sband->n_channels; i++) {1383if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED))1384n_disabled++;1385}13861387/* Not all the 6 GHz channels are disabled, so no need for 6 GHz1388* passive scan1389*/1390if (n_disabled != sband->n_channels) {1391IWL_DEBUG_SCAN(mld,1392"6GHz passive scan: 6GHz channels enabled\n");1393return;1394}13951396/* all conditions to enable 6 GHz passive scan are satisfied */1397IWL_DEBUG_SCAN(mld, "6GHz passive scan: can be enabled\n");1398params->enable_6ghz_passive = true;1399}14001401static void1402iwl_mld_scan_set_link_id(struct iwl_mld *mld, struct ieee80211_vif *vif,1403struct iwl_mld_scan_params *params,1404s8 tsf_report_link_id,1405enum iwl_mld_scan_status scan_status)1406{1407struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);1408struct iwl_mld_link *link;14091410if (tsf_report_link_id < 0) {1411if (vif->active_links)1412tsf_report_link_id = __ffs(vif->active_links);1413else1414tsf_report_link_id = 0;1415}14161417link = iwl_mld_link_dereference_check(mld_vif, tsf_report_link_id);1418if (!WARN_ON(!link)) {1419params->fw_link_id = link->fw_id;1420/* we to store fw_link_id only for regular scan,1421* and use it in scan complete notif1422*/1423if (scan_status == IWL_MLD_SCAN_REGULAR)1424mld->scan.fw_link_id = link->fw_id;1425} else {1426mld->scan.fw_link_id = IWL_MLD_INVALID_FW_ID;1427params->fw_link_id = IWL_MLD_INVALID_FW_ID;1428}1429}14301431static int1432_iwl_mld_single_scan_start(struct iwl_mld *mld, struct ieee80211_vif *vif,1433struct cfg80211_scan_request *req,1434struct ieee80211_scan_ies *ies,1435enum iwl_mld_scan_status scan_status)1436{1437struct iwl_host_cmd hcmd = {1438.id = WIDE_ID(LONG_GROUP, SCAN_REQ_UMAC),1439.len = { mld->scan.cmd_size, },1440.data = { mld->scan.cmd, },1441.dataflags = { IWL_HCMD_DFL_NOCOPY, },1442};1443struct iwl_mld_scan_iter_data scan_iter_data = {1444.current_vif = vif,1445};1446struct cfg80211_sched_scan_plan scan_plan = {.iterations = 1};1447struct iwl_mld_scan_params params = {};1448int ret, uid;14491450/* we should have failed registration if scan_cmd was NULL */1451if (WARN_ON(!mld->scan.cmd))1452return -ENOMEM;14531454if (!iwl_mld_scan_fits(mld, req->n_ssids, ies, req->n_channels))1455return -ENOBUFS;14561457ieee80211_iterate_active_interfaces_mtx(mld->hw,1458IEEE80211_IFACE_ITER_NORMAL,1459iwl_mld_scan_iterator,1460&scan_iter_data);14611462params.type = iwl_mld_get_scan_type(mld, vif, &scan_iter_data);1463params.n_ssids = req->n_ssids;1464params.flags = req->flags;1465params.n_channels = req->n_channels;1466params.delay = 0;1467params.ssids = req->ssids;1468params.channels = req->channels;1469params.mac_addr = req->mac_addr;1470params.mac_addr_mask = req->mac_addr_mask;1471params.no_cck = req->no_cck;1472params.pass_all = true;1473params.n_match_sets = 0;1474params.match_sets = NULL;1475params.scan_plans = &scan_plan;1476params.n_scan_plans = 1;14771478params.n_6ghz_params = req->n_6ghz_params;1479params.scan_6ghz_params = req->scan_6ghz_params;1480params.scan_6ghz = req->scan_6ghz;14811482ether_addr_copy(params.bssid, req->bssid);1483/* TODO: CDB - per-band flag */1484params.respect_p2p_go =1485iwl_mld_get_respect_p2p_go(mld, vif,1486scan_iter_data.global_low_latency);14871488if (req->duration)1489params.iter_notif = true;14901491iwl_mld_scan_set_link_id(mld, vif, ¶ms, req->tsf_report_link_id,1492scan_status);14931494iwl_mld_scan_build_probe_req(mld, vif, ies, ¶ms);14951496iwl_mld_scan_6ghz_passive_scan(mld, ¶ms, vif);14971498uid = iwl_mld_scan_build_cmd(mld, vif, ¶ms, scan_status,1499scan_iter_data.global_low_latency);1500if (uid < 0)1501return uid;15021503ret = iwl_mld_send_cmd(mld, &hcmd);1504if (ret) {1505IWL_ERR(mld, "Scan failed! ret %d\n", ret);1506return ret;1507}15081509IWL_DEBUG_SCAN(mld, "Scan request send success: status=%u, uid=%u\n",1510scan_status, uid);15111512mld->scan.uid_status[uid] = scan_status;1513mld->scan.status |= scan_status;15141515if (params.enable_6ghz_passive)1516mld->scan.last_6ghz_passive_jiffies = jiffies;15171518return 0;1519}15201521static int1522iwl_mld_scan_send_abort_cmd_status(struct iwl_mld *mld, int uid, u32 *status)1523{1524struct iwl_umac_scan_abort abort_cmd = {1525.uid = cpu_to_le32(uid),1526};1527struct iwl_host_cmd cmd = {1528.id = WIDE_ID(LONG_GROUP, SCAN_ABORT_UMAC),1529.flags = CMD_WANT_SKB,1530.data = { &abort_cmd },1531.len[0] = sizeof(abort_cmd),1532};1533struct iwl_rx_packet *pkt;1534struct iwl_cmd_response *resp;1535u32 resp_len;1536int ret;15371538ret = iwl_mld_send_cmd(mld, &cmd);1539if (ret)1540return ret;15411542pkt = cmd.resp_pkt;15431544resp_len = iwl_rx_packet_payload_len(pkt);1545if (IWL_FW_CHECK(mld, resp_len != sizeof(*resp),1546"Scan Abort: unexpected response length %d\n",1547resp_len)) {1548ret = -EIO;1549goto out;1550}15511552resp = (void *)pkt->data;1553*status = le32_to_cpu(resp->status);15541555out:1556iwl_free_resp(&cmd);1557return ret;1558}15591560static int1561iwl_mld_scan_abort(struct iwl_mld *mld, int type, int uid, bool *wait)1562{1563enum iwl_umac_scan_abort_status status;1564int ret;15651566*wait = true;15671568IWL_DEBUG_SCAN(mld, "Sending scan abort, uid %u\n", uid);15691570ret = iwl_mld_scan_send_abort_cmd_status(mld, uid, &status);15711572IWL_DEBUG_SCAN(mld, "Scan abort: ret=%d status=%u\n", ret, status);15731574/* We don't need to wait to scan complete in the following cases:1575* 1. Driver failed to send the scan abort cmd.1576* 2. The FW is no longer familiar with the scan that needs to be1577* stopped. It is expected that the scan complete notification was1578* already received but not yet processed.1579*1580* In both cases the flow should continue similar to the case that the1581* scan was really aborted.1582*/1583if (ret || status == IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND)1584*wait = false;15851586return ret;1587}15881589static int1590iwl_mld_scan_stop_wait(struct iwl_mld *mld, int type, int uid)1591{1592struct iwl_notification_wait wait_scan_done;1593static const u16 scan_comp_notif[] = { SCAN_COMPLETE_UMAC };1594bool wait = true;1595int ret;15961597iwl_init_notification_wait(&mld->notif_wait, &wait_scan_done,1598scan_comp_notif,1599ARRAY_SIZE(scan_comp_notif),1600NULL, NULL);16011602IWL_DEBUG_SCAN(mld, "Preparing to stop scan, type=%x\n", type);16031604ret = iwl_mld_scan_abort(mld, type, uid, &wait);1605if (ret) {1606IWL_DEBUG_SCAN(mld, "couldn't stop scan type=%d\n", type);1607goto return_no_wait;1608}16091610if (!wait) {1611IWL_DEBUG_SCAN(mld, "no need to wait for scan type=%d\n", type);1612goto return_no_wait;1613}16141615return iwl_wait_notification(&mld->notif_wait, &wait_scan_done, HZ);16161617return_no_wait:1618iwl_remove_notification(&mld->notif_wait, &wait_scan_done);1619return ret;1620}16211622int iwl_mld_sched_scan_start(struct iwl_mld *mld,1623struct ieee80211_vif *vif,1624struct cfg80211_sched_scan_request *req,1625struct ieee80211_scan_ies *ies,1626int type)1627{1628struct iwl_host_cmd hcmd = {1629.id = WIDE_ID(LONG_GROUP, SCAN_REQ_UMAC),1630.len = { mld->scan.cmd_size, },1631.data = { mld->scan.cmd, },1632.dataflags = { IWL_HCMD_DFL_NOCOPY, },1633};1634struct iwl_mld_scan_params params = {};1635struct iwl_mld_scan_iter_data scan_iter_data = {1636.current_vif = vif,1637};1638bool non_psc_included = false;1639int ret, uid;16401641/* we should have failed registration if scan_cmd was NULL */1642if (WARN_ON(!mld->scan.cmd))1643return -ENOMEM;16441645/* FW supports only a single periodic scan */1646if (mld->scan.status & (IWL_MLD_SCAN_SCHED | IWL_MLD_SCAN_NETDETECT))1647return -EBUSY;16481649ieee80211_iterate_active_interfaces_mtx(mld->hw,1650IEEE80211_IFACE_ITER_NORMAL,1651iwl_mld_scan_iterator,1652&scan_iter_data);16531654params.type = iwl_mld_get_scan_type(mld, vif, &scan_iter_data);1655params.flags = req->flags;1656params.n_ssids = req->n_ssids;1657params.ssids = req->ssids;1658params.n_channels = req->n_channels;1659params.channels = req->channels;1660params.mac_addr = req->mac_addr;1661params.mac_addr_mask = req->mac_addr_mask;1662params.no_cck = false;1663params.pass_all = iwl_mld_scan_pass_all(mld, req);1664params.n_match_sets = req->n_match_sets;1665params.match_sets = req->match_sets;1666params.n_scan_plans = req->n_scan_plans;1667params.scan_plans = req->scan_plans;1668/* TODO: CDB - per-band flag */1669params.respect_p2p_go =1670iwl_mld_get_respect_p2p_go(mld, vif,1671scan_iter_data.global_low_latency);16721673/* UMAC scan supports up to 16-bit delays, trim it down to 16-bits */1674params.delay = req->delay > U16_MAX ? U16_MAX : req->delay;16751676eth_broadcast_addr(params.bssid);16771678ret = iwl_mld_config_sched_scan_profiles(mld, req);1679if (ret)1680return ret;16811682iwl_mld_scan_build_probe_req(mld, vif, ies, ¶ms);16831684ret = iwl_mld_sched_scan_handle_non_psc_channels(¶ms,1685&non_psc_included);1686if (ret)1687goto out;16881689if (!iwl_mld_scan_fits(mld, req->n_ssids, ies, params.n_channels)) {1690ret = -ENOBUFS;1691goto out;1692}16931694uid = iwl_mld_scan_build_cmd(mld, vif, ¶ms, type,1695scan_iter_data.global_low_latency);1696if (uid < 0) {1697ret = uid;1698goto out;1699}17001701ret = iwl_mld_send_cmd(mld, &hcmd);1702if (!ret) {1703IWL_DEBUG_SCAN(mld,1704"Sched scan request send success: type=%u, uid=%u\n",1705type, uid);1706mld->scan.uid_status[uid] = type;1707mld->scan.status |= type;1708} else {1709IWL_ERR(mld, "Sched scan failed! ret %d\n", ret);1710mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_DISABLED;1711}17121713out:1714if (non_psc_included)1715kfree(params.channels);1716return ret;1717}17181719int iwl_mld_scan_stop(struct iwl_mld *mld, int type, bool notify)1720{1721int uid, ret;17221723IWL_DEBUG_SCAN(mld,1724"Request to stop scan: type=0x%x, status=0x%x\n",1725type, mld->scan.status);17261727if (!(mld->scan.status & type))1728return 0;17291730uid = iwl_mld_scan_uid_by_status(mld, type);1731/* must be valid, we just checked it's running */1732if (WARN_ON_ONCE(uid < 0))1733return uid;17341735ret = iwl_mld_scan_stop_wait(mld, type, uid);1736if (ret)1737IWL_DEBUG_SCAN(mld, "Failed to stop scan\n");17381739/* Clear the scan status so the next scan requests will1740* succeed and mark the scan as stopping, so that the Rx1741* handler doesn't do anything, as the scan was stopped from1742* above. Also remove the handler to not notify mac802111743* erroneously after a new scan starts, for example.1744*/1745mld->scan.status &= ~type;1746mld->scan.uid_status[uid] = IWL_MLD_SCAN_NONE;1747iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_SCAN,1748uid);17491750if (type == IWL_MLD_SCAN_REGULAR) {1751if (notify) {1752struct cfg80211_scan_info info = {1753.aborted = true,1754};17551756ieee80211_scan_completed(mld->hw, &info);1757}1758} else if (notify) {1759ieee80211_sched_scan_stopped(mld->hw);1760mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_DISABLED;1761}17621763return ret;1764}17651766int iwl_mld_regular_scan_start(struct iwl_mld *mld, struct ieee80211_vif *vif,1767struct cfg80211_scan_request *req,1768struct ieee80211_scan_ies *ies)1769{1770/* Clear survey data when starting the first part of a regular scan */1771if (req->first_part && mld->channel_survey)1772memset(mld->channel_survey->channels, 0,1773sizeof(mld->channel_survey->channels[0]) *1774mld->channel_survey->n_channels);17751776if (vif->type == NL80211_IFTYPE_P2P_DEVICE)1777iwl_mld_emlsr_block_tmp_non_bss(mld);17781779return _iwl_mld_single_scan_start(mld, vif, req, ies,1780IWL_MLD_SCAN_REGULAR);1781}17821783static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld,1784struct ieee80211_vif *vif,1785struct ieee80211_channel **channels,1786size_t n_channels)1787{1788struct cfg80211_scan_request *req __free(kfree) = NULL;1789struct ieee80211_scan_ies ies = {};1790size_t size;1791int ret;17921793IWL_DEBUG_SCAN(mld, "Starting Internal MLO scan: n_channels=%zu\n",1794n_channels);17951796size = struct_size(req, channels, n_channels);1797req = kzalloc(size, GFP_KERNEL);1798if (!req)1799return;18001801/* set the requested channels */1802for (int i = 0; i < n_channels; i++)1803req->channels[i] = channels[i];18041805req->n_channels = n_channels;18061807/* set the rates */1808for (int i = 0; i < NUM_NL80211_BANDS; i++)1809if (mld->wiphy->bands[i])1810req->rates[i] =1811(1 << mld->wiphy->bands[i]->n_bitrates) - 1;18121813req->wdev = ieee80211_vif_to_wdev(vif);1814req->wiphy = mld->wiphy;1815req->scan_start = jiffies;1816req->tsf_report_link_id = -1;18171818ret = _iwl_mld_single_scan_start(mld, vif, req, &ies,1819IWL_MLD_SCAN_INT_MLO);18201821if (!ret)1822mld->scan.last_mlo_scan_time = ktime_get_boottime_ns();18231824IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret);1825}18261827#define IWL_MLD_MLO_SCAN_BLOCKOUT_TIME 5 /* seconds */18281829void iwl_mld_int_mlo_scan(struct iwl_mld *mld, struct ieee80211_vif *vif)1830{1831struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS];1832struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);1833unsigned long usable_links = ieee80211_vif_usable_links(vif);1834size_t n_channels = 0;1835u8 link_id;18361837lockdep_assert_wiphy(mld->wiphy);18381839if (!IWL_MLD_AUTO_EML_ENABLE || !vif->cfg.assoc ||1840!ieee80211_vif_is_mld(vif) || hweight16(vif->valid_links) == 1)1841return;18421843if (mld->scan.status & IWL_MLD_SCAN_INT_MLO) {1844IWL_DEBUG_SCAN(mld, "Internal MLO scan is already running\n");1845return;1846}18471848if (mld_vif->last_link_activation_time > ktime_get_boottime_seconds() -1849IWL_MLD_MLO_SCAN_BLOCKOUT_TIME) {1850/* timing doesn't matter much, so use the blockout time */1851wiphy_delayed_work_queue(mld->wiphy,1852&mld_vif->mlo_scan_start_wk,1853IWL_MLD_MLO_SCAN_BLOCKOUT_TIME);1854return;1855}18561857for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {1858struct ieee80211_bss_conf *link_conf =1859link_conf_dereference_check(vif, link_id);18601861if (WARN_ON_ONCE(!link_conf))1862continue;18631864channels[n_channels++] = link_conf->chanreq.oper.chan;1865}18661867if (!n_channels)1868return;18691870iwl_mld_int_mlo_scan_start(mld, vif, channels, n_channels);1871}18721873void iwl_mld_handle_scan_iter_complete_notif(struct iwl_mld *mld,1874struct iwl_rx_packet *pkt)1875{1876struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data;1877u32 uid = __le32_to_cpu(notif->uid);18781879if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status),1880"FW reports out-of-range scan UID %d\n", uid))1881return;18821883if (mld->scan.uid_status[uid] == IWL_MLD_SCAN_REGULAR)1884mld->scan.start_tsf = le64_to_cpu(notif->start_tsf);18851886IWL_DEBUG_SCAN(mld,1887"UMAC Scan iteration complete: status=0x%x scanned_channels=%d\n",1888notif->status, notif->scanned_channels);18891890if (mld->scan.pass_all_sched_res == SCHED_SCAN_PASS_ALL_STATE_FOUND) {1891IWL_DEBUG_SCAN(mld, "Pass all scheduled scan results found\n");1892ieee80211_sched_scan_results(mld->hw);1893mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_ENABLED;1894}18951896IWL_DEBUG_SCAN(mld,1897"UMAC Scan iteration complete: scan started at %llu (TSF)\n",1898le64_to_cpu(notif->start_tsf));1899}19001901void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,1902struct iwl_rx_packet *pkt)1903{1904IWL_DEBUG_SCAN(mld, "Scheduled scan results\n");1905ieee80211_sched_scan_results(mld->hw);1906}19071908void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,1909struct iwl_rx_packet *pkt)1910{1911struct iwl_umac_scan_complete *notif = (void *)pkt->data;1912bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED);1913u32 uid = __le32_to_cpu(notif->uid);19141915if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status),1916"FW reports out-of-range scan UID %d\n", uid))1917return;19181919IWL_DEBUG_SCAN(mld,1920"Scan completed: uid=%u type=%u, status=%s, EBS=%s\n",1921uid, mld->scan.uid_status[uid],1922notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?1923"completed" : "aborted",1924iwl_mld_scan_ebs_status_str(notif->ebs_status));1925IWL_DEBUG_SCAN(mld, "Scan completed: scan_status=0x%x\n",1926mld->scan.status);1927IWL_DEBUG_SCAN(mld,1928"Scan completed: line=%u, iter=%u, elapsed time=%u\n",1929notif->last_schedule, notif->last_iter,1930__le32_to_cpu(notif->time_from_last_iter));19311932if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status),1933"FW reports scan UID %d we didn't trigger\n", uid))1934return;19351936/* if the scan is already stopping, we don't need to notify mac80211 */1937if (mld->scan.uid_status[uid] == IWL_MLD_SCAN_REGULAR) {1938struct cfg80211_scan_info info = {1939.aborted = aborted,1940.scan_start_tsf = mld->scan.start_tsf,1941};1942int fw_link_id = mld->scan.fw_link_id;1943struct ieee80211_bss_conf *link_conf = NULL;19441945if (fw_link_id != IWL_MLD_INVALID_FW_ID)1946link_conf =1947wiphy_dereference(mld->wiphy,1948mld->fw_id_to_bss_conf[fw_link_id]);19491950/* It is possible that by the time the scan is complete the1951* link was already removed and is not valid.1952*/1953if (link_conf)1954ether_addr_copy(info.tsf_bssid, link_conf->bssid);1955else1956IWL_DEBUG_SCAN(mld, "Scan link is no longer valid\n");19571958ieee80211_scan_completed(mld->hw, &info);19591960/* Scan is over, we can check again the tpt counters */1961iwl_mld_stop_ignoring_tpt_updates(mld);1962} else if (mld->scan.uid_status[uid] == IWL_MLD_SCAN_SCHED) {1963ieee80211_sched_scan_stopped(mld->hw);1964mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_DISABLED;1965} else if (mld->scan.uid_status[uid] == IWL_MLD_SCAN_INT_MLO) {1966IWL_DEBUG_SCAN(mld, "Internal MLO scan completed\n");19671968/*1969* We limit link selection to internal MLO scans as otherwise1970* we do not know whether all channels were covered.1971*/1972iwl_mld_select_links(mld);1973}19741975mld->scan.status &= ~mld->scan.uid_status[uid];19761977IWL_DEBUG_SCAN(mld, "Scan completed: after update: scan_status=0x%x\n",1978mld->scan.status);19791980mld->scan.uid_status[uid] = IWL_MLD_SCAN_NONE;19811982if (notif->ebs_status != IWL_SCAN_EBS_SUCCESS &&1983notif->ebs_status != IWL_SCAN_EBS_INACTIVE)1984mld->scan.last_ebs_failed = true;1985}19861987/* This function is used in nic restart flow, to inform mac80211 about scans1988* that were aborted by restart flow or by an assert.1989*/1990void iwl_mld_report_scan_aborted(struct iwl_mld *mld)1991{1992int uid;19931994uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_REGULAR);1995if (uid >= 0) {1996struct cfg80211_scan_info info = {1997.aborted = true,1998};19992000ieee80211_scan_completed(mld->hw, &info);2001mld->scan.uid_status[uid] = IWL_MLD_SCAN_NONE;2002}20032004uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_SCHED);2005if (uid >= 0) {2006mld->scan.pass_all_sched_res = SCHED_SCAN_PASS_ALL_STATE_DISABLED;2007mld->scan.uid_status[uid] = IWL_MLD_SCAN_NONE;20082009/* sched scan will be restarted by mac80211 in reconfig.2010* report to mac80211 that sched scan stopped only if we won't2011* restart the firmware.2012*/2013if (!iwlwifi_mod_params.fw_restart)2014ieee80211_sched_scan_stopped(mld->hw);2015}20162017uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_INT_MLO);2018if (uid >= 0) {2019IWL_DEBUG_SCAN(mld, "Internal MLO scan aborted\n");2020mld->scan.uid_status[uid] = IWL_MLD_SCAN_NONE;2021}20222023BUILD_BUG_ON(IWL_MLD_SCAN_NONE != 0);2024memset(mld->scan.uid_status, 0, sizeof(mld->scan.uid_status));2025}20262027int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld)2028{2029u8 scan_cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, SCAN_REQ_UMAC,2030IWL_FW_CMD_VER_UNKNOWN);2031size_t scan_cmd_size;20322033if (scan_cmd_ver == 17) {2034scan_cmd_size = sizeof(struct iwl_scan_req_umac_v17);2035} else {2036IWL_ERR(mld, "Unexpected scan cmd version %d\n", scan_cmd_ver);2037return -EINVAL;2038}20392040mld->scan.cmd = kmalloc(scan_cmd_size, GFP_KERNEL);2041if (!mld->scan.cmd)2042return -ENOMEM;20432044mld->scan.cmd_size = scan_cmd_size;20452046return 0;2047}20482049static int iwl_mld_chanidx_from_phy(struct iwl_mld *mld,2050enum nl80211_band band,2051u16 phy_chan_num)2052{2053struct ieee80211_supported_band *sband = mld->wiphy->bands[band];20542055if (WARN_ON_ONCE(!sband))2056return -EINVAL;20572058for (int chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) {2059struct ieee80211_channel *channel = &sband->channels[chan_idx];20602061if (channel->hw_value == phy_chan_num)2062return chan_idx;2063}20642065return -EINVAL;2066}20672068void iwl_mld_handle_channel_survey_notif(struct iwl_mld *mld,2069struct iwl_rx_packet *pkt)2070{2071const struct iwl_umac_scan_channel_survey_notif *notif =2072(void *)pkt->data;2073struct iwl_mld_survey_channel *info;2074enum nl80211_band band;2075int chan_idx;20762077if (!mld->channel_survey) {2078size_t n_channels = 0;20792080for (band = 0; band < NUM_NL80211_BANDS; band++) {2081if (!mld->wiphy->bands[band])2082continue;20832084n_channels += mld->wiphy->bands[band]->n_channels;2085}20862087mld->channel_survey = kzalloc(struct_size(mld->channel_survey,2088channels, n_channels),2089GFP_KERNEL);20902091if (!mld->channel_survey)2092return;20932094mld->channel_survey->n_channels = n_channels;2095n_channels = 0;2096for (band = 0; band < NUM_NL80211_BANDS; band++) {2097if (!mld->wiphy->bands[band])2098continue;20992100mld->channel_survey->bands[band] =2101&mld->channel_survey->channels[n_channels];2102n_channels += mld->wiphy->bands[band]->n_channels;2103}2104}21052106band = iwl_mld_phy_band_to_nl80211(le32_to_cpu(notif->band));2107chan_idx = iwl_mld_chanidx_from_phy(mld, band,2108le32_to_cpu(notif->channel));2109if (WARN_ON_ONCE(chan_idx < 0))2110return;21112112IWL_DEBUG_SCAN(mld, "channel survey received for freq %d\n",2113mld->wiphy->bands[band]->channels[chan_idx].center_freq);21142115info = &mld->channel_survey->bands[band][chan_idx];21162117/* Times are all in ms */2118info->time = le32_to_cpu(notif->active_time);2119info->time_busy = le32_to_cpu(notif->busy_time);2120info->noise =2121iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise));2122}21232124int iwl_mld_mac80211_get_survey(struct ieee80211_hw *hw, int idx,2125struct survey_info *survey)2126{2127struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2128int curr_idx = 0;21292130if (!mld->channel_survey)2131return -ENOENT;21322133/* Iterate bands/channels to find the requested index.2134* Logically this returns the entry with index "idx" from a flattened2135* survey result array that only contains channels with information.2136* The current index into this flattened array is tracked in curr_idx.2137*/2138for (enum nl80211_band band = 0; band < NUM_NL80211_BANDS; band++) {2139struct ieee80211_supported_band *sband =2140mld->wiphy->bands[band];21412142if (!sband)2143continue;21442145for (int per_band_idx = 0;2146per_band_idx < sband->n_channels;2147per_band_idx++) {2148struct iwl_mld_survey_channel *info =2149&mld->channel_survey->bands[band][per_band_idx];21502151/* Skip entry entirely, it was not reported/scanned,2152* do not increase curr_idx for this entry.2153*/2154if (!info->time)2155continue;21562157/* Search did not reach the requested entry yet,2158* increment curr_idx and continue.2159*/2160if (idx != curr_idx) {2161curr_idx++;2162continue;2163}21642165/* Found (the next) channel to report */2166survey->channel = &sband->channels[per_band_idx];2167survey->filled = SURVEY_INFO_TIME |2168SURVEY_INFO_TIME_BUSY;2169survey->time = info->time;2170survey->time_busy = info->time_busy;2171survey->noise = info->noise;2172if (survey->noise < 0)2173survey->filled |= SURVEY_INFO_NOISE_DBM;21742175return 0;2176}2177}21782179return -ENOENT;2180}218121822183