Browse Source

qcacld-3.0: Update preauth candidate entry to scan table

During SAE roam auth offload, update the beacon/probe response
frame coming from the FW via WMI_ROAM_FRAME_EVENTID into the
scan db.

When the bss info of the preauth candidate is unavailable in
the host/kernel scan entry, supplicant fails to determine the
proper SAE PWE config of the peer and the commit request fails.

Change-Id: Ia782ece7bebf8274f949fe9fb3b2a2882bf47597
CRs-Fixed: 3075458
Surya Prakash Sivaraj 3 years ago
parent
commit
6ae47b3e0b

+ 21 - 0
components/target_if/connection_mgr/inc/target_if_cm_roam_event.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -142,6 +143,19 @@ target_if_pmkid_request_event_handler(ol_scn_t scn, uint8_t *event,
  */
 void
 target_if_cm_roam_register_rx_ops(struct wlan_cm_roam_rx_ops *rx_ops);
+
+/**
+ * target_if_roam_frame_event_handler - Target IF API to receive
+ * Beacon/probe for the roaming candidate.
+ * @scn: target handle
+ * @event: event buffer
+ * @len: event buffer length
+ *
+ * Return: int for success or error code
+ */
+int
+target_if_roam_frame_event_handler(ol_scn_t scn, uint8_t *event,
+				   uint32_t len);
 #else /* WLAN_FEATURE_ROAM_OFFLOAD */
 static inline
 void
@@ -182,5 +196,12 @@ target_if_pmkid_request_event_handler(ol_scn_t scn, uint8_t *event,
 {
 	return 0;
 }
+
+static inline int
+target_if_roam_frame_event_handler(ol_scn_t scn, uint8_t *event,
+				   uint32_t len)
+{
+	return 0;
+}
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 #endif

+ 54 - 0
components/target_if/connection_mgr/src/target_if_cm_roam_event.c

@@ -63,6 +63,7 @@ target_if_cm_roam_register_rx_ops(struct wlan_cm_roam_rx_ops *rx_ops)
 	rx_ops->roam_stats_event_rx = cm_roam_stats_event_handler;
 	rx_ops->roam_auth_offload_event = cm_roam_auth_offload_event_handler;
 	rx_ops->roam_pmkid_request_event_rx = cm_roam_pmkid_request_handler;
+	rx_ops->roam_candidate_frame_event = cm_roam_candidate_event_handler;
 }
 
 int
@@ -519,6 +520,49 @@ done:
 	return qdf_status_to_os_return(qdf_status);
 }
 
+int
+target_if_roam_frame_event_handler(ol_scn_t scn, uint8_t *event,
+				   uint32_t len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct roam_scan_candidate_frame frame = {0};
+	struct wlan_cm_roam_rx_ops *roam_rx_ops;
+	QDF_STATUS qdf_status;
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	qdf_status = wmi_extract_roam_candidate_frame_event(wmi_handle, event,
+							    len, &frame);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		target_if_err("parsing of event failed, %d", qdf_status);
+		return -EINVAL;
+	}
+
+	roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc);
+	if (!roam_rx_ops || !roam_rx_ops->roam_candidate_frame_event) {
+		target_if_err("No valid roam rx ops");
+		return -EINVAL;
+	}
+
+	qdf_status = roam_rx_ops->roam_candidate_frame_event(psoc,
+							     &frame);
+	if (QDF_IS_STATUS_ERROR(qdf_status))
+		return -EINVAL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS
 target_if_roam_offload_register_events(struct wlan_objmgr_psoc *psoc)
 {
@@ -616,5 +660,15 @@ target_if_roam_offload_register_events(struct wlan_objmgr_psoc *psoc)
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	ret = wmi_unified_register_event_handler(handle,
+				wmi_roam_frame_event_id,
+				target_if_roam_frame_event_handler,
+				WMI_RX_SERIALIZER_CTX);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		target_if_err("wmi event(%u) registration failed, ret: %d",
+			      wmi_roam_frame_event_id, ret);
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	return QDF_STATUS_SUCCESS;
 }

+ 107 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -546,3 +547,109 @@ err:
 	}
 	return status;
 }
