From 20f95ac91bf3a7082e851d700af2ed708807bac7 Mon Sep 17 00:00:00 2001
From: Ashwin Adiga <ashwin.adiga@infineon.com>
Date: Sun, 5 May 2024 08:46:44 -0500
Subject: [PATCH] non-upstream: mkeep_alive and tko string vendor cmds

IW vendor commands for mkeep_alive & tko are being added
here which uses string parsing infrastructure.

Example for mkeep_alive: wl -> iw

1. wl mkeep_alive 0 1000
2. echo 'mkeep_alive 0 1000 ' | iw dev wlan0 vendor
send 0x000319 0x1C -

Example for tko: wl -> iw
1. wl tko enable 1
2. echo 'tko enable 1 ' | iw dev wlan0 vendor
send 0x000319 0x1C -

Signed-off-by: Ashwin Adiga <ashwin.adiga@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/vendor_ifx.c  | 85 +++++++++++++++++++
 .../broadcom/brcm80211/brcmfmac/vendor_ifx.h  | 32 +++++++
 2 files changed, 117 insertions(+)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
index 6755167d0..c8bffb02e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
@@ -49,6 +49,8 @@
 
 static const struct ifx_vendor_cmdstr ifx_vndr_cmdstr[] = {
 	{ "offload_config", ifx_vndr_cmdstr_offload_config},
+	{ "mkeep_alive", ifx_vndr_cmdstr_mkeep_alive},
+	{ "tko", ifx_vndr_cmdstr_tko},
 	{ NULL, NULL }
 };
 
@@ -886,6 +888,89 @@ int ifx_vndr_cmdstr_offload_config(struct wiphy *wiphy, struct wireless_dev *wde
 	return ret;
 }
 
+int ifx_vndr_cmdstr_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
+				char cmd_str[VNDR_CMD_STR_NUM][VNDR_CMD_STR_MAX_LEN],
+				long *cmd_val)
+{
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_if *ifp;
+	int ret = 0;
+	struct ifx_mkeep_alive mkeep_alive = {0};
+	bool immed_flag = 0;
+
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+	ifp = vif->ifp;
+
+	/* echo 'mkeep_alive 0 1000 ' | iw dev wlan0 vendor
+	 * send 0x000319 0x1C -
+	 */
+
+	if (cmd_val[0] < 0 || cmd_val[0] > 4 || cmd_val[1] < 0) {
+		brcmf_err("Invalid command format\n");
+		return -EINVAL;
+	}
+	if (cmd_str[1] && (strlen(cmd_str[1]) == 9) &&
+	    (memcmp(cmd_str[1], "immediate", 9)) == 0) {
+		immed_flag = 1;
+	}
+	mkeep_alive.period_msec = cmd_val[1];
+	if (mkeep_alive.period_msec & WL_MKEEP_ALIVE_IMMEDIATE) {
+		brcmf_err("Period %d too large\n", mkeep_alive.period_msec);
+		return -EINVAL;
+	}
+	if (immed_flag && mkeep_alive.period_msec)
+		mkeep_alive.period_msec |= WL_MKEEP_ALIVE_IMMEDIATE;
+
+	mkeep_alive.version = WL_MKEEP_ALIVE_VERSION;
+	mkeep_alive.length = offsetof(struct ifx_mkeep_alive, data);
+	mkeep_alive.keep_alive_id = cmd_val[0];
+	mkeep_alive.len_bytes = 0;
+
+	ret = brcmf_fil_bsscfg_data_set(ifp, "mkeep_alive", (void *)&mkeep_alive,
+					mkeep_alive.length);
+	if (ret)
+		brcmf_err("Failed to set mkeeplive params: %d\n", ret);
+
+	return ret;
+}
+
+int ifx_vndr_cmdstr_tko(struct wiphy *wiphy, struct wireless_dev *wdev,
+			char cmd_str[VNDR_CMD_STR_NUM][VNDR_CMD_STR_MAX_LEN],
+			long *cmd_val)
+{
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_if *ifp;
+	int ret = 0;
+	struct ifx_tko tko = {0};
+	struct ifx_tko_enable *tko_enable;
+	int length;
+
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+	ifp = vif->ifp;
+
+	/* echo 'tko enable 1 ' | iw dev wlan0 vendor
+	 * send 0x000319 0x1C -
+	 */
+	if (cmd_str[1] && (strlen(cmd_str[1]) == 6) &&
+	    (memcmp(cmd_str[1], "enable", 6) == 0) &&
+	     (cmd_val[0] == 0 || cmd_val[0] == 1)) {
+		tko_enable = (struct ifx_tko_enable *)tko.data;
+		tko.subcmd_id = WL_TKO_SUBCMD_ENABLE;
+		tko.len = sizeof(*tko_enable);
+		tko_enable->enable = cmd_val[0];
+
+		length = offsetof(struct ifx_tko, data) + tko.len;
+		ret = brcmf_fil_bsscfg_data_set(ifp, "tko", (void *)&tko, length);
+		if (ret)
+			brcmf_err("Failed to enable/disable tko: %d\n", ret);
+	} else {
+		brcmf_err("Invalid tko command format\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
 int ifx_cfg80211_vndr_cmds_str(struct wiphy *wiphy, struct wireless_dev *wdev,
 			       const void *data, int len)
 {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
index fdf6546a6..6e2218a3c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
@@ -702,6 +702,32 @@ struct ifx_maxidle_wnm {
 	int protect;
 };
 
+#define WL_MKEEP_ALIVE_VERSION		1
+#define WL_MKEEP_ALIVE_IMMEDIATE	0x80000000
+
+struct ifx_mkeep_alive {
+	u16 version;		/* Version for mkeep_alive */
+	u16 length;		/* length of fixed parameters in the structure */
+	u32 period_msec;	/* high bit on means immediate send */
+	u16 len_bytes;
+	u8 keep_alive_id;	/* 0 - 3 for N = 4 */
+	u8 data[1];
+};
+
+struct ifx_tko {
+	u16 subcmd_id;		/* subcommand id */
+	u16 len;		/* total length of data[] */
+	u8 data[1];		/* subcommand data */
+};
+
+/* subcommand ids */
+#define WL_TKO_SUBCMD_ENABLE		3	/* enable/disable */
+
+struct ifx_tko_enable {
+	u8 enable;		/* 1 - enable, 0 - disable */
+	u8 pad[3];		/* 4-byte struct alignment */
+};
+
 /* String based vendor commands infra
  */
 #define VNDR_CMD_STR_NUM	15
@@ -762,6 +788,12 @@ int ifx_cfg80211_vndr_cmds_wnm_wl_cap(struct wiphy *wiphy,
 int ifx_vndr_cmdstr_offload_config(struct wiphy *wiphy, struct wireless_dev *wdev,
 				   char cmd_str[VNDR_CMD_STR_NUM][VNDR_CMD_STR_MAX_LEN],
 				   long cmd_val[VNDR_CMD_VAL_NUM]);
+int ifx_vndr_cmdstr_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
+				char cmd_str[VNDR_CMD_STR_NUM][VNDR_CMD_STR_MAX_LEN],
+				long *cmd_val);
+int ifx_vndr_cmdstr_tko(struct wiphy *wiphy, struct wireless_dev *wdev,
+			char cmd_str[VNDR_CMD_STR_NUM][VNDR_CMD_STR_MAX_LEN],
+			long *cmd_val);
 int ifx_cfg80211_vndr_cmds_str(struct wiphy *wiphy, struct wireless_dev *wdev,
 			       const void *data, int len);
 
-- 
2.39.5 (Apple Git-154)

