Browse Source

qcacld-3.0: Support to notify SMPS OPMODE RRM event

Support to deliver SMPS, OPMODE to user app, and
deliver RRM report to son module.

Change-Id: I9e12043e59878c5e46d24f02717356ad40d7e35d
CRs-Fixed: 3056538
Li Feng 3 years ago
parent
commit
2152af2589

+ 101 - 0
components/son/dispatcher/inc/son_api.h

@@ -26,6 +26,41 @@
 #include <wlan_objmgr_pdev_obj.h>
 #include <reg_services_public_struct.h>
 
+/**
+ * mlme_deliver_cb - cb to deliver mlme event
+ * @vdev: pointer to vdev
+ * @event_len: event length
+ * @event_buf: event buffer
+ *
+ * @Return: 0 if event is sent successfully
+ */
+typedef int (*mlme_deliver_cb)(struct wlan_objmgr_vdev *vdev,
+			       uint32_t event_len,
+			       const uint8_t *event_buf);
+
+/**
+ * enum SON_MLME_DELIVER_CB_TYPE - mlme deliver cb type
+ * @SON_MLME_DELIVER_CB_TYPE_OPMODE: cb to deliver opmode
+ * @SON_MLME_DELIVER_CB_TYPE_SMPS: cb to deliver smps
+ */
+enum SON_MLME_DELIVER_CB_TYPE {
+	SON_MLME_DELIVER_CB_TYPE_OPMODE,
+	SON_MLME_DELIVER_CB_TYPE_SMPS,
+};
+
+/**
+ * wlan_son_register_mlme_deliver_cb - register mlme deliver cb
+ * @psoc: pointer to psoc
+ * @cb: mlme deliver cb
+ * @type: mlme deliver cb type
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_son_register_mlme_deliver_cb(struct wlan_objmgr_psoc *psoc,
+				  mlme_deliver_cb cb,
+				  enum SON_MLME_DELIVER_CB_TYPE type);
+
 /**
  * wlan_son_get_chan_flag() - get chan flag
  * @pdev: pointer to pdev
@@ -108,6 +143,46 @@ int wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev *vdev,
 			       struct wlan_objmgr_peer *peer,
 			       uint32_t irssi);
 
+/**
+ * wlan_son_deliver_opmode() - notity user app of opmode
+ * @vdev: vdev objmgr
+ * @bw: channel width defined in enum eSirMacHTChannelWidth
+ * @nss: supported rx nss
+ * @addr: source addr
+ *
+ * Return: 0 if event is sent successfully
+ */
+int wlan_son_deliver_opmode(struct wlan_objmgr_vdev *vdev,
+			    uint8_t bw,
+			    uint8_t nss,
+			    uint8_t *addr);
+
+/**
+ * wlan_son_deliver_smps() - notity user app of smps
+ * @vdev: vdev objmgr
+ * @is_static: is_static
+ * @addr: source addr
+ *
+ * Return: 0 if event is sent successfully
+ */
+int wlan_son_deliver_smps(struct wlan_objmgr_vdev *vdev,
+			  uint8_t is_static,
+			  uint8_t *addr);
+
+/**
+ * wlan_son_deliver_rrm_rpt() - notity son module of rrm rpt
+ * @vdev: vdev objmgr
+ * @addr: sender addr
+ * @frm: points to measurement report
+ * @flen: frame length
+ *
+ * Return: 0 if event is sent successfully
+ */
+int wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev *vdev,
+			     uint8_t *addr,
+			     uint8_t *frm,
+			     uint32_t flen);
+
 #else
 
 static inline bool wlan_son_peer_is_kickout_allow(struct wlan_objmgr_vdev *vdev,
@@ -144,5 +219,31 @@ int wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev *vdev,
 {
 	return -EINVAL;
 }
+
+static inline
+int wlan_son_deliver_opmode(struct wlan_objmgr_vdev *vdev,
+			    uint8_t bw,
+			    uint8_t nss,
+			    uint8_t *addr)
+{
+	return -EINVAL;
+}
+
+static inline
+int wlan_son_deliver_smps(struct wlan_objmgr_vdev *vdev,
+			  uint8_t is_static,
+			  uint8_t *addr)
+{
+	return -EINVAL;
+}
+
+static inline
+int wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev *vdev,
+			     uint8_t *mac_addr,
+			     uint8_t *frm,
+			     uint32_t flen)
+{
+	return -EINVAL;
+}
 #endif /*WLAN_FEATURE_SON*/
 #endif

+ 23 - 0
components/son/dispatcher/inc/son_ucfg_api.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 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
@@ -23,6 +24,7 @@
 #include <qdf_trace.h>
 #include <wlan_objmgr_pdev_obj.h>
 #include <wlan_mlme_ucfg_api.h>
