Browse Source

qcacld-3.0: Send connected AP beacon data to userspace

Once driver gets QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING vendor
command with an attribute for start, firmware sends all
beacons to host for the connected peer. Host extract required info
(SSID, BSSID, Channel number, Beacon Interval, Timestamp, System
timestamp) from incoming beacon for connected AP and sends it to
userspace. Userspace needs this data for WIPS.

Change-Id: I9d6dd068a076bda79881043946be3133ee87fe84
CRs-Fixed: 2431354
Abhinav Kumar 6 years ago
parent
commit
4d1f9f442d

+ 7 - 0
core/hdd/inc/wlan_hdd_bcn_recv.h

@@ -50,7 +50,14 @@ int wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy,
 		WIPHY_VENDOR_CMD_NEED_RUNNING,				\
 	.doit = wlan_hdd_cfg80211_bcn_rcv_start				\
 },
+
+#define BCN_RECV_FEATURE_VENDOR_EVENTS			\
+[QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX] = {		\
+	.vendor_id = QCA_NL80211_VENDOR_ID,			\
+	.subcmd = QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING	\
+},
 #else
 #define BCN_RECV_FEATURE_VENDOR_COMMANDS
+#define BCN_RECV_FEATURE_VENDOR_EVENTS
 #endif
 

+ 117 - 1
core/hdd/src/wlan_hdd_bcn_recv.c

@@ -30,6 +30,8 @@
 #include "osif_sync.h"
 #include "wlan_hdd_bcn_recv.h"
 
+#define BOOTTIME QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED
+
 static const struct nla_policy
 beacon_reporting_params[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE] = {.type = NLA_U8},
@@ -38,6 +40,101 @@ beacon_reporting_params[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD] = {.type = NLA_U8},
 };
 
