Browse Source

qcacmn: Add only frames with valid channel in scan cache

Kernel reject the beacon/probe resp frame with invalid channel in
DS,HT info and HE IE, but same frame is added in the scan cache
and when mlme refer this frame, connect issues are seen due to
invalid channel.

Thus do not add the entry in scan cache.

Change-Id: Ib2891f95034b04be26c5feefed7c4354d8bb367a
CRs-Fixed: 2708975
Utkarsh Bhatnagar 5 years ago
parent
commit
1035366308

+ 13 - 1
umac/scan/core/src/wlan_scan_cache_db.c

@@ -955,7 +955,19 @@ QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn)
 			qdf_mem_free(scan_node);
 			continue;
 		}
-
+		/* Do not add invalid channel entry as kernel will reject it */
+		if (scan_obj->drop_bcn_on_invalid_freq &&
+		    wlan_reg_is_disable_for_freq(pdev,
+					scan_entry->channel.chan_freq)) {
+			scm_nofl_debug("Drop frame for invalid freq %d: %pM Seq Num: %d RSSI %d",
+				       scan_entry->channel.chan_freq,
+				       scan_entry->bssid.bytes,
+				       scan_entry->seq_num,
+				       scan_entry->rssi_raw);
+			util_scan_free_cache_entry(scan_entry);
+			qdf_mem_free(scan_node);
+			continue;
+		}
 		if (scan_obj->cb.update_beacon)
 			scan_obj->cb.update_beacon(pdev, scan_entry);
 

+ 2 - 0
umac/scan/core/src/wlan_scan_main.h