+
+QDF_STATUS
+cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc,
+				struct roam_scan_candidate_frame *candidate)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_pdev *pdev;
+	struct cnx_mgr *cm_ctx;
+	uint32_t ie_offset, ie_len;
+	uint8_t *ie_ptr = NULL;
+	uint8_t *extracted_ie = NULL;
+	uint8_t primary_channel, band;
+	qdf_freq_t op_freq;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, candidate->vdev_id,
+						    WLAN_MLME_CM_ID);
+	if (!vdev) {
+		mlme_err("vdev object is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		mlme_err("pdev object is NULL");
+		goto err;
+	}
+
+	cm_ctx = cm_get_cm_ctx(vdev);
+	if (!cm_ctx) {
+		mlme_err("cm ctx is NULL");
+		goto err;
+	}
+
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG,
+			   candidate->frame, candidate->frame_length);
+	/* Fixed parameters offset */
+	ie_offset = sizeof(struct wlan_frame_hdr) + MAC_B_PR_SSID_OFFSET;
+
+	if (candidate->frame_length <= ie_offset) {
+		mlme_err("Invalid frame length");
+		goto err;
+	}
+
+	ie_ptr = candidate->frame + ie_offset;
+	ie_len = candidate->frame_length - ie_offset;
+
+	/* For 2.4GHz,5GHz get channel from DS IE */
+	extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_DSPARMS,
+							   ie_ptr, ie_len);
+	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_DSPARMS &&
+	    extracted_ie[1] == WLAN_DS_PARAM_IE_MAX_LEN) {
+		band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
+		primary_channel = *(extracted_ie + 2);
+		mlme_debug("Extracted primary channel from DS : %d",
+			   primary_channel);
+		goto update_beacon;
+	}
+
+	/* For HT, VHT and non-6GHz HE, get channel from HTINFO IE */
+	extracted_ie = (uint8_t *)
+			wlan_get_ie_ptr_from_eid(WLAN_ELEMID_HTINFO_ANA,
+						 ie_ptr, ie_len);
+	if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_HTINFO_ANA &&
+	    extracted_ie[1] == sizeof(struct wlan_ie_htinfo_cmn)) {
+		band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
+		primary_channel =
+			((struct wlan_ie_htinfo *)extracted_ie)->
+						hi_ie.hi_ctrlchannel;
+		mlme_debug("Extracted primary channel from HT INFO : %d",
+			   primary_channel);
+		goto update_beacon;
+	}
+	/* For 6GHz, get channel from HE OP IE */
+	extracted_ie = (uint8_t *)
+			wlan_get_ext_ie_ptr_from_ext_id(WLAN_HEOP_OUI_TYPE,
+							(uint8_t)
+							WLAN_HEOP_OUI_SIZE,
+							ie_ptr, ie_len);
+	if (extracted_ie && !qdf_mem_cmp(&extracted_ie[2], WLAN_HEOP_OUI_TYPE,
+					 WLAN_HEOP_OUI_SIZE) &&
+	    extracted_ie[1] <= WLAN_MAX_HEOP_IE_LEN) {
+		band = BIT(REG_BAND_6G);
+		primary_channel = util_scan_get_6g_oper_channel(extracted_ie);
+		mlme_debug("Extracted primary channel from HE OP : %d",
+			   primary_channel);
+		if (primary_channel)
+			goto update_beacon;
+	}
+
+	mlme_err("Primary channel was not found in the candidate scan entry");
+	goto err;
+
+update_beacon:
+	op_freq = wlan_reg_chan_band_to_freq(pdev, primary_channel, band);
+	mlme_debug("Roaming candidate frequency : %d", op_freq);
+	cm_inform_bcn_probe(cm_ctx, candidate->frame, candidate->frame_length,
+			    op_freq,
+			    0, /* Real RSSI will be updated by Roam synch ind */
+			    cm_ctx->active_cm_id);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+	return QDF_STATUS_SUCCESS;
+err:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
+	return QDF_STATUS_E_FAILURE;
+}

+ 18 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h

@@ -1128,6 +1128,17 @@ void cm_report_roam_rt_stats(struct wlan_objmgr_psoc *psoc,
 			     enum roam_rt_stats_type events,
 			     struct roam_stats_event *roam_info,
 			     uint32_t value, uint8_t idx);
+/**
+ * cm_roam_candidate_event_handler() - CM callback to save roam
+ * candidate entry in scan db
+ *
+ * @psoc - psoc objmgr ptr
+ * @frame - roam scan candidate info
+ */
+QDF_STATUS
+cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc,
+				struct roam_scan_candidate_frame *candidate);
+
 #else
 static inline
 void wlan_cm_roam_activate_pcl_per_vdev(struct wlan_objmgr_psoc *psoc,
@@ -1294,6 +1305,13 @@ cm_report_roam_rt_stats(struct wlan_objmgr_psoc *psoc,
 			struct roam_stats_event *roam_info,
 			uint32_t value, uint8_t idx)
 {}
+
+static inline QDF_STATUS
+cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc,
+				struct roam_scan_candidate_frame *candidate)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
 #ifdef WLAN_FEATURE_FIPS

+ 16 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -2433,6 +2433,18 @@ struct roam_offload_synch_ind {
 #endif
 };
 
