wifi: iwlwifi: modify scan request and results when in link protection
authorAvraham Stern <avraham.stern@intel.com>
Tue, 18 Apr 2023 09:28:11 +0000 (12:28 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 20 Apr 2023 09:45:55 +0000 (11:45 +0200)
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: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230418122405.c1b55de3d704.I3895eebe18b3b672607695c887d728e113fc85ec@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c

index 203eb72..6e7470d 100644 (file)
@@ -826,6 +826,12 @@ struct iwl_time_sync_data {
        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 {
        /* for logger access */
        struct device *dev;
@@ -1177,6 +1183,8 @@ struct iwl_mvm {
        bool pldr_sync;
 
        struct iwl_time_sync_data time_sync;
+
+       struct iwl_mei_scan_filter mei_scan_filter;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -2304,6 +2312,7 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
                                          struct ieee80211_vif *vif,
                                          const struct ieee80211_sta *sta,
                                          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_remove(struct iwl_mvm *mvm);
@@ -2515,6 +2524,22 @@ static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)
                                         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,
                                          struct ieee80211_vif *vif,
                                          bool forbidden);
index 8bb865e..26c3f00 100644 (file)
@@ -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);
 
+       iwl_mvm_mei_scan_filter_init(&mvm->mei_scan_filter);
+
        if (iwl_mvm_start_get_nvm(mvm)) {
                /*
                 * Getting NVM failed while CSME is the owner, but we are
index 542f665..e1d02c2 100644 (file)
@@ -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) &&
-           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,
                                                link_sta);
-
 out:
        rcu_read_unlock();
 }
index 1e20f95..fe7cb33 100644 (file)
@@ -2624,6 +2624,80 @@ static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
        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,
                                  struct ieee80211_vif *vif,
                                  struct iwl_host_cmd *hcmd,
@@ -2636,6 +2710,8 @@ static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm,
        lockdep_assert_held(&mvm->mutex);
        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)) {
                hcmd->id = SCAN_OFFLOAD_REQUEST_CMD;
 
@@ -2992,6 +3068,8 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
        u32 uid = __le32_to_cpu(notif->uid);
        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)))
                return;