@@ -493,6 +493,7 @@ struct scan_cb {
  * @miracast_enabled: miracast enabled
  * @disable_timeout: command timeout disabled
  * @drop_bcn_on_chan_mismatch: drop bcn if channel mismatch
+ * @drop_bcn_on_invalid_freq: drop bcn if freq is invalid in IEs (DS/HT/HE)
  * @scan_start_request_buff: buffer used to pass
  *      scan config to event handlers
  * @rnr_channel_db: RNR channel list database
@@ -519,6 +520,7 @@ struct wlan_scan_obj {
 	bool miracast_enabled;
 	bool disable_timeout;
 	bool drop_bcn_on_chan_mismatch;
+	bool drop_bcn_on_invalid_freq;
 	struct scan_start_request scan_start_request_buff;
 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
 	struct channel_list_db rnr_channel_db;

+ 22 - 0
umac/scan/dispatcher/inc/wlan_scan_cfg.h

@@ -58,6 +58,27 @@ enum scan_mode_6ghz {
 		true,\
 		"drop bcn on channel mismatch")
 
+/*
+ * <ini>
+ * drop_bcn_on_invalid_freq - drop the beacon or probe resp with invalid freq
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to decide whether to drop the beacon/probe resp or not
+ * if channel received in DS param, HT info and HE IE is invalid.
+ *
+ * Related: None
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_DROP_BCN_ON_INVALID_FREQ CFG_INI_BOOL(\
+		"drop_bcn_on_invalid_freq",\
+		true,\
+		"drop bcn on invalid freq in HT, DS, HE IE")
+
 /*
  * <ini>
  * gActiveMaxChannelTime - Set max channel time for active scan
@@ -1206,6 +1227,7 @@ enum scan_mode_6ghz {
 
 #define CFG_SCAN_ALL \
 	CFG(CFG_DROP_BCN_ON_CHANNEL_MISMATCH) \
+	CFG(CFG_DROP_BCN_ON_INVALID_FREQ) \
 	CFG(CFG_ENABLE_WAKE_LOCK_IN_SCAN) \
 	CFG(CFG_ACTIVE_MAX_CHANNEL_TIME) \
 	CFG(CFG_ENABLE_DFS_SCAN) \

+ 2 - 0
umac/scan/dispatcher/src/wlan_scan_ucfg_api.c

@@ -936,6 +936,8 @@ wlan_scan_global_init(struct wlan_objmgr_psoc *psoc,
 	scan_obj->scan_disabled = 0;
 	scan_obj->drop_bcn_on_chan_mismatch =
 			 cfg_get(psoc, CFG_DROP_BCN_ON_CHANNEL_MISMATCH);
+	scan_obj->drop_bcn_on_invalid_freq =
+			 cfg_get(psoc, CFG_DROP_BCN_ON_INVALID_FREQ);
 	scan_obj->disable_timeout = false;
 	scan_obj->scan_def.active_dwell =
 			 cfg_get(psoc, CFG_ACTIVE_MAX_CHANNEL_TIME);

+ 104 - 30
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -236,25 +236,52 @@ static struct he_oper_6g_param *util_scan_get_he_6g_params(uint8_t *he_ops)
 	return (struct he_oper_6g_param *)he_ops;
 }
 
-static void
-util_scan_get_chan_from_he_6g_params(struct scan_cache_entry *scan_params,
-				     uint8_t *chan_idx, bool *he_6g_dup_bcon)
+static QDF_STATUS
+util_scan_get_chan_from_he_6g_params(struct wlan_objmgr_pdev *pdev,
+				     struct scan_cache_entry *scan_params,
+				     qdf_freq_t *chan_freq,
+				     bool *he_6g_dup_bcon, uint8_t band_mask)
 {
 	struct he_oper_6g_param *he_6g_params;
 	uint8_t *he_ops;
+	struct wlan_scan_obj *scan_obj;
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		scm_err("psoc is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	scan_obj = wlan_psoc_get_scan_obj(psoc);
+	if (!scan_obj) {
+		scm_err("scan_obj is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
 
 	*he_6g_dup_bcon = false;
 
 	he_ops = util_scan_entry_heop(scan_params);
 	if (!util_scan_entry_hecap(scan_params) || !he_ops)
-		return;
+		return QDF_STATUS_SUCCESS;
 
 	he_6g_params = util_scan_get_he_6g_params(he_ops);
 	if (!he_6g_params)
-		return;
+		return QDF_STATUS_SUCCESS;
 
-	*chan_idx = he_6g_params->primary_channel;
+	*chan_freq = wlan_reg_chan_band_to_freq(pdev,
+						he_6g_params->primary_channel,
+						band_mask);
+	if (scan_obj->drop_bcn_on_invalid_freq &&
+	    wlan_reg_is_disable_for_freq(pdev, *chan_freq)) {
+		scm_debug_rl("%pM: Drop as invalid channel %d freq %d in HE 6Ghz params",
+			     scan_params->bssid.bytes,
+			     he_6g_params->primary_channel, *chan_freq);
+		return QDF_STATUS_E_INVAL;
+	}
 	*he_6g_dup_bcon = he_6g_params->duplicate_beacon ? true : false;
+
+	return QDF_STATUS_SUCCESS;
 }
 
 static enum wlan_phymode
@@ -312,10 +339,15 @@ util_scan_get_phymode_6g(struct wlan_objmgr_pdev *pdev,
 	return phymode;
 }
 #else
-static void
-util_scan_get_chan_from_he_6g_params(struct scan_cache_entry *scan_params,
-				     uint8_t *chan_idx, bool *he_6g_dup_bcon)
-{}
+static QDF_STATUS
+util_scan_get_chan_from_he_6g_params(struct wlan_objmgr_pdev *pdev,
+				     struct scan_cache_entry *scan_params,
+				     qdf_freq_t *chan_freq,
+				     bool *he_6g_dup_bcon,
+				     uint8_t band_mask)
+{
+	return QDF_STATUS_SUCCESS;
+}
 static inline enum wlan_phymode
 util_scan_get_phymode_6g(struct wlan_objmgr_pdev *pdev,
 			 struct scan_cache_entry *scan_params)
@@ -842,12 +874,28 @@ util_scan_parse_vendor_ie(struct scan_cache_entry *scan_params,
 }
 
 static QDF_STATUS
-util_scan_populate_bcn_ie_list(struct scan_cache_entry *scan_params,
-			       uint8_t *chan_idx)
+util_scan_populate_bcn_ie_list(struct wlan_objmgr_pdev *pdev,
+			       struct scan_cache_entry *scan_params,
+			       qdf_freq_t *chan_freq, uint8_t band_mask)
 {
 	struct ie_header *ie, *sub_ie;
 	uint32_t ie_len, sub_ie_len;
 	QDF_STATUS status;
+	uint8_t chan_idx;
+	struct wlan_scan_obj *scan_obj;
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		scm_err("psoc is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	scan_obj = wlan_psoc_get_scan_obj(psoc);
+	if (!scan_obj) {
+		scm_err("scan_obj is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
 
 	ie_len = util_scan_entry_ie_len(scan_params);
 	ie = (struct ie_header *)
@@ -883,8 +931,18 @@ util_scan_populate_bcn_ie_list(struct scan_cache_entry *scan_params,
 			if (ie->ie_len != WLAN_DS_PARAM_IE_MAX_LEN)
 				return QDF_STATUS_E_INVAL;
 			scan_params->ie_list.ds_param = (uint8_t *)ie;
-			*chan_idx =
+			chan_idx =
 				((struct ds_ie *)ie)->cur_chan;
+			*chan_freq = wlan_reg_chan_band_to_freq(pdev, chan_idx,
+								band_mask);
+			/* Drop if invalid freq */
+			if (scan_obj->drop_bcn_on_invalid_freq &&
+			    wlan_reg_is_disable_for_freq(pdev, *chan_freq)) {
+				scm_debug_rl("%pM: Drop as invalid channel %d freq %d in DS IE",
+					     scan_params->bssid.bytes,
+					     chan_idx, *chan_freq);
+				return QDF_STATUS_E_INVAL;
+			}
 			break;
 		case WLAN_ELEMID_TIM:
 			if (ie->ie_len < WLAN_TIM_IE_MIN_LENGTH)
@@ -961,9 +1019,18 @@ util_scan_populate_bcn_ie_list(struct scan_cache_entry *scan_params,
 				goto err;
 			scan_params->ie_list.htinfo =
 			  (uint8_t *)&(((struct wlan_ie_htinfo *) ie)->hi_ie);
-			*chan_idx =
-				((struct wlan_ie_htinfo_cmn *)
-			  (scan_params->ie_list.htinfo))->hi_ctrlchannel;
+			chan_idx = ((struct wlan_ie_htinfo_cmn *)
+				 (scan_params->ie_list.htinfo))->hi_ctrlchannel;
+			*chan_freq = wlan_reg_chan_band_to_freq(pdev, chan_idx,
+								band_mask);
+			/* Drop if invalid freq */
+			if (scan_obj->drop_bcn_on_invalid_freq &&
+			    wlan_reg_is_disable_for_freq(pdev, *chan_freq)) {
+				scm_debug_rl("%pM: Drop as invalid channel %d freq %d in HT_INFO IE",
+					     scan_params->bssid.bytes,
+					     chan_idx, *chan_freq);
+				return QDF_STATUS_E_INVAL;
+			}
 			break;
 		case WLAN_ELEMID_WAPI:
 			if (ie->ie_len < WLAN_WAPI_IE_MIN_LEN)
@@ -1412,8 +1479,10 @@ util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
 	struct scan_cache_entry *scan_entry;
 	struct qbss_load_ie *qbss_load;
 	struct scan_cache_node *scan_node;
-	uint8_t i, chan_idx = 0;
+	uint8_t i;
+	qdf_freq_t chan_freq = 0;
 	bool he_6g_dup_bcon = false;
+	uint8_t band_mask;
 
 	scan_entry = qdf_mem_malloc_atomic(sizeof(*scan_entry));
 	if (!scan_entry) {
@@ -1454,6 +1523,7 @@ util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
 	/* Copy per chain rssi to scan entry */
 	qdf_mem_copy(scan_entry->per_chain_rssi, rx_param->rssi_ctl,
 		     WLAN_MGMT_TXRX_HOST_MAX_ANTENNA);
+	band_mask = BIT(wlan_reg_freq_to_band(rx_param->chan_freq));
 
 	if (!wlan_psoc_nif_fw_ext_cap_get(wlan_pdev_get_psoc(pdev),
 					  WLAN_SOC_CEXT_HW_DB2DBM)) {
@@ -1490,9 +1560,11 @@ util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
 	scan_entry->raw_frame.len = frame_len;
 	qdf_mem_copy(scan_entry->raw_frame.ptr,
 		frame, frame_len);
-	status = util_scan_populate_bcn_ie_list(scan_entry, &chan_idx);
+	status = util_scan_populate_bcn_ie_list(pdev, scan_entry, &chan_freq,
+						band_mask);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		scm_debug("failed to parse beacon IE");
+		scm_debug("%pM: failed to parse beacon IE",
+			  scan_entry->bssid.bytes);
 		qdf_mem_free(scan_entry->raw_frame.ptr);
 		qdf_mem_free(scan_entry);
 		return QDF_STATUS_E_FAILURE;
@@ -1510,19 +1582,21 @@ util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
 	if (scan_entry->ie_list.p2p)
 		scan_entry->is_p2p = true;
 
-	if (!chan_idx && util_scan_entry_hecap(scan_entry))
-		util_scan_get_chan_from_he_6g_params(scan_entry, &chan_idx,
-						     &he_6g_dup_bcon);
+	if (!chan_freq && util_scan_entry_hecap(scan_entry)) {
+		status = util_scan_get_chan_from_he_6g_params(pdev, scan_entry,
+							      &chan_freq,
+							      &he_6g_dup_bcon,
+							      band_mask);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			qdf_mem_free(scan_entry->raw_frame.ptr);
+			qdf_mem_free(scan_entry);
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
 
-	if (chan_idx) {
-		uint8_t band_mask = BIT(wlan_reg_freq_to_band(
-							rx_param->chan_freq));
+	if (chan_freq)
+		scan_entry->channel.chan_freq = chan_freq;
 
-		scan_entry->channel.chan_freq =
-			wlan_reg_chan_band_to_freq(
-				pdev, chan_idx,
-				band_mask);
-	}
 	/* If no channel info is present in beacon use meta channel */
 	if (!scan_entry->channel.chan_freq) {
 		scan_entry->channel.chan_freq = rx_param->chan_freq;