From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 1371 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 979 insertions(+), 392 deletions(-) diff --git a/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 75790b1..baf5f0a 100644 --- a/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ @@ -22,6 +11,7 @@ #include <linux/vmalloc.h> #include <net/cfg80211.h> #include <net/netlink.h> +#include <uapi/linux/if_arp.h> #include <brcmu_utils.h> #include <defs.h> @@ -33,6 +23,7 @@ #include "p2p.h" #include "btcoex.h" #include "pno.h" +#include "fwsignal.h" #include "cfg80211.h" #include "feature.h" #include "fwil.h" @@ -65,6 +56,7 @@ #define RSN_AKM_PSK 2 /* Pre-shared Key */ #define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */ #define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */ +#define RSN_AKM_SAE 8 /* SAE */ #define RSN_CAP_LEN 2 /* Length of RSN capabilities */ #define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3)) #define RSN_CAP_MFPR_MASK BIT(6) @@ -93,8 +85,13 @@ #define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000) +#define BRCMF_PS_MAX_TIMEOUT_MS 2000 + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) + +#define BRCMF_MAX_CHANSPEC_LIST \ + (BRCMF_DCMD_MEDLEN / sizeof(__le32) - 1) static bool check_vif_up(struct brcmf_cfg80211_vif *vif) { @@ -200,9 +197,9 @@ */ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), /* IEEE 802.11a, channel 36..64 */ - REG_RULE(5150-10, 5350+10, 80, 6, 20, 0), + REG_RULE(5150-10, 5350+10, 160, 6, 20, 0), /* IEEE 802.11a, channel 100..165 */ - REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), } + REG_RULE(5470-10, 5850+10, 160, 6, 20, 0), } }; /* Note: brcmf_cipher_suites is an array of int defining which cipher suites @@ -287,8 +284,26 @@ else ch_inf.sb = BRCMU_CHAN_SB_UU; break; - case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_160: + ch_inf.bw = BRCMU_CHAN_BW_160; + if (primary_offset == -70) + ch_inf.sb = BRCMU_CHAN_SB_LLL; + else if (primary_offset == -50) + ch_inf.sb = BRCMU_CHAN_SB_LLU; + else if (primary_offset == -30) + ch_inf.sb = BRCMU_CHAN_SB_LUL; + else if (primary_offset == -10) + ch_inf.sb = BRCMU_CHAN_SB_LUU; + else if (primary_offset == 10) + ch_inf.sb = BRCMU_CHAN_SB_ULL; + else if (primary_offset == 30) + ch_inf.sb = BRCMU_CHAN_SB_ULU; + else if (primary_offset == 50) + ch_inf.sb = BRCMU_CHAN_SB_UUL; + else + ch_inf.sb = BRCMU_CHAN_SB_UUU; + break; + case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: default: @@ -307,6 +322,7 @@ } d11inf->encchspec(&ch_inf); + brcmf_dbg(TRACE, "chanspec: 0x%x\n", ch_inf.chspec); return ch_inf.chspec; } @@ -457,6 +473,7 @@ static int send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key) { + struct brcmf_pub *drvr = ifp->drvr; int err; struct brcmf_wsec_key_le key_le; @@ -468,7 +485,7 @@ sizeof(key_le)); if (err) - brcmf_err("wsec_key error (%d)\n", err); + bphy_err(drvr, "wsec_key error (%d)\n", err); return err; } @@ -508,6 +525,7 @@ static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_mbss_ssid_le mbss_ssid_le; int bsscfgidx; int err; @@ -524,7 +542,7 @@ err = brcmf_fil_bsscfg_data_set(ifp, "bsscfg:ssid", &mbss_ssid_le, sizeof(mbss_ssid_le)); if (err < 0) - brcmf_err("setting ssid failed %d\n", err); + bphy_err(drvr, "setting ssid failed %d\n", err); return err; } @@ -542,6 +560,7 @@ { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_vif *vif; int err; @@ -567,7 +586,7 @@ BRCMF_VIF_EVENT_TIMEOUT); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (!err) { - brcmf_err("timeout occurred\n"); + bphy_err(drvr, "timeout occurred\n"); err = -EIO; goto fail; } @@ -575,7 +594,7 @@ /* interface created in firmware */ ifp = vif->ifp; if (!ifp) { - brcmf_err("no if pointer provided\n"); + bphy_err(drvr, "no if pointer provided\n"); err = -ENOENT; goto fail; } @@ -583,7 +602,7 @@ strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); err = brcmf_net_attach(ifp, true); if (err) { - brcmf_err("Registering netdevice failed\n"); + bphy_err(drvr, "Registering netdevice failed\n"); free_netdev(ifp->ndev); goto fail; } @@ -608,19 +627,97 @@ return vif->wdev.iftype == NL80211_IFTYPE_ADHOC; } +/** + * brcmf_mon_add_vif() - create monitor mode virtual interface + * + * @wiphy: wiphy device of new interface. + * @name: name of the new interface. + */ +static struct wireless_dev *brcmf_mon_add_vif(struct wiphy *wiphy, + const char *name) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_vif *vif; + struct net_device *ndev; + struct brcmf_if *ifp; + int err; + + if (cfg->pub->mon_if) { + err = -EEXIST; + goto err_out; + } + + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_MONITOR); + if (IS_ERR(vif)) { + err = PTR_ERR(vif); + goto err_out; + } + + ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN, ether_setup); + if (!ndev) { + err = -ENOMEM; + goto err_free_vif; + } + ndev->type = ARPHRD_IEEE80211_RADIOTAP; + ndev->ieee80211_ptr = &vif->wdev; + ndev->needs_free_netdev = true; + ndev->priv_destructor = brcmf_cfg80211_free_netdev; + SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); + + ifp = netdev_priv(ndev); + ifp->vif = vif; + ifp->ndev = ndev; + ifp->drvr = cfg->pub; + + vif->ifp = ifp; + vif->wdev.netdev = ndev; + + err = brcmf_net_mon_attach(ifp); + if (err) { + brcmf_err("Failed to attach %s device\n", ndev->name); + free_netdev(ndev); + goto err_free_vif; + } + + cfg->pub->mon_if = ifp; + + return &vif->wdev; + +err_free_vif: + brcmf_free_vif(vif); +err_out: + return ERR_PTR(err); +} + +static int brcmf_mon_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = wdev->netdev; + + ndev->netdev_ops->ndo_stop(ndev); + + brcmf_net_detach(ndev, true); + + cfg->pub->mon_if = NULL; + + return 0; +} + static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, const char *name, unsigned char name_assign_type, enum nl80211_iftype type, struct vif_params *params) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct wireless_dev *wdev; int err; brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); if (err) { - brcmf_err("iface validation failed: err=%d\n", err); + bphy_err(drvr, "iface validation failed: err=%d\n", err); return ERR_PTR(err); } switch (type) { @@ -628,9 +725,10 @@ case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: return ERR_PTR(-EOPNOTSUPP); + case NL80211_IFTYPE_MONITOR: + return brcmf_mon_add_vif(wiphy, name); case NL80211_IFTYPE_AP: wdev = brcmf_ap_add_vif(wiphy, name, params); break; @@ -645,8 +743,8 @@ } if (IS_ERR(wdev)) - brcmf_err("add iface %s type %d failed: err=%d\n", - name, type, (int)PTR_ERR(wdev)); + bphy_err(drvr, "add iface %s type %d failed: err=%d\n", name, + type, (int)PTR_ERR(wdev)); else brcmf_cfg80211_update_proto_addr_mode(wdev); @@ -661,12 +759,13 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc) { + struct brcmf_pub *drvr = ifp->drvr; s32 err = 0; if (check_vif_up(ifp->vif)) { err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); if (err) { - brcmf_err("fail to set mpc\n"); + bphy_err(drvr, "fail to set mpc\n"); return; } brcmf_dbg(INFO, "MPC : %d\n", mpc); @@ -677,6 +776,7 @@ struct brcmf_if *ifp, bool aborted, bool fw_abort) { + struct brcmf_pub *drvr = cfg->pub; struct brcmf_scan_params_le params_le; struct cfg80211_scan_request *scan_request; u64 reqid; @@ -711,7 +811,7 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, ¶ms_le, sizeof(params_le)); if (err) - brcmf_err("Scan abort failed\n"); + bphy_err(drvr, "Scan abort failed\n"); } brcmf_scan_config_mpc(ifp, 1); @@ -756,6 +856,7 @@ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = wdev->netdev; struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; int ret; int err; @@ -763,7 +864,7 @@ err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0); if (err) { - brcmf_err("interface_remove failed %d\n", err); + bphy_err(drvr, "interface_remove failed %d\n", err); goto err_unarm; } @@ -771,7 +872,7 @@ ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL, BRCMF_VIF_EVENT_TIMEOUT); if (!ret) { - brcmf_err("timeout occurred\n"); + bphy_err(drvr, "timeout occurred\n"); err = -EIO; goto err_unarm; } @@ -810,9 +911,10 @@ case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: return -EOPNOTSUPP; + case NL80211_IFTYPE_MONITOR: + return brcmf_mon_del_vif(wiphy, wdev); case NL80211_IFTYPE_AP: return brcmf_cfg80211_del_ap_iface(wiphy, wdev); case NL80211_IFTYPE_P2P_CLIENT: @@ -834,6 +936,7 @@ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_vif *vif = ifp->vif; + struct brcmf_pub *drvr = cfg->pub; s32 infra = 0; s32 ap = 0; s32 err = 0; @@ -873,14 +976,14 @@ } err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type); if (err) { - brcmf_err("iface validation failed: err=%d\n", err); + bphy_err(drvr, "iface validation failed: err=%d\n", err); return err; } switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: - brcmf_err("type (%d) : currently we do not support this type\n", - type); + bphy_err(drvr, "type (%d) : currently we do not support this type\n", + type); return -EOPNOTSUPP; case NL80211_IFTYPE_ADHOC: infra = 0; @@ -908,7 +1011,7 @@ } else { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); if (err) { - brcmf_err("WLC_SET_INFRA error (%d)\n", err); + bphy_err(drvr, "WLC_SET_INFRA error (%d)\n", err); err = -EAGAIN; goto done; } @@ -999,6 +1102,7 @@ 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); struct brcmf_escan_params_le *params; @@ -1030,7 +1134,7 @@ if (err == -EBUSY) brcmf_dbg(INFO, "system busy : escan canceled\n"); else - brcmf_err("error (%d)\n", err); + bphy_err(drvr, "error (%d)\n", err); } kfree(params); @@ -1067,6 +1171,7 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_vif *vif; s32 err = 0; @@ -1076,21 +1181,22 @@ return -EIO; if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status); + bphy_err(drvr, "Scanning already: status (%lu)\n", + cfg->scan_status); return -EAGAIN; } if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) { - brcmf_err("Scanning being aborted: status (%lu)\n", - cfg->scan_status); + bphy_err(drvr, "Scanning being aborted: status (%lu)\n", + cfg->scan_status); return -EAGAIN; } if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) { - brcmf_err("Scanning suppressed: status (%lu)\n", - cfg->scan_status); + bphy_err(drvr, "Scanning suppressed: status (%lu)\n", + cfg->scan_status); return -EAGAIN; } if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) { - brcmf_err("Connecting: status (%lu)\n", vif->sme_state); + bphy_err(drvr, "Connecting: status (%lu)\n", vif->sme_state); return -EAGAIN; } @@ -1124,7 +1230,7 @@ return 0; scan_out: - brcmf_err("scan error (%d)\n", err); + bphy_err(drvr, "scan error (%d)\n", err); clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); cfg->scan_request = NULL; return err; @@ -1132,36 +1238,41 @@ static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; s32 err = 0; - err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh", - rts_threshold); + err = brcmf_fil_iovar_int_set(ifp, "rtsthresh", rts_threshold); if (err) - brcmf_err("Error (%d)\n", err); + bphy_err(drvr, "Error (%d)\n", err); return err; } static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; s32 err = 0; - err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh", + err = brcmf_fil_iovar_int_set(ifp, "fragthresh", frag_threshold); if (err) - brcmf_err("Error (%d)\n", err); + bphy_err(drvr, "Error (%d)\n", err); return err; } static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; s32 err = 0; u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL); - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry); + err = brcmf_fil_cmd_int_set(ifp, cmd, retry); if (err) { - brcmf_err("cmd (%d) , error (%d)\n", cmd, err); + bphy_err(drvr, "cmd (%d) , error (%d)\n", cmd, err); return err; } return err; @@ -1237,49 +1348,83 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) { + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_wsec_pmk_le pmk; - int i, err; + int err; - /* convert to firmware key format */ - pmk.key_len = cpu_to_le16(pmk_len << 1); - pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE); - for (i = 0; i < pmk_len; i++) - snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]); + memset(&pmk, 0, sizeof(pmk)); + + /* pass pmk directly */ + pmk.key_len = cpu_to_le16(pmk_len); + pmk.flags = cpu_to_le16(0); + memcpy(pmk.key, pmk_data, pmk_len); /* store psk in firmware */ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, &pmk, sizeof(pmk)); if (err < 0) - brcmf_err("failed to change PSK in firmware (len=%u)\n", - pmk_len); + bphy_err(drvr, "failed to change PSK in firmware (len=%u)\n", + pmk_len); return err; } -static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) +static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, + u16 pwd_len) +{ + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_sae_pwd_le sae_pwd; + int err; + + if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { + bphy_err(drvr, "sae_password must be less than %d\n", + BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); + return -EINVAL; + } + + sae_pwd.key_len = cpu_to_le16(pwd_len); + memcpy(sae_pwd.key, pwd_data, pwd_len); + + err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, + sizeof(sae_pwd)); + if (err < 0) + bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", + pwd_len); + + return err; +} + +static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason, + bool locally_generated) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); + struct brcmf_pub *drvr = cfg->pub; + bool bus_up = drvr->bus_if->state == BRCMF_BUS_UP; s32 err = 0; brcmf_dbg(TRACE, "Enter\n"); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) { - brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n"); - err = brcmf_fil_cmd_data_set(vif->ifp, - BRCMF_C_DISASSOC, NULL, 0); - if (err) { - brcmf_err("WLC_DISASSOC failed (%d)\n", err); + if (bus_up) { + brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n"); + err = brcmf_fil_cmd_data_set(vif->ifp, + BRCMF_C_DISASSOC, NULL, 0); + if (err) + bphy_err(drvr, "WLC_DISASSOC failed (%d)\n", + err); } + if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) || (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0, - true, GFP_KERNEL); + locally_generated, GFP_KERNEL); } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0); if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { - brcmf_set_pmk(vif->ifp, NULL, 0); + if (bus_up) + brcmf_set_pmk(vif->ifp, NULL, 0); vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE; } brcmf_dbg(TRACE, "Exit\n"); @@ -1292,6 +1437,7 @@ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; + struct brcmf_pub *drvr = cfg->pub; struct brcmf_join_params join_params; size_t join_params_size = 0; s32 err = 0; @@ -1356,7 +1502,7 @@ err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec); if (err) { - brcmf_err("wsec failed (%d)\n", err); + bphy_err(drvr, "wsec failed (%d)\n", err); goto done; } @@ -1368,7 +1514,7 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd); if (err) { - brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err); + bphy_err(drvr, "WLC_SET_BCNPRD failed (%d)\n", err); goto done; } @@ -1413,7 +1559,7 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL, target_channel); if (err) { - brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err); + bphy_err(drvr, "WLC_SET_CHANNEL failed (%d)\n", err); goto done; } } else @@ -1425,7 +1571,7 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, join_params_size); if (err) { - brcmf_err("WLC_SET_SSID failed (%d)\n", err); + bphy_err(drvr, "WLC_SET_SSID failed (%d)\n", err); goto done; } @@ -1450,7 +1596,7 @@ return 0; } - brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING); + brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING, true); brcmf_net_setcarrier(ifp, false); brcmf_dbg(TRACE, "Exit\n"); @@ -1461,7 +1607,9 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, struct cfg80211_connect_params *sme) { + struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; @@ -1470,12 +1618,14 @@ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) + val = WPA3_AUTH_SAE_PSK; else val = WPA_AUTH_DISABLED; brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); + err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", val); if (err) { - brcmf_err("set wpa_auth failed (%d)\n", err); + bphy_err(drvr, "set wpa_auth failed (%d)\n", err); return err; } sec = &profile->sec; @@ -1486,7 +1636,9 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, struct cfg80211_connect_params *sme) { + struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; @@ -1500,15 +1652,19 @@ val = 1; brcmf_dbg(CONN, "shared key\n"); break; + case NL80211_AUTHTYPE_SAE: + val = 3; + brcmf_dbg(CONN, "SAE authentication\n"); + break; default: val = 2; brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type); break; } - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val); + err = brcmf_fil_bsscfg_int_set(ifp, "auth", val); if (err) { - brcmf_err("set auth failed (%d)\n", err); + bphy_err(drvr, "set auth failed (%d)\n", err); return err; } sec = &profile->sec; @@ -1520,7 +1676,9 @@ brcmf_set_wsec_mode(struct net_device *ndev, struct cfg80211_connect_params *sme) { + struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_cfg80211_security *sec; s32 pval = 0; s32 gval = 0; @@ -1543,8 +1701,8 @@ pval = AES_ENABLED; break; default: - brcmf_err("invalid cipher pairwise (%d)\n", - sme->crypto.ciphers_pairwise[0]); + bphy_err(drvr, "invalid cipher pairwise (%d)\n", + sme->crypto.ciphers_pairwise[0]); return -EINVAL; } } @@ -1564,8 +1722,8 @@ gval = AES_ENABLED; break; default: - brcmf_err("invalid cipher group (%d)\n", - sme->crypto.cipher_group); + bphy_err(drvr, "invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } @@ -1578,9 +1736,9 @@ pval = AES_ENABLED; wsec = pval | gval; - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec); + err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); if (err) { - brcmf_err("error (%d)\n", err); + bphy_err(drvr, "error (%d)\n", err); return err; } @@ -1596,6 +1754,7 @@ { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; + struct brcmf_pub *drvr = ifp->drvr; s32 val; s32 err; const struct brcmf_tlv *rsn_ie; @@ -1607,13 +1766,14 @@ u16 count; profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + profile->is_ft = false; if (!sme->crypto.n_akm_suites) return 0; err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val); if (err) { - brcmf_err("could not get wpa_auth (%d)\n", err); + bphy_err(drvr, "could not get wpa_auth (%d)\n", err); return err; } if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { @@ -1627,8 +1787,8 @@ val = WPA_AUTH_PSK; break; default: - brcmf_err("invalid cipher group (%d)\n", - sme->crypto.cipher_group); + bphy_err(drvr, "invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { @@ -1649,9 +1809,33 @@ case WLAN_AKM_SUITE_PSK: val = WPA2_AUTH_PSK; break; + case WLAN_AKM_SUITE_FT_8021X: + val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; + profile->is_ft = true; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; + break; + case WLAN_AKM_SUITE_FT_PSK: + val = WPA2_AUTH_PSK | WPA2_AUTH_FT; + profile->is_ft = true; + break; default: - brcmf_err("invalid cipher group (%d)\n", - sme->crypto.cipher_group); + bphy_err(drvr, "invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; + } + } else if (val & WPA3_AUTH_SAE_PSK) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_SAE: + val = WPA3_AUTH_SAE_PSK; + if (sme->crypto.sae_pwd) { + brcmf_dbg(INFO, "using SAE offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; + } + break; + default: + bphy_err(drvr, "invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } @@ -1697,7 +1881,7 @@ brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); if (err) { - brcmf_err("could not set wpa_auth (%d)\n", err); + bphy_err(drvr, "could not set wpa_auth (%d)\n", err); return err; } @@ -1708,6 +1892,8 @@ brcmf_set_sharedkey(struct net_device *ndev, struct cfg80211_connect_params *sme) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); struct brcmf_cfg80211_security *sec; struct brcmf_wsec_key key; @@ -1723,7 +1909,8 @@ brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions, sec->cipher_pairwise); - if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) + if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2 | + NL80211_WPA_VERSION_3)) return 0; if (!(sec->cipher_pairwise & @@ -1734,7 +1921,7 @@ key.len = (u32) sme->key_len; key.index = (u32) sme->key_idx; if (key.len > sizeof(key.data)) { - brcmf_err("Too long key length (%u)\n", key.len); + bphy_err(drvr, "Too long key length (%u)\n", key.len); return -EINVAL; } memcpy(key.data, sme->key, key.len); @@ -1747,24 +1934,24 @@ key.algo = CRYPTO_ALGO_WEP128; break; default: - brcmf_err("Invalid algorithm (%d)\n", - sme->crypto.ciphers_pairwise[0]); + bphy_err(drvr, "Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0]); return -EINVAL; } /* Set the new key/index */ brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n", key.len, key.index, key.algo); brcmf_dbg(CONN, "key \"%s\"\n", key.data); - err = send_key_to_dongle(netdev_priv(ndev), &key); + err = send_key_to_dongle(ifp, &key); if (err) return err; if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { brcmf_dbg(CONN, "set auth_type to shared key\n"); val = WL_AUTH_SHARED_KEY; /* shared key */ - err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val); + err = brcmf_fil_bsscfg_int_set(ifp, "auth", val); if (err) - brcmf_err("set auth failed (%d)\n", err); + bphy_err(drvr, "set auth failed (%d)\n", err); } return err; } @@ -1784,6 +1971,7 @@ static void brcmf_set_join_pref(struct brcmf_if *ifp, struct cfg80211_bss_selection *bss_select) { + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_join_pref_params join_pref_params[2]; enum nl80211_band band; int err, i = 0; @@ -1822,7 +2010,7 @@ err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params, sizeof(join_pref_params)); if (err) - brcmf_err("Set join_pref error (%d)\n", err); + bphy_err(drvr, "Set join_pref error (%d)\n", err); } static s32 @@ -1833,6 +2021,7 @@ struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct ieee80211_channel *chan = sme->channel; + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_join_params join_params; size_t join_params_size; const struct brcmf_tlv *rsn_ie; @@ -1849,7 +2038,7 @@ return -EIO; if (!sme->ssid) { - brcmf_err("Invalid ssid\n"); + bphy_err(drvr, "Invalid ssid\n"); return -EOPNOTSUPP; } @@ -1878,7 +2067,7 @@ err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); if (err) - brcmf_err("Set Assoc REQ IE Failed\n"); + bphy_err(drvr, "Set Assoc REQ IE Failed\n"); else brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n"); @@ -1899,36 +2088,37 @@ err = brcmf_set_wpa_version(ndev, sme); if (err) { - brcmf_err("wl_set_wpa_version failed (%d)\n", err); + bphy_err(drvr, "wl_set_wpa_version failed (%d)\n", err); goto done; } sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type); err = brcmf_set_auth_type(ndev, sme); if (err) { - brcmf_err("wl_set_auth_type failed (%d)\n", err); + bphy_err(drvr, "wl_set_auth_type failed (%d)\n", err); goto done; } err = brcmf_set_wsec_mode(ndev, sme); if (err) { - brcmf_err("wl_set_set_cipher failed (%d)\n", err); + bphy_err(drvr, "wl_set_set_cipher failed (%d)\n", err); goto done; } err = brcmf_set_key_mgmt(ndev, sme); if (err) { - brcmf_err("wl_set_key_mgmt failed (%d)\n", err); + bphy_err(drvr, "wl_set_key_mgmt failed (%d)\n", err); goto done; } err = brcmf_set_sharedkey(ndev, sme); if (err) { - brcmf_err("brcmf_set_sharedkey failed (%d)\n", err); + bphy_err(drvr, "brcmf_set_sharedkey failed (%d)\n", err); goto done; } - if (sme->crypto.psk) { + if (sme->crypto.psk && + profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) { err = -EINVAL; goto done; @@ -1941,17 +2131,29 @@ /* enable firmware supplicant for this interface */ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); if (err < 0) { - brcmf_err("failed to enable fw supplicant\n"); + bphy_err(drvr, "failed to enable fw supplicant\n"); goto done; } } - if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); - if (err) + else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { + /* clean up user-space RSNE */ + err = brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0); + if (err) { + bphy_err(drvr, "failed to clean up user-space RSNE\n"); goto done; + } + err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, + sme->crypto.sae_pwd_len); + if (!err && sme->crypto.psk) + err = brcmf_set_pmk(ifp, sme->crypto.psk, + BRCMF_WSEC_MAX_PSK_LEN); } + if (err) + goto done; /* Join with specific BSSID and cached SSID * If SSID is zero join based on BSSID only @@ -2036,7 +2238,7 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, join_params_size); if (err) - brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err); + bphy_err(drvr, "BRCMF_C_SET_SSID failed (%d)\n", err); done: if (err) @@ -2049,8 +2251,10 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; + struct brcmf_pub *drvr = cfg->pub; struct brcmf_scb_val_le scbval; s32 err = 0; @@ -2067,7 +2271,7 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC, &scbval, sizeof(scbval)); if (err) - brcmf_err("error (%d)\n", err); + bphy_err(drvr, "error (%d)\n", err); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -2080,6 +2284,7 @@ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = cfg_to_ndev(cfg); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; s32 err; s32 disable; u32 qdbm = 127; @@ -2094,7 +2299,7 @@ case NL80211_TX_POWER_LIMITED: case NL80211_TX_POWER_FIXED: if (mbm < 0) { - brcmf_err("TX_POWER_FIXED - dbm is negative\n"); + bphy_err(drvr, "TX_POWER_FIXED - dbm is negative\n"); err = -EINVAL; goto done; } @@ -2104,7 +2309,7 @@ qdbm |= WL_TXPWR_OVERRIDE; break; default: - brcmf_err("Unsupported type %d\n", type); + bphy_err(drvr, "Unsupported type %d\n", type); err = -EINVAL; goto done; } @@ -2112,11 +2317,11 @@ disable = WL_RADIO_SW_DISABLE << 16; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable); if (err) - brcmf_err("WLC_SET_RADIO error (%d)\n", err); + bphy_err(drvr, "WLC_SET_RADIO error (%d)\n", err); err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm); if (err) - brcmf_err("qtxpower error (%d)\n", err); + bphy_err(drvr, "qtxpower error (%d)\n", err); done: brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE); @@ -2127,7 +2332,9 @@ brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, s32 *dbm) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_vif *vif = wdev_to_vif(wdev); + struct brcmf_pub *drvr = cfg->pub; s32 qdbm = 0; s32 err; @@ -2137,7 +2344,7 @@ err = brcmf_fil_iovar_int_get(vif->ifp, "qtxpower", &qdbm); if (err) { - brcmf_err("error (%d)\n", err); + bphy_err(drvr, "error (%d)\n", err); goto done; } *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4; @@ -2152,6 +2359,7 @@ u8 key_idx, bool unicast, bool multicast) { struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; u32 index; u32 wsec; s32 err = 0; @@ -2163,7 +2371,7 @@ err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); if (err) { - brcmf_err("WLC_GET_WSEC error (%d)\n", err); + bphy_err(drvr, "WLC_GET_WSEC error (%d)\n", err); goto done; } @@ -2173,7 +2381,7 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_KEY_PRIMARY, index); if (err) - brcmf_err("error (%d)\n", err); + bphy_err(drvr, "error (%d)\n", err); } done: brcmf_dbg(TRACE, "Exit\n"); @@ -2222,7 +2430,9 @@ u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_wsec_key *key; s32 val; s32 wsec; @@ -2237,7 +2447,7 @@ if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { /* we ignore this key index in this case */ - brcmf_err("invalid key index (%d)\n", key_idx); + bphy_err(drvr, "invalid key index (%d)\n", key_idx); return -EINVAL; } @@ -2246,7 +2456,7 @@ mac_addr); if (params->key_len > sizeof(key->data)) { - brcmf_err("Too long key length (%u)\n", params->key_len); + bphy_err(drvr, "Too long key length (%u)\n", params->key_len); return -EINVAL; } @@ -2266,6 +2476,17 @@ memcpy(key->data, params->key, key->len); if (!ext_key) key->flags = BRCMF_PRIMARY_KEY; + + if (params->seq && params->seq_len == 6) { + /* rx iv */ + u8 *ivptr; + + ivptr = (u8 *)params->seq; + key->rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | + (ivptr[3] << 8) | ivptr[2]; + key->rxiv.lo = (ivptr[1] << 8) | ivptr[0]; + key->iv_initialized = true; + } switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: @@ -2300,7 +2521,7 @@ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); break; default: - brcmf_err("Invalid cipher (0x%x)\n", params->cipher); + bphy_err(drvr, "Invalid cipher (0x%x)\n", params->cipher); err = -EINVAL; goto done; } @@ -2311,13 +2532,13 @@ err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); if (err) { - brcmf_err("get wsec error (%d)\n", err); + bphy_err(drvr, "get wsec error (%d)\n", err); goto done; } wsec |= val; err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); if (err) { - brcmf_err("set wsec error (%d)\n", err); + bphy_err(drvr, "set wsec error (%d)\n", err); goto done; } @@ -2332,9 +2553,11 @@ void (*callback)(void *cookie, struct key_params *params)) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct key_params params; struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; + struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_security *sec; s32 wsec; s32 err = 0; @@ -2348,7 +2571,7 @@ err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); if (err) { - brcmf_err("WLC_GET_WSEC error (%d)\n", err); + bphy_err(drvr, "WLC_GET_WSEC error (%d)\n", err); /* Ignore this error, may happen during DISASSOC */ err = -EAGAIN; goto done; @@ -2369,7 +2592,7 @@ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); } else { - brcmf_err("Invalid algo (0x%x)\n", wsec); + bphy_err(drvr, "Invalid algo (0x%x)\n", wsec); err = -EINVAL; goto done; } @@ -2399,6 +2622,7 @@ static void brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; s32 err; u8 key_idx; struct brcmf_wsec_key *key; @@ -2415,18 +2639,18 @@ err = send_key_to_dongle(ifp, key); if (err) { - brcmf_err("Setting WEP key failed (%d)\n", err); + bphy_err(drvr, "Setting WEP key failed (%d)\n", err); return; } err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); if (err) { - brcmf_err("get wsec error (%d)\n", err); + bphy_err(drvr, "get wsec error (%d)\n", err); return; } wsec |= WEP_ENABLED; err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); if (err) - brcmf_err("set wsec error (%d)\n", err); + bphy_err(drvr, "set wsec error (%d)\n", err); } static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si) @@ -2452,6 +2676,7 @@ static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si) { + struct brcmf_pub *drvr = ifp->drvr; struct { __le32 len; struct brcmf_bss_info_le bss_le; @@ -2467,7 +2692,7 @@ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); if (err) { - brcmf_err("Failed to get bss info (%d)\n", err); + bphy_err(drvr, "Failed to get bss info (%d)\n", err); goto out_kfree; } si->filled |= BIT_ULL(NL80211_STA_INFO_BSS_PARAM); @@ -2489,6 +2714,7 @@ brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp, struct station_info *sinfo) { + struct brcmf_pub *drvr = ifp->drvr; struct brcmf_scb_val_le scbval; struct brcmf_pktcnt_le pktcnt; s32 err; @@ -2498,7 +2724,7 @@ /* Get the current tx rate */ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); if (err < 0) { - brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err); + bphy_err(drvr, "BRCMF_C_GET_RATE error (%d)\n", err); return err; } sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); @@ -2508,7 +2734,7 @@ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scbval, sizeof(scbval)); if (err) { - brcmf_err("BRCMF_C_GET_RSSI error (%d)\n", err); + bphy_err(drvr, "BRCMF_C_GET_RSSI error (%d)\n", err); return err; } rssi = le32_to_cpu(scbval.val); @@ -2518,7 +2744,7 @@ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt, sizeof(pktcnt)); if (err) { - brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err); + bphy_err(drvr, "BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err); return err; } sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS) | @@ -2537,7 +2763,9 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_scb_val_le scb_val; s32 err = 0; struct brcmf_sta_info_le sta_info_le; @@ -2567,7 +2795,7 @@ &sta_info_le, sizeof(sta_info_le)); if (err < 0) { - brcmf_err("GET STA INFO failed, %d\n", err); + bphy_err(drvr, "GET STA INFO failed, %d\n", err); goto done; } } @@ -2638,7 +2866,8 @@ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, &scb_val, sizeof(scb_val)); if (err) { - brcmf_err("Could not get rssi (%d)\n", err); + bphy_err(drvr, "Could not get rssi (%d)\n", + err); goto done; } else { rssi = le32_to_cpu(scb_val.val); @@ -2659,6 +2888,7 @@ { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; s32 err; brcmf_dbg(TRACE, "Enter, idx %d\n", idx); @@ -2669,8 +2899,8 @@ &cfg->assoclist, sizeof(cfg->assoclist)); if (err) { - brcmf_err("BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n", - err); + bphy_err(drvr, "BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n", + err); cfg->assoclist.count = 0; return -EOPNOTSUPP; } @@ -2690,6 +2920,7 @@ s32 err = 0; struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; brcmf_dbg(TRACE, "Enter\n"); @@ -2718,10 +2949,16 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); if (err) { if (err == -ENODEV) - brcmf_err("net_device is not ready yet\n"); + bphy_err(drvr, "net_device is not ready yet\n"); else - brcmf_err("error (%d)\n", err); + bphy_err(drvr, "error (%d)\n", err); } + + err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret", + min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS)); + if (err) + bphy_err(drvr, "Unable to set pm timeout, (%d)\n", err); + done: brcmf_dbg(TRACE, "Exit\n"); return err; @@ -2731,6 +2968,7 @@ struct brcmf_bss_info_le *bi) { struct wiphy *wiphy = cfg_to_wiphy(cfg); + struct brcmf_pub *drvr = cfg->pub; struct cfg80211_bss *bss; enum nl80211_band band; struct brcmu_chan ch; @@ -2743,8 +2981,8 @@ struct cfg80211_inform_bss bss_data = {}; if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { - brcmf_err("Bss info is larger than buffer. Discarding\n"); - return 0; + bphy_err(drvr, "Bss info is larger than buffer. Discarding\n"); + return -EINVAL; } if (!bi->ctl_ch) { @@ -2802,6 +3040,7 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg) { + struct brcmf_pub *drvr = cfg->pub; struct brcmf_scan_results *bss_list; struct brcmf_bss_info_le *bi = NULL; /* must be initialized */ s32 err = 0; @@ -2810,8 +3049,8 @@ bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf; if (bss_list->count != 0 && bss_list->version != BRCMF_BSS_INFO_VERSION) { - brcmf_err("Version %d != WL_BSS_INFO_VERSION\n", - bss_list->version); + bphy_err(drvr, "Version %d != WL_BSS_INFO_VERSION\n", + bss_list->version); return -EOPNOTSUPP; } brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count); @@ -2828,6 +3067,7 @@ struct net_device *ndev, const u8 *bssid) { struct wiphy *wiphy = cfg_to_wiphy(cfg); + struct brcmf_pub *drvr = cfg->pub; struct ieee80211_channel *notify_channel; struct brcmf_bss_info_le *bi = NULL; struct ieee80211_supported_band *band; @@ -2855,7 +3095,7 @@ err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); if (err) { - brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err); + bphy_err(drvr, "WLC_GET_BSS_INFO failed: %d\n", err); goto CleanUp; } @@ -2909,10 +3149,9 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) { + struct brcmf_pub *drvr = cfg->pub; struct brcmf_bss_info_le *bi; const struct brcmf_tlv *tim; - u16 beacon_interval; - u8 dtim_period; size_t ie_len; u8 *ie; s32 err = 0; @@ -2925,7 +3164,7 @@ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX); if (err) { - brcmf_err("Could not get bss info %d\n", err); + bphy_err(drvr, "Could not get bss info %d\n", err); goto update_bss_info_out; } @@ -2936,12 +3175,9 @@ ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset); ie_len = le32_to_cpu(bi->ie_length); - beacon_interval = le16_to_cpu(bi->beacon_period); tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM); - if (tim) - dtim_period = tim->data[1]; - else { + if (!tim) { /* * active scan was done so we could not get dtim * information out of probe response. @@ -2950,10 +3186,9 @@ u32 var; err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var); if (err) { - brcmf_err("wl dtim_assoc failed (%d)\n", err); + bphy_err(drvr, "wl dtim_assoc failed (%d)\n", err); goto update_bss_info_out; } - dtim_period = (u8)var; } update_bss_info_out: @@ -2988,9 +3223,10 @@ { struct brcmf_cfg80211_info *cfg = from_timer(cfg, t, escan_timeout); + struct brcmf_pub *drvr = cfg->pub; if (cfg->int_escan_map || cfg->scan_request) { - brcmf_err("timer expired\n"); + bphy_err(drvr, "timer expired\n"); schedule_work(&cfg->escan_timeout_work); } } @@ -3038,7 +3274,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_cfg80211_info *cfg = drvr->config; s32 status; struct brcmf_escan_result_le *escan_result_le; u32 escan_buflen; @@ -3055,32 +3292,33 @@ goto exit; if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - brcmf_err("scan not ready, bsscfgidx=%d\n", ifp->bsscfgidx); + bphy_err(drvr, "scan not ready, bsscfgidx=%d\n", + ifp->bsscfgidx); return -EPERM; } if (status == BRCMF_E_STATUS_PARTIAL) { brcmf_dbg(SCAN, "ESCAN Partial result\n"); if (e->datalen < sizeof(*escan_result_le)) { - brcmf_err("invalid event data length\n"); + bphy_err(drvr, "invalid event data length\n"); goto exit; } escan_result_le = (struct brcmf_escan_result_le *) data; if (!escan_result_le) { - brcmf_err("Invalid escan result (NULL pointer)\n"); + bphy_err(drvr, "Invalid escan result (NULL pointer)\n"); goto exit; } escan_buflen = le32_to_cpu(escan_result_le->buflen); if (escan_buflen > BRCMF_ESCAN_BUF_SIZE || escan_buflen > e->datalen || escan_buflen < sizeof(*escan_result_le)) { - brcmf_err("Invalid escan buffer length: %d\n", - escan_buflen); + bphy_err(drvr, "Invalid escan buffer length: %d\n", + escan_buflen); goto exit; } if (le16_to_cpu(escan_result_le->bss_count) != 1) { - brcmf_err("Invalid bss_count %d: ignoring\n", - escan_result_le->bss_count); + bphy_err(drvr, "Invalid bss_count %d: ignoring\n", + escan_result_le->bss_count); goto exit; } bss_info_le = &escan_result_le->bss_info_le; @@ -3095,8 +3333,8 @@ bi_length = le32_to_cpu(bss_info_le->length); if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) { - brcmf_err("Ignoring invalid bss_info length: %d\n", - bi_length); + bphy_err(drvr, "Ignoring invalid bss_info length: %d\n", + bi_length); goto exit; } @@ -3104,7 +3342,7 @@ BIT(NL80211_IFTYPE_ADHOC))) { if (le16_to_cpu(bss_info_le->capability) & WLAN_CAPABILITY_IBSS) { - brcmf_err("Ignoring IBSS result\n"); + bphy_err(drvr, "Ignoring IBSS result\n"); goto exit; } } @@ -3112,7 +3350,7 @@ list = (struct brcmf_scan_results *) cfg->escan_info.escan_buf; if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) { - brcmf_err("Buffer is too small: ignoring\n"); + bphy_err(drvr, "Buffer is too small: ignoring\n"); goto exit; } @@ -3248,7 +3486,7 @@ switch (pfn_v1->version) { default: WARN_ON(1); - /* fall-thru */ + fallthrough; case cpu_to_le32(1): netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1); break; @@ -3271,7 +3509,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_cfg80211_info *cfg = drvr->config; struct brcmf_pno_net_info_le *netinfo, *netinfo_start; struct cfg80211_scan_request *request = NULL; struct wiphy *wiphy = cfg_to_wiphy(cfg); @@ -3304,14 +3543,14 @@ WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE); brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count); if (!result_count) { - brcmf_err("FALSE PNO Event. (pfn_count == 0)\n"); + bphy_err(drvr, "FALSE PNO Event. (pfn_count == 0)\n"); goto out_err; } netinfo_start = brcmf_get_netinfo_array(pfn_result); datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result); if (datalen < result_count * sizeof(*netinfo)) { - brcmf_err("insufficient event data\n"); + bphy_err(drvr, "insufficient event data\n"); goto out_err; } @@ -3358,15 +3597,16 @@ struct net_device *ndev, struct cfg80211_sched_scan_request *req) { - struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n", req->n_match_sets, req->n_ssids); if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) { - brcmf_err("Scanning suppressed: status=%lu\n", - cfg->scan_status); + bphy_err(drvr, "Scanning suppressed: status=%lu\n", + cfg->scan_status); return -EAGAIN; } @@ -3444,7 +3684,8 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_cfg80211_info *cfg = drvr->config; struct brcmf_pno_scanresults_le *pfn_result; struct brcmf_pno_net_info_le *netinfo; @@ -3463,8 +3704,8 @@ } if (le32_to_cpu(pfn_result->count) < 1) { - brcmf_err("Invalid result count, expected 1 (%d)\n", - le32_to_cpu(pfn_result->count)); + bphy_err(drvr, "Invalid result count, expected 1 (%d)\n", + le32_to_cpu(pfn_result->count)); return -EINVAL; } @@ -3493,6 +3734,7 @@ static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_wowl_wakeind_le wake_ind_le; struct cfg80211_wowlan_wakeup wakeup_data; struct cfg80211_wowlan_wakeup *wakeup; @@ -3503,7 +3745,7 @@ err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le, sizeof(wake_ind_le)); if (err) { - brcmf_err("Get wowl_wakeind failed, err = %d\n", err); + bphy_err(drvr, "Get wowl_wakeind failed, err = %d\n", err); return; } @@ -3544,7 +3786,7 @@ cfg->wowl.nd_data_completed, BRCMF_ND_INFO_TIMEOUT); if (!timeout) - brcmf_err("No result for wowl net detect\n"); + bphy_err(drvr, "No result for wowl net detect\n"); else wakeup_data.net_detect = cfg->wowl.nd_info; } @@ -3683,7 +3925,7 @@ * disassociate from AP to save power while system is * in suspended state */ - brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED); + brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED, true); /* Make sure WPA_Supplicant receives all the event * generated due to DISASSOC call to the fw to keep * the state fw and WPA_Supplicant state consistent @@ -3733,6 +3975,7 @@ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0]; + struct brcmf_pub *drvr = cfg->pub; s32 err; u32 npmk, i; @@ -3752,15 +3995,12 @@ cfg->pmk_list.npmk = cpu_to_le32(npmk); } } else { - brcmf_err("Too many PMKSA entries cached %d\n", npmk); + bphy_err(drvr, "Too many PMKSA entries cached %d\n", npmk); return -EINVAL; } brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid); - for (i = 0; i < WLAN_PMKID_LEN; i += 4) - brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i], - pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2], - pmk[npmk].pmkid[i + 3]); + brcmf_dbg(CONN, "%*ph\n", WLAN_PMKID_LEN, pmk[npmk].pmkid); err = brcmf_update_pmklist(cfg, ifp); @@ -3775,6 +4015,7 @@ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0]; + struct brcmf_pub *drvr = cfg->pub; s32 err; u32 npmk, i; @@ -3798,7 +4039,7 @@ memset(&pmk[i], 0, sizeof(*pmk)); cfg->pmk_list.npmk = cpu_to_le32(npmk - 1); } else { - brcmf_err("Cache entry not found\n"); + bphy_err(drvr, "Cache entry not found\n"); return -EINVAL; } @@ -3830,19 +4071,20 @@ static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; s32 err; s32 wpa_val; /* set auth */ err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0); if (err < 0) { - brcmf_err("auth error %d\n", err); + bphy_err(drvr, "auth error %d\n", err); return err; } /* set wsec */ err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0); if (err < 0) { - brcmf_err("wsec error %d\n", err); + bphy_err(drvr, "wsec error %d\n", err); return err; } /* set upper-layer auth */ @@ -3852,7 +4094,7 @@ wpa_val = WPA_AUTH_DISABLED; err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_val); if (err < 0) { - brcmf_err("wpa_auth error %d\n", err); + bphy_err(drvr, "wpa_auth error %d\n", err); return err; } @@ -3872,6 +4114,7 @@ const struct brcmf_vs_tlv *wpa_ie, bool is_rsn_ie) { + struct brcmf_pub *drvr = ifp->drvr; u32 auth = 0; /* d11 open authentication */ u16 count; s32 err = 0; @@ -3902,13 +4145,13 @@ /* check for multicast cipher suite */ if (offset + WPA_IE_MIN_OUI_LEN > len) { err = -EINVAL; - brcmf_err("no multicast cipher suite\n"); + bphy_err(drvr, "no multicast cipher suite\n"); goto exit; } if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) { err = -EINVAL; - brcmf_err("ivalid OUI\n"); + bphy_err(drvr, "ivalid OUI\n"); goto exit; } offset += TLV_OUI_LEN; @@ -3930,7 +4173,7 @@ break; default: err = -EINVAL; - brcmf_err("Invalid multi cast cipher info\n"); + bphy_err(drvr, "Invalid multi cast cipher info\n"); goto exit; } @@ -3941,13 +4184,13 @@ /* Check for unicast suite(s) */ if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) { err = -EINVAL; - brcmf_err("no unicast cipher suite\n"); + bphy_err(drvr, "no unicast cipher suite\n"); goto exit; } for (i = 0; i < count; i++) { if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) { err = -EINVAL; - brcmf_err("ivalid OUI\n"); + bphy_err(drvr, "ivalid OUI\n"); goto exit; } offset += TLV_OUI_LEN; @@ -3965,7 +4208,7 @@ pval |= AES_ENABLED; break; default: - brcmf_err("Invalid unicast security info\n"); + bphy_err(drvr, "Invalid unicast security info\n"); } offset++; } @@ -3975,13 +4218,13 @@ /* Check for auth key management suite(s) */ if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) { err = -EINVAL; - brcmf_err("no auth key mgmt suite\n"); + bphy_err(drvr, "no auth key mgmt suite\n"); goto exit; } for (i = 0; i < count; i++) { if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) { err = -EINVAL; - brcmf_err("ivalid OUI\n"); + bphy_err(drvr, "ivalid OUI\n"); goto exit; } offset += TLV_OUI_LEN; @@ -4008,8 +4251,12 @@ brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n"); wpa_auth |= WPA2_AUTH_1X_SHA256; break; + case RSN_AKM_SAE: + brcmf_dbg(TRACE, "RSN_AKM_SAE\n"); + wpa_auth |= WPA3_AUTH_SAE_PSK; + break; default: - brcmf_err("Invalid key mgmt info\n"); + bphy_err(drvr, "Invalid key mgmt info\n"); } offset++; } @@ -4025,11 +4272,12 @@ brcmf_dbg(TRACE, "MFP Required\n"); mfp = BRCMF_MFP_REQUIRED; /* Firmware only supports mfp required in - * combination with WPA2_AUTH_PSK_SHA256 or - * WPA2_AUTH_1X_SHA256. + * combination with WPA2_AUTH_PSK_SHA256, + * WPA2_AUTH_1X_SHA256, or WPA3_AUTH_SAE_PSK. */ if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 | - WPA2_AUTH_1X_SHA256))) { + WPA2_AUTH_1X_SHA256 | + WPA3_AUTH_SAE_PSK))) { err = -EINVAL; goto exit; } @@ -4051,7 +4299,7 @@ err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable", wme_bss_disable); if (err < 0) { - brcmf_err("wme_bss_disable error %d\n", err); + bphy_err(drvr, "wme_bss_disable error %d\n", err); goto exit; } @@ -4065,7 +4313,7 @@ &data[offset], WPA_IE_MIN_OUI_LEN); if (err < 0) { - brcmf_err("bip error %d\n", err); + bphy_err(drvr, "bip error %d\n", err); goto exit; } } @@ -4076,13 +4324,13 @@ /* set auth */ err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth); if (err < 0) { - brcmf_err("auth error %d\n", err); + bphy_err(drvr, "auth error %d\n", err); goto exit; } /* set wsec */ err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); if (err < 0) { - brcmf_err("wsec error %d\n", err); + bphy_err(drvr, "wsec error %d\n", err); goto exit; } /* Configure MFP, this needs to go after wsec otherwise the wsec command @@ -4091,14 +4339,14 @@ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) { err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp); if (err < 0) { - brcmf_err("mfp error %d\n", err); + bphy_err(drvr, "mfp error %d\n", err); goto exit; } } /* set upper-layer auth */ err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth); if (err < 0) { - brcmf_err("wpa_auth error %d\n", err); + bphy_err(drvr, "wpa_auth error %d\n", err); goto exit; } @@ -4146,10 +4394,8 @@ vndr_ies->count++; - brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n", - parsed_info->vndrie.oui[0], - parsed_info->vndrie.oui[1], - parsed_info->vndrie.oui[2], + brcmf_dbg(TRACE, "** OUI %3ph, type 0x%02x\n", + parsed_info->vndrie.oui, parsed_info->vndrie.oui_type); if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT) @@ -4168,9 +4414,7 @@ static u32 brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) { - - strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1); - iebuf[VNDR_IE_CMD_LEN - 1] = '\0'; + strscpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN); put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]); @@ -4184,6 +4428,7 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, const u8 *vndr_ie_buf, u32 vndr_ie_len) { + struct brcmf_pub *drvr; struct brcmf_if *ifp; struct vif_saved_ie *saved_ie; s32 err = 0; @@ -4205,6 +4450,7 @@ if (!vif) return -ENODEV; ifp = vif->ifp; + drvr = ifp->drvr; saved_ie = &vif->saved_ie; brcmf_dbg(TRACE, "bsscfgidx %d, pktflag : 0x%02X\n", ifp->bsscfgidx, @@ -4234,15 +4480,20 @@ mgmt_ie_len = &saved_ie->assoc_req_ie_len; mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie); break; + case BRCMF_VNDR_IE_ASSOCRSP_FLAG: + mgmt_ie_buf = saved_ie->assoc_res_ie; + mgmt_ie_len = &saved_ie->assoc_res_ie_len; + mgmt_ie_buf_len = sizeof(saved_ie->assoc_res_ie); + break; default: err = -EPERM; - brcmf_err("not suitable type\n"); + bphy_err(drvr, "not suitable type\n"); goto exit; } if (vndr_ie_len > mgmt_ie_buf_len) { err = -ENOMEM; - brcmf_err("extra IE size too big\n"); + bphy_err(drvr, "extra IE size too big\n"); goto exit; } @@ -4273,12 +4524,10 @@ for (i = 0; i < old_vndr_ies.count; i++) { vndrie_info = &old_vndr_ies.ie_info[i]; - brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", + brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%3ph\n", vndrie_info->vndrie.id, vndrie_info->vndrie.len, - vndrie_info->vndrie.oui[0], - vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2]); + vndrie_info->vndrie.oui); del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag, vndrie_info->ie_ptr, @@ -4303,19 +4552,17 @@ /* verify remained buf size before copy data */ if (remained_buf_len < (vndrie_info->vndrie.len + VNDR_IE_VSIE_OFFSET)) { - brcmf_err("no space in mgmt_ie_buf: len left %d", - remained_buf_len); + bphy_err(drvr, "no space in mgmt_ie_buf: len left %d", + remained_buf_len); break; } remained_buf_len -= (vndrie_info->ie_len + VNDR_IE_VSIE_OFFSET); - brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n", + brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%3ph\n", vndrie_info->vndrie.id, vndrie_info->vndrie.len, - vndrie_info->vndrie.oui[0], - vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2]); + vndrie_info->vndrie.oui); del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag, vndrie_info->ie_ptr, @@ -4335,7 +4582,7 @@ err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf, total_ie_buf_len); if (err) - brcmf_err("vndr ie set error : %d\n", err); + bphy_err(drvr, "vndr ie set error : %d\n", err); } exit: @@ -4363,13 +4610,14 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, struct cfg80211_beacon_data *beacon) { + struct brcmf_pub *drvr = vif->ifp->drvr; s32 err; /* Set Beacon IEs to FW */ err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG, beacon->tail, beacon->tail_len); if (err) { - brcmf_err("Set Beacon IE Failed\n"); + bphy_err(drvr, "Set Beacon IE Failed\n"); return err; } brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); @@ -4379,9 +4627,60 @@ beacon->proberesp_ies, beacon->proberesp_ies_len); if (err) - brcmf_err("Set Probe Resp IE Failed\n"); + bphy_err(drvr, "Set Probe Resp IE Failed\n"); else brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); + + /* Set Assoc Response IEs to FW */ + err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_ASSOCRSP_FLAG, + beacon->assocresp_ies, + beacon->assocresp_ies_len); + if (err) + brcmf_err("Set Assoc Resp IE Failed\n"); + else + brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc Resp\n"); + + return err; +} + +static s32 +brcmf_parse_configure_security(struct brcmf_if *ifp, + struct cfg80211_ap_settings *settings, + enum nl80211_iftype dev_role) +{ + const struct brcmf_tlv *rsn_ie; + const struct brcmf_vs_tlv *wpa_ie; + s32 err = 0; + + /* find the RSN_IE */ + rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, + settings->beacon.tail_len, WLAN_EID_RSN); + + /* find the WPA_IE */ + wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail, + settings->beacon.tail_len); + + if (wpa_ie || rsn_ie) { + brcmf_dbg(TRACE, "WPA(2) IE is found\n"); + if (wpa_ie) { + /* WPA IE */ + err = brcmf_configure_wpaie(ifp, wpa_ie, false); + if (err < 0) + return err; + } else { + struct brcmf_vs_tlv *tmp_ie; + + tmp_ie = (struct brcmf_vs_tlv *)rsn_ie; + + /* RSN IE */ + err = brcmf_configure_wpaie(ifp, tmp_ie, true); + if (err < 0) + return err; + } + } else { + brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); + brcmf_configure_opensecurity(ifp); + } return err; } @@ -4393,12 +4692,13 @@ s32 ie_offset; struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; + struct cfg80211_crypto_settings *crypto = &settings->crypto; const struct brcmf_tlv *ssid_ie; const struct brcmf_tlv *country_ie; struct brcmf_ssid_le ssid_le; s32 err = -EPERM; - const struct brcmf_tlv *rsn_ie; - const struct brcmf_vs_tlv *wpa_ie; struct brcmf_join_params join_params; enum nl80211_iftype dev_role; struct brcmf_fil_bss_enable_le bss_enable; @@ -4452,43 +4752,14 @@ brcmf_configure_arp_nd_offload(ifp, false); } - /* find the RSN_IE */ - rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, - settings->beacon.tail_len, WLAN_EID_RSN); - - /* find the WPA_IE */ - wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail, - settings->beacon.tail_len); - - if ((wpa_ie != NULL || rsn_ie != NULL)) { - brcmf_dbg(TRACE, "WPA(2) IE is found\n"); - if (wpa_ie != NULL) { - /* WPA IE */ - err = brcmf_configure_wpaie(ifp, wpa_ie, false); - if (err < 0) - goto exit; - } else { - struct brcmf_vs_tlv *tmp_ie; - - tmp_ie = (struct brcmf_vs_tlv *)rsn_ie; - - /* RSN IE */ - err = brcmf_configure_wpaie(ifp, tmp_ie, true); - if (err < 0) - goto exit; - } - } else { - brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); - brcmf_configure_opensecurity(ifp); - } - /* Parameters shared by all radio interfaces */ if (!mbss) { if ((supports_11d) && (is_11d != ifp->vif->is_11d)) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, is_11d); if (err < 0) { - brcmf_err("Regulatory Set Error, %d\n", err); + bphy_err(drvr, "Regulatory Set Error, %d\n", + err); goto exit; } } @@ -4496,8 +4767,8 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, settings->beacon_interval); if (err < 0) { - brcmf_err("Beacon Interval Set Error, %d\n", - err); + bphy_err(drvr, "Beacon Interval Set Error, %d\n", + err); goto exit; } } @@ -4505,17 +4776,20 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD, settings->dtim_period); if (err < 0) { - brcmf_err("DTIM Interval Set Error, %d\n", err); + bphy_err(drvr, "DTIM Interval Set Error, %d\n", + err); goto exit; } } if ((dev_role == NL80211_IFTYPE_AP) && ((ifp->ifidx == 0) || - !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) { + (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB) && + !brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)))) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); if (err < 0) { - brcmf_err("BRCMF_C_DOWN error %d\n", err); + bphy_err(drvr, "BRCMF_C_DOWN error %d\n", + err); goto exit; } brcmf_fil_iovar_int_set(ifp, "apsta", 0); @@ -4523,7 +4797,7 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); if (err < 0) { - brcmf_err("SET INFRA error %d\n", err); + bphy_err(drvr, "SET INFRA error %d\n", err); goto exit; } } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) { @@ -4539,7 +4813,8 @@ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); if (err < 0) { - brcmf_err("setting AP mode failed %d\n", err); + bphy_err(drvr, "setting AP mode failed %d\n", + err); goto exit; } if (!mbss) { @@ -4548,16 +4823,43 @@ */ err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); if (err < 0) { - brcmf_err("Set Channel failed: chspec=%d, %d\n", - chanspec, err); + bphy_err(drvr, "Set Channel failed: chspec=%d, %d\n", + chanspec, err); goto exit; } } err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) { - brcmf_err("BRCMF_C_UP error (%d)\n", err); + bphy_err(drvr, "BRCMF_C_UP error (%d)\n", err); goto exit; } + + if (crypto->psk) { + brcmf_dbg(INFO, "using PSK offload\n"); + profile->use_fwauth |= BIT(BRCMF_PROFILE_FWAUTH_PSK); + err = brcmf_set_pmk(ifp, crypto->psk, + BRCMF_WSEC_MAX_PSK_LEN); + if (err < 0) + goto exit; + } + if (crypto->sae_pwd) { + brcmf_dbg(INFO, "using SAE offload\n"); + profile->use_fwauth |= BIT(BRCMF_PROFILE_FWAUTH_SAE); + err = brcmf_set_sae_password(ifp, crypto->sae_pwd, + crypto->sae_pwd_len); + if (err < 0) + goto exit; + } + if (profile->use_fwauth == 0) + profile->use_fwauth = BIT(BRCMF_PROFILE_FWAUTH_NONE); + + err = brcmf_parse_configure_security(ifp, settings, + NL80211_IFTYPE_AP); + if (err < 0) { + bphy_err(drvr, "brcmf_parse_configure_security error\n"); + goto exit; + } + /* On DOWN the firmware removes the WEP keys, reconfigure * them if they were set. */ @@ -4570,30 +4872,40 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, sizeof(join_params)); if (err < 0) { - brcmf_err("SET SSID error (%d)\n", err); + bphy_err(drvr, "SET SSID error (%d)\n", err); goto exit; } - if (settings->hidden_ssid) { - err = brcmf_fil_iovar_int_set(ifp, "closednet", 1); - if (err) { - brcmf_err("closednet error (%d)\n", err); - goto exit; - } + err = brcmf_fil_iovar_int_set(ifp, "closednet", + settings->hidden_ssid); + if (err) { + bphy_err(drvr, "%s closednet error (%d)\n", + settings->hidden_ssid ? + "enabled" : "disabled", + err); + goto exit; } brcmf_dbg(TRACE, "AP mode configuration complete\n"); } else if (dev_role == NL80211_IFTYPE_P2P_GO) { err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); if (err < 0) { - brcmf_err("Set Channel failed: chspec=%d, %d\n", - chanspec, err); + bphy_err(drvr, "Set Channel failed: chspec=%d, %d\n", + chanspec, err); goto exit; } + + err = brcmf_parse_configure_security(ifp, settings, + NL80211_IFTYPE_P2P_GO); + if (err < 0) { + brcmf_err("brcmf_parse_configure_security error\n"); + goto exit; + } + err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, sizeof(ssid_le)); if (err < 0) { - brcmf_err("setting ssid failed %d\n", err); + bphy_err(drvr, "setting ssid failed %d\n", err); goto exit; } bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx); @@ -4601,7 +4913,7 @@ err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, sizeof(bss_enable)); if (err < 0) { - brcmf_err("bss_enable config failed %d\n", err); + bphy_err(drvr, "bss_enable config failed %d\n", err); goto exit; } @@ -4624,7 +4936,10 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = cfg->pub; + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; s32 err; struct brcmf_fil_bss_enable_le bss_enable; struct brcmf_join_params join_params; @@ -4635,6 +4950,14 @@ /* Due to most likely deauths outstanding we sleep */ /* first to make sure they get processed by fw. */ msleep(400); + + if (profile->use_fwauth != BIT(BRCMF_PROFILE_FWAUTH_NONE)) { + if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_PSK)) + brcmf_set_pmk(ifp, NULL, 0); + if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_SAE)) + brcmf_set_sae_password(ifp, NULL, 0); + profile->use_fwauth = BIT(BRCMF_PROFILE_FWAUTH_NONE); + } if (ifp->vif->mbss) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); @@ -4649,13 +4972,13 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, sizeof(join_params)); if (err < 0) - brcmf_err("SET SSID error (%d)\n", err); + bphy_err(drvr, "SET SSID error (%d)\n", err); err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); if (err < 0) - brcmf_err("BRCMF_C_DOWN error %d\n", err); + bphy_err(drvr, "BRCMF_C_DOWN error %d\n", err); err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); if (err < 0) - brcmf_err("setting AP mode failed %d\n", err); + bphy_err(drvr, "setting AP mode failed %d\n", err); if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) brcmf_fil_iovar_int_set(ifp, "mbss", 0); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, @@ -4663,7 +4986,7 @@ /* Bring device back up so it can be used again */ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) - brcmf_err("BRCMF_C_UP error %d\n", err); + bphy_err(drvr, "BRCMF_C_UP error %d\n", err); brcmf_vif_clear_mgmt_ies(ifp->vif); } else { @@ -4672,7 +4995,7 @@ err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, sizeof(bss_enable)); if (err < 0) - brcmf_err("bss_enable config failed %d\n", err); + bphy_err(drvr, "bss_enable config failed %d\n", err); } brcmf_set_mpc(ifp, 1); brcmf_configure_arp_nd_offload(ifp, true); @@ -4701,6 +5024,7 @@ struct station_del_parameters *params) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_scb_val_le scbval; struct brcmf_if *ifp = netdev_priv(ndev); s32 err; @@ -4720,7 +5044,8 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scbval)); if (err) - brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err); + bphy_err(drvr, "SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", + err); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -4730,6 +5055,8 @@ brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_parameters *params) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_if *ifp = netdev_priv(ndev); s32 err; @@ -4750,27 +5077,21 @@ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE, (void *)mac, ETH_ALEN); if (err < 0) - brcmf_err("Setting SCB (de-)authorize failed, %d\n", err); + bphy_err(drvr, "Setting SCB (de-)authorize failed, %d\n", err); return err; } static void -brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, - struct wireless_dev *wdev, - u16 frame_type, bool reg) +brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct mgmt_frame_regs *upd) { struct brcmf_cfg80211_vif *vif; - u16 mgmt_type; - brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg); - - mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); - if (reg) - vif->mgmt_rx_reg |= BIT(mgmt_type); - else - vif->mgmt_rx_reg &= ~BIT(mgmt_type); + + vif->mgmt_rx_reg = upd->interface_stypes; } @@ -4780,6 +5101,7 @@ { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct ieee80211_channel *chan = params->chan; + struct brcmf_pub *drvr = cfg->pub; const u8 *buf = params->buf; size_t len = params->len; const struct ieee80211_mgmt *mgmt; @@ -4800,7 +5122,7 @@ mgmt = (const struct ieee80211_mgmt *)buf; if (!ieee80211_is_mgmt(mgmt->frame_control)) { - brcmf_err("Driver only allows MGMT packet type\n"); + bphy_err(drvr, "Driver only allows MGMT packet type\n"); return -EPERM; } @@ -4831,13 +5153,13 @@ GFP_KERNEL); } else if (ieee80211_is_action(mgmt->frame_control)) { if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) { - brcmf_err("invalid action frame length\n"); + bphy_err(drvr, "invalid action frame length\n"); err = -EINVAL; goto exit; } af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); if (af_params == NULL) { - brcmf_err("unable to allocate frame\n"); + bphy_err(drvr, "unable to allocate frame\n"); err = -ENOMEM; goto exit; } @@ -4859,7 +5181,7 @@ &freq); chan_nr = ieee80211_frequency_to_channel(freq); af_params->channel = cpu_to_le32(chan_nr); - + af_params->dwell_time = cpu_to_le32(params->wait); memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], le16_to_cpu(action_frame->len)); @@ -4888,6 +5210,7 @@ u64 cookie) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_vif *vif; int err = 0; @@ -4895,7 +5218,7 @@ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; if (vif == NULL) { - brcmf_err("No p2p device available for probe response\n"); + bphy_err(drvr, "No p2p device available for probe response\n"); err = -ENODEV; goto exit; } @@ -4910,20 +5233,19 @@ { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = wdev->netdev; - struct brcmf_if *ifp; + struct brcmf_pub *drvr = cfg->pub; struct brcmu_chan ch; enum nl80211_band band = 0; enum nl80211_chan_width width = 0; u32 chanspec; int freq, err; - if (!ndev) + if (!ndev || drvr->bus_if->state != BRCMF_BUS_UP) return -ENODEV; - ifp = netdev_priv(ndev); - err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec); + err = brcmf_fil_iovar_int_get(netdev_priv(ndev), "chanspec", &chanspec); if (err) { - brcmf_err("chanspec failed (%d)\n", err); + bphy_err(drvr, "chanspec failed (%d)\n", err); return err; } @@ -5045,6 +5367,8 @@ struct net_device *ndev, const u8 *peer, enum nl80211_tdls_operation oper) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_if *ifp; struct brcmf_tdls_iovar_le info; int ret = 0; @@ -5062,7 +5386,7 @@ ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint", &info, sizeof(info)); if (ret < 0) - brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret); + bphy_err(drvr, "tdls_endpoint iovar failed: ret=%d\n", ret); return ret; } @@ -5073,6 +5397,8 @@ struct cfg80211_connect_params *sme, u32 changed) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_if *ifp; int err; @@ -5083,7 +5409,7 @@ err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); if (err) - brcmf_err("Set Assoc REQ IE Failed\n"); + bphy_err(drvr, "Set Assoc REQ IE Failed\n"); else brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n"); @@ -5095,6 +5421,8 @@ brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_gtk_rekey_data *gtk) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_gtk_keyinfo_le gtk_le; int ret; @@ -5109,7 +5437,7 @@ ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", >k_le, sizeof(gtk_le)); if (ret < 0) - brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret); + bphy_err(drvr, "gtk_key_info iovar failed: ret=%d\n", ret); return ret; } @@ -5178,7 +5506,8 @@ .change_station = brcmf_cfg80211_change_station, .sched_scan_start = brcmf_cfg80211_sched_scan_start, .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, - .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, + .update_mgmt_frame_registrations = + brcmf_cfg80211_update_mgmt_frame_registrations, .mgmt_tx = brcmf_cfg80211_mgmt_tx, .remain_on_channel = brcmf_p2p_remain_on_channel, .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, @@ -5212,6 +5541,7 @@ struct brcmf_cfg80211_vif *vif_walk; struct brcmf_cfg80211_vif *vif; bool mbss; + struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", sizeof(*vif)); @@ -5224,7 +5554,8 @@ brcmf_init_prof(&vif->profile); - if (type == NL80211_IFTYPE_AP) { + if (type == NL80211_IFTYPE_AP && + brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { mbss = false; list_for_each_entry(vif_walk, &cfg->vif_list, list) { if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) { @@ -5263,14 +5594,16 @@ u32 event = e->event_code; u32 status = e->status; - if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK && + if ((vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK || + vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_SAE) && event == BRCMF_E_PSK_SUP && status == BRCMF_E_STATUS_FWSUP_COMPLETED) set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { brcmf_dbg(CONN, "Processing set ssid\n"); memcpy(vif->profile.bssid, e->addr, ETH_ALEN); - if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK) + if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK && + vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_SAE) return true; set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); @@ -5341,11 +5674,151 @@ conn_info->resp_ie_len = 0; } +u8 brcmf_map_prio_to_prec(void *config, u8 prio) +{ + struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config; + + if (!cfg) + return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? + (prio ^ 2) : prio; + + /* For those AC(s) with ACM flag set to 1, convert its 4-level priority + * to an 8-level precedence which is the same as BE's + */ + if (prio > PRIO_8021D_EE && + cfg->ac_priority[prio] == cfg->ac_priority[PRIO_8021D_BE]) + return cfg->ac_priority[prio] * 2; + + /* Conversion of 4-level priority to 8-level precedence */ + if (prio == PRIO_8021D_BE || prio == PRIO_8021D_BK || + prio == PRIO_8021D_CL || prio == PRIO_8021D_VO) + return cfg->ac_priority[prio] * 2; + else + return cfg->ac_priority[prio] * 2 + 1; +} + +u8 brcmf_map_prio_to_aci(void *config, u8 prio) +{ + /* Prio here refers to the 802.1d priority in range of 0 to 7. + * ACI here refers to the WLAN AC Index in range of 0 to 3. + * This function will return ACI corresponding to input prio. + */ + struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config; + + if (cfg) + return cfg->ac_priority[prio]; + + return prio; +} + +static void brcmf_init_wmm_prio(u8 *priority) +{ + /* Initialize AC priority array to default + * 802.1d priority as per following table: + * 802.1d prio 0,3 maps to BE + * 802.1d prio 1,2 maps to BK + * 802.1d prio 4,5 maps to VI + * 802.1d prio 6,7 maps to VO + */ + priority[0] = BRCMF_FWS_FIFO_AC_BE; + priority[3] = BRCMF_FWS_FIFO_AC_BE; + priority[1] = BRCMF_FWS_FIFO_AC_BK; + priority[2] = BRCMF_FWS_FIFO_AC_BK; + priority[4] = BRCMF_FWS_FIFO_AC_VI; + priority[5] = BRCMF_FWS_FIFO_AC_VI; + priority[6] = BRCMF_FWS_FIFO_AC_VO; + priority[7] = BRCMF_FWS_FIFO_AC_VO; +} + +static void brcmf_wifi_prioritize_acparams(const + struct brcmf_cfg80211_edcf_acparam *acp, u8 *priority) +{ + u8 aci; + u8 aifsn; + u8 ecwmin; + u8 ecwmax; + u8 acm; + u8 ranking_basis[EDCF_AC_COUNT]; + u8 aci_prio[EDCF_AC_COUNT]; /* AC_BE, AC_BK, AC_VI, AC_VO */ + u8 index; + + for (aci = 0; aci < EDCF_AC_COUNT; aci++, acp++) { + aifsn = acp->ACI & EDCF_AIFSN_MASK; + acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0; + ecwmin = acp->ECW & EDCF_ECWMIN_MASK; + ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT; + brcmf_dbg(CONN, "ACI %d aifsn %d acm %d ecwmin %d ecwmax %d\n", + aci, aifsn, acm, ecwmin, ecwmax); + /* Default AC_VO will be the lowest ranking value */ + ranking_basis[aci] = aifsn + ecwmin + ecwmax; + /* Initialise priority starting at 0 (AC_BE) */ + aci_prio[aci] = 0; + + /* If ACM is set, STA can't use this AC as per 802.11. + * Change the ranking to BE + */ + if (aci != AC_BE && aci != AC_BK && acm == 1) + ranking_basis[aci] = ranking_basis[AC_BE]; + } + + /* Ranking method which works for AC priority + * swapping when values for cwmin, cwmax and aifsn are varied + * Compare each aci_prio against each other aci_prio + */ + for (aci = 0; aci < EDCF_AC_COUNT; aci++) { + for (index = 0; index < EDCF_AC_COUNT; index++) { + if (index != aci) { + /* Smaller ranking value has higher priority, + * so increment priority for each ACI which has + * a higher ranking value + */ + if (ranking_basis[aci] < ranking_basis[index]) + aci_prio[aci]++; + } + } + } + + /* By now, aci_prio[] will be in range of 0 to 3. + * Use ACI prio to get the new priority value for + * each 802.1d traffic type, in this range. + */ + if (!(aci_prio[AC_BE] == aci_prio[AC_BK] && + aci_prio[AC_BK] == aci_prio[AC_VI] && + aci_prio[AC_VI] == aci_prio[AC_VO])) { + /* 802.1d 0,3 maps to BE */ + priority[0] = aci_prio[AC_BE]; + priority[3] = aci_prio[AC_BE]; + + /* 802.1d 1,2 maps to BK */ + priority[1] = aci_prio[AC_BK]; + priority[2] = aci_prio[AC_BK]; + + /* 802.1d 4,5 maps to VO */ + priority[4] = aci_prio[AC_VI]; + priority[5] = aci_prio[AC_VI]; + + /* 802.1d 6,7 maps to VO */ + priority[6] = aci_prio[AC_VO]; + priority[7] = aci_prio[AC_VO]; + } else { + /* Initialize to default priority */ + brcmf_init_wmm_prio(priority); + } + + brcmf_dbg(CONN, "Adj prio BE 0->%d, BK 1->%d, BK 2->%d, BE 3->%d\n", + priority[0], priority[1], priority[2], priority[3]); + + brcmf_dbg(CONN, "Adj prio VI 4->%d, VI 5->%d, VO 6->%d, VO 7->%d\n", + priority[4], priority[5], priority[6], priority[7]); +} + static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) { + struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_assoc_ielen_le *assoc_info; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + struct brcmf_cfg80211_edcf_acparam edcf_acparam_info[EDCF_AC_COUNT]; u32 req_len; u32 resp_len; s32 err = 0; @@ -5355,19 +5828,24 @@ err = brcmf_fil_iovar_data_get(ifp, "assoc_info", cfg->extra_buf, WL_ASSOC_INFO_MAX); if (err) { - brcmf_err("could not get assoc info (%d)\n", err); + bphy_err(drvr, "could not get assoc info (%d)\n", err); return err; } assoc_info = (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf; req_len = le32_to_cpu(assoc_info->req_len); resp_len = le32_to_cpu(assoc_info->resp_len); + if (req_len > WL_EXTRA_BUF_MAX || resp_len > WL_EXTRA_BUF_MAX) { + bphy_err(drvr, "invalid lengths in assoc info: req %u resp %u\n", + req_len, resp_len); + return -EINVAL; + } if (req_len) { err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies", cfg->extra_buf, WL_ASSOC_INFO_MAX); if (err) { - brcmf_err("could not get assoc req (%d)\n", err); + bphy_err(drvr, "could not get assoc req (%d)\n", err); return err; } conn_info->req_ie_len = req_len; @@ -5385,7 +5863,7 @@ cfg->extra_buf, WL_ASSOC_INFO_MAX); if (err) { - brcmf_err("could not get assoc resp (%d)\n", err); + bphy_err(drvr, "could not get assoc resp (%d)\n", err); return err; } conn_info->resp_ie_len = resp_len; @@ -5394,6 +5872,17 @@ GFP_KERNEL); if (!conn_info->resp_ie) conn_info->resp_ie_len = 0; + + err = brcmf_fil_iovar_data_get(ifp, "wme_ac_sta", + edcf_acparam_info, + sizeof(edcf_acparam_info)); + if (err) { + brcmf_err("could not get wme_ac_sta (%d)\n", err); + return err; + } + + brcmf_wifi_prioritize_acparams(edcf_acparam_info, + cfg->ac_priority); } else { conn_info->resp_ie_len = 0; conn_info->resp_ie = NULL; @@ -5467,6 +5956,11 @@ cfg80211_roamed(ndev, &roam_info, GFP_KERNEL); brcmf_dbg(CONN, "Report roaming result\n"); + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X && profile->is_ft) { + cfg80211_port_authorized(ndev, profile->bssid, GFP_KERNEL); + brcmf_dbg(CONN, "Report port authorized\n"); + } + set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -5514,6 +6008,7 @@ struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { + struct brcmf_pub *drvr = cfg->pub; static int generation; u32 event = e->event_code; u32 reason = e->reason; @@ -5531,7 +6026,7 @@ if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && (reason == BRCMF_E_STATUS_SUCCESS)) { if (!data) { - brcmf_err("No IEs present in ASSOC/REASSOC_IND"); + bphy_err(drvr, "No IEs present in ASSOC/REASSOC_IND\n"); return -EINVAL; } @@ -5589,10 +6084,19 @@ brcmf_net_setcarrier(ifp, true); } else if (brcmf_is_linkdown(ifp->vif, e)) { brcmf_dbg(CONN, "Linkdown\n"); - if (!brcmf_is_ibssmode(ifp->vif)) { + if (!brcmf_is_ibssmode(ifp->vif) && + test_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state)) { + if (memcmp(profile->bssid, e->addr, ETH_ALEN)) + return err; + brcmf_bss_connect_done(cfg, ndev, e, false); brcmf_link_down(ifp->vif, - brcmf_map_fw_linkdown_reason(e)); + brcmf_map_fw_linkdown_reason(e), + e->event_code & + (BRCMF_E_DEAUTH_IND | + BRCMF_E_DISASSOC_IND) + ? false : true); brcmf_init_prof(ndev_to_prof(ndev)); if (ndev != cfg_to_ndev(cfg)) complete(&cfg->vif_disabled); @@ -5804,6 +6308,7 @@ mutex_init(&cfg->usr_sync); brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); + brcmf_init_wmm_prio(cfg->ac_priority); init_completion(&cfg->vif_disabled); return err; } @@ -5823,6 +6328,7 @@ static s32 brcmf_dongle_roam(struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; s32 err; u32 bcn_timeout; __le32 roamtrigger[2]; @@ -5835,7 +6341,7 @@ bcn_timeout = BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON; err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout); if (err) { - brcmf_err("bcn_timeout error (%d)\n", err); + bphy_err(drvr, "bcn_timeout error (%d)\n", err); goto roam_setup_done; } @@ -5847,7 +6353,7 @@ err = brcmf_fil_iovar_int_set(ifp, "roam_off", ifp->drvr->settings->roamoff); if (err) { - brcmf_err("roam_off error (%d)\n", err); + bphy_err(drvr, "roam_off error (%d)\n", err); goto roam_setup_done; } @@ -5855,19 +6361,17 @@ roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER, (void *)roamtrigger, sizeof(roamtrigger)); - if (err) { - brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err); - goto roam_setup_done; - } + if (err) + bphy_err(drvr, "WLC_SET_ROAM_TRIGGER error (%d)\n", err); roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA); roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA, (void *)roam_delta, sizeof(roam_delta)); - if (err) { - brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err); - goto roam_setup_done; - } + if (err) + bphy_err(drvr, "WLC_SET_ROAM_DELTA error (%d)\n", err); + + return 0; roam_setup_done: return err; @@ -5876,25 +6380,26 @@ static s32 brcmf_dongle_scantime(struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; s32 err = 0; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, BRCMF_SCAN_CHANNEL_TIME); if (err) { - brcmf_err("Scan assoc time error (%d)\n", err); + bphy_err(drvr, "Scan assoc time error (%d)\n", err); goto dongle_scantime_out; } err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME, BRCMF_SCAN_UNASSOC_TIME); if (err) { - brcmf_err("Scan unassoc time error (%d)\n", err); + bphy_err(drvr, "Scan unassoc time error (%d)\n", err); goto dongle_scantime_out; } err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME, BRCMF_SCAN_PASSIVE_TIME); if (err) { - brcmf_err("Scan passive time error (%d)\n", err); + bphy_err(drvr, "Scan passive time error (%d)\n", err); goto dongle_scantime_out; } @@ -5926,10 +6431,11 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap[]) { - struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); + struct wiphy *wiphy = cfg_to_wiphy(cfg); + struct brcmf_pub *drvr = cfg->pub; + struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); struct ieee80211_supported_band *band; struct ieee80211_channel *channel; - struct wiphy *wiphy; struct brcmf_chanspec_list *list; struct brcmu_chan ch; int err; @@ -5948,11 +6454,10 @@ err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf, BRCMF_DCMD_MEDLEN); if (err) { - brcmf_err("get chanspecs error (%d)\n", err); + bphy_err(drvr, "get chanspecs error (%d)\n", err); goto fail_pbuf; } - wiphy = cfg_to_wiphy(cfg); band = wiphy->bands[NL80211_BAND_2GHZ]; if (band) for (i = 0; i < band->n_channels; i++) @@ -5963,6 +6468,13 @@ band->channels[i].flags = IEEE80211_CHAN_DISABLED; total = le32_to_cpu(list->count); + if (total > BRCMF_MAX_CHANSPEC_LIST) { + bphy_err(drvr, "Invalid count of channel Spec. (%u)\n", + total); + err = -EINVAL; + goto fail_pbuf; + } + for (i = 0; i < total; i++) { ch.chspec = (u16)le32_to_cpu(list->element[i]); cfg->d11inf.decchspec(&ch); @@ -5972,7 +6484,8 @@ } else if (ch.band == BRCMU_CHAN_BAND_5G) { band = wiphy->bands[NL80211_BAND_5GHZ]; } else { - brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec); + bphy_err(drvr, "Invalid channel Spec. 0x%x.\n", + ch.chspec); continue; } if (!band) @@ -5995,8 +6508,8 @@ /* It seems firmware supports some channel we never * considered. Something new in IEEE standard? */ - brcmf_err("Ignoring unexpected firmware channel %d\n", - ch.control_ch_num); + bphy_err(drvr, "Ignoring unexpected firmware channel %d\n", + ch.control_ch_num); continue; } @@ -6006,11 +6519,21 @@ /* assuming the chanspecs order is HT20, * HT40 upper, HT40 lower, and VHT80. */ - if (ch.bw == BRCMU_CHAN_BW_80) { + switch (ch.bw) { + case BRCMU_CHAN_BW_160: + channel->flags &= ~IEEE80211_CHAN_NO_160MHZ; + break; + case BRCMU_CHAN_BW_80: channel->flags &= ~IEEE80211_CHAN_NO_80MHZ; - } else if (ch.bw == BRCMU_CHAN_BW_40) { + break; + case BRCMU_CHAN_BW_40: brcmf_update_bw40_channel_flag(channel, &ch); - } else { + break; + default: + wiphy_warn(wiphy, "Firmware reported unsupported bandwidth %d\n", + ch.bw); + fallthrough; + case BRCMU_CHAN_BW_20: /* enable the channel and disable other bandwidths * for now as mentioned order assure they are enabled * for subsequent chanspecs. @@ -6042,7 +6565,8 @@ static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg) { - struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); + struct brcmf_pub *drvr = cfg->pub; + struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); struct ieee80211_supported_band *band; struct brcmf_fil_bwcap_le band_bwcap; struct brcmf_chanspec_list *list; @@ -6088,7 +6612,7 @@ err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf, BRCMF_DCMD_MEDLEN); if (err) { - brcmf_err("get chanspecs error (%d)\n", err); + bphy_err(drvr, "get chanspecs error (%d)\n", err); kfree(pbuf); return err; } @@ -6096,6 +6620,13 @@ band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ]; list = (struct brcmf_chanspec_list *)pbuf; num_chan = le32_to_cpu(list->count); + if (num_chan > BRCMF_MAX_CHANSPEC_LIST) { + bphy_err(drvr, "Invalid count of channel Spec. (%u)\n", + num_chan); + kfree(pbuf); + return -EINVAL; + } + for (i = 0; i < num_chan; i++) { ch.chspec = (u16)le32_to_cpu(list->element[i]); cfg->d11inf.decchspec(&ch); @@ -6119,6 +6650,7 @@ static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[]) { + struct brcmf_pub *drvr = ifp->drvr; u32 band, mimo_bwcap; int err; @@ -6145,16 +6677,16 @@ switch (mimo_bwcap) { case WLC_N_BW_40ALL: bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT; - /* fall-thru */ + fallthrough; case WLC_N_BW_20IN2G_40IN5G: bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT; - /* fall-thru */ + fallthrough; case WLC_N_BW_20ALL: bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT; bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT; break; default: - brcmf_err("invalid mimo_bw_cap value\n"); + bphy_err(drvr, "invalid mimo_bw_cap value\n"); } } @@ -6229,8 +6761,9 @@ static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg) { - struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); - struct wiphy *wiphy; + struct brcmf_pub *drvr = cfg->pub; + struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); + struct wiphy *wiphy = cfg_to_wiphy(cfg); u32 nmode = 0; u32 vhtmode = 0; u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT }; @@ -6246,7 +6779,7 @@ (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode); err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode); if (err) { - brcmf_err("nmode error (%d)\n", err); + bphy_err(drvr, "nmode error (%d)\n", err); } else { brcmf_get_bwcap(ifp, bw_cap); } @@ -6256,7 +6789,7 @@ err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain); if (err) { - brcmf_err("rxchain error (%d)\n", err); + bphy_err(drvr, "rxchain error (%d)\n", err); nchain = 1; } else { for (nchain = 0; rxchain; nchain++) @@ -6266,7 +6799,7 @@ err = brcmf_construct_chaninfo(cfg, bw_cap); if (err) { - brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err); + bphy_err(drvr, "brcmf_construct_chaninfo failed (%d)\n", err); return err; } @@ -6278,7 +6811,6 @@ &txbf_bfr_cap); } - wiphy = cfg_to_wiphy(cfg); for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) { band = wiphy->bands[i]; if (band == NULL) @@ -6351,6 +6883,9 @@ * #STA <= 1, #AP <= 1, channels = 1, 2 total * #AP <= 4, matching BI, channels = 1, 4 total * + * no p2p and rsdb: + * #STA <= 1, #AP <= 2, channels = 2, 4 total + * * p2p, no mchan, and mbss: * * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total @@ -6362,6 +6897,10 @@ * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total * #AP <= 4, matching BI, channels = 1, 4 total + * + * p2p, rsdb, and no mbss: + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2, + * channels = 2, 4 total */ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) { @@ -6369,13 +6908,16 @@ struct ieee80211_iface_limit *c0_limits = NULL; struct ieee80211_iface_limit *p2p_limits = NULL; struct ieee80211_iface_limit *mbss_limits = NULL; - bool mbss, p2p; - int i, c, n_combos; + bool mon_flag, mbss, p2p, rsdb, mchan; + int i, c, n_combos, n_limits; + mon_flag = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FLAG); mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS); p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P); + rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB); + mchan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN); - n_combos = 1 + !!p2p + !!mbss; + n_combos = 1 + !!(p2p && !rsdb) + !!mbss; combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL); if (!combo) goto err; @@ -6383,37 +6925,53 @@ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); - - c = 0; - i = 0; - c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); - if (!c0_limits) - goto err; - c0_limits[i].max = 1; - c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); - if (p2p) { - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) - combo[c].num_different_channels = 2; - else - combo[c].num_different_channels = 1; + if (mon_flag) + wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + if (p2p) wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); + + c = 0; + i = 0; + n_limits = 1 + mon_flag + (p2p ? 2 : 0) + (rsdb || !p2p); + c0_limits = kcalloc(n_limits, sizeof(*c0_limits), GFP_KERNEL); + if (!c0_limits) + goto err; + + combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan)); + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); + if (mon_flag) { + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR); + } + if (p2p) { c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); - c0_limits[i].max = 1; + c0_limits[i].max = 1 + rsdb; c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); + } + if (p2p && rsdb) { + c0_limits[i].max = 2; + c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); + combo[c].max_interfaces = 4; + } else if (p2p) { + combo[c].max_interfaces = i; + } else if (rsdb) { + c0_limits[i].max = 2; + c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); + combo[c].max_interfaces = 3; } else { - combo[c].num_different_channels = 1; c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); + combo[c].max_interfaces = i; } - combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = c0_limits; - if (p2p) { + if (p2p && !rsdb) { c++; i = 0; p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); @@ -6436,14 +6994,20 @@ if (mbss) { c++; i = 0; - mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); + n_limits = 1 + mon_flag; + mbss_limits = kcalloc(n_limits, sizeof(*mbss_limits), + GFP_KERNEL); if (!mbss_limits) goto err; mbss_limits[i].max = 4; mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP); + if (mon_flag) { + mbss_limits[i].max = 1; + mbss_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR); + } combo[c].beacon_int_infra_match = true; combo[c].num_different_channels = 1; - combo[c].max_interfaces = 4; + combo[c].max_interfaces = 4 + mon_flag; combo[c].n_limits = i; combo[c].limits = mbss_limits; } @@ -6474,12 +7038,13 @@ { #ifdef CONFIG_PM struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; struct wiphy_wowlan_support *wowl; wowl = kmemdup(&brcmf_wowlan_support, sizeof(brcmf_wowlan_support), GFP_KERNEL); if (!wowl) { - brcmf_err("only support basic wowlan features\n"); + bphy_err(drvr, "only support basic wowlan features\n"); wiphy->wowlan = &brcmf_wowlan_support; return; } @@ -6560,6 +7125,16 @@ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE)) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SAE_OFFLOAD); + } + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWAUTH)) { + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE)) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SAE_OFFLOAD_AP); } wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; @@ -6576,7 +7151,7 @@ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist, sizeof(bandlist)); if (err) { - brcmf_err("could not obtain band info: err=%d\n", err); + bphy_err(drvr, "could not obtain band info: err=%d\n", err); return err; } /* first entry in bandlist is number of bands */ @@ -6618,6 +7193,11 @@ } } + if (wiphy->bands[NL80211_BAND_5GHZ] && + brcmf_feat_is_enabled(ifp, BRCMF_FEAT_DOT11H)) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_DFS_OFFLOAD); + wiphy_read_of_freq_limits(wiphy); return 0; @@ -6625,6 +7205,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) { + struct brcmf_pub *drvr = cfg->pub; struct net_device *ndev; struct wireless_dev *wdev; struct brcmf_if *ifp; @@ -6660,6 +7241,12 @@ brcmf_configure_arp_nd_offload(ifp, true); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_FAKEFRAG, 1); + if (err) { + bphy_err(drvr, "failed to set frameburst mode\n"); + goto default_conf_out; + } + cfg->dongle_up = true; default_conf_out: @@ -6683,7 +7270,7 @@ * from AP to save power */ if (check_vif_up(ifp->vif)) { - brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED); + brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED, true); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep @@ -6837,6 +7424,7 @@ { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_fil_country_le ccreq; s32 err; int i; @@ -6848,8 +7436,8 @@ /* ignore non-ISO3166 country codes */ for (i = 0; i < 2; i++) if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { - brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n", - req->alpha2[0], req->alpha2[1]); + bphy_err(drvr, "not an ISO3166 code (0x%02x 0x%02x)\n", + req->alpha2[0], req->alpha2[1]); return; } @@ -6858,7 +7446,7 @@ err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq)); if (err) { - brcmf_err("Country code iovar returned err = %d\n", err); + bphy_err(drvr, "Country code iovar returned err = %d\n", err); return; } @@ -6868,7 +7456,7 @@ err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq)); if (err) { - brcmf_err("Firmware rejected country setting\n"); + bphy_err(drvr, "Firmware rejected country setting\n"); return; } brcmf_setup_wiphybands(cfg); @@ -6914,13 +7502,13 @@ u16 *cap = NULL; if (!ndev) { - brcmf_err("ndev is invalid\n"); + bphy_err(drvr, "ndev is invalid\n"); return NULL; } cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) { - brcmf_err("Could not allocate wiphy device\n"); + bphy_err(drvr, "Could not allocate wiphy device\n"); return NULL; } @@ -6941,7 +7529,7 @@ err = wl_init_priv(cfg); if (err) { - brcmf_err("Failed to init iwm_priv (%d)\n", err); + bphy_err(drvr, "Failed to init iwm_priv (%d)\n", err); brcmf_free_vif(vif); goto wiphy_out; } @@ -6950,7 +7538,7 @@ /* determine d11 io type before wiphy setup */ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type); if (err) { - brcmf_err("Failed to get D11 version (%d)\n", err); + bphy_err(drvr, "Failed to get D11 version (%d)\n", err); goto priv_out; } cfg->d11inf.io_type = (u8)io_type; @@ -6984,13 +7572,13 @@ #endif err = wiphy_register(wiphy); if (err < 0) { - brcmf_err("Could not register wiphy device (%d)\n", err); + bphy_err(drvr, "Could not register wiphy device (%d)\n", err); goto priv_out; } err = brcmf_setup_wiphybands(cfg); if (err) { - brcmf_err("Setting wiphy bands failed (%d)\n", err); + bphy_err(drvr, "Setting wiphy bands failed (%d)\n", err); goto wiphy_unreg_out; } @@ -7008,24 +7596,24 @@ err = brcmf_fweh_activate_events(ifp); if (err) { - brcmf_err("FWEH activation failed (%d)\n", err); + bphy_err(drvr, "FWEH activation failed (%d)\n", err); goto wiphy_unreg_out; } err = brcmf_p2p_attach(cfg, p2pdev_forced); if (err) { - brcmf_err("P2P initialisation failed (%d)\n", err); + bphy_err(drvr, "P2P initialisation failed (%d)\n", err); goto wiphy_unreg_out; } err = brcmf_btcoex_attach(cfg); if (err) { - brcmf_err("BT-coex initialisation failed (%d)\n", err); + bphy_err(drvr, "BT-coex initialisation failed (%d)\n", err); brcmf_p2p_detach(&cfg->p2p); goto wiphy_unreg_out; } err = brcmf_pno_attach(cfg); if (err) { - brcmf_err("PNO initialisation failed (%d)\n", err); + bphy_err(drvr, "PNO initialisation failed (%d)\n", err); brcmf_btcoex_detach(cfg); brcmf_p2p_detach(&cfg->p2p); goto wiphy_unreg_out; @@ -7045,7 +7633,7 @@ /* (re-) activate FWEH event handling */ err = brcmf_fweh_activate_events(ifp); if (err) { - brcmf_err("FWEH activation failed (%d)\n", err); + bphy_err(drvr, "FWEH activation failed (%d)\n", err); goto detach; } @@ -7085,7 +7673,6 @@ brcmf_pno_detach(cfg); brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); - kfree(cfg->ops); wl_deinit_priv(cfg); brcmf_free_wiphy(cfg->wiphy); kfree(cfg); -- Gitblit v1.6.2