+#include <son_api.h>
 
 /**
  * ucfg_son_get_operation_chan_freq_vdev_id() - get operating chan freq of
@@ -106,4 +108,25 @@ static inline void ucfg_son_get_he_supported(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS ucfg_son_set_peer_kickout_allow(struct wlan_objmgr_vdev *vdev,
 					   struct wlan_objmgr_peer *peer,
 					   bool kickout_allow);
+
+/**
+ * ucfg_son_register_deliver_opmode_cb() - register deliver opmode cb
+ * psoc: pointer to psoc
+ * cb: deliver opmode callback
+ *
+ * Return: QDF_STATUS_SUCCESS on Success else failure.
+ */
+QDF_STATUS ucfg_son_register_deliver_opmode_cb(struct wlan_objmgr_psoc *psoc,
+					       mlme_deliver_cb cb);
+
+/**
+ * ucfg_son_register_deliver_smps_cb() - register deliver smps cb
+ * psoc: pointer to psoc
+ * cb: deliver smps callback
+ *
+ * Return: QDF_STATUS_SUCCESS on Success else failure.
+ */
+
+QDF_STATUS ucfg_son_register_deliver_smps_cb(struct wlan_objmgr_psoc *psoc,
+					     mlme_deliver_cb cb);
 #endif

+ 187 - 0
components/son/dispatcher/src/son_api.c

@@ -24,6 +24,43 @@
 #include <wlan_mlme_api.h>
 #include <ieee80211_external.h>
 
+/**
+ * struct son_mlme_deliver_cbs - son mlme deliver callbacks
+ * @deliver_opmode: cb to deliver opmode
+ * @deliver_smps: cb to deliver smps
+ */
+struct son_mlme_deliver_cbs {
+	mlme_deliver_cb deliver_opmode;
+	mlme_deliver_cb deliver_smps;
+};
+
+static struct son_mlme_deliver_cbs g_son_mlme_deliver_cbs;
+
+QDF_STATUS
+wlan_son_register_mlme_deliver_cb(struct wlan_objmgr_psoc *psoc,
+				  mlme_deliver_cb cb,
+				  enum SON_MLME_DELIVER_CB_TYPE type)
+{
+	if (!psoc) {
+		qdf_err("invalid psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	switch (type) {
+	case SON_MLME_DELIVER_CB_TYPE_OPMODE:
+		g_son_mlme_deliver_cbs.deliver_opmode = cb;
+		break;
+	case SON_MLME_DELIVER_CB_TYPE_SMPS:
+		g_son_mlme_deliver_cbs.deliver_smps = cb;
+		break;
+	default:
+		qdf_err("invalid type");
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * wlan_son_is_he_supported() - is he supported or not
  * @psoc: pointer to psoc
@@ -397,3 +434,153 @@ int wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev *vdev,
 
 	return ret;
 }
+
+int wlan_son_deliver_opmode(struct wlan_objmgr_vdev *vdev,
+			    uint8_t bw,
+			    uint8_t nss,
+			    uint8_t *addr)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct ieee80211_opmode_update_data opmode;
+
+	if (!vdev)
+		return -EINVAL;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc)
+		return -EINVAL;
+
+	opmode.max_chwidth = bw;
+	opmode.num_streams = nss;
+	qdf_mem_copy(opmode.macaddr, addr, QDF_MAC_ADDR_SIZE);
+
+	qdf_debug("bw %d, nss %d, addr " QDF_FULL_MAC_FMT,
+		  bw, nss, QDF_FULL_MAC_REF(addr));
+
+	if (!g_son_mlme_deliver_cbs.deliver_opmode) {
+		qdf_err("invalid deliver opmode cb");
+		return -EINVAL;
+	}
+
+	g_son_mlme_deliver_cbs.deliver_opmode(vdev,
+					      sizeof(opmode),
+					      (uint8_t *)&opmode);
+
+	return 0;
+}
+
+int wlan_son_deliver_smps(struct wlan_objmgr_vdev *vdev,
+			  uint8_t is_static,
+			  uint8_t *addr)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct ieee80211_smps_update_data smps;
+
+	if (!vdev)
+		return -EINVAL;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc)
+		return -EINVAL;
+
+	smps.is_static = is_static;
+	qdf_mem_copy(smps.macaddr, addr, QDF_MAC_ADDR_SIZE);
+
+	qdf_debug("is_static %d, addr" QDF_FULL_MAC_FMT,
+		  is_static, QDF_FULL_MAC_REF(addr));
+
+	if (!g_son_mlme_deliver_cbs.deliver_smps) {
+		qdf_err("invalid deliver smps cb");
+		return -EINVAL;
+	}
+
+	g_son_mlme_deliver_cbs.deliver_smps(vdev,
+					    sizeof(smps),
+					    (uint8_t *)&smps);
+
+	return 0;
+}
+
+int wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev *vdev,
+			     uint8_t *mac_addr,
+			     uint8_t *frm,
+			     uint32_t flen)
+{
+	struct wlan_act_frm_info rrm_info;
+	struct wlan_lmac_if_rx_ops *rx_ops;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_peer *peer;
+	uint8_t sub_type = IEEE80211_FC0_SUBTYPE_ACTION;
+	struct ieee80211_action ia;
+	const uint8_t *ie, *pos, *end;
+	uint8_t total_bcnrpt_count = 0;
+
+	if (!vdev) {
+		qdf_err("invalid vdev");
+		return -EINVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		qdf_err("invalid psoc");
+		return -EINVAL;
+	}
+
+	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
+	if (!rx_ops || !rx_ops->son_rx_ops.process_mgmt_frame) {
+		qdf_err("invalid rx ops");
+		return -EINVAL;
+	}
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, mac_addr, WLAN_SON_ID);
+	if (!peer) {
+		qdf_err("peer is null");
+		return -EINVAL;
+	}
+
+	ia.ia_category = ACTION_CATEGORY_RRM;
+	ia.ia_action = RRM_RADIO_MEASURE_RPT;
+	qdf_mem_zero(&rrm_info, sizeof(rrm_info));
+	rrm_info.ia = &ia;
+	rrm_info.ald_info = 0;
+	qdf_mem_copy(rrm_info.data.rrm_data.macaddr,
+		     mac_addr,
+		     QDF_MAC_ADDR_SIZE);
+	/* IEEE80211_ACTION_RM_TOKEN */
+	rrm_info.data.rrm_data.dialog_token = *frm;
+
+	/* Points to Measurement Report Element */
+	++frm;
+	--flen;
+	pos = frm;
+	end = pos + flen;
+
+	while ((ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_MEASREP,
+					      pos, end - pos))) {
+		if (ie[1] < 3) {
+			qdf_err("Bad Measurement Report element");
+			wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID);
+			return -EINVAL;
+		}
+		if (ie[4] == SIR_MAC_RRM_BEACON_TYPE)
+			++total_bcnrpt_count;
+		pos = ie + ie[1] + 2;
+	}
+
+	rrm_info.data.rrm_data.num_meas_rpts = total_bcnrpt_count;
+
+	qdf_debug("Sta: " QDF_FULL_MAC_FMT
+		  "Category %d Action %d Num_Report %d Rptlen %d",
+		  QDF_FULL_MAC_REF(mac_addr),
+		  ACTION_CATEGORY_RRM,
+		  RRM_RADIO_MEASURE_RPT,
+		  total_bcnrpt_count,
+		  flen);
+
+	rx_ops->son_rx_ops.process_mgmt_frame(vdev, peer, sub_type,
+					      frm, flen, &rrm_info);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID);
+
+	return 0;
+}

