From 7867b89f17ad995dd63d2fe60134a9e757af3859 Mon Sep 17 00:00:00 2001 From: Kshitij Bisht Date: Thu, 25 Apr 2024 15:41:44 -0500 Subject: [PATCH 256/296] non-upstream: vendor cmds string infrastructure with offload_config implementation IW Vendor Command String passing infrastructure is being added in this wherein fmac will handle user supplied strings directly via iw vendor interface. This can be used for migration of any wl cmd to iw wherein parameters passed to wl remain same is for iw. Example : wl -> iw 1. wl offload_config Profile LowPwr 1 -s 0x3df echo 'offload_config Profile LowPwr 1 -s 0x3df ' | iw dev wlan0 vendor send 0x000319 0x1C - 2. wl offload_config Enable 1 echo 'offload_config Enable 1 ' | iw dev wlan0 vendor send 0x000319 0x1C - Signed-off-by: Kshitij Bisht --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 6 + .../broadcom/brcm80211/brcmfmac/cfg80211.h | 2 + .../broadcom/brcm80211/brcmfmac/common.c | 3 +- .../broadcom/brcm80211/brcmfmac/vendor.c | 7 + .../broadcom/brcm80211/brcmfmac/vendor_ifx.c | 172 ++++++++++++++++++ .../broadcom/brcm80211/brcmfmac/vendor_ifx.h | 31 +++- 6 files changed, 219 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index d36a7024fdc1..63ccfce27dda 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -10682,6 +10682,11 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, } } + err = ifx_vndr_cmdstr_hashtbl_init(); + if (err) { + bphy_err(drvr, "vendor_cmd_hashtable initialisation failed (%d)\n", err); + goto detach; + } /* (re-) activate FWEH event handling */ err = brcmf_fweh_activate_events(ifp); if (err) { @@ -10722,6 +10727,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) if (!cfg) return; + ifx_vndr_cmdstr_hashtbl_deinit(); brcmf_pno_detach(cfg); brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 6b2412b8dccf..c886530c1991 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -526,4 +526,6 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_free_netdev(struct net_device *ndev); bool brcmf_is_apmode_operating(struct wiphy *wiphy); void brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev); +int ifx_vndr_cmdstr_hashtbl_init(void); +void ifx_vndr_cmdstr_hashtbl_deinit(void); #endif /* BRCMFMAC_CFG80211_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index b813217044d9..3520c969ad6f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -123,7 +123,8 @@ unsigned int brcmf_offload_feat = BRCMF_OL_ARP | BRCMF_OL_DLTRO | BRCMF_OL_PNO | BRCMF_OL_KEEPALIVE | - BRCMF_OL_GTKOE; + BRCMF_OL_GTKOE | + BRCMF_OL_WOWLPF; module_param_named(offload_feat, brcmf_offload_feat, uint, 0400); MODULE_PARM_DESC(offload_feat, "Offload feat bitmap: 0:arp 1:nd 2:mdns 3:icmp 4:tcp-keepalive " diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c index 853d0c38362d..03085634e1d1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c @@ -350,6 +350,13 @@ const struct wiphy_vendor_command brcmf_vendor_cmds[] = { VENDOR_CMD_RAW_DATA, ifx_cfg80211_vndr_cmds_wnm_wl_cap) }, + { + IFX_SUBCMD(CMDSTR, + (WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV), + VENDOR_CMD_RAW_DATA, + ifx_cfg80211_vndr_cmds_str) + }, }; const struct nl80211_vendor_cmd_info brcmf_vendor_events[] = { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c index 968c6820c346..cbd58f0082d1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c @@ -39,6 +39,18 @@ #include "xtlv.h" #include "twt.h" #include "bus.h" +#include +#include +#include +#include +#include "common.h" + +static const struct ifx_vendor_cmdstr ifx_vndr_cmdstr[] = { + { "offload_config", ifx_vndr_cmdstr_offload_config}, + { NULL, NULL } +}; + +DEFINE_HASHTABLE(vndr_cmd_hashtbl, VNDR_CMD_HASH_BITS); static int ifx_cfg80211_vndr_send_cmd_reply(struct wiphy *wiphy, const void *data, int len) @@ -57,6 +69,45 @@ static int ifx_cfg80211_vndr_send_cmd_reply(struct wiphy *wiphy, return cfg80211_vendor_cmd_reply(skb); } +int ifx_vndr_cmdstr_hashtbl_init(void) +{ + int i; + u32 jhash_key; + + brcmf_dbg(TRACE, "enter\n"); + + hash_init(vndr_cmd_hashtbl); + + /* Initializing the VENDOR CMD hashtable with all the string commmands + * and func_handler in ifx_vndr_str_cmds + */ + for (i = 0; ifx_vndr_cmdstr[i].name; i++) { + struct ifx_vndr_cmdstr_hashtbl *vndr_hashtbl; + + vndr_hashtbl = kzalloc(sizeof(*vndr_hashtbl), GFP_KERNEL); + if (!vndr_hashtbl) + return -ENOMEM; + + vndr_hashtbl->vndr_cmd_addr = (struct ifx_vendor_cmdstr *)&ifx_vndr_cmdstr[i]; + jhash_key = jhash(ifx_vndr_cmdstr[i].name, strlen(ifx_vndr_cmdstr[i].name), 0); + hash_add(vndr_cmd_hashtbl, &vndr_hashtbl->node, jhash_key); + } + + return 0; +} + +void ifx_vndr_cmdstr_hashtbl_deinit(void) +{ + struct ifx_vndr_cmdstr_hashtbl *vndr_hashtbl; + struct hlist_node *tmp_node; + int i; + + hash_for_each_safe(vndr_cmd_hashtbl, i, tmp_node, vndr_hashtbl, node) { + hash_del(&vndr_hashtbl->node); + kfree(vndr_hashtbl); + } +} + static void ifx_cfgvendor_twt_parse_params(const struct nlattr *attr_iter, struct brcmf_twt_params *twt_params) @@ -773,3 +824,124 @@ int ifx_cfg80211_vndr_cmds_wnm_wl_cap(struct wiphy *wiphy, return ret; } + +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]) +{ + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; + int ret = 0; + + vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); + ifp = vif->ifp; + + /* IW CMDSTR TEMPLATE. + * echo 'offload_config Enable 1 ' | iw dev wlan0 vendor send 0x000319 + * 0x1C - + * + * echo 'offload_config Profile LowPwr 1 -s 0x3df ' | 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)) { + brcmf_generic_offload_enable(ifp, brcmf_offload_feat, cmd_val[0]); + } else if (cmd_str[1] && (strlen(cmd_str[1]) == 7) && + (memcmp(cmd_str[1], "Profile", 7)) == 0) { + if (cmd_str[2]) { + unsigned int ol_prof; + + if ((strlen(cmd_str[2]) == 6) && + (memcmp(cmd_str[2], "LowPwr", 6)) == 0) { + ol_prof = BRCMF_OL_PROF_TYPE_LOW_PWR; + } else if ((strlen(cmd_str[2]) == 6) && + (memcmp(cmd_str[2], "MidPwr", 6)) == 0) { + ol_prof = BRCMF_OL_PROF_TYPE_MID_PWR; + } else if ((strlen(cmd_str[2]) == 7) && + (memcmp(cmd_str[2], "HighPwr", 7)) == 0) { + ol_prof = BRCMF_OL_PROF_TYPE_HIGH_PWR; + } else { + brcmf_err("unknown offload_config Profile attr\n"); + return -EINVAL; + } + if (cmd_str[3] && (strlen(cmd_str[3]) == 2) && + (memcmp(cmd_str[3], "-s", 2)) == 0) + brcmf_generic_offload_config(ifp, ~cmd_val[1], ol_prof, cmd_val[0]); + else + brcmf_generic_offload_config(ifp, brcmf_offload_feat, ol_prof, + cmd_val[0]); + } else { + brcmf_err("unknown offload_config Profile attr\n"); + return -EINVAL; + } + } else { + brcmf_err("unknown offload_config attr\n"); + return -EINVAL; + } + + return ret; +} + +int ifx_cfg80211_vndr_cmds_str(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len) +{ + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; + struct ifx_vndr_cmdstr_hashtbl *hash_entry; + u32 jhash_key; + int ret = 0, i = 0, j = 0; + unsigned long val; + char cmd_str[VNDR_CMD_STR_NUM][VNDR_CMD_STR_MAX_LEN] = {{""}}; + long cmd_val[VNDR_CMD_VAL_NUM]; + char *tok = NULL, *buf = NULL; + + buf = (char *)data; + vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); + ifp = vif->ifp; + + memset(cmd_val, -1, VNDR_CMD_VAL_NUM * sizeof(*cmd_val)); + + while ((tok = strsep(&buf, " ")) != NULL) { + if (kstrtoul(tok, 10, &val) == 0) { + cmd_val[j] = val; + j++; + } else if ((strncmp(tok, "0x", 2) == 0) || (strncmp(tok, "0X", 2) == 0)) { + if (kstrtoul(tok, 16, &val) == 0) { + cmd_val[j] = val; + j++; + } else { + brcmf_err("Failed to parse hex token\n"); + return -EINVAL; + } + } else if (strnlen(tok, VNDR_CMD_STR_MAX_LEN) <= VNDR_CMD_STR_MAX_LEN) { + strncpy(cmd_str[i], tok, strnlen(tok, VNDR_CMD_STR_MAX_LEN)); + i++; + } else { + brcmf_err("Failed to parse token\n"); + return -EINVAL; + } + } + + /* Run the user cmd string input via Jenkins hash to pass and search the entry in + * vendor cmd hashtable initialized at load time. + */ + jhash_key = jhash(cmd_str[0], strlen(cmd_str[0]), 0); + + /* Search the user entered vndr cmd entry in the hash table and call its corresponding + * function handler. + */ + hash_for_each_possible(vndr_cmd_hashtbl, hash_entry, node, jhash_key) { + if (hash_entry->vndr_cmd_addr && + (strlen(cmd_str[0]) == strlen(hash_entry->vndr_cmd_addr->name)) && + memcmp(hash_entry->vndr_cmd_addr->name, cmd_str[0], + strlen(hash_entry->vndr_cmd_addr->name)) == 0) { + ret = hash_entry->vndr_cmd_addr->func(wiphy, wdev, + cmd_str, cmd_val); + break; + } + } + + return ret; +} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h index 5addec93ad29..2ece83f5e0f2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h @@ -109,6 +109,10 @@ struct bcm_iov_buf { * * @IFX_VENDOR_SCMD_HWCAPS: Get device's capability. * + * @IFX_VENDOR_SCMD_CMDSTR: New vendor string infra subcmd to handle user supplied strings. + * String parsing and calling corresponding function handler for a specific command + * given by user. + * * @IFX_VENDOR_SCMD_MAX: This acts as a the tail of cmds list. * Make sure it located at the end of the list. */ @@ -141,7 +145,8 @@ enum ifx_nl80211_vendor_subcmds { SCMD(WNM) = 25, SCMD(HWCAPS) = 26, SCMD(WNM_WL_CAP) = 27, - SCMD(MAX) = 28 + SCMD(CMDSTR) = 28, + SCMD(MAX) = 29 }; /* @@ -695,6 +700,25 @@ struct ifx_maxidle_wnm { int protect; }; +/* String based vendor commands infra + */ +#define VNDR_CMD_STR_NUM 15 +#define VNDR_CMD_STR_MAX_LEN 20 +#define VNDR_CMD_VAL_NUM 15 +#define VNDR_CMD_HASH_BITS 4 + +struct ifx_vendor_cmdstr { + const char *name; + int (*func)(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]); +}; + +struct ifx_vndr_cmdstr_hashtbl { + struct ifx_vendor_cmdstr *vndr_cmd_addr; + struct hlist_node node; +}; + int ifx_cfg80211_vndr_cmds_twt(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); int ifx_cfg80211_vndr_cmds_bsscolor(struct wiphy *wiphy, @@ -733,6 +757,11 @@ int ifx_cfg80211_vndr_cmds_hwcaps(struct wiphy *wiphy, int ifx_cfg80211_vndr_cmds_wnm_wl_cap(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len); +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_cfg80211_vndr_cmds_str(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int len); #endif /* IFX_VENDOR_H */ -- 2.25.1