Browse Source

qcacld-3.0: Send scan start indication to userspace

If firmware starts off-channel scan, driver does not
receive beacons. In this case driver should send a
pause event to userspace.

Change-Id: I90ba5c586656486df110778b73b236e5877f8684
CRs-Fixed: 2431359
Abhinav Kumar 6 years ago
parent
commit
0ed614c1c9
4 changed files with 194 additions and 0 deletions
  1. 96 0
      core/hdd/src/wlan_hdd_bcn_recv.c
  2. 23 0
      core/sme/inc/sme_api.h
  3. 11 0
      core/sme/inc/sme_internal.h
  4. 64 0
      core/sme/src/common/sme_api.c

+ 96 - 0
core/hdd/src/wlan_hdd_bcn_recv.c

@@ -76,6 +76,92 @@ int get_beacon_report_data_len(struct wlan_beacon_report *report)
 	return data_len;
 }
 
+/**
+ * get_pause_ind_data_len() - Calculate skb buffer length
+ * @report: Required beacon report
+ *
+ * Calculate length for pause indication to allocate skb buffer
+ *
+ * Return: skb buffer length
+ */
+static int get_pause_ind_data_len(void)
+{
+	uint32_t data_len = NLMSG_HDRLEN;
+
+	/* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE */
+	data_len += nla_total_size(sizeof(u32));
+
+	/* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON */
+	data_len += nla_total_size(sizeof(u32));
+
+	return data_len;
+}
+
+/**
+ * hdd_beacon_recv_pause_indication()- Send vendor event to user space
+ * to inform SCAN started indication
+ * @hdd_handle: hdd handler
+ * @vdev_id: vdev id
+ * @type: scan event type
+ *
+ * Return: None
+ */
+static void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle,
+					     uint8_t vdev_id,
+					     enum scan_event_type type)
+{
+	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
+	struct hdd_adapter *adapter;
+	struct sk_buff *vendor_event;
+	uint32_t data_len;
+	int flags;
+	uint32_t abort_reason;
+
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return;
+
+	adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+	if (hdd_validate_adapter(adapter))
+		return;
+
+	data_len = get_pause_ind_data_len();
+	flags = cds_get_gfp_flags();
+
+	vendor_event =
+		cfg80211_vendor_event_alloc(
+			hdd_ctx->wiphy, NULL,
+			data_len,
+			QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX,
+			flags);
+	if (!vendor_event) {
+		hdd_err("cfg80211_vendor_event_alloc failed");
+		return;
+	}
+
+	switch (type) {
+	case SCAN_EVENT_TYPE_STARTED:
+		abort_reason =
+		  QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED;
+		break;
+	default:
+		abort_reason =
+		     QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED;
+	}
+	/* Send vendor event to user space to inform ABORT */
+	if (nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE,
+			QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE) ||
+	    nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON,
+			abort_reason)) {
+		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
+		kfree_skb(vendor_event);
+		return;
+	}
+
+	cfg80211_vendor_event(vendor_event, flags);
+}
+
 /**
  * hdd_send_bcn_recv_info() - Send beacon info to userspace for
  * connected AP
@@ -211,6 +297,16 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy,
 				return errno;
 			}
 		}
+		qdf_status =
+			sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle,
+					hdd_beacon_recv_pause_indication);
+		if (QDF_IS_STATUS_ERROR(qdf_status)) {
+			hdd_err("bcn_recv_abort_ind cb reg failed = %d",
+				qdf_status);
+			errno = qdf_status_to_os_return(qdf_status);
+			return errno;
+		}
+
 		qdf_status =
 			sme_handle_bcn_recv_start(hdd_ctx->mac_handle,
 						  adapter->vdev_id);

+ 23 - 0
core/sme/inc/sme_api.h

@@ -3455,4 +3455,27 @@ sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id,
 		      void *context);
 #endif /* WLAN_MWS_INFO_DEBUGFS */
 
+#ifdef WLAN_BCN_RECV_FEATURE
+/**
+ * sme_register_bcn_recv_pause_ind_cb() - Register pause ind cb
+ * mac_handle: man handler
+ * cb: callback function to HDD
+ *
+ * This function register HDD callback in order to indicate beacon
+ * receive pause indication to userspace.
+ *
+ * return QDF_STATUS of cb registration
+ */
+QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
+					      beacon_pause_cb cb);
+
+#else
+static inline
+QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
+					      beacon_pause_cb cb)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 #endif /* #if !defined( __SME_API_H ) */

+ 11 - 0
core/sme/inc/sme_internal.h

@@ -265,6 +265,16 @@ typedef void (*hidden_ssid_cb)(hdd_handle_t hdd_handle,
 typedef void (*beacon_report_cb)(hdd_handle_t hdd_handle,
 				 struct wlan_beacon_report *beacon_report);
 
+/**
+ * beacon_pause_cb : scan start callback fun
+ * @hdd_handler: HDD handler
+ * @vdev_id: vdev id
+ * @type: scan event type
+ */
+typedef void (*beacon_pause_cb)(hdd_handle_t hdd_handle,
+				uint8_t vdev_id,
+				enum scan_event_type type);
+
 #ifdef WLAN_FEATURE_MOTION_DETECTION
 typedef QDF_STATUS (*md_host_evt_cb)(void *hdd_ctx, struct sir_md_evt *event);
 #endif /* WLAN_FEATURE_MOTION_DETECTION */
@@ -374,6 +384,7 @@ struct sme_context {
 
 #ifdef WLAN_BCN_RECV_FEATURE
 	beacon_report_cb beacon_report_cb;
+	beacon_pause_cb beacon_pause_cb;
 #endif
 };
 

+ 64 - 0
core/sme/src/common/sme_api.c

@@ -15526,3 +15526,67 @@ sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id,
 	return status;
 }
 #endif /* WLAN_MWS_INFO_DEBUGFS */
+
+#ifdef WLAN_BCN_RECV_FEATURE
+/**
+ * sme_scan_event_handler() - Scan complete event handler
+ * @vdev: vdev obj manager
+ * @event: scan event
+ * @arg: arg of scan event
+ *
+ * This function is getting called after Host receive scan start
+ *
+ * Return: None
+ */
+static void sme_scan_event_handler(struct wlan_objmgr_vdev *vdev,
+				   struct scan_event *event,
+				   void *arg)
+{
+	struct mac_context *mac = arg;
+	struct csr_roam_session *session;
+
+	if (!mac) {
+		sme_err("Invalid mac context");
+		return;
+	}
+
+	if (!CSR_IS_SESSION_VALID(mac, vdev->vdev_objmgr.vdev_id)) {
+		sme_err("Invalid vdev_id: %d", vdev->vdev_objmgr.vdev_id);
+		return;
+	}
+
+	session = CSR_GET_SESSION(mac, vdev->vdev_objmgr.vdev_id);
+
+	if (event->type == SCAN_EVENT_TYPE_STARTED) {
+		if (mac->sme.beacon_pause_cb)
+			mac->sme.beacon_pause_cb(mac->hdd_handle,
+				vdev->vdev_objmgr.vdev_id, event->type);
+	}
+}
+
+QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
+					      beacon_pause_cb cb)
+{
+	QDF_STATUS status;
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+
+	if (!mac) {
+		sme_err("Invalid mac context");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.beacon_pause_cb = cb;
+		sme_release_global_lock(&mac->sme);
+	}
+
+	/* scan event registration */
+	status = ucfg_scan_register_event_handler(mac->pdev,
+						  sme_scan_event_handler, mac);
+	if (QDF_IS_STATUS_ERROR(status))
+		sme_err("scan event register failed ");
+
+	return status;
+}
+#endif