+ 15 - 1
components/son/dispatcher/src/son_ucfg_api.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 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
@@ -22,7 +23,6 @@
 #include <son_ucfg_api.h>
 #include <wlan_mlme_main.h>
 #include <init_deinit_lmac.h>
-#include <son_api.h>
 
 qdf_freq_t
 ucfg_son_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev,
@@ -77,3 +77,17 @@ QDF_STATUS ucfg_son_set_peer_kickout_allow(struct wlan_objmgr_vdev *vdev,
 {
 	return wlan_son_peer_set_kickout_allow(vdev, peer, kickout_allow);
 }
+
+QDF_STATUS ucfg_son_register_deliver_opmode_cb(struct wlan_objmgr_psoc *psoc,
+					       mlme_deliver_cb cb)
+{
+	return wlan_son_register_mlme_deliver_cb(psoc, cb,
+					SON_MLME_DELIVER_CB_TYPE_OPMODE);
+}
+
+QDF_STATUS ucfg_son_register_deliver_smps_cb(struct wlan_objmgr_psoc *psoc,
+					     mlme_deliver_cb cb)
+{
+	return wlan_son_register_mlme_deliver_cb(psoc, cb,
+					SON_MLME_DELIVER_CB_TYPE_SMPS);
+}

+ 83 - 0
core/hdd/src/wlan_hdd_son.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 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
@@ -1311,6 +1312,83 @@ static void hdd_son_modify_acl(struct wlan_objmgr_vdev *vdev,
 	}
 }
 
