wlan: Low Power Heartbeat feature
New customer requirement, Low power heartbeat
FW will handle TCP/UDP level heartbeat failure detection.
Host will send configuration request to FW with parameters.
Host will use TESTMODE as a command path.
Change-Id: I7a0ad93e409fa432c68b9d73aff64b6c3fc13782
CRs-fixed: 518667
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 3993408..9c05427 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -503,6 +503,33 @@
extern struct net_device_ops net_ops_struct;
+#ifdef WLAN_NL80211_TESTMODE
+enum wlan_hdd_tm_attr
+{
+ WLAN_HDD_TM_ATTR_INVALID = 0,
+ WLAN_HDD_TM_ATTR_CMD = 1,
+ WLAN_HDD_TM_ATTR_DATA = 2,
+ WLAN_HDD_TM_ATTR_TYPE = 3,
+ /* keep last */
+ WLAN_HDD_TM_ATTR_AFTER_LAST,
+ WLAN_HDD_TM_ATTR_MAX = WLAN_HDD_TM_ATTR_AFTER_LAST - 1,
+};
+
+enum wlan_hdd_tm_cmd
+{
+ WLAN_HDD_TM_CMD_WLAN_HB = 1,
+};
+
+#define WLAN_HDD_TM_DATA_MAX_LEN 5000
+
+static const struct nla_policy wlan_hdd_tm_policy[WLAN_HDD_TM_ATTR_MAX + 1] =
+{
+ [WLAN_HDD_TM_ATTR_CMD] = { .type = NLA_U32 },
+ [WLAN_HDD_TM_ATTR_DATA] = { .type = NLA_BINARY,
+ .len = WLAN_HDD_TM_DATA_MAX_LEN },
+};
+#endif /* WLAN_NL80211_TESTMODE */
+
/*
* FUNCTION: wlan_hdd_cfg80211_init
* This function is called by hdd_wlan_startup()
@@ -8061,6 +8088,154 @@
return 0;
}
+#ifdef WLAN_NL80211_TESTMODE
+#ifdef FEATURE_WLAN_LPHB
+static void wlan_hdd_cfg80211_lphb_wait_timeout_ind_handler
+(
+ void *pAdapter,
+ void *indCont
+)
+{
+ tSirLPHBTimeoutInd *lphbTimeoutInd;
+ struct sk_buff *skb;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "LPHB wait timeout indication arrived");
+
+ if (NULL == indCont)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "LPHB timeout, invalid argument");
+ return;
+ }
+
+ lphbTimeoutInd = (tSirLPHBTimeoutInd *)indCont;
+ skb = cfg80211_testmode_alloc_event_skb(
+ ((hdd_adapter_t *)pAdapter)->wdev.wiphy,
+ sizeof(tSirLPHBTimeoutInd),
+ GFP_ATOMIC);
+ if (!skb)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "LPHB timeout, NL buffer alloc fail");
+ return;
+ }
+
+ NLA_PUT_U32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_HB);
+ NLA_PUT_U32(skb, WLAN_HDD_TM_ATTR_TYPE, lphbTimeoutInd->protocolType);
+ NLA_PUT(skb, WLAN_HDD_TM_ATTR_DATA,
+ sizeof(tSirLPHBTimeoutInd), lphbTimeoutInd);
+ cfg80211_testmode_event(skb, GFP_ATOMIC);
+ return;
+
+nla_put_failure:
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "NLA Put fail");
+ kfree_skb(skb);
+
+ return;
+}
+#endif /* FEATURE_WLAN_LPHB */
+
+static int wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
+{
+ struct nlattr *tb[WLAN_HDD_TM_ATTR_MAX + 1];
+ int err = 0;
+#ifdef FEATURE_WLAN_LPHB
+ hdd_context_t *pHddCtx = wiphy_priv(wiphy);
+#endif /* FEATURE_WLAN_LPHB */
+
+ err = nla_parse(tb, WLAN_HDD_TM_ATTR_MAX, data, len, wlan_hdd_tm_policy);
+ if (err)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s Testmode INV ATTR", __func__);
+ return err;
+ }
+
+ if (!tb[WLAN_HDD_TM_ATTR_CMD])
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s Testmode INV CMD", __func__);
+ return -EINVAL;
+ }
+
+ switch (nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD]))
+ {
+#ifdef FEATURE_WLAN_LPHB
+ /* Low Power Heartbeat configuration request */
+ case WLAN_HDD_TM_CMD_WLAN_HB:
+ {
+ int buf_len;
+ void *buf;
+ tSirLPHBReq *hb_params = NULL;
+
+ if (!tb[WLAN_HDD_TM_ATTR_DATA])
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s Testmode INV DATA", __func__);
+ return -EINVAL;
+ }
+
+ buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]);
+ buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]);
+ hb_params = (tSirLPHBReq *)vos_mem_malloc(sizeof(tSirLPHBReq));
+ if (NULL == hb_params)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s Request Buffer Alloc Fail", __func__);
+ return -EINVAL;
+ }
+
+ vos_mem_copy(hb_params, buf, buf_len);
+
+ /* LPHB enable and disable request will send to FW
+ * when host suspend and resume
+ * host suspend -> enable LPHB
+ * host resume -> disable LPHB
+ * if host is not suspend, cache into HDD context
+ * and when host goes to suspend, send request to FW */
+ if ((LPHB_SET_EN_PARAMS_INDID == hb_params->cmd) &&
+ (!pHddCtx->hdd_wlan_suspended))
+ {
+ /* Feature enable command cache into HDD context,
+ * if WLAN is not suspend
+ * When WLAN goes into suspend, send enable command to FW */
+ pHddCtx->lphbEnableReq.enable =
+ hb_params->params.lphbEnableReq.enable;
+ pHddCtx->lphbEnableReq.item =
+ hb_params->params.lphbEnableReq.item;
+ pHddCtx->lphbEnableReq.session =
+ hb_params->params.lphbEnableReq.session;
+ vos_mem_free(hb_params);
+ }
+ else
+ {
+ eHalStatus smeStatus;
+
+ /* If WLAN is suspend state, send enable command immediately */
+ smeStatus = sme_LPHBConfigReq((tHalHandle)(pHddCtx->hHal),
+ hb_params,
+ wlan_hdd_cfg80211_lphb_wait_timeout_ind_handler);
+ if (eHAL_STATUS_SUCCESS != smeStatus)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "LPHB Config Fail, disable");
+ pHddCtx->lphbEnableReq.enable = 0;
+ vos_mem_free(hb_params);
+ }
+ }
+ return 0;
+ }
+#endif /* FEATURE_WLAN_LPHB */
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return err;
+}
+#endif /* CONFIG_NL80211_TESTMODE */
+
/* cfg80211_ops */
static struct cfg80211_ops wlan_hdd_cfg80211_ops =
{
@@ -8125,5 +8300,8 @@
.sched_scan_stop = wlan_hdd_cfg80211_sched_scan_stop,
#endif /*FEATURE_WLAN_SCAN_PNO */
.set_mac_acl = wlan_hdd_cfg80211_set_mac_acl,
+#ifdef WLAN_NL80211_TESTMODE
+ .testmode_cmd = wlan_hdd_cfg80211_testmode,
+#endif
};