From 05b1387d4dc2e74a02cf524733d809acc4fd46fb Mon Sep 17 00:00:00 2001 From: Kurt Lee Date: Wed, 27 Apr 2022 22:50:25 -0500 Subject: [PATCH 25/60] non-upstream: wl-cmd: create ops table to do wl commands Creeate wl_cmds to handle wl commands Upstream-Status: Inappropriate [DEY specific] Signed-off-by: Ian Lin Signed-off-by: Kurt Lee --- src/drivers/driver_brcm_wlu.c | 247 ++++++++++++++++++++++++------ src/drivers/driver_brcm_wlu.h | 2 +- src/drivers/driver_brcm_wlu_cmd.h | 23 +++ src/drivers/driver_nl80211.c | 27 ++-- 4 files changed, 240 insertions(+), 59 deletions(-) create mode 100644 src/drivers/driver_brcm_wlu_cmd.h diff --git a/src/drivers/driver_brcm_wlu.c b/src/drivers/driver_brcm_wlu.c index 4fc03e446..8e568f9f6 100644 --- a/src/drivers/driver_brcm_wlu.c +++ b/src/drivers/driver_brcm_wlu.c @@ -10,7 +10,110 @@ #include "common.h" #include "common/brcm_vendor.h" #include "common/brcm_wl_ioctl.h" +#include "common/brcm_wl_ioctl_defs.h" #include "common/wpa_common.h" +#include "driver_brcm_wlu_cmd.h" + +static cmd_func_t wl_rate; +static cmd_func_t wl_varint; + +#define RATE_2G_USAGE \ +"\tEither \"auto\", or a simple CCK/DSSS/OFDM rate value:\n" \ +"\t1 2 5.5 11 6 9 12 18 24 36 48 54\n\n" \ +"\tOr options to specify legacy, HT, or VHT rate:\n" \ +"\t-r R, --rate=R : legacy rate (CCK, DSSS, OFDM)\n" \ +"\t-h M, --ht=M : HT MCS index [0-23]\n" \ +"\t-v M[xS], --vht=M[xS] : VHT MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. 5x2 is MCS=5, Nss=2\n" \ +"\t-c cM[sS] : VHT (c notation) MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. c5s2 is MCS=5, Nss=2\n" \ +"\t-e M[xS], --he=M[xS] : HE rate M [0-11],\n" \ +"\t-s S, --ss=S : VHT Nss [1-8], number of spatial streams, default 1.\n" \ +"\t : Only used with -v/--vht when MxS format is not used\n" \ +"\t-x T, --exp=T : Tx Expansion, number of tx chains (NTx) beyond the minimum\n" \ +"\t : required for the space-time-streams, exp = NTx - Nsts\n" \ +"\t--stbc : Use STBC expansion, otherwise no STBC\n" \ +"\t-l, --ldpc : Use LDPC encoding, otherwise no LDPC\n" \ +"\t-g, --sgi : Guard interval. Different values for HT/VHT\n" \ +"\t : Use Short Guard Interval otherwise standard GI\n" \ +"\t-i, --hegi : Guard interval. Different values for HE\n" \ +"\t : For HE, cp_ltf combination allowed values (0,1,2,3)\n" \ +"\t-b, --bandwidth : transmit bandwidth in MHz [2.5, 5, 10, 20, 40, 80, 160] eg. -b 20\n" \ +"\t-d D, --dcm=D : Use -d to set DCM, otherwise no DCM\n" \ +"\t : (only when is MCS [0, 1], NSS 1, -b 20)\n" \ +"\t-n R, --er=R : R [106,242] HE Range extension\n" \ +"\t : otherwise no Rang extension and works only in 20 MHz" + +#define RATE_5G_6G_USAGE \ +"\tEither \"auto\", or a simple OFDM rate value:\n" \ +"\t6 9 12 18 24 36 48 54\n\n" \ +"\tOr options to specify legacy OFDM, HT, or VHT rate:\n" \ +"\t-r R, --rate=R : legacy OFDM rate\n" \ +"\t-h M, --ht=M : HT MCS index [0-23]\n" \ +"\t-v M[xS], --vht=M[xS] : VHT MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. 5x2 is MCS=5, Nss=2\n" \ +"\t-c cM[sS] : VHT (c notation) MCS index M [0-9],\n" \ +"\t : and optionally Nss S [1-8], eg. c5s2 is MCS=5, Nss=2\n" \ +"\t-e M[xS], --he=M[xS] : HE rate M [0-11],\n" \ +"\t-s S, --ss=S : VHT Nss [1-8], number of spatial streams, default 1.\n" \ +"\t : Only used with -v/--vht when MxS format is not used\n" \ +"\t-x T, --exp=T : Tx Expansion, number of tx chains (NTx) beyond the minimum\n" \ +"\t : required for the space-time-streams, exp = NTx - Nsts\n" \ +"\t--stbc : Use STBC expansion, otherwise no STBC\n" \ +"\t-l, --ldpc : Use LDPC encoding, otherwise no LDPC\n" \ +"\t-g, --sgi : Guard interval. Different values for HT/VHT\n" \ +"\t : Use Short Guard Interval otherwise standard GI\n" \ +"\t-i, --hegi : Guard interval. Different values for HE\n" \ +"\t : For HE cp_ltf combination allowed values (0,1,2,3)\n" \ +"\t-b, --bandwidth : transmit bandwidth in MHz [2.5, 5, 10, 20, 40, 80, 160] eg. -b 20\n" \ +"\t-d D, --dcm=D : Use -d to set DCM, otherwise no DCM\n" \ +"\t : (only when is MCS [0, 1], NSS 1, -b 20)\n" \ +"\t-n R, --er=R : R [106,242] HE Range extension\n" \ +"\t : otherwise no Rang extension and works only in 20 MHz" + +/* If the new command needs to be part of 'wc.exe' tool used for WMM, + * be sure to modify wc_cmds[] array as well + * + * If you add a command, please update wlu_cmd.c cmd2cat to categorize the command. + */ +cmd_t wl_cmds[] = { + { "2g_rate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for data frames in the 2.4G band:\n\n" + RATE_2G_USAGE + }, + { "2g_mrate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for mulitcast/broadcast data frames in the 2.4G band:\n\n" + RATE_2G_USAGE + }, + { "5g_rate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for data frames in the 5G band:\n\n" + RATE_5G_6G_USAGE + }, + { "5g_mrate", wl_rate, WLC_GET_VAR, WLC_SET_VAR, + "Force a fixed rate for mulitcast/broadcast data frames in the 5G band:\n\n" + RATE_5G_6G_USAGE + }, + { NULL, NULL, 0, 0, NULL } +}; + +cmd_t wl_varcmd = {"var", wl_varint, -1, -1, "unrecognized name, type -h for help"}; + +/* common function to find a command */ +cmd_t * +wlu_find_cmd(char *name) +{ + cmd_t *cmd = wl_cmds; + + /* search cmd in cmd table */ + for (; cmd->name; cmd++) { + /* stop if we find a matching name */ + if (!os_strncasecmp(cmd->name, name, os_strlen(cmd->name))) { + break; + } + } + + return (cmd->name != NULL) ? cmd : NULL; +} /* * Format a ratespec for output of any of the wl_rate() iovars @@ -113,8 +216,7 @@ wl_rate_print(char *rate_buf, size_t buf_len, u32 rspec) * return FALSE if the arg does not look like MxS or cMsS, where M and S are single digits * return TRUE if the arg does look like MxS or cMsS, setting mcsp to M, and nssp to S */ -//static int -int +static int wl_parse_he_vht_spec(const char* cp, int* mcsp, int* nssp) { char *startp, *endp; @@ -171,12 +273,13 @@ wl_parse_he_vht_spec(const char* cp, int* mcsp, int* nssp) } -int wl_rate_set(char *cmd, char *set_buf, u32 *set_buf_len) +static int +wl_rate(char *cmd, char *buf, u32 *buf_len, bool *get, bool *is_get_int) { int ret = -1; - char *pos; - //bool legacy_set = false, ht_set = false, vht_set = false, he_set = false; - bool he_set = false; + char *pos, *param = cmd; + bool auto_set = false; + bool legacy_set = false, ht_set = false, vht_set = false, he_set = false; int rate, mcs, Nss, tx_exp, bw; bool stbc, ldpc, sgi, dcm, er; u8 hegi; @@ -198,7 +301,48 @@ int wl_rate_set(char *cmd, char *set_buf, u32 *set_buf_len) dcm = false; er = false; - pos = os_strstr(cmd, "-r "); + pos = os_strstr(cmd, "5g_rate"); + if (pos) { + param = cmd + strlen("5g_rate"); + os_memcpy(buf, cmd, strlen("5g_rate")); //Keep last byte as 0x00 + *is_get_int = true; + *buf_len += strlen("5g_rate"); + + if (os_strncasecmp(cmd, "5g_rate ", 8) == 0) { + param += 1; + *get = false; + cmd += strlen("5g_rate "); + *buf_len += 1; + } + } + + pos = os_strstr(cmd, "2g_rate"); + if (pos) { + param = cmd + strlen("2g_rate"); + os_memcpy(buf, cmd, strlen("2g_rate")); //Keep last byte as 0x00 + *is_get_int = true; + *buf_len += strlen("2g_rate"); + + if (os_strncasecmp(cmd, "2g_rate ", 8) == 0) { + param += 1; + *get = false; + cmd += strlen("2g_rate "); + *buf_len += 1; + } + } + + if (*get == true) { + ret = 0; + goto exit; + } + + /* Option: -l or --ldpc */ + pos = os_strstr(param, "auto"); + if (pos) { + auto_set = true; + } + + pos = os_strstr(param, "-r "); if (pos) { pos += 3; rate = atoi(pos) * 2; @@ -207,7 +351,7 @@ int wl_rate_set(char *cmd, char *set_buf, u32 *set_buf_len) } /* Option: -e or --he */ - pos = os_strstr(cmd, "-e "); + pos = os_strstr(param, "-e "); if (pos) { char var_str[10]; pos += 3; @@ -240,7 +384,7 @@ int wl_rate_set(char *cmd, char *set_buf, u32 *set_buf_len) } - pos = os_strstr(cmd, "-i "); + pos = os_strstr(param, "-i "); if (pos) { if (!he_set) { wpa_printf(MSG_DEBUG, ":use -i option only in he "); @@ -264,11 +408,39 @@ int wl_rate_set(char *cmd, char *set_buf, u32 *set_buf_len) } /* Option: -l or --ldpc */ - pos = os_strstr(cmd, "-l"); + pos = os_strstr(param, "-l"); if (pos) { ldpc = true; } + /* set the ratespec encoding type and basic rate value */ + if (auto_set) { + rspec = 0; + } else if (legacy_set) { + rspec = WL_RSPEC_ENCODE_RATE; /* 11abg */ + rspec |= rate; + } else if (ht_set) { + rspec = WL_RSPEC_ENCODE_HT; /* 11n HT */ + rspec |= mcs; + } else if (vht_set) { + rspec = WL_RSPEC_ENCODE_VHT; /* 11ac VHT */ + if (Nss == 0) { + Nss = 1; /* default Nss = 1 if --ss option not given */ + } + rspec |= (Nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs; + } else if (he_set) { + rspec = WL_RSPEC_ENCODE_HE; /* 11ax HE */ + if (Nss == 0) { + Nss = WL_RSPEC_HE_NSS_UNSPECIFIED; + } + rspec |= (Nss << WL_RSPEC_HE_NSS_SHIFT) | mcs; + } else { + wpa_printf(MSG_ERROR, + "%s: Invalid rate set for %s option\n", + "wl", param); + goto exit; + } + /* set the other rspec fields */ rspec |= (tx_exp << WL_RSPEC_TXEXP_SHIFT); rspec |= bw; @@ -279,54 +451,39 @@ int wl_rate_set(char *cmd, char *set_buf, u32 *set_buf_len) rspec |= (dcm << WL_RSPEC_DCM_SHIFT); rspec |= (er << WL_RSPEC_ER_SHIFT); - os_memcpy(set_buf + *set_buf_len, (char *)&rspec, sizeof(rspec)); - *set_buf_len += sizeof(rspec); + os_memcpy(buf + *buf_len, (char *)&rspec, sizeof(rspec)); + *buf_len += sizeof(rspec); ret = 0; exit: return ret; } +/* just issue a wl_var_setint() or a wl_var_getint() if there is a 2nd arg */ +static int +wl_varint(char *cmd, char *buf, u32 *buf_len, bool *get, bool *is_get_int) +{ + return -1; +} -int wl_do_cmd(char *cmd, char *smbuf, u32 *msglen, bool *set, bool *is_get_int) +int wl_do_cmd(char *cmd, char *smbuf, u32 *msglen, bool *get, bool *is_get_int) { + cmd_t *wl_cmd = NULL; int ret = -1; - char *pos; - - pos = os_strstr(cmd, "5g_rate"); - if (pos) { - os_memcpy(smbuf, cmd, strlen("5g_rate")); //Keep last byte as 0x00 - *is_get_int = true; - *msglen += strlen("5g_rate"); - - if (os_strncasecmp(cmd, "5g_rate ", 8) == 0) { - *set = true; - cmd += strlen("5g_rate "); - *msglen += 1; - ret = wl_rate_set(cmd, smbuf, msglen); - if (ret != 0) - goto exit; - } - } + /* search for command */ + wl_cmd = wlu_find_cmd(cmd); - pos = os_strstr(cmd, "2g_rate"); - if (pos) { - os_memcpy(smbuf, cmd, strlen("2g_rate")); //Keep last byte as 0x00 - *is_get_int = true; - *msglen += strlen("2g_rate"); - - if (os_strncasecmp(cmd, "2g_rate ", 8) == 0) { - *set = true; - cmd += strlen("2g_rate "); - *msglen += 1; - - ret = wl_rate_set(cmd, smbuf, msglen); - if (ret != 0) - goto exit; - } + /* defaults to using the set_var and get_var commands */ + if (!wl_cmd) { + wl_cmd = &wl_varcmd; } + /* do command */ + ret = (*wl_cmd->func)(cmd, smbuf, msglen, get, is_get_int); + if (ret != 0) + goto exit; + ret = 0; exit: return ret; } diff --git a/src/drivers/driver_brcm_wlu.h b/src/drivers/driver_brcm_wlu.h index 7fc9118fc..a943a0832 100644 --- a/src/drivers/driver_brcm_wlu.h +++ b/src/drivers/driver_brcm_wlu.h @@ -9,4 +9,4 @@ /* Format a ratespec for output of any of the wl_rate() iovars */ char* wl_rate_print(char *rate_buf, size_t buf_len, u32 rspec); -int wl_do_cmd(char *cmd, char *smbuf, u32 *msglen, bool *set, bool *is_get_int); +int wl_do_cmd(char *cmd, char *smbuf, u32 *msglen, bool *get, bool *is_get_int); diff --git a/src/drivers/driver_brcm_wlu_cmd.h b/src/drivers/driver_brcm_wlu_cmd.h new file mode 100644 index 000000000..8443a625e --- /dev/null +++ b/src/drivers/driver_brcm_wlu_cmd.h @@ -0,0 +1,23 @@ +/* + * Broadcom Corporation OUI and vendor specific assignments + * Copyright (c) 2020, Broadcom Corporation. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +typedef struct cmd cmd_t; +typedef int (cmd_func_t)(char *cmd, char *buf, u32 *buf_len, bool *set, bool *is_get_int); + +/* generic command line argument handler */ +struct cmd { + const char *name; + cmd_func_t *func; + int get; + int set; + const char *help; +}; + +/* list of command line arguments */ +extern cmd_t wl_cmds[]; + diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index a6b9c860d..de58b17e1 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -10141,7 +10141,7 @@ static int nl80211_wl_reply_handler(struct nl_msg *msg, void *arg) genlmsg_attrlen(gnlh, 0), NULL); if (tb_msg[NL80211_ATTR_VENDOR_DATA]) { - wpa_printf(MSG_INFO, "nl80211: Vendor Data Found"); + wpa_printf(MSG_INFO, "nl80211: wl data found"); ret = nla_parse_nested(bcmnl, BCM_NLATTR_MAX, tb_msg[NL80211_ATTR_VENDOR_DATA], NULL); if (ret != 0) @@ -10163,7 +10163,7 @@ int nl80211_wl_command(void *priv, char *cmd, char *buf, size_t buf_len) char smbuf[WLC_IOCTL_SMLEN * 2] = {0x00}; char outbuf[WLC_IOCTL_MEDLEN] = {0x00}; u32 msglen = 0; - bool set = false; + bool get = true; bool is_get_int = false; u32 output_val = 0x00; @@ -10172,7 +10172,7 @@ int nl80211_wl_command(void *priv, char *cmd, char *buf, size_t buf_len) if (!msg) return -ENOMEM; - ret = wl_do_cmd(cmd, smbuf, &msglen, &set, &is_get_int); + ret = wl_do_cmd(cmd, smbuf, &msglen, &get, &is_get_int); if (ret != 0) goto exit; @@ -10182,22 +10182,23 @@ int nl80211_wl_command(void *priv, char *cmd, char *buf, size_t buf_len) */ if (msglen > 0x600) msglen = 0x600; - if (set) - msglen += sizeof(struct bcm_nlmsg_hdr); - else + if (get) msglen = WLC_IOCTL_SMLEN; + else + msglen += sizeof(struct bcm_nlmsg_hdr); + nlioc = malloc(msglen); if (nlioc == NULL) { nlmsg_free(msg); return -ENOMEM; } - if (set) - nlioc->cmd = WLC_SET_VAR; - else + if (get) nlioc->cmd = WLC_GET_VAR; + else + nlioc->cmd = WLC_SET_VAR; nlioc->len = msglen - sizeof(struct bcm_nlmsg_hdr); nlioc->offset = sizeof(struct bcm_nlmsg_hdr); - nlioc->set = set; + nlioc->set = !get; nlioc->magic = 0; os_memcpy(((void *)nlioc) + nlioc->offset, smbuf, msglen - nlioc->offset); @@ -10213,14 +10214,14 @@ int nl80211_wl_command(void *priv, char *cmd, char *buf, size_t buf_len) ret = send_and_recv_msgs(drv, msg, nl80211_wl_reply_handler, outbuf, NULL, NULL); msg = NULL; if (ret) { - wpa_printf(MSG_ERROR, "nl80211: vendor cmd failed: " + wpa_printf(MSG_ERROR, "nl80211: wl cmd failed: " "ret=%d (%s)", ret, strerror(-ret)); ret = 0; } - wpa_printf(MSG_DEBUG, "nl80211: vendor cmd sent successfully "); + wpa_printf(MSG_DEBUG, "nl80211: wl cmd sent successfully "); - if (set == false && is_get_int == true) { + if (get == true && is_get_int == true) { os_memcpy(&output_val, outbuf, sizeof(output_val)); wl_rate_print(buf, buf_len, output_val); ret = buf_len; -- 2.17.1