849 lines
25 KiB
Diff
849 lines
25 KiB
Diff
From 1cfe2ac93a1b50a6fd2f6d0022ece6e0f2a91259 Mon Sep 17 00:00:00 2001
|
|
From: Kurt Lee <kurt.lee@cypress.com>
|
|
Date: Sun, 10 Apr 2022 22:10:51 -0500
|
|
Subject: [PATCH 23/60] non-upstream: wl-cmd: create interface to support
|
|
driver priv command
|
|
|
|
1. Create "wl" command interface to set/get driver information
|
|
2. Create files and compile flag to separate this feature
|
|
3. Support 2g_rate/5g_rate command
|
|
|
|
Upstream-Status: Inappropriate [DEY specific]
|
|
|
|
Signed-off-by: Ian Lin <ian.lin@infineon.com>
|
|
Signed-off-by: Kurt Lee <kurt.lee@infineon.com>
|
|
---
|
|
hostapd/ctrl_iface.c | 20 +++
|
|
hostapd/defconfig_base | 2 +
|
|
hostapd/hostapd_cli.c | 11 ++
|
|
src/ap/ap_drv_ops.h | 10 ++
|
|
src/common/brcm_wl_ioctl.h | 10 ++
|
|
src/common/brcm_wl_ioctl_defs.h | 15 ++
|
|
src/common/brcm_wl_rspec.h | 104 +++++++++++
|
|
src/drivers/driver.h | 1 +
|
|
src/drivers/driver_brcm_nl80211.h | 26 +++
|
|
src/drivers/driver_brcm_wlu.c | 289 ++++++++++++++++++++++++++++++
|
|
src/drivers/driver_brcm_wlu.h | 12 ++
|
|
src/drivers/driver_nl80211.c | 149 +++++++++++++++
|
|
src/drivers/drivers.mak | 5 +
|
|
wpa_supplicant/defconfig_base | 2 +
|
|
14 files changed, 655 insertions(+)
|
|
create mode 100644 src/common/brcm_wl_ioctl.h
|
|
create mode 100644 src/common/brcm_wl_ioctl_defs.h
|
|
create mode 100644 src/common/brcm_wl_rspec.h
|
|
create mode 100644 src/drivers/driver_brcm_nl80211.h
|
|
create mode 100644 src/drivers/driver_brcm_wlu.c
|
|
create mode 100644 src/drivers/driver_brcm_wlu.h
|
|
|
|
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
|
|
index 86adf18e5..ec1a2d1e3 100644
|
|
--- a/hostapd/ctrl_iface.c
|
|
+++ b/hostapd/ctrl_iface.c
|
|
@@ -3499,6 +3499,21 @@ static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
|
|
}
|
|
#endif /* ANDROID */
|
|
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+static int hostapd_ctrl_iface_wl_cmd(struct hostapd_data *hapd, char *cmd,
|
|
+ char *buf, size_t buflen)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = hostapd_drv_wl_cmd(hapd, cmd, buf, buflen);
|
|
+ if (ret == 0) {
|
|
+ ret = os_snprintf(buf, buflen, "%s\n", "OK");
|
|
+ if (os_snprintf_error(buflen, ret))
|
|
+ ret = -1;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
|
|
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
|
char *buf, char *reply,
|
|
@@ -4016,6 +4031,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
|
reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
|
|
reply_size);
|
|
#endif /* ANDROID */
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+ } else if (os_strncmp(buf, "WL ", 3) == 0) {
|
|
+ reply_len = hostapd_ctrl_iface_wl_cmd(hapd, buf + 3, reply,
|
|
+ reply_size);
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
} else {
|
|
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
|
|
reply_len = 16;
|
|
diff --git a/hostapd/defconfig_base b/hostapd/defconfig_base
|
|
index dafcf0f6c..4e4f0f784 100644
|
|
--- a/hostapd/defconfig_base
|
|
+++ b/hostapd/defconfig_base
|
|
@@ -21,6 +21,8 @@ CONFIG_DRIVER_NL80211=y
|
|
# QCA vendor extensions to nl80211
|
|
#CONFIG_DRIVER_NL80211_QCA=y
|
|
|
|
+CONFIG_DRIVER_BRCM_WL=y
|
|
+
|
|
# driver_nl80211.c requires libnl. If you are compiling it yourself
|
|
# you may need to point hostapd to your version of libnl.
|
|
#
|
|
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
|
|
index 260912111..9ab2342c9 100644
|
|
--- a/hostapd/hostapd_cli.c
|
|
+++ b/hostapd/hostapd_cli.c
|
|
@@ -1549,6 +1549,13 @@ static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
|
#endif /* ANDROID */
|
|
|
|
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+static int hostapd_cli_cmd_wl(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
|
+{
|
|
+ return hostapd_cli_cmd(ctrl, "WL", 1, argc, argv);
|
|
+}
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
+
|
|
struct hostapd_cli_cmd {
|
|
const char *cmd;
|
|
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
|
@@ -1744,6 +1751,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
|
{ "driver", hostapd_cli_cmd_driver, NULL,
|
|
"<driver sub command> [<hex formatted data>] = send driver command data" },
|
|
#endif /* ANDROID */
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+ { "wl", hostapd_cli_cmd_wl, NULL,
|
|
+ "<driver sub command> [<hex formatted data>] = send brcm wl command data" },
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
{ NULL, NULL, NULL, NULL }
|
|
};
|
|
|
|
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
|
|
index 61c8f64eb..5bf092c46 100644
|
|
--- a/src/ap/ap_drv_ops.h
|
|
+++ b/src/ap/ap_drv_ops.h
|
|
@@ -403,6 +403,16 @@ static inline int hostapd_drv_driver_cmd(struct hostapd_data *hapd,
|
|
}
|
|
#endif /* ANDROID */
|
|
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+static inline int hostapd_drv_wl_cmd(struct hostapd_data *hapd,
|
|
+ char *cmd, char *buf, size_t buf_len)
|
|
+{
|
|
+ if (!hapd->driver->wl_cmd)
|
|
+ return -1;
|
|
+ return hapd->driver->wl_cmd(hapd->drv_priv, cmd, buf, buf_len);
|
|
+}
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
+
|
|
#ifdef CONFIG_TESTING_OPTIONS
|
|
static inline int
|
|
hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type,
|
|
diff --git a/src/common/brcm_wl_ioctl.h b/src/common/brcm_wl_ioctl.h
|
|
new file mode 100644
|
|
index 000000000..768b78616
|
|
--- /dev/null
|
|
+++ b/src/common/brcm_wl_ioctl.h
|
|
@@ -0,0 +1,10 @@
|
|
+/*
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#include "common/brcm_wl_ioctl_defs.h"
|
|
+#include "common/brcm_wl_rspec.h"
|
|
diff --git a/src/common/brcm_wl_ioctl_defs.h b/src/common/brcm_wl_ioctl_defs.h
|
|
new file mode 100644
|
|
index 000000000..1834be6fa
|
|
--- /dev/null
|
|
+++ b/src/common/brcm_wl_ioctl_defs.h
|
|
@@ -0,0 +1,15 @@
|
|
+/*
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
|
|
+#define WLC_IOCTL_MEDLEN 1896 /* "med" length ioctl buffer required */
|
|
+
|
|
+/* common ioctl definitions */
|
|
+#define WLC_GET_VAR 262 /* get value of named variable */
|
|
+#define WLC_SET_VAR 263 /* set named variable to value */
|
|
+
|
|
diff --git a/src/common/brcm_wl_rspec.h b/src/common/brcm_wl_rspec.h
|
|
new file mode 100644
|
|
index 000000000..d10e82597
|
|
--- /dev/null
|
|
+++ b/src/common/brcm_wl_rspec.h
|
|
@@ -0,0 +1,104 @@
|
|
+/*
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+/* Rate spec. definitions */
|
|
+#define WL_RSPEC_RATE_MASK 0x000000FF /**< Legacy rate or MCS or MCS + NSS */
|
|
+#define WL_RSPEC_TXEXP_MASK 0x00000300 /**< Tx chain expansion beyond Nsts */
|
|
+#define WL_RSPEC_TXEXP_SHIFT 8
|
|
+#define WL_RSPEC_HE_GI_MASK 0x00000C00 /* HE GI indices */
|
|
+#define WL_RSPEC_HE_GI_SHIFT 10
|
|
+#define WL_RSPEC_BW_MASK 0x00070000 /**< Band width */
|
|
+#define WL_RSPEC_BW_SHIFT 16
|
|
+#define WL_RSPEC_ER_MASK 0x0000C000 /**< Range extension mask */
|
|
+#define WL_RSPEC_ER_SHIFT 14
|
|
+#define WL_RSPEC_ER_ENAB_MASK 0x00008000 /**< Range extension enable */
|
|
+#define WL_RSPEC_ER_ENAB_SHIFT 15
|
|
+#define WL_RSPEC_ER_TONE_MASK 0x00004000 /**< Range extension tone config */
|
|
+#define WL_RSPEC_ER_TONE_SHIFT 14
|
|
+
|
|
+#define WL_RSPEC_DCM 0x00080000 /**< Dual Carrier Modulation */
|
|
+#define WL_RSPEC_DCM_SHIFT 19
|
|
+#define WL_RSPEC_STBC 0x00100000 /**< STBC expansion, Nsts = 2 * Nss */
|
|
+#define WL_RSPEC_TXBF 0x00200000
|
|
+#define WL_RSPEC_LDPC 0x00400000
|
|
+#define WL_RSPEC_SGI 0x00800000
|
|
+#define WL_RSPEC_SHORT_PREAMBLE 0x00800000 /**< DSSS short preable - Encoding 0 */
|
|
+#define WL_RSPEC_ENCODING_MASK 0x03000000 /**< Encoding of RSPEC_RATE field */
|
|
+#define WL_RSPEC_ENCODING_SHIFT 24
|
|
+
|
|
+#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /**< override rate only */
|
|
+#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /**< override both rate & mode */
|
|
+
|
|
+/* ======== RSPEC_HE_GI|RSPEC_SGI fields for HE ======== */
|
|
+
|
|
+/* GI for HE */
|
|
+#define RSPEC_HE_LTF_GI(rspec) (((rspec) & WL_RSPEC_HE_GI_MASK) >> WL_RSPEC_HE_GI_SHIFT)
|
|
+#define WL_RSPEC_HE_1x_LTF_GI_0_8us (0x0)
|
|
+#define WL_RSPEC_HE_2x_LTF_GI_0_8us (0x1)
|
|
+#define WL_RSPEC_HE_2x_LTF_GI_1_6us (0x2)
|
|
+#define WL_RSPEC_HE_4x_LTF_GI_3_2us (0x3)
|
|
+#define RSPEC_ISHEGI(rspec) (RSPEC_HE_LTF_GI(rspec) > WL_RSPEC_HE_1x_LTF_GI_0_8us)
|
|
+#define HE_GI_TO_RSPEC(gi) (((gi) << WL_RSPEC_HE_GI_SHIFT) & WL_RSPEC_HE_GI_MASK)
|
|
+
|
|
+/* RSPEC Macros for extracting and using HE-ER and DCM */
|
|
+#define RSPEC_HE_DCM(rspec) (((rspec) & WL_RSPEC_DCM) >> WL_RSPEC_DCM_SHIFT)
|
|
+#define RSPEC_HE_ER(rspec) (((rspec) & WL_RSPEC_ER_MASK) >> WL_RSPEC_ER_SHIFT)
|
|
+#define RSPEC_HE_ER_ENAB(rspec) (((rspec) & WL_RSPEC_ER_ENAB_MASK) >> \
|
|
+ WL_RSPEC_ER_ENAB_SHIFT)
|
|
+#define RSPEC_HE_ER_TONE(rspec) (((rspec) & WL_RSPEC_ER_TONE_MASK) >> \
|
|
+ WL_RSPEC_ER_TONE_SHIFT)
|
|
+/* ======== RSPEC_RATE field ======== */
|
|
+
|
|
+/* Encoding 0 - legacy rate */
|
|
+/* DSSS, CCK, and OFDM rates in [500kbps] units */
|
|
+#define WL_RSPEC_LEGACY_RATE_MASK 0x0000007F
|
|
+#define WLC_RATE_1M 2
|
|
+#define WLC_RATE_2M 4
|
|
+#define WLC_RATE_5M5 11
|
|
+#define WLC_RATE_11M 22
|
|
+#define WLC_RATE_6M 12
|
|
+#define WLC_RATE_9M 18
|
|
+#define WLC_RATE_12M 24
|
|
+#define WLC_RATE_18M 36
|
|
+#define WLC_RATE_24M 48
|
|
+#define WLC_RATE_36M 72
|
|
+#define WLC_RATE_48M 96
|
|
+#define WLC_RATE_54M 108
|
|
+
|
|
+/* Encoding 1 - HT MCS */
|
|
+#define WL_RSPEC_HT_MCS_MASK 0x0000007F /**< HT MCS value mask in rspec */
|
|
+
|
|
+/* Encoding 2 - VHT MCS + NSS */
|
|
+#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /**< VHT MCS value mask in rspec */
|
|
+#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /**< VHT Nss value mask in rspec */
|
|
+#define WL_RSPEC_VHT_NSS_SHIFT 4 /**< VHT Nss value shift in rspec */
|
|
+
|
|
+/* Encoding 3 - HE MCS + NSS */
|
|
+#define WL_RSPEC_HE_MCS_MASK 0x0000000F /**< HE MCS value mask in rspec */
|
|
+#define WL_RSPEC_HE_NSS_MASK 0x000000F0 /**< HE Nss value mask in rspec */
|
|
+#define WL_RSPEC_HE_NSS_SHIFT 4 /**< HE Nss value shift in rpsec */
|
|
+
|
|
+/* ======== RSPEC_BW field ======== */
|
|
+
|
|
+#define WL_RSPEC_BW_UNSPECIFIED 0
|
|
+#define WL_RSPEC_BW_20MHZ 0x00010000
|
|
+#define WL_RSPEC_BW_40MHZ 0x00020000
|
|
+#define WL_RSPEC_BW_80MHZ 0x00030000
|
|
+#define WL_RSPEC_BW_160MHZ 0x00040000
|
|
+#define WL_RSPEC_BW_10MHZ 0x00050000
|
|
+#define WL_RSPEC_BW_5MHZ 0x00060000
|
|
+#define WL_RSPEC_BW_2P5MHZ 0x00070000
|
|
+
|
|
+/* ======== RSPEC_ENCODING field ======== */
|
|
+
|
|
+#define WL_RSPEC_ENCODE_RATE 0x00000000 /**< Legacy rate is stored in RSPEC_RATE */
|
|
+#define WL_RSPEC_ENCODE_HT 0x01000000 /**< HT MCS is stored in RSPEC_RATE */
|
|
+#define WL_RSPEC_ENCODE_VHT 0x02000000 /**< VHT MCS and NSS are stored in RSPEC_RATE */
|
|
+#define WL_RSPEC_ENCODE_HE 0x03000000 /**< HE MCS and NSS are stored in RSPEC_RATE */
|
|
+#define WL_RSPEC_HE_NSS_UNSPECIFIED 0xF
|
|
+
|
|
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
|
|
index fb3f8b4a8..3d48f6f07 100644
|
|
--- a/src/drivers/driver.h
|
|
+++ b/src/drivers/driver.h
|
|
@@ -3861,6 +3861,7 @@ struct wpa_driver_ops {
|
|
*/
|
|
int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
|
|
#endif /* ANDROID */
|
|
+ int (*wl_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
|
|
|
|
/**
|
|
* vendor_cmd - Execute vendor specific command
|
|
diff --git a/src/drivers/driver_brcm_nl80211.h b/src/drivers/driver_brcm_nl80211.h
|
|
new file mode 100644
|
|
index 000000000..40a84d125
|
|
--- /dev/null
|
|
+++ b/src/drivers/driver_brcm_nl80211.h
|
|
@@ -0,0 +1,26 @@
|
|
+/*
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+struct bcm_nlmsg_hdr {
|
|
+ uint cmd; /* common ioctl definition */
|
|
+ int len; /* expected return buffer length */
|
|
+ uint offset; /* user buffer offset */
|
|
+ uint set; /* get or set request optional */
|
|
+ uint magic; /* magic number for verification */
|
|
+};
|
|
+
|
|
+enum bcmnl_attrs {
|
|
+ BCM_NLATTR_UNSPEC,
|
|
+
|
|
+ BCM_NLATTR_LEN,
|
|
+ BCM_NLATTR_DATA,
|
|
+
|
|
+ __BCM_NLATTR_AFTER_LAST,
|
|
+ BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1
|
|
+};
|
|
+
|
|
diff --git a/src/drivers/driver_brcm_wlu.c b/src/drivers/driver_brcm_wlu.c
|
|
new file mode 100644
|
|
index 000000000..f2264ebcc
|
|
--- /dev/null
|
|
+++ b/src/drivers/driver_brcm_wlu.c
|
|
@@ -0,0 +1,289 @@
|
|
+/*
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#include "includes.h"
|
|
+#include "common.h"
|
|
+#include "common/brcm_vendor.h"
|
|
+#include "common/brcm_wl_ioctl.h"
|
|
+#include "common/wpa_common.h"
|
|
+
|
|
+/*
|
|
+ * 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)
|
|
+{
|
|
+ uint encode, rate, txexp, bw_val;
|
|
+ const char* stbc;
|
|
+ const char* ldpc;
|
|
+ const char* bw;
|
|
+ const char* dcm;
|
|
+ const char* er;
|
|
+ u8 valid_encding = false;
|
|
+
|
|
+ encode = (rspec & WL_RSPEC_ENCODING_MASK);
|
|
+ rate = (rspec & WL_RSPEC_RATE_MASK);
|
|
+ txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
|
|
+ bw_val = (rspec & WL_RSPEC_BW_MASK);
|
|
+ stbc = ((rspec & WL_RSPEC_STBC) != 0) ? " stbc" : "";
|
|
+ ldpc = ((rspec & WL_RSPEC_LDPC) != 0) ? " ldpc" : "";
|
|
+ dcm = ((rspec & WL_RSPEC_DCM) != 0) ? " dcm" : "";
|
|
+
|
|
+ if (RSPEC_HE_ER_ENAB(rspec) != 0) {
|
|
+ er = RSPEC_HE_ER_TONE(rspec) ? " er 106" : " er 242";
|
|
+ } else {
|
|
+ er = "";
|
|
+ }
|
|
+
|
|
+ if (bw_val == WL_RSPEC_BW_UNSPECIFIED) {
|
|
+ bw = "auto";
|
|
+ } else if (bw_val == WL_RSPEC_BW_20MHZ) {
|
|
+ bw = "20";
|
|
+ } else if (bw_val == WL_RSPEC_BW_40MHZ) {
|
|
+ bw = "40";
|
|
+ } else if (bw_val == WL_RSPEC_BW_80MHZ) {
|
|
+ bw = "80";
|
|
+ } else if (bw_val == WL_RSPEC_BW_160MHZ) {
|
|
+ bw = "160";
|
|
+ } else if (bw_val == WL_RSPEC_BW_10MHZ) {
|
|
+ bw = "10";
|
|
+ } else if (bw_val == WL_RSPEC_BW_5MHZ) {
|
|
+ bw = "5";
|
|
+ } else if (bw_val == WL_RSPEC_BW_2P5MHZ) {
|
|
+ bw = "2.5";
|
|
+ } else {
|
|
+ bw = "???";
|
|
+ }
|
|
+
|
|
+ if ((rspec & ~WL_RSPEC_TXEXP_MASK) == 0) { /* Ignore TxExpansion for NULL rspec check */
|
|
+ valid_encding = true;
|
|
+ os_snprintf(rate_buf, buf_len, "auto");
|
|
+ } else if (encode == WL_RSPEC_ENCODE_HE) {
|
|
+ const char* gi_ltf[] = {" 1xLTF GI 0.8us", " 2xLTF GI 0.8us",
|
|
+ " 2xLTF GI 1.6us", " 4xLTF GI 3.2us"};
|
|
+ u8 gi_int = RSPEC_HE_LTF_GI(rspec);
|
|
+ uint mcs = (rspec & WL_RSPEC_HE_MCS_MASK);
|
|
+ uint Nss = (rspec & WL_RSPEC_HE_NSS_MASK) >> WL_RSPEC_HE_NSS_SHIFT;
|
|
+
|
|
+ valid_encding = true;
|
|
+
|
|
+ os_snprintf(rate_buf, buf_len, "he mcs %d Nss %d Tx Exp %d BW %s%s%s%s%s%s",
|
|
+ mcs, Nss, txexp, bw, stbc, ldpc, gi_ltf[gi_int], dcm, er);
|
|
+
|
|
+ } else {
|
|
+ const char* sgi;
|
|
+ sgi = ((rspec & WL_RSPEC_SGI) != 0) ? " sgi" : "";
|
|
+ if (encode == WL_RSPEC_ENCODE_RATE) {
|
|
+
|
|
+ valid_encding = true;
|
|
+
|
|
+ os_snprintf(rate_buf, buf_len, "rate %d%s Mbps Tx Exp %d",
|
|
+ rate/2, (rate % 2)?".5":"", txexp);
|
|
+ } else if (encode == WL_RSPEC_ENCODE_HT) {
|
|
+
|
|
+ valid_encding = true;
|
|
+
|
|
+ os_snprintf(rate_buf, buf_len, "ht mcs %d Tx Exp %d BW %s%s%s%s",
|
|
+ rate, txexp, bw, stbc, ldpc, sgi);
|
|
+ } else if (encode == WL_RSPEC_ENCODE_VHT) {
|
|
+ uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK);
|
|
+ uint Nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
|
|
+
|
|
+ valid_encding = true;
|
|
+
|
|
+ os_snprintf(rate_buf, buf_len, "vht mcs %d Nss %d Tx Exp %d BW %s%s%s%s",
|
|
+ mcs, Nss, txexp, bw, stbc, ldpc, sgi);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!valid_encding) {
|
|
+ os_snprintf(rate_buf, buf_len, "<unknown encoding for ratespec 0x%08X>", rspec);
|
|
+ }
|
|
+
|
|
+ return rate_buf;
|
|
+}
|
|
+
|
|
+
|
|
+/* parse the -v/--vht or -c argument for the wl_rate() command.
|
|
+ * 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
|
|
+wl_parse_he_vht_spec(const char* cp, int* mcsp, int* nssp)
|
|
+{
|
|
+ char *startp, *endp;
|
|
+ char c;
|
|
+ int mcs, nss;
|
|
+ char sx;
|
|
+
|
|
+ if (cp == NULL || cp[0] == '\0') {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (cp[0] == 'c') {
|
|
+ startp = (char*)cp + 1;
|
|
+ sx = 's';
|
|
+ }
|
|
+ else {
|
|
+ startp = (char*)cp;
|
|
+ sx = 'x';
|
|
+ }
|
|
+
|
|
+ mcs = (int)strtol(startp, &endp, 10);
|
|
+ /* verify MCS 0-11, and next char is 's' or 'x' */
|
|
+ /* HE MCS is 0-11, VHT MCS 0-9 and prop MCS 10-11 */
|
|
+ if (mcs < 0 || mcs > 11 || endp[0] != sx) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /* grab the char after the 'x'/'s' and convert to value */
|
|
+ c = endp[1];
|
|
+ nss = 0;
|
|
+ if (isdigit((int)c)) {
|
|
+ nss = c - '0';
|
|
+ }
|
|
+
|
|
+ /* consume trailing space after digit */
|
|
+ cp = &endp[2];
|
|
+ while (isspace((int)(*cp))) {
|
|
+ cp++;
|
|
+ }
|
|
+
|
|
+ /* check for trailing garbage after digit */
|
|
+ if (cp[0] != '\0') {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (nss < 1 || nss > 8) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ *mcsp = mcs;
|
|
+ *nssp = nss;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+int wl_rate_set(char *cmd, char *set_buf, u32 *set_buf_len)
|
|
+{
|
|
+ int ret = -1;
|
|
+ char *pos;
|
|
+ //bool legacy_set = false, ht_set = false, vht_set = false, he_set = false;
|
|
+ bool he_set = false;
|
|
+ int rate, mcs, Nss, tx_exp, bw;
|
|
+ bool stbc, ldpc, sgi, dcm, er;
|
|
+ u8 hegi;
|
|
+
|
|
+ u32 rspec = 0;
|
|
+ int val_int = 0;
|
|
+ char *endp;
|
|
+
|
|
+ /* set default values */
|
|
+ rate = 0;
|
|
+ mcs = 0;
|
|
+ Nss = 0;
|
|
+ tx_exp = 0;
|
|
+ stbc = false;
|
|
+ ldpc = false;
|
|
+ sgi = false;
|
|
+ hegi = 0xFF;
|
|
+ bw = 0;
|
|
+ dcm = false;
|
|
+ er = false;
|
|
+
|
|
+ pos = os_strstr(cmd, "-r ");
|
|
+ if (pos) {
|
|
+ pos += 3;
|
|
+ rate = atoi(pos) * 2;
|
|
+ rspec = WL_RSPEC_ENCODE_RATE; /* 11abg */
|
|
+ rspec |= rate;
|
|
+ }
|
|
+
|
|
+ /* Option: -e or --he */
|
|
+ pos = os_strstr(cmd, "-e ");
|
|
+ if (pos) {
|
|
+ char var_str[10];
|
|
+ pos += 3;
|
|
+ endp = os_strchr(pos, ' ');
|
|
+ if (endp == NULL)
|
|
+ endp = os_strchr(pos, '\0');
|
|
+ os_memcpy(var_str, pos, endp - pos);
|
|
+ var_str[endp - pos] = '\0';
|
|
+
|
|
+ val_int = (int)strtol(var_str, &endp, 10);
|
|
+ if (*endp == '\0') {
|
|
+ mcs = val_int;
|
|
+ he_set = true;
|
|
+ } else if (wl_parse_he_vht_spec(var_str, &mcs, &Nss)) {
|
|
+ he_set = true;
|
|
+ } else {
|
|
+ wpa_printf(MSG_DEBUG, "%s: could not parse \"%s\""
|
|
+ "as a value for %s option",
|
|
+ "5g_rate", pos, "-e");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ pos = os_strstr(cmd, "-i ");
|
|
+ if (pos) {
|
|
+ if (!he_set) {
|
|
+ wpa_printf(MSG_DEBUG, ":use -i option only in he ");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ pos += 3;
|
|
+ val_int = (int)strtol(pos, &endp, 10);
|
|
+ if (*endp == '\0') {
|
|
+ if (val_int < 4)
|
|
+ {
|
|
+ hegi = val_int;
|
|
+ }
|
|
+ else {
|
|
+ wpa_printf(MSG_DEBUG, "%s: could not parse "
|
|
+ "\"%s\" as a value for %s option",
|
|
+ "5g_rate", pos, "-i");
|
|
+ goto exit;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Option: -l or --ldpc */
|
|
+ pos = os_strstr(cmd, "-l");
|
|
+ if (pos) {
|
|
+ ldpc = true;
|
|
+ }
|
|
+
|
|
+ /* set the other rspec fields */
|
|
+ rspec |= (tx_exp << WL_RSPEC_TXEXP_SHIFT);
|
|
+ rspec |= bw;
|
|
+ rspec |= (stbc ? WL_RSPEC_STBC : 0);
|
|
+ rspec |= (ldpc ? WL_RSPEC_LDPC : 0);
|
|
+ rspec |= (sgi ? WL_RSPEC_SGI : 0);
|
|
+ rspec |= ((hegi != 0xFF) ? HE_GI_TO_RSPEC(hegi) : 0);
|
|
+ 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);
|
|
+
|
|
+ ret = 0;
|
|
+exit:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
diff --git a/src/drivers/driver_brcm_wlu.h b/src/drivers/driver_brcm_wlu.h
|
|
new file mode 100644
|
|
index 000000000..67832dc6a
|
|
--- /dev/null
|
|
+++ b/src/drivers/driver_brcm_wlu.h
|
|
@@ -0,0 +1,12 @@
|
|
+/*
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+/* 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_rate_set(char *cmd, char *set_buf, u32 *set_buf_len);
|
|
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
|
|
index 964486c11..8b04f9dc9 100644
|
|
--- a/src/drivers/driver_nl80211.c
|
|
+++ b/src/drivers/driver_nl80211.c
|
|
@@ -28,6 +28,11 @@
|
|
#include "common/qca-vendor.h"
|
|
#include "common/qca-vendor-attr.h"
|
|
#include "common/brcm_vendor.h"
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+#include "common/brcm_wl_ioctl.h"
|
|
+#include "driver_brcm_wlu.h"
|
|
+#include "drivers/driver_brcm_nl80211.h"
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
#include "common/ieee802_11_defs.h"
|
|
#include "common/ieee802_11_common.h"
|
|
#include "common/wpa_common.h"
|
|
@@ -10121,6 +10126,147 @@ static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+static int nl80211_wl_reply_handler(struct nl_msg *msg, void *arg)
|
|
+{
|
|
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
|
|
+ struct nlattr *bcmnl[BCM_NLATTR_MAX + 1];
|
|
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
|
+ char *buf = arg;
|
|
+ int ret = 0;
|
|
+
|
|
+ wpa_printf(MSG_INFO, "nl80211: wl command reply handler");
|
|
+
|
|
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
|
+ genlmsg_attrlen(gnlh, 0), NULL);
|
|
+
|
|
+ if (tb_msg[NL80211_ATTR_VENDOR_DATA]) {
|
|
+ wpa_printf(MSG_INFO, "nl80211: Vendor Data Found");
|
|
+ ret = nla_parse_nested(bcmnl, BCM_NLATTR_MAX,
|
|
+ tb_msg[NL80211_ATTR_VENDOR_DATA], NULL);
|
|
+ if (ret != 0)
|
|
+ return NL_SKIP;
|
|
+ os_memcpy(buf, nla_data(bcmnl[BCM_NLATTR_DATA]), nla_get_u16(bcmnl[BCM_NLATTR_LEN]));
|
|
+ }
|
|
+
|
|
+ return NL_SKIP;
|
|
+}
|
|
+
|
|
+
|
|
+int nl80211_wl_command(void *priv, char *cmd, char *buf, size_t buf_len)
|
|
+{
|
|
+ struct i802_bss *bss = priv;
|
|
+ struct wpa_driver_nl80211_data *drv = bss->drv;
|
|
+ struct nl_msg *msg;
|
|
+ int ret = -1;
|
|
+ struct bcm_nlmsg_hdr *nlioc;
|
|
+ char *pos;
|
|
+ char smbuf[WLC_IOCTL_SMLEN * 2] = {0x00};
|
|
+ char outbuf[WLC_IOCTL_MEDLEN] = {0x00};
|
|
+ u32 msglen = 0;
|
|
+ bool set = false;
|
|
+
|
|
+ bool is_get_int = false;
|
|
+ u32 output_val = 0x00;
|
|
+
|
|
+ msg = nlmsg_alloc();
|
|
+ if (!msg)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* nlmsg_alloc() can only allocate default_pagesize packet, cap
|
|
+ * any buffer send down to 1536 bytes
|
|
+ * DO NOT switch to nlmsg_alloc_size because Android doesn't support it
|
|
+ */
|
|
+ if (msglen > 0x600)
|
|
+ msglen = 0x600;
|
|
+ if (set)
|
|
+ msglen += sizeof(struct bcm_nlmsg_hdr);
|
|
+ else
|
|
+ msglen = WLC_IOCTL_SMLEN;
|
|
+ nlioc = malloc(msglen);
|
|
+ if (nlioc == NULL) {
|
|
+ nlmsg_free(msg);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ if (set)
|
|
+ nlioc->cmd = WLC_SET_VAR;
|
|
+ else
|
|
+ nlioc->cmd = WLC_GET_VAR;
|
|
+ nlioc->len = msglen - sizeof(struct bcm_nlmsg_hdr);
|
|
+ nlioc->offset = sizeof(struct bcm_nlmsg_hdr);
|
|
+ nlioc->set = set;
|
|
+ nlioc->magic = 0;
|
|
+ os_memcpy(((void *)nlioc) + nlioc->offset, smbuf, msglen - nlioc->offset);
|
|
+
|
|
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
|
|
+ if (nl80211_set_iface_id(msg, bss) < 0) {
|
|
+ goto nla_put_failure;
|
|
+ }
|
|
+
|
|
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM);
|
|
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_PRIV_STR);
|
|
+ NLA_PUT(msg, NL80211_ATTR_VENDOR_DATA, msglen, nlioc);
|
|
+
|
|
+ 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: "
|
|
+ "ret=%d (%s)", ret, strerror(-ret));
|
|
+ ret = 0;
|
|
+ }
|
|
+
|
|
+ wpa_printf(MSG_DEBUG, "nl80211: vendor cmd sent successfully ");
|
|
+
|
|
+ if (set == false && is_get_int == true) {
|
|
+ os_memcpy(&output_val, outbuf, sizeof(output_val));
|
|
+ wl_rate_print(buf, buf_len, output_val);
|
|
+ ret = buf_len;
|
|
+ }
|
|
+
|
|
+nla_put_failure:
|
|
+exit:
|
|
+
|
|
+ nlmsg_free(msg);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
+
|
|
+
|
|
static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
|
|
unsigned int subcmd, const u8 *data,
|
|
size_t data_len, enum nested_attr nested_attr,
|
|
@@ -12263,6 +12409,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
|
.driver_cmd = wpa_driver_nl80211_driver_cmd,
|
|
#endif /* !ANDROID_LIB_STUB */
|
|
#endif /* ANDROID */
|
|
+#ifdef CONFIG_DRIVER_BRCM_WL
|
|
+ .wl_cmd = nl80211_wl_command,
|
|
+#endif /* CONFIG_DRIVER_BRCM_WL */
|
|
.vendor_cmd = nl80211_vendor_cmd,
|
|
.set_qos_map = nl80211_set_qos_map,
|
|
.get_wowlan = nl80211_get_wowlan,
|
|
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
|
|
index a03d4a034..a986fa379 100644
|
|
--- a/src/drivers/drivers.mak
|
|
+++ b/src/drivers/drivers.mak
|
|
@@ -30,6 +30,11 @@ ifdef CONFIG_DRIVER_NL80211_BRCM
|
|
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
|
|
endif
|
|
|
|
+ifdef CONFIG_DRIVER_BRCM_WL
|
|
+DRV_CFLAGS += -DCONFIG_DRIVER_BRCM_WL
|
|
+DRV_OBJS += ../src/drivers/driver_brcm_wlu.o
|
|
+endif
|
|
+
|
|
ifdef CONFIG_DRIVER_MACSEC_QCA
|
|
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
|
|
DRV_OBJS += ../src/drivers/driver_macsec_qca.o
|
|
diff --git a/wpa_supplicant/defconfig_base b/wpa_supplicant/defconfig_base
|
|
index 4f71b50ff..d4be24c34 100644
|
|
--- a/wpa_supplicant/defconfig_base
|
|
+++ b/wpa_supplicant/defconfig_base
|
|
@@ -34,6 +34,8 @@ CONFIG_DRIVER_NL80211=y
|
|
# QCA vendor extensions to nl80211
|
|
#CONFIG_DRIVER_NL80211_QCA=y
|
|
|
|
+CONFIG_DRIVER_BRCM_WL=y
|
|
+
|
|
# driver_nl80211.c requires libnl. If you are compiling it yourself
|
|
# you may need to point hostapd to your version of libnl.
|
|
#
|
|
--
|
|
2.17.1
|
|
|