+/**
+ * get_beacon_report_data_len() - Calculate length for beacon
+ * report to allocate skb buffer
+ * @report: beacon report structure
+ *
+ * Return: skb buffer length
+ */
+static
+int get_beacon_report_data_len(struct wlan_beacon_report *report)
+{
+	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_SSID */
+	data_len += nla_total_size(report->ssid.length);
+
+	/* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID */
+	data_len += nla_total_size(ETH_ALEN);
+
+	/* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ */
+	data_len += nla_total_size(sizeof(u32));
+
+	/* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI */
+	data_len += nla_total_size(sizeof(u16));
+
+	/* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF */
+	data_len += nla_total_size(sizeof(uint64_t));
+
+	/* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED */
+	data_len += nla_total_size(sizeof(uint64_t));
+
+	return data_len;
+}
+
+/**
+ * hdd_send_bcn_recv_info() - Send beacon info to userspace for
+ * connected AP
+ * @hdd_handle: hdd_handle to get hdd_adapter
+ * @beacon_report: Required beacon report
+ *
+ * Send beacon info to userspace for connected AP through a vendor event:
+ * QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING.
+ */
+static void hdd_send_bcn_recv_info(hdd_handle_t hdd_handle,
+				   struct wlan_beacon_report *beacon_report)
+{
+	struct sk_buff *vendor_event;
+	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
+	uint32_t data_len;
+	int flags = cds_get_gfp_flags();
+
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return;
+
+	data_len = get_beacon_report_data_len(beacon_report);
+
+	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;
+	}
+
+	if (nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE,
+			QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO) ||
+	    nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID,
+		    beacon_report->ssid.length, beacon_report->ssid.ssid) ||
+	    nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID,
+		    ETH_ALEN, beacon_report->bssid.bytes) ||
+	    nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ,
+			beacon_report->frequency) ||
+	    nla_put_u16(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI,
+			beacon_report->beacon_interval) ||
+	    wlan_cfg80211_nla_put_u64(vendor_event,
+				      QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF,
+				      beacon_report->time_stamp) ||
+	    wlan_cfg80211_nla_put_u64(vendor_event, BOOTTIME,
+				      beacon_report->boot_time)) {
+		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
+		kfree_skb(vendor_event);
+		return;
+	}
+
+	cfg80211_vendor_event(vendor_event, flags);
+}
+
 /**
  * __wlan_hdd_cfg80211_bcn_rcv_start() - enable/disable beacon reporting
  * indication
@@ -62,6 +159,7 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy,
 	uint32_t bcn_report;
 	int errno;
 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	bool active_report;
 
 	hdd_enter_dev(dev);
 
@@ -74,6 +172,11 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy,
 		return -EINVAL;
 	}
 
+	if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
+		hdd_err("STA not in connected state");
+		return -EINVAL;
+	}
+
 	errno =
 	   wlan_cfg80211_nla_parse(tb,
 				   QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX,
@@ -88,13 +191,26 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy,
 		hdd_err("attr beacon report OP type failed");
 		return -EINVAL;
 	}
+	active_report =
+		!!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING];
+	hdd_debug("attr active_report %d", active_report);
 
 	bcn_report =
 		nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE]);
 	hdd_debug("Bcn Report: OP type:%d", bcn_report);
 
 	if (bcn_report == QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START) {
-		/* Vendor event is intended for Start*/
+		if (active_report) {
+			qdf_status = sme_register_bcn_report_pe_cb(
+							hdd_ctx->mac_handle,
+							hdd_send_bcn_recv_info);
+			if (QDF_IS_STATUS_ERROR(qdf_status)) {
+				hdd_err("bcn recv info 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);

+ 3 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -1507,6 +1507,9 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
 		.vendor_id = QCA_NL80211_VENDOR_ID,
 		.subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES,
 	},
+
+	BCN_RECV_FEATURE_VENDOR_EVENTS
+
 #ifdef WLAN_UMAC_CONVERGENCE
 	COMMON_VENDOR_EVENTS
 #endif

+ 2 - 0
core/mac/inc/ani_global.h

@@ -673,6 +673,8 @@ typedef struct sAniSirLim {
 	uint8_t retry_packet_cnt;
 	uint8_t beacon_probe_rsp_cnt_per_scan;
 	wlan_scan_requester req_id;
+	QDF_STATUS (*sme_bcn_rcv_callback)(hdd_handle_t hdd_handle,
+				struct wlan_beacon_report *beacon_report);
 } tAniSirLim, *tpAniSirLim;
 
 struct mgmt_frm_reg_info {

+ 19 - 0
core/mac/inc/sir_api.h

@@ -186,6 +186,25 @@ struct rsn_caps {
 	uint16_t Reserved:8;
 };
 
+/**
+ * struct wlan_beacon_report - Beacon info to be send to userspace
+ * @ssid: ssid present in beacon
+ * @bssid: bssid present in beacon
+ * @frequency: channel frequency in MHz
+ * @beacon_interval: Interval between two consecutive beacons
+ * @time_stamp: time stamp at which beacon received from AP
+ * @boot_time: Boot time when beacon received
+ */
+struct wlan_beacon_report {
+	struct wlan_ssid ssid;
+	struct qdf_mac_addr bssid;
+	uint32_t frequency;
+	uint16_t beacon_interval;
+	qdf_time_t time_stamp;
+	qdf_time_t boot_time;
+};
+
+
 /* / Result codes Firmware return to Host SW */
 typedef enum eSirResultCodes {
 	eSIR_SME_SUCCESS,

+ 2 - 1
core/mac/inc/wni_api.h

@@ -237,7 +237,8 @@ enum eWniMsgTypes {
 	eWNI_SME_HIDDEN_SSID_RESTART_RSP = SIR_SME_MSG_TYPES_BEGIN + 151,
 	eWNI_SME_FW_STATUS_IND = SIR_SME_MSG_TYPES_BEGIN + 152,
 	eWNI_SME_STA_CSA_CONTINUE_REQ = SIR_SME_MSG_TYPES_BEGIN + 153,
-	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 154
+	WNI_SME_REGISTER_BCN_REPORT_SEND_CB = SIR_SME_MSG_TYPES_BEGIN + 154,
+	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 155
 };
 
 typedef struct sAniCfgTxRateCtrs {

+ 1 - 0
core/mac/src/pe/lim/lim_process_message_queue.c

@@ -1727,6 +1727,7 @@ static void lim_process_messages(struct mac_context *mac_ctx,
 	case eWNI_SME_UPDATE_EDCA_PROFILE:
 	case WNI_SME_UPDATE_MU_EDCA_PARAMS:
 	case WNI_SME_CFG_ACTION_FRM_HE_TB_PPDU:
+	case WNI_SME_REGISTER_BCN_REPORT_SEND_CB:
 		/* These messages are from HDD.No need to respond to HDD */
 		lim_process_normal_hdd_msg(mac_ctx, msg, false);
 		break;

+ 33 - 0
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -390,6 +390,36 @@ static bool __lim_process_sme_sys_ready_ind(struct mac_context *mac,
 	return false;
 }
 
+#ifdef WLAN_BCN_RECV_FEATURE
+/**
+ * lim_register_bcn_report_send_cb() - Register bcn receive start
+ * indication handler callback
+ * @mac: Pointer to Global MAC structure
+ * @msg: A pointer to the SME message buffer
+ *
+ * Once driver gets QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING vendor
+ * command with attribute for start only. LIM layer register a sme
+ * callback through this function.
+ *
+ * Return: None.
+ */
+static void lim_register_bcn_report_send_cb(struct mac_context *mac,
+					    struct scheduler_msg *msg)
+{
+	if (!msg) {
+		pe_err("Invalid message");
+		return;
+	}
+
+	mac->lim.sme_bcn_rcv_callback = msg->callback;
+}
+#else
+static inline
+void lim_register_bcn_report_send_cb(struct mac_context *mac,
+				     struct scheduler_msg *msg)
+{
+}
+#endif
 /**
  *lim_configure_ap_start_bss_session() - Configure the AP Start BSS in session.
  *@mac_ctx: Pointer to Global MAC structure
@@ -4982,6 +5012,9 @@ bool lim_process_sme_req_messages(struct mac_context *mac,
 		lim_process_sme_cfg_action_frm_in_tb_ppdu(mac,
 				(struct  sir_cfg_action_frm_tb_ppdu *)pMsgBuf);
 		break;
+	case WNI_SME_REGISTER_BCN_REPORT_SEND_CB:
+		lim_register_bcn_report_send_cb(mac, pMsg);
+		break;
 	default:
 		qdf_mem_free((void *)pMsg->bodyptr);
 		pMsg->bodyptr = NULL;

+ 67 - 2
core/mac/src/pe/sch/sch_beacon_process.c

@@ -1083,6 +1083,69 @@ void sch_beacon_process_for_ap(struct mac_context *mac_ctx,
 	}
 }
 
+#ifdef WLAN_BCN_RECV_FEATURE
+/*
+ * sch_send_beacon_report() - To Fill beacon report for
+ * each beacon coming from connected peer and sends it
+ * to upper layer
+ * @mac_ctx: Mac context
+ * @beacon_struct: Pointing to beacon structure
+ * @session: pointer to the PE session
+ *
+ * Return: None
+ */
+static
+void sch_send_beacon_report(struct mac_context *mac_ctx,
+			    struct sSirProbeRespBeacon *beacon_struct,
+			    struct pe_session *session)
+{
+	struct wlan_beacon_report beacon_report;
+
+	if (!mac_ctx->lim.sme_bcn_rcv_callback) {
+		pe_err("sme_bcn_rcv_callback is NULL");
+		return;
+	}
+
+	if (!LIM_IS_STA_ROLE(session)) {
+		pe_err("Session is not for STA");
+		return;
+	}
+
+	if (sir_compare_mac_addr(session->bssId, beacon_struct->bssid)) {
+		/* Prepare beacon report from incoming beacon */
+		qdf_mem_copy(beacon_report.bssid.bytes, beacon_struct->bssid,
+			     sizeof(tSirMacAddr));
+
+		qdf_mem_copy(&beacon_report.time_stamp,
+			     &beacon_struct->timeStamp, sizeof(qdf_time_t));
+		beacon_report.beacon_interval = beacon_struct->beaconInterval;
+		beacon_report.frequency =
+				cds_chan_to_freq(beacon_struct->channelNumber);
+
+		beacon_report.ssid.length = beacon_struct->ssId.length;
+		qdf_mem_copy(&beacon_report.ssid.ssid,
+			     &beacon_struct->ssId.ssId,
+			     beacon_report.ssid.length);
+
+		beacon_report.boot_time =
+				qdf_do_div(qdf_get_monotonic_boottime(),
+					   QDF_MC_TIMER_TO_MS_UNIT);
+
+		/* Send report to upper layer */
+		mac_ctx->lim.sme_bcn_rcv_callback(mac_ctx->hdd_handle,
+						  &beacon_report);
+	}
+}
+
+#else
+static inline
+void sch_send_beacon_report(struct mac_context *mac_ctx,
+			    struct sSirProbeRespBeacon *beacon_struct,
+			    struct pe_session *session)
+{
+}
+#endif
+
 /**
  * sch_beacon_process() - process the beacon frame
  * @mac_ctx: mac global context
@@ -1108,11 +1171,13 @@ sch_beacon_process(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
 	 * Now process the beacon in the context of the BSS which is
 	 * transmitting the beacons, if one is found
 	 */
-	if (!session)
+	if (!session) {
 		__sch_beacon_process_no_session(mac_ctx, &bcn, rx_pkt_info);
-	else
+	} else {
+		sch_send_beacon_report(mac_ctx, &bcn, session);
 		__sch_beacon_process_for_session(mac_ctx, &bcn, rx_pkt_info,
 						 session);
+	}
 }
 
 /**

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

@@ -411,6 +411,28 @@ QDF_STATUS sme_update_config(mac_handle_t mac_handle,
 QDF_STATUS sme_set11dinfo(mac_handle_t mac_handle,
 			  struct sme_config_params *pSmeConfigParams);
 QDF_STATUS sme_hdd_ready_ind(mac_handle_t mac_handle);
+
+#ifdef WLAN_BCN_RECV_FEATURE
+/*
+ * sme_register_bcn_report_pe_cb() - Register SME callback
+ * @mac_handle: The handle returned by mac_open.
+ * @cb: cb of type beacon_report_cb
+ *
+ * This function Register SME callback in order to send
+ * beacon report to upper layer
+ *
+ * Return QDF_STATUS_SUCCESS -
+ */
+QDF_STATUS
+sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb);
+#else
+static inline QDF_STATUS
+sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * sme_ser_cmd_callback() - callback from serialization module
  * @cmd: serialization command

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

@@ -257,6 +257,14 @@ typedef void (*lost_link_info_cb)(hdd_handle_t hdd_handle,
 typedef void (*hidden_ssid_cb)(hdd_handle_t hdd_handle,
 				uint8_t vdev_id);
 
+/**
+ * typedef bcn_report_cb - recv bcn callback fun
+ * @hdd_handle: HDD handle registered with SME
+ * @beacon_report: Beacon report structure
+ */
+typedef void (*beacon_report_cb)(hdd_handle_t hdd_handle,
+				 struct wlan_beacon_report *beacon_report);
+
 #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 */
@@ -364,6 +372,9 @@ struct sme_context {
 						  wmi_mws_coex_cmd_id cmd_id);
 #endif /* WLAN_MWS_INFO_DEBUGFS */
 
+#ifdef WLAN_BCN_RECV_FEATURE
+	beacon_report_cb beacon_report_cb;
+#endif
 };
 
 #endif /* #if !defined( __SMEINTERNAL_H ) */

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

@@ -1135,6 +1135,26 @@ QDF_STATUS sme_hdd_ready_ind(mac_handle_t mac_handle)
 	return status;
 }
 
+#ifdef WLAN_BCN_RECV_FEATURE
+QDF_STATUS
+sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb)
+{
+	struct scheduler_msg msg = {0};
+	QDF_STATUS status;
+
+	msg.type = WNI_SME_REGISTER_BCN_REPORT_SEND_CB;
+	msg.callback = cb;
+
+	status = scheduler_post_message(QDF_MODULE_ID_SME,
+					QDF_MODULE_ID_PE,
+					QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(status))
+		sme_err("Failed to post message to LIM");
+
+	return status;
+}
+#endif
+
 QDF_STATUS sme_get_valid_channels(uint8_t *chan_list, uint32_t *list_len)
 {
 	struct mac_context *mac_ctx = sme_get_mac_context();