+/*
+ * struct roam_scan_candidate_frame Roam candidate scan entry
+ * vdev_id : vdev id
+ * frame_len : Length of the beacon/probe rsp frame
+ * frame : Pointer to the frame
+ */
+struct roam_scan_candidate_frame {
+	uint8_t vdev_id;
+	uint32_t frame_length;
+	uint8_t *frame;
+};
+
 /**
  * wlan_cm_roam_rx_ops  - structure of rx function pointers for
  * roaming related commands
@@ -2445,6 +2457,7 @@ struct roam_offload_synch_ind {
  * @roam_stats_event_rx: Rx ops function pointer for roam stats event
  * @roam_auth_offload_event: Rx ops function pointer for auth offload event
  * @roam_pmkid_request_event_rx: Rx ops function pointer for roam pmkid event
+ * @roam_candidate_frame_event : Rx ops function pointer for roam frame event
  */
 struct wlan_cm_roam_rx_ops {
 	QDF_STATUS (*roam_sync_event)(struct wlan_objmgr_psoc *psoc,
@@ -2467,5 +2480,8 @@ struct wlan_cm_roam_rx_ops {
 	(*roam_auth_offload_event)(struct auth_offload_event *auth_event);
 	QDF_STATUS
 	(*roam_pmkid_request_event_rx)(struct roam_pmkid_req_event *list);
+	QDF_STATUS
+	(*roam_candidate_frame_event)(struct wlan_objmgr_psoc *psoc,
+				      struct roam_scan_candidate_frame *frame);
 };
 #endif

+ 14 - 0
components/wmi/inc/wmi_unified_roam_api.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -408,6 +409,19 @@ QDF_STATUS
 wmi_extract_roam_pmkid_request(wmi_unified_t wmi_handle,
 			       uint8_t *event, uint32_t data_len,
 			       struct roam_pmkid_req_event **data);
+
+/**
+ * wmi_extract_roam_candidate_frame_event() - Extract the roam candidate
+ * scan entry and update the scan db
+ * @wmi_handle: wmi handle
+ * @event: Event data received from firmware
+ * @len: Event data length received from firmware
+ * @data: Extract the event and fill in data
+ */
+QDF_STATUS
+wmi_extract_roam_candidate_frame_event(wmi_unified_t wmi_handle, uint8_t *event,
+				       uint32_t len,
+				       struct roam_scan_candidate_frame *data);
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
 /**

+ 14 - 0
components/wmi/src/wmi_unified_roam_api.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -487,4 +488,17 @@ wmi_extract_roam_pmkid_request(wmi_unified_t wmi_handle,
 
 	return QDF_STATUS_E_FAILURE;
 }
+
+QDF_STATUS
+wmi_extract_roam_candidate_frame_event(wmi_unified_t wmi_handle, uint8_t *event,
+				       uint32_t len,
+				       struct roam_scan_candidate_frame *data)
+{
+	if (wmi_handle->ops->extract_roam_candidate_frame)
+		return wmi_handle->ops->extract_roam_candidate_frame(
+								  wmi_handle,
+								  event,
+								  len, data);
+	return QDF_STATUS_E_FAILURE;
+}
 #endif

+ 47 - 0
components/wmi/src/wmi_unified_roam_tlv.c

@@ -3234,6 +3234,52 @@ extract_roam_pmkid_request_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS
+extract_roam_candidate_frame_tlv(wmi_unified_t wmi_handle, uint8_t *event,
+				 uint32_t len,
+				 struct roam_scan_candidate_frame *data)
+{
+	WMI_ROAM_FRAME_EVENTID_param_tlvs *param_buf = NULL;
+	wmi_roam_frame_event_fixed_param *frame_params = NULL;
+
+	if (!event || !len) {
+		wmi_debug("Empty roam candidate frame event");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	param_buf = (WMI_ROAM_FRAME_EVENTID_param_tlvs *)event;
+	if (!param_buf) {
+		wmi_err("received null buf from target");
+		return -EINVAL;
+	}
+
+	frame_params =
+		(wmi_roam_frame_event_fixed_param *)param_buf->fixed_param;
+
+	if (frame_params->vdev_id >= WLAN_MAX_VDEVS) {
+		wmi_debug("Invalid VDEV id %d", frame_params->vdev_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (frame_params->frame_length > param_buf->num_frame) {
+		wmi_debug("Invalid frame length %d expected : %d",
+			  frame_params->frame_length,
+			  param_buf->num_frame);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!param_buf->frame) {
+		wmi_debug("Frame pointer is Null");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	data->vdev_id = frame_params->vdev_id;
+	data->frame_length = frame_params->frame_length;
+	data->frame = (uint8_t *)param_buf->frame;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
 {
 	struct wmi_ops *ops = wmi_handle->ops;
@@ -3258,6 +3304,7 @@ void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
 	ops->send_roam_invoke_cmd = send_roam_invoke_cmd_tlv;
 	ops->send_vdev_set_pcl_cmd = send_vdev_set_pcl_cmd_tlv;
 	ops->send_set_roam_trigger_cmd = send_set_roam_trigger_cmd_tlv;
+	ops->extract_roam_candidate_frame = extract_roam_candidate_frame_tlv;
 }
 #else
 static inline QDF_STATUS