Commit 0d255883 authored by Avraham Stern's avatar Avraham Stern Committed by Johannes Berg

wifi: iwlwifi: modify scan request and results when in link protection

When CSME is connected and has link protection set, the driver must
connect to the same AP CSME is connected to.
When in link protection, modify scan request parameters to include
only the channel of the AP CSME is connected to and scan for the
same SSID. In addition, filter the scan results to include only
results from the same AP. This will make sure the driver will connect
to the same AP and will do it fast enough to keep the session alive.
Signed-off-by: default avatarAvraham Stern <avraham.stern@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230418122405.c1b55de3d704.I3895eebe18b3b672607695c887d728e113fc85ec@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 0120e6b3
...@@ -826,6 +826,12 @@ struct iwl_time_sync_data { ...@@ -826,6 +826,12 @@ struct iwl_time_sync_data {
bool active; bool active;
}; };
struct iwl_mei_scan_filter {
bool is_mei_limited_scan;
struct sk_buff_head scan_res;
struct work_struct scan_work;
};
struct iwl_mvm { struct iwl_mvm {
/* for logger access */ /* for logger access */
struct device *dev; struct device *dev;
...@@ -1177,6 +1183,8 @@ struct iwl_mvm { ...@@ -1177,6 +1183,8 @@ struct iwl_mvm {
bool pldr_sync; bool pldr_sync;
struct iwl_time_sync_data time_sync; struct iwl_time_sync_data time_sync;
struct iwl_mei_scan_filter mei_scan_filter;
}; };
/* Extract MVM priv from op_mode and _hw */ /* Extract MVM priv from op_mode and _hw */
...@@ -2304,6 +2312,7 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, ...@@ -2304,6 +2312,7 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
const struct ieee80211_sta *sta, const struct ieee80211_sta *sta,
u16 tid); u16 tid);
void iwl_mvm_mei_scan_filter_init(struct iwl_mei_scan_filter *mei_scan_filter);
void iwl_mvm_ptp_init(struct iwl_mvm *mvm); void iwl_mvm_ptp_init(struct iwl_mvm *mvm);
void iwl_mvm_ptp_remove(struct iwl_mvm *mvm); void iwl_mvm_ptp_remove(struct iwl_mvm *mvm);
...@@ -2515,6 +2524,22 @@ static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm) ...@@ -2515,6 +2524,22 @@ static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)
sw_rfkill); sw_rfkill);
} }
static inline bool iwl_mvm_mei_filter_scan(struct iwl_mvm *mvm,
struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
if (mvm->mei_scan_filter.is_mei_limited_scan &&
(ieee80211_is_probe_resp(mgmt->frame_control) ||
ieee80211_is_beacon(mgmt->frame_control))) {
skb_queue_tail(&mvm->mei_scan_filter.scan_res, skb);
schedule_work(&mvm->mei_scan_filter.scan_work);
return true;
}
return false;
}
void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm, void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
bool forbidden); bool forbidden);
......
...@@ -1375,6 +1375,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -1375,6 +1375,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->mei_registered = !iwl_mei_register(mvm, &mei_ops); mvm->mei_registered = !iwl_mei_register(mvm, &mei_ops);
iwl_mvm_mei_scan_filter_init(&mvm->mei_scan_filter);
if (iwl_mvm_start_get_nvm(mvm)) { if (iwl_mvm_start_get_nvm(mvm)) {
/* /*
* Getting NVM failed while CSME is the owner, but we are * Getting NVM failed while CSME is the owner, but we are
......
...@@ -2588,10 +2588,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -2588,10 +2588,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
} }
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc) && if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc) &&
likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr2))) likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr2)) &&
likely(!iwl_mvm_mei_filter_scan(mvm, skb)))
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta, iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta,
link_sta); link_sta);
out: out:
rcu_read_unlock(); rcu_read_unlock();
} }
......
...@@ -2624,6 +2624,80 @@ static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { ...@@ -2624,6 +2624,80 @@ static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
IWL_SCAN_UMAC_HANDLER(12), IWL_SCAN_UMAC_HANDLER(12),
}; };
static void iwl_mvm_mei_scan_work(struct work_struct *wk)
{
struct iwl_mei_scan_filter *scan_filter =
container_of(wk, struct iwl_mei_scan_filter, scan_work);
struct iwl_mvm *mvm =
container_of(scan_filter, struct iwl_mvm, mei_scan_filter);
struct iwl_mvm_csme_conn_info *info;
struct sk_buff *skb;
u8 bssid[ETH_ALEN];
mutex_lock(&mvm->mutex);
info = iwl_mvm_get_csme_conn_info(mvm);
memcpy(bssid, info->conn_info.bssid, ETH_ALEN);
mutex_unlock(&mvm->mutex);
while ((skb = skb_dequeue(&scan_filter->scan_res))) {
struct ieee80211_mgmt *mgmt = (void *)skb->data;
if (!memcmp(mgmt->bssid, bssid, ETH_ALEN))
ieee80211_rx_irqsafe(mvm->hw, skb);
else
kfree_skb(skb);
}
}
void iwl_mvm_mei_scan_filter_init(struct iwl_mei_scan_filter *mei_scan_filter)
{
skb_queue_head_init(&mei_scan_filter->scan_res);
INIT_WORK(&mei_scan_filter->scan_work, iwl_mvm_mei_scan_work);
}
/* In case CSME is connected and has link protection set, this function will
* override the scan request to scan only the associated channel and only for
* the associated SSID.
*/
static void iwl_mvm_mei_limited_scan(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params)
{
struct iwl_mvm_csme_conn_info *info = iwl_mvm_get_csme_conn_info(mvm);
struct iwl_mei_conn_info *conn_info;
struct ieee80211_channel *chan;
if (!info) {
IWL_DEBUG_SCAN(mvm, "mei_limited_scan: no connection info\n");
return;
}
conn_info = &info->conn_info;
if (!info->conn_info.lp_state || !info->conn_info.ssid_len)
return;
if (!params->n_channels || !params->n_ssids)
return;
mvm->mei_scan_filter.is_mei_limited_scan = true;
chan = ieee80211_get_channel(mvm->hw->wiphy,
ieee80211_channel_to_frequency(conn_info->channel,
conn_info->band));
if (!chan) {
IWL_DEBUG_SCAN(mvm,
"Failed to get CSME channel (chan=%u band=%u)\n",
conn_info->channel, conn_info->band);
return;
}
params->n_channels = 1;
params->channels[0] = chan;
params->n_ssids = 1;
params->ssids[0].ssid_len = conn_info->ssid_len;
memcpy(params->ssids[0].ssid, conn_info->ssid, conn_info->ssid_len);
}
static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct iwl_host_cmd *hcmd, struct iwl_host_cmd *hcmd,
...@@ -2636,6 +2710,8 @@ static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, ...@@ -2636,6 +2710,8 @@ static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
memset(mvm->scan_cmd, 0, mvm->scan_cmd_size); memset(mvm->scan_cmd, 0, mvm->scan_cmd_size);
iwl_mvm_mei_limited_scan(mvm, params);
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
hcmd->id = SCAN_OFFLOAD_REQUEST_CMD; hcmd->id = SCAN_OFFLOAD_REQUEST_CMD;
...@@ -2992,6 +3068,8 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, ...@@ -2992,6 +3068,8 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
u32 uid = __le32_to_cpu(notif->uid); u32 uid = __le32_to_cpu(notif->uid);
bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED); bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED);
mvm->mei_scan_filter.is_mei_limited_scan = false;
if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status))) if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status)))
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment