mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-07-18 05:36:57 +08:00
337 lines
12 KiB
Diff
337 lines
12 KiB
Diff
From 289dcba688d11fbaace7b9011ec1aab5c85f78ba Mon Sep 17 00:00:00 2001
|
|
From: Hector Martin <marcan@marcan.st>
|
|
Date: Mon, 20 Dec 2021 03:39:44 +0900
|
|
Subject: [PATCH 104/171] brcmfmac: cfg80211: Add support for scan params v2
|
|
|
|
This new API version is required for at least the BCM4387 firmware. Add
|
|
support for it, with a fallback to the v1 API.
|
|
|
|
Acked-by: Linus Walleij <linus.walleij@linaro.org>
|
|
Signed-off-by: Hector Martin <marcan@marcan.st>
|
|
---
|
|
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 113 ++++++++++++++----
|
|
.../broadcom/brcm80211/brcmfmac/feature.c | 1 +
|
|
.../broadcom/brcm80211/brcmfmac/feature.h | 4 +-
|
|
.../broadcom/brcm80211/brcmfmac/fwil_types.h | 49 +++++++-
|
|
4 files changed, 145 insertions(+), 22 deletions(-)
|
|
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
index 605206abe424..3d477f2e5b20 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
@@ -770,12 +770,50 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
|
|
}
|
|
}
|
|
|
|
+static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
|
|
+ struct brcmf_scan_params_v2_le *params_le,
|
|
+ struct cfg80211_scan_request *request);
|
|
+
|
|
+static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le,
|
|
+ struct brcmf_scan_params_le *params_le)
|
|
+{
|
|
+ size_t params_size;
|
|
+ u32 ch;
|
|
+ int n_channels, n_ssids;
|
|
+
|
|
+ memcpy(¶ms_le->ssid_le, ¶ms_v2_le->ssid_le,
|
|
+ sizeof(params_le->ssid_le));
|
|
+ memcpy(¶ms_le->bssid, ¶ms_v2_le->bssid,
|
|
+ sizeof(params_le->bssid));
|
|
+
|
|
+ params_le->bss_type = params_v2_le->bss_type;
|
|
+ params_le->scan_type = params_v2_le->scan_type;
|
|
+ params_le->nprobes = params_v2_le->nprobes;
|
|
+ params_le->active_time = params_v2_le->active_time;
|
|
+ params_le->passive_time = params_v2_le->passive_time;
|
|
+ params_le->home_time = params_v2_le->home_time;
|
|
+ params_le->channel_num = params_v2_le->channel_num;
|
|
+
|
|
+ ch = le32_to_cpu(params_v2_le->channel_num);
|
|
+ n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK;
|
|
+ n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT;
|
|
+
|
|
+ params_size = sizeof(u16) * n_channels;
|
|
+ if (n_ssids > 0) {
|
|
+ params_size = roundup(params_size, sizeof(u32));
|
|
+ params_size += sizeof(struct brcmf_ssid_le) * n_ssids;
|
|
+ }
|
|
+
|
|
+ memcpy(¶ms_le->channel_list[0],
|
|
+ ¶ms_v2_le->channel_list[0], params_size);
|
|
+}
|
|
+
|
|
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
|
|
struct brcmf_if *ifp, bool aborted,
|
|
bool fw_abort)
|
|
{
|
|
struct brcmf_pub *drvr = cfg->pub;
|
|
- struct brcmf_scan_params_le params_le;
|
|
+ struct brcmf_scan_params_v2_le params_v2_le;
|
|
struct cfg80211_scan_request *scan_request;
|
|
u64 reqid;
|
|
u32 bucket;
|
|
@@ -794,20 +832,23 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
|
|
if (fw_abort) {
|
|
/* Do a scan abort to stop the driver's scan engine */
|
|
brcmf_dbg(SCAN, "ABORT scan in firmware\n");
|
|
- memset(¶ms_le, 0, sizeof(params_le));
|
|
- eth_broadcast_addr(params_le.bssid);
|
|
- params_le.bss_type = DOT11_BSSTYPE_ANY;
|
|
- params_le.scan_type = 0;
|
|
- params_le.channel_num = cpu_to_le32(1);
|
|
- params_le.nprobes = cpu_to_le32(1);
|
|
- params_le.active_time = cpu_to_le32(-1);
|
|
- params_le.passive_time = cpu_to_le32(-1);
|
|
- params_le.home_time = cpu_to_le32(-1);
|
|
- /* Scan is aborted by setting channel_list[0] to -1 */
|
|
- params_le.channel_list[0] = cpu_to_le16(-1);
|
|
+
|
|
+ brcmf_escan_prep(cfg, ¶ms_v2_le, NULL);
|
|
+
|
|
/* E-Scan (or anyother type) can be aborted by SCAN */
|
|
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
|
|
- ¶ms_le, sizeof(params_le));
|
|
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
|
|
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
|
|
+ ¶ms_v2_le,
|
|
+ sizeof(params_v2_le));
|
|
+ } else {
|
|
+ struct brcmf_scan_params_le params_le;
|
|
+
|
|
+ brcmf_scan_params_v2_to_v1(¶ms_v2_le, ¶ms_le);
|
|
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
|
|
+ ¶ms_le,
|
|
+ sizeof(params_le));
|
|
+ }
|
|
+
|
|
if (err)
|
|
bphy_err(drvr, "Scan abort failed\n");
|
|
}
|
|
@@ -1027,7 +1068,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
|
|
}
|
|
|
|
static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
|
|
- struct brcmf_scan_params_le *params_le,
|
|
+ struct brcmf_scan_params_v2_le *params_le,
|
|
struct cfg80211_scan_request *request)
|
|
{
|
|
u32 n_ssids;
|
|
@@ -1036,9 +1077,14 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
|
|
s32 offset;
|
|
u16 chanspec;
|
|
char *ptr;
|
|
+ int length;
|
|
struct brcmf_ssid_le ssid_le;
|
|
|
|
eth_broadcast_addr(params_le->bssid);
|
|
+
|
|
+ length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
|
|
+
|
|
+ params_le->version = BRCMF_SCAN_PARAMS_VERSION_V2;
|
|
params_le->bss_type = DOT11_BSSTYPE_ANY;
|
|
params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
|
|
params_le->channel_num = 0;
|
|
@@ -1048,6 +1094,15 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
|
|
params_le->home_time = cpu_to_le32(-1);
|
|
memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le));
|
|
|
|
+ /* Scan abort */
|
|
+ if (!request) {
|
|
+ length += sizeof(u16);
|
|
+ params_le->channel_num = cpu_to_le32(1);
|
|
+ params_le->channel_list[0] = cpu_to_le16(-1);
|
|
+ params_le->length = cpu_to_le16(length);
|
|
+ return;
|
|
+ }
|
|
+
|
|
n_ssids = request->n_ssids;
|
|
n_channels = request->n_channels;
|
|
|
|
@@ -1055,6 +1110,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
|
|
brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
|
|
n_channels);
|
|
if (n_channels > 0) {
|
|
+ length += roundup(sizeof(u16) * n_channels, sizeof(u32));
|
|
for (i = 0; i < n_channels; i++) {
|
|
chanspec = channel_to_chanspec(&cfg->d11inf,
|
|
request->channels[i]);
|
|
@@ -1065,12 +1121,14 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
|
|
} else {
|
|
brcmf_dbg(SCAN, "Scanning all channels\n");
|
|
}
|
|
+
|
|
/* Copy ssid array if applicable */
|
|
brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
|
|
if (n_ssids > 0) {
|
|
- offset = offsetof(struct brcmf_scan_params_le, channel_list) +
|
|
+ offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) +
|
|
n_channels * sizeof(u16);
|
|
offset = roundup(offset, sizeof(u32));
|
|
+ length += sizeof(ssid_le) * n_ssids,
|
|
ptr = (char *)params_le + offset;
|
|
for (i = 0; i < n_ssids; i++) {
|
|
memset(&ssid_le, 0, sizeof(ssid_le));
|
|
@@ -1090,6 +1148,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
|
|
brcmf_dbg(SCAN, "Performing passive scan\n");
|
|
params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
|
|
}
|
|
+ params_le->length = cpu_to_le16(length);
|
|
/* Adding mask to channel numbers */
|
|
params_le->channel_num =
|
|
cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
|
|
@@ -1101,8 +1160,8 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
|
|
struct cfg80211_scan_request *request)
|
|
{
|
|
struct brcmf_pub *drvr = cfg->pub;
|
|
- s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
|
|
- offsetof(struct brcmf_escan_params_le, params_le);
|
|
+ s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE +
|
|
+ offsetof(struct brcmf_escan_params_le, params_v2_le);
|
|
struct brcmf_escan_params_le *params;
|
|
s32 err = 0;
|
|
|
|
@@ -1122,8 +1181,22 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
|
|
goto exit;
|
|
}
|
|
BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
|
|
- brcmf_escan_prep(cfg, ¶ms->params_le, request);
|
|
- params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
|
|
+ brcmf_escan_prep(cfg, ¶ms->params_v2_le, request);
|
|
+
|
|
+ params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2);
|
|
+
|
|
+ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
|
|
+ struct brcmf_escan_params_le *params_v1;
|
|
+
|
|
+ params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
|
|
+ params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE;
|
|
+ params_v1 = kzalloc(params_size, GFP_KERNEL);
|
|
+ params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
|
|
+ brcmf_scan_params_v2_to_v1(¶ms->params_v2_le, ¶ms_v1->params_le);
|
|
+ kfree(params);
|
|
+ params = params_v1;
|
|
+ }
|
|
+
|
|
params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
|
|
params->sync_id = cpu_to_le16(0x1234);
|
|
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
|
|
index d2ac844e1e9f..19df83399a45 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
|
|
@@ -288,6 +288,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
|
|
ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
|
|
|
|
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
|
|
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver");
|
|
|
|
if (drvr->settings->feature_disable) {
|
|
brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
|
|
index d1f4257af696..9d098a068d13 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
|
|
@@ -29,6 +29,7 @@
|
|
* DOT11H: firmware supports 802.11h
|
|
* SAE: simultaneous authentication of equals
|
|
* FWAUTH: Firmware authenticator
|
|
+ * SCAN_V2: Version 2 scan params
|
|
*/
|
|
#define BRCMF_FEAT_LIST \
|
|
BRCMF_FEAT_DEF(MBSS) \
|
|
@@ -51,7 +52,8 @@
|
|
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
|
|
BRCMF_FEAT_DEF(DOT11H) \
|
|
BRCMF_FEAT_DEF(SAE) \
|
|
- BRCMF_FEAT_DEF(FWAUTH)
|
|
+ BRCMF_FEAT_DEF(FWAUTH) \
|
|
+ BRCMF_FEAT_DEF(SCAN_V2)
|
|
|
|
/*
|
|
* Quirks:
|
|
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
|
|
index c87b829adb0d..648dc302b998 100644
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
|
|
@@ -48,6 +48,10 @@
|
|
|
|
/* size of brcmf_scan_params not including variable length array */
|
|
#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
|
|
+#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE 72
|
|
+
|
|
+/* version of brcmf_scan_params structure */
|
|
+#define BRCMF_SCAN_PARAMS_VERSION_V2 2
|
|
|
|
/* masks for channel and ssid count */
|
|
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
|
|
@@ -67,6 +71,7 @@
|
|
#define BRCMF_PRIMARY_KEY (1 << 1)
|
|
#define DOT11_BSSTYPE_ANY 2
|
|
#define BRCMF_ESCAN_REQ_VERSION 1
|
|
+#define BRCMF_ESCAN_REQ_VERSION_V2 2
|
|
|
|
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
|
|
|
|
@@ -386,6 +391,45 @@ struct brcmf_scan_params_le {
|
|
__le16 channel_list[1]; /* list of chanspecs */
|
|
};
|
|
|
|
+struct brcmf_scan_params_v2_le {
|
|
+ __le16 version; /* structure version */
|
|
+ __le16 length; /* structure length */
|
|
+ struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
|
|
+ u8 bssid[ETH_ALEN]; /* default: bcast */
|
|
+ s8 bss_type; /* default: any,
|
|
+ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
|
|
+ */
|
|
+ u8 pad;
|
|
+ __le32 scan_type; /* flags, 0 use default */
|
|
+ __le32 nprobes; /* -1 use default, number of probes per channel */
|
|
+ __le32 active_time; /* -1 use default, dwell time per channel for
|
|
+ * active scanning
|
|
+ */
|
|
+ __le32 passive_time; /* -1 use default, dwell time per channel
|
|
+ * for passive scanning
|
|
+ */
|
|
+ __le32 home_time; /* -1 use default, dwell time for the
|
|
+ * home channel between channel scans
|
|
+ */
|
|
+ __le32 channel_num; /* count of channels and ssids that follow
|
|
+ *
|
|
+ * low half is count of channels in
|
|
+ * channel_list, 0 means default (use all
|
|
+ * available channels)
|
|
+ *
|
|
+ * high half is entries in struct brcmf_ssid
|
|
+ * array that follows channel_list, aligned for
|
|
+ * s32 (4 bytes) meaning an odd channel count
|
|
+ * implies a 2-byte pad between end of
|
|
+ * channel_list and first ssid
|
|
+ *
|
|
+ * if ssid count is zero, single ssid in the
|
|
+ * fixed parameter portion is assumed, otherwise
|
|
+ * ssid in the fixed portion is ignored
|
|
+ */
|
|
+ __le16 channel_list[1]; /* list of chanspecs */
|
|
+};
|
|
+
|
|
struct brcmf_scan_results {
|
|
u32 buflen;
|
|
u32 version;
|
|
@@ -397,7 +441,10 @@ struct brcmf_escan_params_le {
|
|
__le32 version;
|
|
__le16 action;
|
|
__le16 sync_id;
|
|
- struct brcmf_scan_params_le params_le;
|
|
+ union {
|
|
+ struct brcmf_scan_params_le params_le;
|
|
+ struct brcmf_scan_params_v2_le params_v2_le;
|
|
+ };
|
|
};
|
|
|
|
struct brcmf_escan_result_le {
|
|
--
|
|
2.34.1
|
|
|