+static int hdd_son_send_cfg_event(struct wlan_objmgr_vdev *vdev,
+				  uint32_t event_id,
+				  uint32_t event_len,
+				  const uint8_t *event_buf)
+{
+	struct hdd_adapter *adapter;
+	uint32_t len;
+	uint32_t idx;
+	struct sk_buff *skb;
+
+	if (!event_buf) {
+		hdd_err("invalid event buf");
+		return -EINVAL;
+	}
+
+	adapter = wlan_hdd_get_adapter_from_objmgr(vdev);
+	if (!adapter) {
+		hdd_err("null adapter");
+		return -EINVAL;
+	}
+
+	len = nla_total_size(sizeof(event_id)) +
+			nla_total_size(event_len) +
+			NLMSG_HDRLEN;
+	idx = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION_INDEX;
+	skb = cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy,
+					  &adapter->wdev,
+					  len,
+					  idx,
+					  GFP_KERNEL);
+	if (!skb) {
+		hdd_err("failed to alloc cfg80211 vendor event");
+		return -EINVAL;
+	}
+
+	if (nla_put_u32(skb,
+			QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND,
+			event_id)) {
+		hdd_err("failed to put attr config generic command");
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	if (nla_put(skb,
+		    QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA,
+		    event_len,
+		    event_buf)) {
+		hdd_err("failed to put attr config generic data");
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	cfg80211_vendor_event(skb, GFP_KERNEL);
+
+	return 0;
+}
+
+static int hdd_son_deliver_opmode(struct wlan_objmgr_vdev *vdev,
+				  uint32_t event_len,
+				  const uint8_t *event_buf)
+{
+	return hdd_son_send_cfg_event(vdev,
+				      QCA_NL80211_VENDOR_SUBCMD_OPMODE_UPDATE,
+				      event_len,
+				      event_buf);
+}
+
+static int hdd_son_deliver_smps(struct wlan_objmgr_vdev *vdev,
+				uint32_t event_len,
+				const uint8_t *event_buf)
+{
+	return hdd_son_send_cfg_event(vdev,
+				      QCA_NL80211_VENDOR_SUBCMD_SMPS_UPDATE,
+				      event_len,
+				      event_buf);
+}
+
 void hdd_son_register_callbacks(struct hdd_context *hdd_ctx)
 {
 	struct son_callbacks cb_obj = {0};
@@ -1338,4 +1416,9 @@ void hdd_son_register_callbacks(struct hdd_context *hdd_ctx)
 	cb_obj.os_if_modify_acl = hdd_son_modify_acl;
 
 	os_if_son_register_hdd_callbacks(hdd_ctx->psoc, &cb_obj);
+
+	ucfg_son_register_deliver_opmode_cb(hdd_ctx->psoc,
+					    hdd_son_deliver_opmode);
+	ucfg_son_register_deliver_smps_cb(hdd_ctx->psoc,
+					  hdd_son_deliver_smps);
 }

+ 20 - 0
core/mac/src/pe/lim/lim_process_action_frame.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
@@ -52,6 +53,7 @@
 #include <cdp_txrx_peer_ops.h>
 #include "dot11f.h"
 #include "wlan_p2p_cfg_api.h"
+#include "son_api.h"
 
 #define SA_QUERY_REQ_MIN_LEN \
 (DOT11F_FF_CATEGORY_LEN + DOT11F_FF_ACTION_LEN + DOT11F_FF_TRANSACTIONID_LEN)
@@ -367,6 +369,10 @@ update_nss:
 		lim_set_nss_change(mac_ctx, session, sta_ptr->vhtSupportedRxNss,
 			mac_hdr->sa);
 	}
+	wlan_son_deliver_opmode(session->vdev,
+				ch_bw,
+				sta_ptr->vhtSupportedRxNss,
+				mac_hdr->sa);
 
 end:
 	qdf_mem_free(operating_mode_frm);
@@ -1128,6 +1134,9 @@ __lim_process_sm_power_save_update(struct mac_context *mac, uint8_t *pRxPacketIn
 	pSta->htMIMOPSState = state;
 	lim_post_sm_state_update(mac, pSta->htMIMOPSState,
 				 pSta->staAddr, pe_session->smeSessionId);
+	wlan_son_deliver_smps(pe_session->vdev,
+			      (eSIR_HT_MIMO_PS_STATIC == state) ? 1 : 0,
+			      pSta->staAddr);
 }
 
 
@@ -1824,6 +1833,17 @@ void lim_process_action_frame(struct mac_context *mac_ctx,
 		break;
 
 	case ACTION_CATEGORY_RRM:
+
+		if (mac_ctx->rrm.rrmPEContext.rrmEnable &&
+		    LIM_IS_AP_ROLE(session) &&
+		    action_hdr->actionID == RRM_RADIO_MEASURE_RPT) {
+			mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
+			wlan_son_deliver_rrm_rpt(session->vdev,
+				 mac_hdr->sa,
+				 body_ptr + sizeof(tSirMacActionFrameHdr),
+				 frame_len - sizeof(tSirMacActionFrameHdr));
+		}
+
 		/* Ignore RRM measurement request until DHCP is set */
 		if (mac_ctx->rrm.rrmPEContext.rrmEnable &&
 		    mac_ctx->roam.roamSession[session->smeSessionId].dhcp_done) {