wlan: Changes for supporting RSSI Monitoring feature
Framework should get a indication whenever AP breaches rssi range.
Add support to set the rssi range in FW and forward the breach
event from FW to framework.
Change-Id: I08248d15fde966aad2ba54614d444b7310b3775a
CRs-Fixed: 916888
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 6e1e29d..9840645 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -6201,6 +6201,301 @@
}
+/*
+ * define short names for the global vendor params
+ * used by __wlan_hdd_cfg80211_monitor_rssi()
+ */
+#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
+#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID
+#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL
+#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI
+#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_rssi_monitor_start_done - callback to be executed when rssi
+ monitor start is completed successfully.
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+void hdd_rssi_monitor_start_done(void *fwRssiMonitorCbContext, VOS_STATUS status)
+{
+ hdd_context_t* pHddCtx = (hdd_context_t*)fwRssiMonitorCbContext;
+
+ if (NULL == pHddCtx)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: HDD context is NULL",__func__);
+ return;
+ }
+
+ if (VOS_STATUS_SUCCESS == status)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO, FL("Rssi Monitor start successful"));
+ }
+ else
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL("Rssi Monitor start not successful"));
+ }
+
+ return;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_rssi_monitor_stop_done - callback to be executed when rssi monitor
+ stop is completed successfully.
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+void hdd_rssi_monitor_stop_done(void *fwRssiMonitorCbContext, VOS_STATUS status)
+{
+ hdd_context_t* pHddCtx = (hdd_context_t*)fwRssiMonitorCbContext;
+
+ if (NULL == pHddCtx)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: HDD context is NULL",__func__);
+ return;
+ }
+
+ if (VOS_STATUS_SUCCESS == status)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO, FL("Rssi Monitor stop successful"));
+ }
+ else
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL("Rssi Monitor stop not successful"));
+ }
+
+ return;
+}
+
+/**
+ * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+
+static int
+__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ struct net_device *dev = wdev->netdev;
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+ hdd_station_ctx_t *pHddStaCtx;
+ struct nlattr *tb[PARAM_MAX + 1];
+ tpSirRssiMonitorReq pReq;
+ eHalStatus status;
+ int ret;
+ uint32_t control;
+ static const struct nla_policy policy[PARAM_MAX + 1] = {
+ [PARAM_REQUEST_ID] = { .type = NLA_U32 },
+ [PARAM_CONTROL] = { .type = NLA_U32 },
+ [PARAM_MIN_RSSI] = { .type = NLA_S8 },
+ [PARAM_MAX_RSSI] = { .type = NLA_S8 },
+ };
+
+ ENTER();
+
+ ret = wlan_hdd_validate_context(hdd_ctx);
+ if (0 != ret) {
+ return -EINVAL;
+ }
+
+ if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) {
+ hddLog(LOGE, FL("Not in Connected state!"));
+ return -ENOTSUPP;
+ }
+
+ if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) {
+ hddLog(LOGE, FL("Invalid ATTR"));
+ return -EINVAL;
+ }
+
+ if (!tb[PARAM_REQUEST_ID]) {
+ hddLog(LOGE, FL("attr request id failed"));
+ return -EINVAL;
+ }
+
+ if (!tb[PARAM_CONTROL]) {
+ hddLog(LOGE, FL("attr control failed"));
+ return -EINVAL;
+ }
+
+ pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+
+ pReq = vos_mem_malloc(sizeof(tSirRssiMonitorReq));
+ if(NULL == pReq)
+ {
+ hddLog(LOGE,
+ FL("vos_mem_alloc failed "));
+ return eHAL_STATUS_FAILED_ALLOC;
+ }
+ vos_mem_set(pReq, sizeof(tSirRssiMonitorReq), 0);
+
+ pReq->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]);
+ pReq->sessionId = pAdapter->sessionId;
+ pReq->rssiMonitorCbContext = hdd_ctx;
+ control = nla_get_u32(tb[PARAM_CONTROL]);
+ vos_mem_copy( &pReq->currentBssId, pHddStaCtx->conn_info.bssId, WNI_CFG_BSSID_LEN);
+
+ hddLog(LOG1, FL("Request Id: %u Session_id: %d Control: %d"),
+ pReq->requestId, pReq->sessionId, control);
+
+ if (control == QCA_WLAN_RSSI_MONITORING_START) {
+ if (!tb[PARAM_MIN_RSSI]) {
+ hddLog(LOGE, FL("attr min rssi failed"));
+ return -EINVAL;
+ }
+
+ if (!tb[PARAM_MAX_RSSI]) {
+ hddLog(LOGE, FL("attr max rssi failed"));
+ return -EINVAL;
+ }
+
+ pReq->minRssi = nla_get_s8(tb[PARAM_MIN_RSSI]);
+ pReq->maxRssi = nla_get_s8(tb[PARAM_MAX_RSSI]);
+ pReq->rssiMonitorCallback = hdd_rssi_monitor_start_done;
+
+ if (!(pReq->minRssi < pReq->maxRssi)) {
+ hddLog(LOGW, FL("min_rssi: %d must be less than max_rssi: %d"),
+ pReq->minRssi, pReq->maxRssi);
+ return -EINVAL;
+ }
+ hddLog(LOG1, FL("Min_rssi: %d Max_rssi: %d"),
+ pReq->minRssi, pReq->maxRssi);
+ status = sme_StartRssiMonitoring(hdd_ctx->hHal, pReq);
+
+ }
+ else if (control == QCA_WLAN_RSSI_MONITORING_STOP) {
+ pReq->rssiMonitorCallback = hdd_rssi_monitor_stop_done;
+ status = sme_StopRssiMonitoring(hdd_ctx->hHal, pReq);
+ }
+ else {
+ hddLog(LOGE, FL("Invalid control cmd: %d"), control);
+ return -EINVAL;
+ }
+
+ if (!HAL_STATUS_SUCCESS(status)) {
+ hddLog(LOGE,
+ FL("sme_set_rssi_monitoring failed(err=%d)"), status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * done with short names for the global vendor params
+ * used by __wlan_hdd_cfg80211_monitor_rssi()
+ */
+#undef PARAM_MAX
+#undef PARAM_CONTROL
+#undef PARAM_REQUEST_ID
+#undef PARAM_MAX_RSSI
+#undef PARAM_MIN_RSSI
+
+/**
+ * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring
+ * @wiphy: wiphy structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of @data
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int
+wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ int ret;
+
+ vos_ssr_protect(__func__);
+ ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len);
+ vos_ssr_unprotect(__func__);
+
+ return ret;
+}
+
+/**
+ * hdd_rssi_threshold_breached_cb() - rssi breached NL event
+ * @hddctx: HDD context
+ * @data: rssi breached event data
+ *
+ * This function reads the rssi breached event %data and fill in the skb with
+ * NL attributes and send up the NL event.
+ * This callback execute in atomic context and must not invoke any
+ * blocking calls.
+ *
+ * Return: none
+ */
+void hdd_rssi_threshold_breached_cb(void *hddctx,
+ struct rssi_breach_event *data)
+{
+ hdd_context_t *pHddCtx = (hdd_context_t *)hddctx;
+ int status;
+ struct sk_buff *skb;
+
+ ENTER();
+ status = wlan_hdd_validate_context(pHddCtx);
+
+ if (0 != status) {
+ return;
+ }
+
+ if (!data) {
+ hddLog(LOGE, FL("data is null"));
+ return;
+ }
+
+ skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ NULL,
+#endif
+ EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
+ QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX,
+ GFP_KERNEL);
+
+ if (!skb) {
+ hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
+ return;
+ }
+
+ hddLog(LOG1, "Req Id: %u Current rssi: %d",
+ data->request_id, data->curr_rssi);
+ hddLog(LOG1, "Current BSSID: "MAC_ADDRESS_STR,
+ MAC_ADDR_ARRAY(data->curr_bssid.bytes));
+
+ if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
+ data->request_id) ||
+ nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
+ sizeof(data->curr_bssid), data->curr_bssid.bytes) ||
+ nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI,
+ data->curr_rssi)) {
+ hddLog(LOGE, FL("nla put fail"));
+ goto fail;
+ }
+
+ cfg80211_vendor_event(skb, GFP_KERNEL);
+ return;
+
+fail:
+ kfree_skb(skb);
+ return;
+}
+
+
+
/**
* __wlan_hdd_cfg80211_setband() - set band
* @wiphy: Pointer to wireless phy
@@ -6486,6 +6781,14 @@
WIPHY_VENDOR_CMD_NEED_NETDEV |
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlan_hdd_cfg80211_monitor_rssi
}
};
@@ -6608,8 +6911,11 @@
{
.vendor_id = QCA_NL80211_VENDOR_ID,
.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO,
- }
-
+ },
+ [QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = {
+ .vendor_id = QCA_NL80211_VENDOR_ID,
+ .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI
+ },
};