瀏覽代碼

qcacld-3.0: Update correct chan info to kernel

Scenario here is:
1. AP configured in 320 MHz
2. Set country code = KR in DUT, It means DUT does not
   support connection in 320 MHz.
3. Trigger connection with AP, while processing driver
   founds, country code is KR, so downgraded connected
   channel with to next max supported channel width as
   per regulatory rule (which is 160 MHz here) and
   successfully associated with AP in 160 MHz.
4. After connection Host receives “get_channel” request
   from kernel.
5. Host gets currently connected BSSID and fetch
   corresponding channel information from scan cache.
6. As scan cache gets updated via beacon/probe response
   from AP and here advertise beacon/probe response in
   320 MHz. This results value of channel width for
   connected BSSID is 320 MHz and same host fill in
   get_channel response.
7. By this time driver connected in 160 MHz and
   connected channel width indicated to kernel is 320 MHz.
   Due to mismatch in channel width, kernel triggered
   disconnection.

Fix is to update connected channel width in response to
“get_channel” request.

Change-Id: I7c4a262d337f9deb8cb4436cae537d0069a98de1
CRs-Fixed: 3810073
Abhinav Kumar 1 年之前
父節點
當前提交
99708500c0
共有 1 個文件被更改,包括 61 次插入20 次删除
  1. 61 20
      core/hdd/src/wlan_hdd_cfg80211.c

+ 61 - 20
core/hdd/src/wlan_hdd_cfg80211.c

@@ -29044,12 +29044,47 @@ static int wlan_hdd_cfg80211_get_vdev_chan_info(struct hdd_context *hdd_ctx,
 	chan_info->ch_cfreq1 = ch_params.mhz_freq_seg0;
 	chan_info->ch_cfreq2 = ch_params.mhz_freq_seg1;
 
-	hdd_debug("vdev: %d, freq: %d, freq1: %d, freq2: %d, ch_width: %d",
+	hdd_debug("vdev: %d, freq: %d, freq1: %d, freq2: %d, ch_width: %d, max_ch_width:%d",
 		  vdev_id, chan_info->ch_freq, chan_info->ch_cfreq1,
-		  chan_info->ch_cfreq2, chan_info->ch_width);
+		  chan_info->ch_cfreq2, chan_info->ch_width,
+		  ch_params.ch_width);
+
 	return 0;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
+static int
+wlan_hdd_get_standby_link_chan_info(struct hdd_adapter *adapter, int link_id,
+				    struct wlan_channel *chan_info)
+{
+	struct wlan_objmgr_vdev *vdev;
+	int ret;
+
+	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
+	if (!vdev)
+		return -EINVAL;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		hdd_debug("not a mlo vdev");
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+		return -EINVAL;
+	}
+
+	ret = mlo_mgr_get_per_link_chan_info(vdev, link_id, chan_info);
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+
+	return ret;
+}
+#else
+static inline int
+wlan_hdd_get_standby_link_chan_info(struct hdd_adapter *adapter, int link_id,
+				    struct wlan_channel *chan_info)
+{
+	return -EINVAL;
+}
+#endif
+
 static int
 wlan_hdd_cfg80211_get_channel_sta(struct wiphy *wiphy,
 				  struct cfg80211_chan_def *chandef,
@@ -29057,7 +29092,7 @@ wlan_hdd_cfg80211_get_channel_sta(struct wiphy *wiphy,
 				  struct hdd_adapter *adapter, int link_id)
 {
 	struct hdd_station_ctx *sta_ctx = NULL;
-	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_vdev *link_vdev;
 	bool is_legacy_phymode = false;
 	struct wlan_channel chan_info;
 	int ret = 0;
@@ -29072,16 +29107,13 @@ wlan_hdd_cfg80211_get_channel_sta(struct wiphy *wiphy,
 	if (sta_ctx->conn_info.dot11mode < eCSR_CFG_DOT11_MODE_11N)
 		is_legacy_phymode = true;
 
-	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
-	if (!vdev) {
-		hdd_debug("vdev null");
-		return -EINVAL;
-	}
-
-	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
-		ret = mlo_mgr_get_per_link_chan_info(vdev, link_id, &chan_info);
-		if (ret != 0)
-			goto release;
+	link_vdev = wlan_key_get_link_vdev(adapter, WLAN_OSIF_ID, link_id);
+	if (!link_vdev) {
+		/* request is for standby link */
+		ret =  wlan_hdd_get_standby_link_chan_info(adapter, link_id,
+							   &chan_info);
+		if (ret)
+			return ret;
 
 		ch_params.ch_width = chan_info.ch_width;
 		ch_params.center_freq_seg1 = chan_info.ch_cfreq2;
@@ -29091,12 +29123,23 @@ wlan_hdd_cfg80211_get_channel_sta(struct wiphy *wiphy,
 							REG_CURRENT_PWR_MODE);
 		chan_info.ch_cfreq1 = ch_params.mhz_freq_seg0;
 		chan_info.ch_cfreq2 = ch_params.mhz_freq_seg1;
+		hdd_debug("max allowed ch_width:%d, ap ch_width: %d",
+			  ch_params.ch_width, chan_info.ch_width);
+		/*
+		 * To take care scenarios when AP channel width and max
+		 * supported ch_width for connection in STA may different.
+		 * For example, a case where AP advertise beacon/probe response
+		 * in 320 MHz and STA (configured with country code = KR)
+		 * supports max ch_width 160 MHz.
+		 */
+		if (ch_params.ch_width < chan_info.ch_width)
+			chan_info.ch_width = ch_params.ch_width;
 	} else {
-		ret = wlan_hdd_cfg80211_get_vdev_chan_info(hdd_ctx, vdev,
-							   link_id,
-							   &chan_info);
-		if (ret != 0)
-			goto release;
+		ret = wlan_hdd_cfg80211_get_vdev_chan_info(hdd_ctx, link_vdev,
+							   link_id, &chan_info);
+		wlan_key_put_link_vdev(link_vdev, WLAN_OSIF_ID);
+		if (ret)
+			return ret;
 	}
 
 	chandef->chan = ieee80211_get_channel(wiphy, chan_info.ch_freq);
@@ -29112,8 +29155,6 @@ wlan_hdd_cfg80211_get_channel_sta(struct wiphy *wiphy,
 		  chan_info.ch_freq, chandef->width, chandef->center_freq1,
 		  chandef->center_freq2);
 
-release:
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
 	return ret;
 }