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 203eb7233c77b96468833bb73103a6dc2a469320..6e7470d3a826d35ded09d840985893907205d671 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 8bb865e708dc4fd6a01726aaee000b97c95270e4..26c3f00d6f7dfd8ed475a4a0c0241e5e7a30704c 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 542f6658f2d4566f6581fbd158f3586809f18006..e1d02c260e69d504a35f6ddf3cf8d04b23751a9a 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 1e20f9538640dc400f9d1127409a4ddb48eac7dc..fe7cb33d55934081b057dc09c96a4c400b4c060b 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;