diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c')
| -rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 5039 |
1 files changed, 2581 insertions, 2458 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index c1abaa6db59..d8fa276e368 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -16,17 +16,9 @@ /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/kernel.h> -#include <linux/if_arp.h> -#include <linux/sched.h> -#include <linux/kthread.h> -#include <linux/netdevice.h> -#include <linux/bitops.h> #include <linux/etherdevice.h> -#include <linux/ieee80211.h> -#include <linux/uaccess.h> +#include <linux/module.h> #include <net/cfg80211.h> #include <net/netlink.h> @@ -34,7 +26,13 @@ #include <defs.h> #include <brcmu_wifi.h> #include "dhd.h" +#include "dhd_dbg.h" +#include "tracepoint.h" +#include "fwil_types.h" +#include "p2p.h" +#include "btcoex.h" #include "wl_cfg80211.h" +#include "fwil.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 #define BRCMF_PNO_VERSION 2 @@ -48,14 +46,13 @@ #define BRCMF_PNO_SCAN_COMPLETE 1 #define BRCMF_PNO_SCAN_INCOMPLETE 0 -#define TLV_LEN_OFF 1 /* length offset */ -#define TLV_HDR_LEN 2 /* header length */ -#define TLV_BODY_OFF 2 /* body offset */ -#define TLV_OUI_LEN 3 /* oui id length */ +#define BRCMF_IFACE_MAX_CNT 3 + #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ #define WPA_OUI_TYPE 1 #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ #define WME_OUI_TYPE 2 +#define WPS_OUI_TYPE 4 #define VS_IE_FIXED_HDR_LEN 6 #define WPA_IE_VERSION_LEN 2 @@ -81,26 +78,23 @@ #define VNDR_IE_PKTFLAG_OFFSET 8 #define VNDR_IE_VSIE_OFFSET 12 #define VNDR_IE_HDR_SIZE 12 -#define VNDR_IE_BEACON_FLAG 0x1 -#define VNDR_IE_PRBRSP_FLAG 0x2 -#define MAX_VNDR_IE_NUMBER 5 +#define VNDR_IE_PARSE_LIMIT 5 #define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */ #define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */ +#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 +#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 +#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20 + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) -static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; - -static u32 brcmf_dbg_level = WL_DBG_ERR; - -static bool check_sys_up(struct wiphy *wiphy) +static bool check_vif_up(struct brcmf_cfg80211_vif *vif) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - if (!test_bit(WL_STATUS_READY, &cfg->status)) { - WL_INFO("device is not ready : status (%d)\n", - (int)cfg->status); + if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) { + brcmf_dbg(INFO, "device is not ready : status (%lu)\n", + vif->sme_state); return false; } return true; @@ -191,70 +185,13 @@ static struct ieee80211_channel __wl_5ghz_a_channels[] = { CHAN5G(216, 0), }; -static struct ieee80211_channel __wl_5ghz_n_channels[] = { - CHAN5G(32, 0), CHAN5G(34, 0), - CHAN5G(36, 0), CHAN5G(38, 0), - CHAN5G(40, 0), CHAN5G(42, 0), - CHAN5G(44, 0), CHAN5G(46, 0), - CHAN5G(48, 0), CHAN5G(50, 0), - CHAN5G(52, 0), CHAN5G(54, 0), - CHAN5G(56, 0), CHAN5G(58, 0), - CHAN5G(60, 0), CHAN5G(62, 0), - CHAN5G(64, 0), CHAN5G(66, 0), - CHAN5G(68, 0), CHAN5G(70, 0), - CHAN5G(72, 0), CHAN5G(74, 0), - CHAN5G(76, 0), CHAN5G(78, 0), - CHAN5G(80, 0), CHAN5G(82, 0), - CHAN5G(84, 0), CHAN5G(86, 0), - CHAN5G(88, 0), CHAN5G(90, 0), - CHAN5G(92, 0), CHAN5G(94, 0), - CHAN5G(96, 0), CHAN5G(98, 0), - CHAN5G(100, 0), CHAN5G(102, 0), - CHAN5G(104, 0), CHAN5G(106, 0), - CHAN5G(108, 0), CHAN5G(110, 0), - CHAN5G(112, 0), CHAN5G(114, 0), - CHAN5G(116, 0), CHAN5G(118, 0), - CHAN5G(120, 0), CHAN5G(122, 0), - CHAN5G(124, 0), CHAN5G(126, 0), - CHAN5G(128, 0), CHAN5G(130, 0), - CHAN5G(132, 0), CHAN5G(134, 0), - CHAN5G(136, 0), CHAN5G(138, 0), - CHAN5G(140, 0), CHAN5G(142, 0), - CHAN5G(144, 0), CHAN5G(145, 0), - CHAN5G(146, 0), CHAN5G(147, 0), - CHAN5G(148, 0), CHAN5G(149, 0), - CHAN5G(150, 0), CHAN5G(151, 0), - CHAN5G(152, 0), CHAN5G(153, 0), - CHAN5G(154, 0), CHAN5G(155, 0), - CHAN5G(156, 0), CHAN5G(157, 0), - CHAN5G(158, 0), CHAN5G(159, 0), - CHAN5G(160, 0), CHAN5G(161, 0), - CHAN5G(162, 0), CHAN5G(163, 0), - CHAN5G(164, 0), CHAN5G(165, 0), - CHAN5G(166, 0), CHAN5G(168, 0), - CHAN5G(170, 0), CHAN5G(172, 0), - CHAN5G(174, 0), CHAN5G(176, 0), - CHAN5G(178, 0), CHAN5G(180, 0), - CHAN5G(182, 0), CHAN5G(184, 0), - CHAN5G(186, 0), CHAN5G(188, 0), - CHAN5G(190, 0), CHAN5G(192, 0), - CHAN5G(194, 0), CHAN5G(196, 0), - CHAN5G(198, 0), CHAN5G(200, 0), - CHAN5G(202, 0), CHAN5G(204, 0), - CHAN5G(206, 0), CHAN5G(208, 0), - CHAN5G(210, 0), CHAN5G(212, 0), - CHAN5G(214, 0), CHAN5G(216, 0), - CHAN5G(218, 0), CHAN5G(220, 0), - CHAN5G(222, 0), CHAN5G(224, 0), - CHAN5G(226, 0), CHAN5G(228, 0), -}; - static struct ieee80211_supported_band __wl_band_2ghz = { .band = IEEE80211_BAND_2GHZ, .channels = __wl_2ghz_channels, .n_channels = ARRAY_SIZE(__wl_2ghz_channels), .bitrates = wl_g_rates, .n_bitrates = wl_g_rates_size, + .ht_cap = {IEEE80211_HT_CAP_SUP_WIDTH_20_40, true}, }; static struct ieee80211_supported_band __wl_band_5ghz_a = { @@ -265,12 +202,28 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .n_bitrates = wl_a_rates_size, }; -static struct ieee80211_supported_band __wl_band_5ghz_n = { - .band = IEEE80211_BAND_5GHZ, - .channels = __wl_5ghz_n_channels, - .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), - .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size, +/* This is to override regulatory domains defined in cfg80211 module (reg.c) + * By default world regulatory domain defined in reg.c puts the flags + * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165). + * With respect to these flags, wpa_supplicant doesn't * start p2p + * operations on 5GHz channels. All the changes in world regulatory + * domain are to be done here. + */ +static const struct ieee80211_regdomain brcmf_regdom = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), + /* If any */ + /* IEEE 802.11 channel 14 - Only JP enables + * this and for 802.11b only + */ + 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), + /* IEEE 802.11a, channel 100..165 */ + REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), } }; static const u32 __wl_cipher_suites[] = { @@ -281,13 +234,6 @@ static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_AES_CMAC, }; -/* tag_ID/length/value_buffer tuple */ -struct brcmf_tlv { - u8 id; - u8 len; - u8 data[1]; -}; - /* Vendor specific ie. id = 221, oui and type defines exact ie */ struct brcmf_vs_tlv { u8 id; @@ -304,9 +250,13 @@ struct parsed_vndr_ie_info { struct parsed_vndr_ies { u32 count; - struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; + struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; }; +static int brcmf_roamoff; +module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR); +MODULE_PARM_DESC(roamoff, "do not use internal roaming engine"); + /* Quarter dBm units to mW * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 * Table is offset so the last entry is largest mW value that fits in @@ -391,57 +341,150 @@ static u8 brcmf_mw_to_qdbm(u16 mw) return qdbm; } -/* function for reading/writing a single u32 from/to the dongle */ -static int -brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par) +static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, + struct cfg80211_chan_def *ch) { - int err; - __le32 par_le = cpu_to_le32(*par); + struct brcmu_chan ch_inf; + s32 primary_offset; - err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32)); - *par = le32_to_cpu(par_le); + brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n", + ch->chan->center_freq, ch->center_freq1, ch->width); + ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1); + primary_offset = ch->center_freq1 - ch->chan->center_freq; + switch (ch->width) { + case NL80211_CHAN_WIDTH_20: + ch_inf.bw = BRCMU_CHAN_BW_20; + WARN_ON(primary_offset != 0); + break; + case NL80211_CHAN_WIDTH_40: + ch_inf.bw = BRCMU_CHAN_BW_40; + if (primary_offset < 0) + ch_inf.sb = BRCMU_CHAN_SB_U; + else + ch_inf.sb = BRCMU_CHAN_SB_L; + break; + case NL80211_CHAN_WIDTH_80: + ch_inf.bw = BRCMU_CHAN_BW_80; + if (primary_offset < 0) { + if (primary_offset < -CH_10MHZ_APART) + ch_inf.sb = BRCMU_CHAN_SB_UU; + else + ch_inf.sb = BRCMU_CHAN_SB_UL; + } else { + if (primary_offset > CH_10MHZ_APART) + ch_inf.sb = BRCMU_CHAN_SB_LL; + else + ch_inf.sb = BRCMU_CHAN_SB_LU; + } + break; + default: + WARN_ON_ONCE(1); + } + switch (ch->chan->band) { + case IEEE80211_BAND_2GHZ: + ch_inf.band = BRCMU_CHAN_BAND_2G; + break; + case IEEE80211_BAND_5GHZ: + ch_inf.band = BRCMU_CHAN_BAND_5G; + break; + default: + WARN_ON_ONCE(1); + } + d11inf->encchspec(&ch_inf); - return err; + return ch_inf.chspec; } -static s32 -brcmf_dev_iovar_setbuf_bsscfg(struct net_device *ndev, s8 *name, - void *param, s32 paramlen, - void *buf, s32 buflen, s32 bssidx) -{ - s32 err = -ENOMEM; - u32 len; - - len = brcmf_c_mkiovar_bsscfg(name, param, paramlen, - buf, buflen, bssidx); - BUG_ON(!len); - if (len > 0) - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); - if (err) - WL_ERR("error (%d)\n", err); +u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, + struct ieee80211_channel *ch) +{ + struct brcmu_chan ch_inf; - return err; + ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq); + ch_inf.bw = BRCMU_CHAN_BW_20; + d11inf->encchspec(&ch_inf); + + return ch_inf.chspec; } -static s32 -brcmf_dev_iovar_getbuf_bsscfg(struct net_device *ndev, s8 *name, - void *param, s32 paramlen, - void *buf, s32 buflen, s32 bssidx) -{ - s32 err = -ENOMEM; - u32 len; - - len = brcmf_c_mkiovar_bsscfg(name, param, paramlen, - buf, buflen, bssidx); - BUG_ON(!len); - if (len > 0) - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, buf, len); - if (err) - WL_ERR("error (%d)\n", err); +/* Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag + */ +const struct brcmf_tlv * +brcmf_parse_tlvs(const void *buf, int buflen, uint key) +{ + const struct brcmf_tlv *elt = buf; + int totlen = buflen; - return err; + /* find tagged parameter */ + while (totlen >= TLV_HDR_LEN) { + int len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) + return elt; + + elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + + return NULL; +} + +/* Is any of the tlvs the expected entry? If + * not update the tlvs buffer pointer/length. + */ +static bool +brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, + const u8 *oui, u32 oui_len, u8 type) +{ + /* If the contents match the OUI and the type */ + if (ie[TLV_LEN_OFF] >= oui_len + 1 && + !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && + type == ie[TLV_BODY_OFF + oui_len]) { + return true; + } + + if (tlvs == NULL) + return false; + /* point to the next ie */ + ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return false; } +static struct brcmf_vs_tlv * +brcmf_find_wpaie(const u8 *parse, u32 len) +{ + const struct brcmf_tlv *ie; + + while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { + if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len, + WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) + return (struct brcmf_vs_tlv *)ie; + } + return NULL; +} + +static struct brcmf_vs_tlv * +brcmf_find_wpsie(const u8 *parse, u32 len) +{ + const struct brcmf_tlv *ie; + + while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { + if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, + WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE)) + return (struct brcmf_vs_tlv *)ie; + } + return NULL; +} + + static void convert_key_from_CPU(struct brcmf_wsec_key *key, struct brcmf_wsec_key_le *key_le) { @@ -457,393 +500,284 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key, } static int -send_key_to_dongle(struct brcmf_cfg80211_info *cfg, s32 bssidx, - struct net_device *ndev, struct brcmf_wsec_key *key) +send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) { int err; struct brcmf_wsec_key_le key_le; convert_key_from_CPU(key, &key_le); - err = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le, - sizeof(key_le), - cfg->extra_buf, - WL_EXTRA_BUF_MAX, bssidx); + brcmf_netdev_wait_pend8021x(ndev); + + err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le, + sizeof(key_le)); if (err) - WL_ERR("wsec_key error (%d)\n", err); + brcmf_err("wsec_key error (%d)\n", err); return err; } static s32 -brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) +brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - s32 infra = 0; - s32 ap = 0; - s32 err = 0; - - WL_TRACE("Enter, ndev=%p, type=%d\n", ndev, type); + s32 err; + u32 mode; - switch (type) { - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_WDS: - WL_ERR("type (%d) : currently we do not support this type\n", - type); - return -EOPNOTSUPP; - case NL80211_IFTYPE_ADHOC: - cfg->conf->mode = WL_MODE_IBSS; - infra = 0; - break; - case NL80211_IFTYPE_STATION: - cfg->conf->mode = WL_MODE_BSS; - infra = 1; - break; - case NL80211_IFTYPE_AP: - cfg->conf->mode = WL_MODE_AP; - ap = 1; - break; - default: - err = -EINVAL; - goto done; - } + if (enable) + mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY; + else + mode = 0; - if (ap) { - set_bit(WL_STATUS_AP_CREATING, &cfg->status); - if (!cfg->ap_info) - cfg->ap_info = kzalloc(sizeof(*cfg->ap_info), - GFP_KERNEL); - if (!cfg->ap_info) { - err = -ENOMEM; - goto done; - } - WL_INFO("IF Type = AP\n"); + /* Try to set and enable ARP offload feature, this may fail, then it */ + /* is simply not supported and err 0 will be returned */ + err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode); + if (err) { + brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n", + mode, err); + err = 0; } else { - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); + err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable); if (err) { - WL_ERR("WLC_SET_INFRA error (%d)\n", err); - err = -EAGAIN; - goto done; - } - WL_INFO("IF Type = %s\n", - (cfg->conf->mode == WL_MODE_IBSS) ? - "Adhoc" : "Infra"); + brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n", + enable, err); + err = 0; + } else + brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n", + enable, mode); } - ndev->ieee80211_ptr->iftype = type; - -done: - WL_TRACE("Exit\n"); return err; } -static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val) +static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) { - s8 buf[BRCMF_DCMD_SMLEN]; - u32 len; - s32 err = 0; - __le32 val_le; - - val_le = cpu_to_le32(val); - len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf, - sizeof(buf)); - BUG_ON(!len); - - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); - if (err) - WL_ERR("error (%d)\n", err); + enum nl80211_iftype iftype; - return err; -} - -static s32 -brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval) -{ - union { - s8 buf[BRCMF_DCMD_SMLEN]; - __le32 val; - } var; - u32 len; - u32 data_null; - s32 err = 0; - - len = - brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), - sizeof(var.buf)); - BUG_ON(!len); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len); - if (err) - WL_ERR("error (%d)\n", err); - - *retval = le32_to_cpu(var.val); - - return err; + iftype = vif->wdev.iftype; + return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO; } -static s32 -brcmf_dev_intvar_set_bsscfg(struct net_device *ndev, s8 *name, u32 val, - s32 bssidx) +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) { - s8 buf[BRCMF_DCMD_SMLEN]; - __le32 val_le; - - val_le = cpu_to_le32(val); - - return brcmf_dev_iovar_setbuf_bsscfg(ndev, name, &val_le, - sizeof(val_le), buf, sizeof(buf), - bssidx); + return vif->wdev.iftype == NL80211_IFTYPE_ADHOC; } -static s32 -brcmf_dev_intvar_get_bsscfg(struct net_device *ndev, s8 *name, s32 *val, - s32 bssidx) +static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { - s8 buf[BRCMF_DCMD_SMLEN]; - s32 err; - __le32 val_le; - - memset(buf, 0, sizeof(buf)); - err = brcmf_dev_iovar_getbuf_bsscfg(ndev, name, val, sizeof(*val), buf, - sizeof(buf), bssidx); - if (err == 0) { - memcpy(&val_le, buf, sizeof(val_le)); - *val = le32_to_cpu(val_le); + brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP: + 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_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_P2P_DEVICE: + return brcmf_p2p_add_vif(wiphy, name, type, flags, params); + case NL80211_IFTYPE_UNSPECIFIED: + default: + return ERR_PTR(-EINVAL); } - return err; } - -/* - * For now brcmf_find_bssidx will return 0. Once p2p gets implemented this - * should return the ndev matching bssidx. - */ -static s32 -brcmf_find_bssidx(struct brcmf_cfg80211_info *cfg, struct net_device *ndev) -{ - return 0; -} - -static void brcmf_set_mpc(struct net_device *ndev, int mpc) +void brcmf_set_mpc(struct brcmf_if *ifp, int mpc) { s32 err = 0; - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - if (test_bit(WL_STATUS_READY, &cfg->status)) { - err = brcmf_dev_intvar_set(ndev, "mpc", mpc); + if (check_vif_up(ifp->vif)) { + err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); if (err) { - WL_ERR("fail to set mpc\n"); + brcmf_err("fail to set mpc\n"); return; } - WL_INFO("MPC : %d\n", mpc); + brcmf_dbg(INFO, "MPC : %d\n", mpc); } } -static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le, - struct brcmf_ssid *ssid) +s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, + struct brcmf_if *ifp, bool aborted, + bool fw_abort) { - memcpy(params_le->bssid, ether_bcast, ETH_ALEN); - params_le->bss_type = DOT11_BSSTYPE_ANY; - params_le->scan_type = 0; - params_le->channel_num = 0; - params_le->nprobes = cpu_to_le32(-1); - params_le->active_time = cpu_to_le32(-1); - params_le->passive_time = cpu_to_le32(-1); - params_le->home_time = cpu_to_le32(-1); - if (ssid && ssid->SSID_len) { - params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len); - memcpy(¶ms_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len); - } -} - -static s32 -brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param, - s32 paramlen, void *bufptr, s32 buflen) -{ - s32 iolen; - - iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); - BUG_ON(!iolen); - - return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen); -} - -static s32 -brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param, - s32 paramlen, void *bufptr, s32 buflen) -{ - s32 iolen; - - iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); - BUG_ON(!iolen); + struct brcmf_scan_params_le params_le; + struct cfg80211_scan_request *scan_request; + s32 err = 0; - return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen); -} + brcmf_dbg(SCAN, "Enter\n"); -static s32 -brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, - struct brcmf_ssid *ssid, u16 action) -{ - s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + - offsetof(struct brcmf_iscan_params_le, params_le); - struct brcmf_iscan_params_le *params; - s32 err = 0; + /* clear scan request, because the FW abort can cause a second call */ + /* to this functon and might cause a double cfg80211_scan_done */ + scan_request = cfg->scan_request; + cfg->scan_request = NULL; - if (ssid && ssid->SSID_len) - params_size += sizeof(struct brcmf_ssid); - params = kzalloc(params_size, GFP_KERNEL); - if (!params) - return -ENOMEM; - BUG_ON(params_size >= BRCMF_DCMD_SMLEN); + if (timer_pending(&cfg->escan_timeout)) + del_timer_sync(&cfg->escan_timeout); - brcmf_iscan_prep(¶ms->params_le, ssid); + if (fw_abort) { + /* Do a scan abort to stop the driver's scan engine */ + brcmf_dbg(SCAN, "ABORT scan in firmware\n"); + memset(¶ms_le, 0, sizeof(params_le)); + memset(params_le.bssid, 0xFF, ETH_ALEN); + params_le.bss_type = DOT11_BSSTYPE_ANY; + params_le.scan_type = 0; + params_le.channel_num = cpu_to_le32(1); + params_le.nprobes = cpu_to_le32(1); + params_le.active_time = cpu_to_le32(-1); + params_le.passive_time = cpu_to_le32(-1); + params_le.home_time = cpu_to_le32(-1); + /* Scan is aborted by setting channel_list[0] to -1 */ + params_le.channel_list[0] = cpu_to_le16(-1); + /* E-Scan (or anyother type) can be aborted by SCAN */ + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, + ¶ms_le, sizeof(params_le)); + if (err) + brcmf_err("Scan abort failed\n"); + } - params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION); - params->action = cpu_to_le16(action); - params->scan_duration = cpu_to_le16(0); + brcmf_set_mpc(ifp, 1); - err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size, - iscan->dcmd_buf, BRCMF_DCMD_SMLEN); - if (err) { - if (err == -EBUSY) - WL_INFO("system busy : iscan canceled\n"); - else - WL_ERR("error (%d)\n", err); + /* + * e-scan can be initiated by scheduled scan + * which takes precedence. + */ + if (cfg->sched_escan) { + brcmf_dbg(SCAN, "scheduled scan completed\n"); + cfg->sched_escan = false; + if (!aborted) + cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); + } else if (scan_request) { + brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", + aborted ? "Aborted" : "Done"); + cfg80211_scan_done(scan_request, aborted); } + if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) + brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n"); - kfree(params); return err; } -static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg) +static +int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - struct net_device *ndev = cfg_to_ndev(cfg); - struct brcmf_ssid ssid; - __le32 passive_scan; - s32 err = 0; + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev->netdev; - /* Broadcast scan by default */ - memset(&ssid, 0, sizeof(ssid)); + /* vif event pending in firmware */ + if (brcmf_cfg80211_vif_event_armed(cfg)) + return -EBUSY; - iscan->state = WL_ISCAN_STATE_SCANING; + if (ndev) { + if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) && + cfg->escan_info.ifp == netdev_priv(ndev)) + brcmf_notify_escan_complete(cfg, netdev_priv(ndev), + true, true); - passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); - err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); - if (err) { - WL_ERR("error (%d)\n", err); - return err; + brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1); } - brcmf_set_mpc(ndev, 0); - cfg->iscan_kickstart = true; - err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); - if (err) { - brcmf_set_mpc(ndev, 1); - cfg->iscan_kickstart = false; - return err; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_MESH_POINT: + return -EOPNOTSUPP; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_P2P_DEVICE: + return brcmf_p2p_del_vif(wiphy, wdev); + case NL80211_IFTYPE_UNSPECIFIED: + default: + return -EINVAL; } - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - return err; + return -EOPNOTSUPP; } static s32 -brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid) +brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) { - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; - __le32 passive_scan; - bool iscan_req; - bool spec_scan; + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_vif *vif = ifp->vif; + s32 infra = 0; + s32 ap = 0; s32 err = 0; - u32 SSID_len; - if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { - WL_ERR("Scanning already : status (%lu)\n", cfg->status); - return -EAGAIN; - } - if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) { - WL_ERR("Scanning being aborted : status (%lu)\n", - cfg->status); - return -EAGAIN; - } - if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) { - WL_ERR("Connecting : status (%lu)\n", - cfg->status); - return -EAGAIN; - } + brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type); - iscan_req = false; - spec_scan = false; - if (request) { - /* scan bss */ - ssids = request->ssids; - if (cfg->iscan_on && (!ssids || !ssids->ssid_len)) - iscan_req = true; - } else { - /* scan in ibss */ - /* we don't do iscan in ibss */ - ssids = this_ssid; + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + brcmf_err("type (%d) : currently we do not support this type\n", + type); + return -EOPNOTSUPP; + case NL80211_IFTYPE_ADHOC: + infra = 0; + break; + case NL80211_IFTYPE_STATION: + /* Ignore change for p2p IF. Unclear why supplicant does this */ + if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) || + (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) { + brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n"); + /* WAR: It is unexpected to get a change of VIF for P2P + * IF, but it happens. The request can not be handled + * but returning EPERM causes a crash. Returning 0 + * without setting ieee80211_ptr->iftype causes trace + * (WARN_ON) but it works with wpa_supplicant + */ + return 0; + } + infra = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + ap = 1; + break; + default: + err = -EINVAL; + goto done; } - cfg->scan_request = request; - set_bit(WL_STATUS_SCANNING, &cfg->status); - if (iscan_req) { - err = brcmf_do_iscan(cfg); - if (!err) - return err; - else - goto scan_out; - } else { - WL_SCAN("ssid \"%s\", ssid_len (%d)\n", - ssids->ssid, ssids->ssid_len); - memset(&sr->ssid_le, 0, sizeof(sr->ssid_le)); - SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len); - sr->ssid_le.SSID_len = cpu_to_le32(0); - if (SSID_len) { - memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len); - sr->ssid_le.SSID_len = cpu_to_le32(SSID_len); - spec_scan = true; - } else { - WL_SCAN("Broadcast scan\n"); + if (ap) { + if (type == NL80211_IFTYPE_P2P_GO) { + brcmf_dbg(INFO, "IF Type = P2P GO\n"); + err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO); } - - passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); - if (err) { - WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); - goto scan_out; + if (!err) { + set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); + brcmf_dbg(INFO, "IF Type = AP\n"); } - brcmf_set_mpc(ndev, 0); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le, - sizeof(sr->ssid_le)); + } else { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); if (err) { - if (err == -EBUSY) - WL_INFO("system busy : scan for \"%s\" " - "canceled\n", sr->ssid_le.SSID); - else - WL_ERR("WLC_SCAN error (%d)\n", err); - - brcmf_set_mpc(ndev, 1); - goto scan_out; + brcmf_err("WLC_SET_INFRA error (%d)\n", err); + err = -EAGAIN; + goto done; } + brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ? + "Adhoc" : "Infra"); } + ndev->ieee80211_ptr->iftype = type; - return 0; +done: + brcmf_dbg(TRACE, "Exit\n"); -scan_out: - clear_bit(WL_STATUS_SCANNING, &cfg->status); - cfg->scan_request = NULL; return err; } -static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, +static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + struct brcmf_scan_params_le *params_le, struct cfg80211_scan_request *request) { u32 n_ssids; @@ -851,12 +785,10 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, s32 i; s32 offset; u16 chanspec; - u16 channel; - struct ieee80211_channel *req_channel; char *ptr; struct brcmf_ssid_le ssid_le; - memcpy(params_le->bssid, ether_bcast, ETH_ALEN); + memset(params_le->bssid, 0xFF, ETH_ALEN); params_le->bss_type = DOT11_BSSTYPE_ANY; params_le->scan_type = 0; params_le->channel_num = 0; @@ -873,40 +805,21 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, n_ssids = request->n_ssids; n_channels = request->n_channels; /* Copy channel array if applicable */ - WL_SCAN("### List of channelspecs to scan ### %d\n", n_channels); + brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n", + n_channels); if (n_channels > 0) { for (i = 0; i < n_channels; i++) { - chanspec = 0; - req_channel = request->channels[i]; - channel = ieee80211_frequency_to_channel( - req_channel->center_freq); - if (req_channel->band == IEEE80211_BAND_2GHZ) - chanspec |= WL_CHANSPEC_BAND_2G; - else - chanspec |= WL_CHANSPEC_BAND_5G; - - if (req_channel->flags & IEEE80211_CHAN_NO_HT40) { - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - } else { - chanspec |= WL_CHANSPEC_BW_40; - if (req_channel->flags & - IEEE80211_CHAN_NO_HT40PLUS) - chanspec |= WL_CHANSPEC_CTL_SB_LOWER; - else - chanspec |= WL_CHANSPEC_CTL_SB_UPPER; - } - - chanspec |= (channel & WL_CHANSPEC_CHAN_MASK); - WL_SCAN("Chan : %d, Channel spec: %x\n", - channel, chanspec); + chanspec = channel_to_chanspec(&cfg->d11inf, + request->channels[i]); + brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n", + request->channels[i]->hw_value, chanspec); params_le->channel_list[i] = cpu_to_le16(chanspec); } } else { - WL_SCAN("Scanning all channels\n"); + brcmf_dbg(SCAN, "Scanning all channels\n"); } /* Copy ssid array if applicable */ - WL_SCAN("### List of SSIDs to scan ### %d\n", n_ssids); + brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids); if (n_ssids > 0) { offset = offsetof(struct brcmf_scan_params_le, channel_list) + n_channels * sizeof(u16); @@ -919,18 +832,19 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, memcpy(ssid_le.SSID, request->ssids[i].ssid, request->ssids[i].ssid_len); if (!ssid_le.SSID_len) - WL_SCAN("%d: Broadcast scan\n", i); + brcmf_dbg(SCAN, "%d: Broadcast scan\n", i); else - WL_SCAN("%d: scan for %s size =%d\n", i, - ssid_le.SSID, ssid_le.SSID_len); + brcmf_dbg(SCAN, "%d: scan for %s size =%d\n", + i, ssid_le.SSID, ssid_le.SSID_len); memcpy(ptr, &ssid_le, sizeof(ssid_le)); ptr += sizeof(ssid_le); } } else { - WL_SCAN("Broadcast scan %p\n", request->ssids); + brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids); if ((request->ssids) && request->ssids->ssid_len) { - WL_SCAN("SSID %s len=%d\n", params_le->ssid_le.SSID, - request->ssids->ssid_len); + brcmf_dbg(SCAN, "SSID %s len=%d\n", + params_le->ssid_le.SSID, + request->ssids->ssid_len); params_le->ssid_le.SSID_len = cpu_to_le32(request->ssids->ssid_len); memcpy(¶ms_le->ssid_le.SSID, request->ssids->ssid, @@ -944,70 +858,7 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, } static s32 -brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - bool aborted, bool fw_abort) -{ - struct brcmf_scan_params_le params_le; - struct cfg80211_scan_request *scan_request; - s32 err = 0; - - WL_SCAN("Enter\n"); - - /* clear scan request, because the FW abort can cause a second call */ - /* to this functon and might cause a double cfg80211_scan_done */ - scan_request = cfg->scan_request; - cfg->scan_request = NULL; - - if (timer_pending(&cfg->escan_timeout)) - del_timer_sync(&cfg->escan_timeout); - - if (fw_abort) { - /* Do a scan abort to stop the driver's scan engine */ - WL_SCAN("ABORT scan in firmware\n"); - memset(¶ms_le, 0, sizeof(params_le)); - memcpy(params_le.bssid, ether_bcast, ETH_ALEN); - params_le.bss_type = DOT11_BSSTYPE_ANY; - params_le.scan_type = 0; - params_le.channel_num = cpu_to_le32(1); - params_le.nprobes = cpu_to_le32(1); - params_le.active_time = cpu_to_le32(-1); - params_le.passive_time = cpu_to_le32(-1); - params_le.home_time = cpu_to_le32(-1); - /* Scan is aborted by setting channel_list[0] to -1 */ - params_le.channel_list[0] = cpu_to_le16(-1); - /* E-Scan (or anyother type) can be aborted by SCAN */ - err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, ¶ms_le, - sizeof(params_le)); - if (err) - WL_ERR("Scan abort failed\n"); - } - /* - * e-scan can be initiated by scheduled scan - * which takes precedence. - */ - if (cfg->sched_escan) { - WL_SCAN("scheduled scan completed\n"); - cfg->sched_escan = false; - if (!aborted) - cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); - brcmf_set_mpc(ndev, 1); - } else if (scan_request) { - WL_SCAN("ESCAN Completed scan: %s\n", - aborted ? "Aborted" : "Done"); - cfg80211_scan_done(scan_request, aborted); - brcmf_set_mpc(ndev, 1); - } - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { - WL_ERR("Scan complete while device not scanning\n"); - return -EPERM; - } - - return err; -} - -static s32 -brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, +brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, struct cfg80211_scan_request *request, u16 action) { s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + @@ -1015,7 +866,7 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, struct brcmf_escan_params_le *params; s32 err = 0; - WL_SCAN("E-SCAN START\n"); + brcmf_dbg(SCAN, "E-SCAN START\n"); if (request != NULL) { /* Allocate space for populating ssids in struct */ @@ -1031,18 +882,17 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, goto exit; } BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN); - brcmf_escan_prep(¶ms->params_le, request); + brcmf_escan_prep(cfg, ¶ms->params_le, request); params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); params->action = cpu_to_le16(action); params->sync_id = cpu_to_le16(0x1234); - err = brcmf_dev_iovar_setbuf(ndev, "escan", params, params_size, - cfg->escan_ioctl_buf, BRCMF_DCMD_MEDLEN); + err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size); if (err) { if (err == -EBUSY) - WL_INFO("system busy : escan canceled\n"); + brcmf_dbg(INFO, "system busy : escan canceled\n"); else - WL_ERR("error (%d)\n", err); + brcmf_err("error (%d)\n", err); } kfree(params); @@ -1052,66 +902,76 @@ exit: static s32 brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, - struct net_device *ndev, struct cfg80211_scan_request *request) + struct brcmf_if *ifp, struct cfg80211_scan_request *request) { s32 err; - __le32 passive_scan; + u32 passive_scan; struct brcmf_scan_results *results; + struct escan_info *escan = &cfg->escan_info; - WL_SCAN("Enter\n"); - cfg->escan_info.ndev = ndev; - cfg->escan_info.wiphy = wiphy; - cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING; - passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); + brcmf_dbg(SCAN, "Enter\n"); + escan->ifp = ifp; + escan->wiphy = wiphy; + escan->escan_state = WL_ESCAN_STATE_SCANNING; + passive_scan = cfg->active_scan ? 0 : 1; + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN, + passive_scan); if (err) { - WL_ERR("error (%d)\n", err); + brcmf_err("error (%d)\n", err); return err; } - brcmf_set_mpc(ndev, 0); + brcmf_set_mpc(ifp, 0); results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf; results->version = 0; results->count = 0; results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE; - err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START); + err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START); if (err) - brcmf_set_mpc(ndev, 1); + brcmf_set_mpc(ifp, 1); return err; } static s32 -brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, +brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid) { - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); + struct brcmf_if *ifp = vif->ifp; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; - __le32 passive_scan; + struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int; + u32 passive_scan; bool escan_req; bool spec_scan; s32 err; u32 SSID_len; - WL_SCAN("START ESCAN\n"); + brcmf_dbg(SCAN, "START ESCAN\n"); - if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { - WL_ERR("Scanning already : status (%lu)\n", cfg->status); + if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + brcmf_err("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); return -EAGAIN; } - if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) { - WL_ERR("Scanning being aborted : status (%lu)\n", - cfg->status); + if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) { + brcmf_err("Scanning suppressed: status (%lu)\n", + cfg->scan_status); return -EAGAIN; } - if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) { - WL_ERR("Connecting : status (%lu)\n", - cfg->status); + if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { + brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state); return -EAGAIN; } + /* If scan req comes for p2p0, send it over primary I/F */ + if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) + vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; + /* Arm scan timeout timer */ mod_timer(&cfg->escan_timeout, jiffies + WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); @@ -1128,16 +988,19 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, } cfg->scan_request = request; - set_bit(WL_STATUS_SCANNING, &cfg->status); + set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); if (escan_req) { - err = brcmf_do_escan(cfg, wiphy, ndev, request); - if (!err) - return err; - else + cfg->escan_info.run = brcmf_run_escan; + err = brcmf_p2p_scan_prep(wiphy, request, vif); + if (err) + goto scan_out; + + err = brcmf_do_escan(cfg, wiphy, vif->ifp, request); + if (err) goto scan_out; } else { - WL_SCAN("ssid \"%s\", ssid_len (%d)\n", - ssids->ssid, ssids->ssid_len); + brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n", + ssids->ssid, ssids->ssid_len); memset(&sr->ssid_le, 0, sizeof(sr->ssid_le)); SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len); sr->ssid_le.SSID_len = cpu_to_le32(0); @@ -1147,26 +1010,26 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, sr->ssid_le.SSID_len = cpu_to_le32(SSID_len); spec_scan = true; } else - WL_SCAN("Broadcast scan\n"); + brcmf_dbg(SCAN, "Broadcast scan\n"); - passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); + passive_scan = cfg->active_scan ? 0 : 1; + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN, + passive_scan); if (err) { - WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); + brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err); goto scan_out; } - brcmf_set_mpc(ndev, 0); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le, - sizeof(sr->ssid_le)); + brcmf_set_mpc(ifp, 0); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, + &sr->ssid_le, sizeof(sr->ssid_le)); if (err) { if (err == -EBUSY) - WL_INFO("BUSY: scan for \"%s\" canceled\n", - sr->ssid_le.SSID); + brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n", + sr->ssid_le.SSID); else - WL_ERR("WLC_SCAN error (%d)\n", err); + brcmf_err("WLC_SCAN error (%d)\n", err); - brcmf_set_mpc(ndev, 1); + brcmf_set_mpc(ifp, 1); goto scan_out; } } @@ -1174,7 +1037,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, return 0; scan_out: - clear_bit(WL_STATUS_SCANNING, &cfg->status); + clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); if (timer_pending(&cfg->escan_timeout)) del_timer_sync(&cfg->escan_timeout); cfg->scan_request = NULL; @@ -1182,27 +1045,22 @@ scan_out: } static s32 -brcmf_cfg80211_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) +brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { - struct net_device *ndev = request->wdev->netdev; - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); + struct brcmf_cfg80211_vif *vif; s32 err = 0; - WL_TRACE("Enter\n"); - - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev); + if (!check_vif_up(vif)) return -EIO; - if (cfg->iscan_on) - err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL); - else if (cfg->escan_on) - err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL); + err = brcmf_cfg80211_escan(wiphy, vif, request, NULL); if (err) - WL_ERR("scan error (%d)\n", err); + brcmf_err("scan error (%d)\n", err); - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -1210,9 +1068,10 @@ static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold) { s32 err = 0; - err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold); + err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh", + rts_threshold); if (err) - WL_ERR("Error (%d)\n", err); + brcmf_err("Error (%d)\n", err); return err; } @@ -1221,9 +1080,10 @@ static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) { s32 err = 0; - err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold); + err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh", + frag_threshold); if (err) - WL_ERR("Error (%d)\n", err); + brcmf_err("Error (%d)\n", err); return err; } @@ -1231,11 +1091,11 @@ static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) { s32 err = 0; - u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL); + u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL); - err = brcmf_exec_dcmd_u32(ndev, cmd, &retry); + err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry); if (err) { - WL_ERR("cmd (%d) , error (%d)\n", cmd, err); + brcmf_err("cmd (%d) , error (%d)\n", cmd, err); return err; } return err; @@ -1245,10 +1105,11 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = cfg_to_ndev(cfg); + struct brcmf_if *ifp = netdev_priv(ndev); s32 err = 0; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; if (changed & WIPHY_PARAM_RTS_THRESHOLD && @@ -1281,7 +1142,7 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) } done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -1290,49 +1151,28 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) memset(prof, 0, sizeof(*prof)); } -static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, - size_t *join_params_size) -{ - u16 chanspec = 0; - - if (ch != 0) { - if (ch <= CH_MAX_2G_CHANNEL) - chanspec |= WL_CHANSPEC_BAND_2G; - else - chanspec |= WL_CHANSPEC_BAND_5G; - - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - - *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + - sizeof(u16); - - chanspec |= (ch & WL_CHANSPEC_CHAN_MASK); - join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec); - join_params->params_le.chanspec_num = cpu_to_le32(1); - - WL_CONN("join_params->params.chanspec_list[0]= %#X," - "channel %d, chanspec %#X\n", - chanspec, ch, chanspec); - } -} - -static void brcmf_link_down(struct brcmf_cfg80211_info *cfg) +static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) { - struct net_device *ndev = NULL; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); s32 err = 0; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); + + if (test_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); + } + clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); + cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL); - if (cfg->link_up) { - ndev = cfg_to_ndev(cfg); - WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); - err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0); - if (err) - WL_ERR("WLC_DISASSOC failed (%d)\n", err); - cfg->link_up = false; } - WL_TRACE("Exit\n"); + 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); + brcmf_dbg(TRACE, "Exit\n"); } static s32 @@ -1340,68 +1180,72 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_join_params join_params; size_t join_params_size = 0; s32 err = 0; s32 wsec = 0; s32 bcnprd; + u16 chanspec; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; if (params->ssid) - WL_CONN("SSID: %s\n", params->ssid); + brcmf_dbg(CONN, "SSID: %s\n", params->ssid); else { - WL_CONN("SSID: NULL, Not supported\n"); + brcmf_dbg(CONN, "SSID: NULL, Not supported\n"); return -EOPNOTSUPP; } - set_bit(WL_STATUS_CONNECTING, &cfg->status); + set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); if (params->bssid) - WL_CONN("BSSID: %pM\n", params->bssid); + brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid); else - WL_CONN("No BSSID specified\n"); + brcmf_dbg(CONN, "No BSSID specified\n"); - if (params->channel) - WL_CONN("channel: %d\n", params->channel->center_freq); + if (params->chandef.chan) + brcmf_dbg(CONN, "channel: %d\n", + params->chandef.chan->center_freq); else - WL_CONN("no channel specified\n"); + brcmf_dbg(CONN, "no channel specified\n"); if (params->channel_fixed) - WL_CONN("fixed channel required\n"); + brcmf_dbg(CONN, "fixed channel required\n"); else - WL_CONN("no fixed channel required\n"); + brcmf_dbg(CONN, "no fixed channel required\n"); if (params->ie && params->ie_len) - WL_CONN("ie len: %d\n", params->ie_len); + brcmf_dbg(CONN, "ie len: %d\n", params->ie_len); else - WL_CONN("no ie specified\n"); + brcmf_dbg(CONN, "no ie specified\n"); if (params->beacon_interval) - WL_CONN("beacon interval: %d\n", params->beacon_interval); + brcmf_dbg(CONN, "beacon interval: %d\n", + params->beacon_interval); else - WL_CONN("no beacon interval specified\n"); + brcmf_dbg(CONN, "no beacon interval specified\n"); if (params->basic_rates) - WL_CONN("basic rates: %08X\n", params->basic_rates); + brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates); else - WL_CONN("no basic rates specified\n"); + brcmf_dbg(CONN, "no basic rates specified\n"); if (params->privacy) - WL_CONN("privacy required\n"); + brcmf_dbg(CONN, "privacy required\n"); else - WL_CONN("no privacy required\n"); + brcmf_dbg(CONN, "no privacy required\n"); /* Configure Privacy for starter */ if (params->privacy) wsec |= WEP_ENABLED; - err = brcmf_dev_intvar_set(ndev, "wsec", wsec); + err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec); if (err) { - WL_ERR("wsec failed (%d)\n", err); + brcmf_err("wsec failed (%d)\n", err); goto done; } @@ -1411,9 +1255,9 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, else bcnprd = 100; - err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd); if (err) { - WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err); + brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err); goto done; } @@ -1434,29 +1278,33 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, BRCMF_ASSOC_PARAMS_FIXED_SIZE; memcpy(profile->bssid, params->bssid, ETH_ALEN); } else { - memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); + memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); memset(profile->bssid, 0, ETH_ALEN); } /* Channel */ - if (params->channel) { + if (params->chandef.chan) { u32 target_channel; cfg->channel = ieee80211_frequency_to_channel( - params->channel->center_freq); + params->chandef.chan->center_freq); if (params->channel_fixed) { /* adding chanspec */ - brcmf_ch_to_chanspec(cfg->channel, - &join_params, &join_params_size); + chanspec = chandef_to_chanspec(&cfg->d11inf, + ¶ms->chandef); + join_params.params_le.chanspec_list[0] = + cpu_to_le16(chanspec); + join_params.params_le.chanspec_num = cpu_to_le32(1); + join_params_size += sizeof(join_params.params_le); } /* set channel for starter */ target_channel = cfg->channel; - err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL, - &target_channel); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL, + target_channel); if (err) { - WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err); + brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err); goto done; } } else @@ -1465,33 +1313,33 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, cfg->ibss_starter = false; - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, - &join_params, join_params_size); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, + &join_params, join_params_size); if (err) { - WL_ERR("WLC_SET_SSID failed (%d)\n", err); + brcmf_err("WLC_SET_SSID failed (%d)\n", err); goto done; } done: if (err) - clear_bit(WL_STATUS_CONNECTING, &cfg->status); - WL_TRACE("Exit\n"); + clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); + brcmf_dbg(TRACE, "Exit\n"); return err; } static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); s32 err = 0; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; - brcmf_link_down(cfg); + brcmf_link_down(ifp->vif); - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -1499,8 +1347,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) static s32 brcmf_set_wpa_version(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; @@ -1511,10 +1358,10 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; else val = WPA_AUTH_DISABLED; - WL_CONN("setting wpa_auth to 0x%0x\n", val); - err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); + brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); if (err) { - WL_ERR("set wpa_auth failed (%d)\n", err); + brcmf_err("set wpa_auth failed (%d)\n", err); return err; } sec = &profile->sec; @@ -1525,8 +1372,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, static s32 brcmf_set_auth_type(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; @@ -1534,27 +1380,27 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, switch (sme->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: val = 0; - WL_CONN("open system\n"); + brcmf_dbg(CONN, "open system\n"); break; case NL80211_AUTHTYPE_SHARED_KEY: val = 1; - WL_CONN("shared key\n"); + brcmf_dbg(CONN, "shared key\n"); break; case NL80211_AUTHTYPE_AUTOMATIC: val = 2; - WL_CONN("automatic\n"); + brcmf_dbg(CONN, "automatic\n"); break; case NL80211_AUTHTYPE_NETWORK_EAP: - WL_CONN("network eap\n"); + brcmf_dbg(CONN, "network eap\n"); default: val = 2; - WL_ERR("invalid auth type (%d)\n", sme->auth_type); + brcmf_err("invalid auth type (%d)\n", sme->auth_type); break; } - err = brcmf_dev_intvar_set(ndev, "auth", val); + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val); if (err) { - WL_ERR("set auth failed (%d)\n", err); + brcmf_err("set auth failed (%d)\n", err); return err; } sec = &profile->sec; @@ -1563,14 +1409,14 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, } static s32 -brcmf_set_set_cipher(struct net_device *ndev, - struct cfg80211_connect_params *sme) +brcmf_set_wsec_mode(struct net_device *ndev, + struct cfg80211_connect_params *sme, bool mfp) { - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); struct brcmf_cfg80211_security *sec; s32 pval = 0; s32 gval = 0; + s32 wsec; s32 err = 0; if (sme->crypto.n_ciphers_pairwise) { @@ -1589,8 +1435,8 @@ brcmf_set_set_cipher(struct net_device *ndev, pval = AES_ENABLED; break; default: - WL_ERR("invalid cipher pairwise (%d)\n", - sme->crypto.ciphers_pairwise[0]); + brcmf_err("invalid cipher pairwise (%d)\n", + sme->crypto.ciphers_pairwise[0]); return -EINVAL; } } @@ -1610,16 +1456,26 @@ brcmf_set_set_cipher(struct net_device *ndev, gval = AES_ENABLED; break; default: - WL_ERR("invalid cipher group (%d)\n", - sme->crypto.cipher_group); + brcmf_err("invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } - WL_CONN("pval (%d) gval (%d)\n", pval, gval); - err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval); + brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval); + /* In case of privacy, but no security and WPS then simulate */ + /* setting AES. WPS-2.0 allows no security */ + if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval && + sme->privacy) + pval = AES_ENABLED; + + if (mfp) + wsec = pval | gval | MFP_CAPABLE; + else + wsec = pval | gval; + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec); if (err) { - WL_ERR("error (%d)\n", err); + brcmf_err("error (%d)\n", err); return err; } @@ -1633,16 +1489,16 @@ brcmf_set_set_cipher(struct net_device *ndev, static s32 brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; if (sme->crypto.n_akm_suites) { - err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val); + err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), + "wpa_auth", &val); if (err) { - WL_ERR("could not get wpa_auth (%d)\n", err); + brcmf_err("could not get wpa_auth (%d)\n", err); return err; } if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { @@ -1654,8 +1510,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) val = WPA_AUTH_PSK; break; default: - WL_ERR("invalid cipher group (%d)\n", - sme->crypto.cipher_group); + brcmf_err("invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { @@ -1667,16 +1523,17 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) val = WPA2_AUTH_PSK; break; default: - WL_ERR("invalid cipher group (%d)\n", - sme->crypto.cipher_group); + brcmf_err("invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } - WL_CONN("setting wpa_auth to %d\n", val); - err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); + brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), + "wpa_auth", val); if (err) { - WL_ERR("could not set wpa_auth (%d)\n", err); + brcmf_err("could not set wpa_auth (%d)\n", err); return err; } } @@ -1690,22 +1547,20 @@ static s32 brcmf_set_sharedkey(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); struct brcmf_cfg80211_security *sec; struct brcmf_wsec_key key; s32 val; s32 err = 0; - s32 bssidx; - WL_CONN("key len (%d)\n", sme->key_len); + brcmf_dbg(CONN, "key len (%d)\n", sme->key_len); if (sme->key_len == 0) return 0; sec = &profile->sec; - WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n", - sec->wpa_versions, sec->cipher_pairwise); + 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)) return 0; @@ -1718,7 +1573,7 @@ brcmf_set_sharedkey(struct net_device *ndev, key.len = (u32) sme->key_len; key.index = (u32) sme->key_idx; if (key.len > sizeof(key.data)) { - WL_ERR("Too long key length (%u)\n", key.len); + brcmf_err("Too long key length (%u)\n", key.len); return -EINVAL; } memcpy(key.data, sme->key, key.len); @@ -1731,119 +1586,242 @@ brcmf_set_sharedkey(struct net_device *ndev, key.algo = CRYPTO_ALGO_WEP128; break; default: - WL_ERR("Invalid algorithm (%d)\n", - sme->crypto.ciphers_pairwise[0]); + brcmf_err("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0]); return -EINVAL; } /* Set the new key/index */ - WL_CONN("key length (%d) key index (%d) algo (%d)\n", - key.len, key.index, key.algo); - WL_CONN("key \"%s\"\n", key.data); - bssidx = brcmf_find_bssidx(cfg, ndev); - err = send_key_to_dongle(cfg, bssidx, ndev, &key); + 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(ndev, &key); if (err) return err; if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { - WL_CONN("set auth_type to shared key\n"); + brcmf_dbg(CONN, "set auth_type to shared key\n"); val = WL_AUTH_SHARED_KEY; /* shared key */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", val, bssidx); + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val); if (err) - WL_ERR("set auth failed (%d)\n", err); + brcmf_err("set auth failed (%d)\n", err); } return err; } +static +enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp, + enum nl80211_auth_type type) +{ + u32 ci; + if (type == NL80211_AUTHTYPE_AUTOMATIC) { + /* shift to ignore chip revision */ + ci = brcmf_get_chip_info(ifp) >> 4; + switch (ci) { + case 43236: + brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n"); + return NL80211_AUTHTYPE_OPEN_SYSTEM; + default: + break; + } + } + return type; +} + static s32 brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_connect_params *sme) + struct cfg80211_connect_params *sme) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct ieee80211_channel *chan = sme->channel; struct brcmf_join_params join_params; size_t join_params_size; - struct brcmf_ssid ssid; - + const struct brcmf_tlv *rsn_ie; + const struct brcmf_vs_tlv *wpa_ie; + const void *ie; + u32 ie_len; + struct brcmf_ext_join_params_le *ext_join_params; + u16 chanspec; s32 err = 0; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; if (!sme->ssid) { - WL_ERR("Invalid ssid\n"); + brcmf_err("Invalid ssid\n"); return -EOPNOTSUPP; } - set_bit(WL_STATUS_CONNECTING, &cfg->status); + if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) { + /* A normal (non P2P) connection request setup. */ + ie = NULL; + ie_len = 0; + /* find the WPA_IE */ + wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len); + if (wpa_ie) { + ie = wpa_ie; + ie_len = wpa_ie->len + TLV_HDR_LEN; + } else { + /* find the RSN_IE */ + rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, + sme->ie_len, + WLAN_EID_RSN); + if (rsn_ie) { + ie = rsn_ie; + ie_len = rsn_ie->len + TLV_HDR_LEN; + } + } + brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len); + } + + 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"); + else + brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n"); + + set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); if (chan) { cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); - WL_CONN("channel (%d), center_req (%d)\n", - cfg->channel, chan->center_freq); - } else + chanspec = channel_to_chanspec(&cfg->d11inf, chan); + brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n", + cfg->channel, chan->center_freq, chanspec); + } else { cfg->channel = 0; + chanspec = 0; + } - WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); + brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); err = brcmf_set_wpa_version(ndev, sme); if (err) { - WL_ERR("wl_set_wpa_version failed (%d)\n", err); + brcmf_err("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) { - WL_ERR("wl_set_auth_type failed (%d)\n", err); + brcmf_err("wl_set_auth_type failed (%d)\n", err); goto done; } - err = brcmf_set_set_cipher(ndev, sme); + err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED); if (err) { - WL_ERR("wl_set_set_cipher failed (%d)\n", err); + brcmf_err("wl_set_set_cipher failed (%d)\n", err); goto done; } err = brcmf_set_key_mgmt(ndev, sme); if (err) { - WL_ERR("wl_set_key_mgmt failed (%d)\n", err); + brcmf_err("wl_set_key_mgmt failed (%d)\n", err); goto done; } err = brcmf_set_sharedkey(ndev, sme); if (err) { - WL_ERR("brcmf_set_sharedkey failed (%d)\n", err); + brcmf_err("brcmf_set_sharedkey failed (%d)\n", err); + goto done; + } + + profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID), + (u32)sme->ssid_len); + memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); + if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + profile->ssid.SSID[profile->ssid.SSID_len] = 0; + brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID, + profile->ssid.SSID_len); + } + + /* Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) + + offsetof(struct brcmf_assoc_params_le, chanspec_list); + if (cfg->channel) + join_params_size += sizeof(u16); + ext_join_params = kzalloc(join_params_size, GFP_KERNEL); + if (ext_join_params == NULL) { + err = -ENOMEM; goto done; } + ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); + memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, + profile->ssid.SSID_len); + + /* Set up join scan parameters */ + ext_join_params->scan_le.scan_type = -1; + ext_join_params->scan_le.home_time = cpu_to_le32(-1); + + if (sme->bssid) + memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN); + else + memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN); + + if (cfg->channel) { + ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1); + + ext_join_params->assoc_le.chanspec_list[0] = + cpu_to_le16(chanspec); + /* Increase dwell time to receive probe response or detect + * beacon from target AP at a noisy air only during connect + * command. + */ + ext_join_params->scan_le.active_time = + cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); + ext_join_params->scan_le.passive_time = + cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); + /* To sync with presence period of VSDB GO send probe request + * more frequently. Probe request will be stopped when it gets + * probe response from target AP/GO. + */ + ext_join_params->scan_le.nprobes = + cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / + BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); + } else { + ext_join_params->scan_le.active_time = cpu_to_le32(-1); + ext_join_params->scan_le.passive_time = cpu_to_le32(-1); + ext_join_params->scan_le.nprobes = cpu_to_le32(-1); + } + + err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, + join_params_size); + kfree(ext_join_params); + if (!err) + /* This is it. join command worked, we are done */ + goto done; + /* join command failed, fallback to set ssid */ memset(&join_params, 0, sizeof(join_params)); join_params_size = sizeof(join_params.ssid_le); - profile->ssid.SSID_len = min_t(u32, - sizeof(ssid.SSID), (u32)sme->ssid_len); memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); - memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); - memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); - - if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) - WL_CONN("ssid \"%s\", len (%d)\n", - ssid.SSID, ssid.SSID_len); + if (sme->bssid) + memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN); + else + memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); - brcmf_ch_to_chanspec(cfg->channel, - &join_params, &join_params_size); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, - &join_params, join_params_size); + if (cfg->channel) { + join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec); + join_params.params_le.chanspec_num = cpu_to_le32(1); + join_params_size += sizeof(join_params.params_le); + } + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, + &join_params, join_params_size); if (err) - WL_ERR("WLC_SET_SSID failed (%d)\n", err); + brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err); done: if (err) - clear_bit(WL_STATUS_CONNECTING, &cfg->status); - WL_TRACE("Exit\n"); + clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -1851,44 +1829,44 @@ static s32 brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_scb_val_le scbval; s32 err = 0; - WL_TRACE("Enter. Reason code = %d\n", reason_code); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code); + if (!check_vif_up(ifp->vif)) return -EIO; - clear_bit(WL_STATUS_CONNECTED, &cfg->status); + clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); + cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL); memcpy(&scbval.ea, &profile->bssid, ETH_ALEN); scbval.val = cpu_to_le32(reason_code); - err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval, - sizeof(struct brcmf_scb_val_le)); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC, + &scbval, sizeof(scbval)); if (err) - WL_ERR("error (%d)\n", err); + brcmf_err("error (%d)\n", err); - cfg->link_up = false; - - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } static s32 -brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, +brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_tx_power_setting type, s32 mbm) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = cfg_to_ndev(cfg); + struct brcmf_if *ifp = netdev_priv(ndev); u16 txpwrmw; s32 err = 0; s32 disable = 0; s32 dbm = MBM_TO_DBM(mbm); - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; switch (type) { @@ -1897,7 +1875,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, case NL80211_TX_POWER_LIMITED: case NL80211_TX_POWER_FIXED: if (dbm < 0) { - WL_ERR("TX_POWER_FIXED - dbm is negative\n"); + brcmf_err("TX_POWER_FIXED - dbm is negative\n"); err = -EINVAL; goto done; } @@ -1905,40 +1883,42 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, } /* Make sure radio is off or on as far as software is concerned */ disable = WL_RADIO_SW_DISABLE << 16; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable); if (err) - WL_ERR("WLC_SET_RADIO error (%d)\n", err); + brcmf_err("WLC_SET_RADIO error (%d)\n", err); if (dbm > 0xffff) txpwrmw = 0xffff; else txpwrmw = (u16) dbm; - err = brcmf_dev_intvar_set(ndev, "qtxpower", - (s32) (brcmf_mw_to_qdbm(txpwrmw))); + err = brcmf_fil_iovar_int_set(ifp, "qtxpower", + (s32)brcmf_mw_to_qdbm(txpwrmw)); if (err) - WL_ERR("qtxpower error (%d)\n", err); + brcmf_err("qtxpower error (%d)\n", err); cfg->conf->tx_power = dbm; done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } -static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + s32 *dbm) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg); + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); s32 txpwrdbm; u8 result; s32 err = 0; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; - err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); + err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm); if (err) { - WL_ERR("error (%d)\n", err); + brcmf_err("error (%d)\n", err); goto done; } @@ -1946,7 +1926,7 @@ static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) *dbm = (s32) brcmf_qdbm_to_mw(result); done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -1954,34 +1934,32 @@ static s32 brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool unicast, bool multicast) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); u32 index; u32 wsec; s32 err = 0; - s32 bssidx; - WL_TRACE("Enter\n"); - WL_CONN("key index (%d)\n", key_idx); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CONN, "key index (%d)\n", key_idx); + if (!check_vif_up(ifp->vif)) return -EIO; - bssidx = brcmf_find_bssidx(cfg, ndev); - err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); + err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); if (err) { - WL_ERR("WLC_GET_WSEC error (%d)\n", err); + brcmf_err("WLC_GET_WSEC error (%d)\n", err); goto done; } if (wsec & WEP_ENABLED) { /* Just select a new current key */ index = key_idx; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY, - &index); + err = brcmf_fil_cmd_int_set(ifp, + BRCMF_C_SET_KEY_PRIMARY, index); if (err) - WL_ERR("error (%d)\n", err); + brcmf_err("error (%d)\n", err); } done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -1989,11 +1967,10 @@ static s32 brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, 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_wsec_key key; - struct brcmf_wsec_key_le key_le; s32 err = 0; - s32 bssidx; + u8 keybuf[8]; memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; @@ -2002,24 +1979,24 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, if (!is_multicast_ether_addr(mac_addr)) memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); key.len = (u32) params->key_len; - bssidx = brcmf_find_bssidx(cfg, ndev); /* check for key index change */ if (key.len == 0) { /* key delete */ - err = send_key_to_dongle(cfg, bssidx, ndev, &key); + err = send_key_to_dongle(ndev, &key); if (err) - WL_ERR("key delete error (%d)\n", err); + brcmf_err("key delete error (%d)\n", err); } else { if (key.len > sizeof(key.data)) { - WL_ERR("Invalid key length (%d)\n", key.len); + brcmf_err("Invalid key length (%d)\n", key.len); return -EINVAL; } - WL_CONN("Setting the key index %d\n", key.index); + brcmf_dbg(CONN, "Setting the key index %d\n", key.index); memcpy(key.data, params->key, key.len); - if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { - u8 keybuf[8]; + if (!brcmf_is_apmode(ifp->vif) && + (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { + brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); memcpy(keybuf, &key.data[24], sizeof(keybuf)); memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); memcpy(&key.data[16], keybuf, sizeof(keybuf)); @@ -2039,37 +2016,31 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: key.algo = CRYPTO_ALGO_WEP1; - WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); break; case WLAN_CIPHER_SUITE_WEP104: key.algo = CRYPTO_ALGO_WEP128; - WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: key.algo = CRYPTO_ALGO_TKIP; - WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); break; case WLAN_CIPHER_SUITE_AES_CMAC: key.algo = CRYPTO_ALGO_AES_CCM; - WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); break; case WLAN_CIPHER_SUITE_CCMP: key.algo = CRYPTO_ALGO_AES_CCM; - WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); break; default: - WL_ERR("Invalid cipher (0x%x)\n", params->cipher); + brcmf_err("Invalid cipher (0x%x)\n", params->cipher); return -EINVAL; } - convert_key_from_CPU(&key, &key_le); - - brcmf_netdev_wait_pend8021x(ndev); - err = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le, - sizeof(key_le), - cfg->extra_buf, - WL_EXTRA_BUF_MAX, bssidx); + err = send_key_to_dongle(ndev, &key); if (err) - WL_ERR("wsec_key error (%d)\n", err); + brcmf_err("wsec_key error (%d)\n", err); } return err; } @@ -2079,21 +2050,22 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, 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_wsec_key key; s32 val; s32 wsec; s32 err = 0; u8 keybuf[8]; - s32 bssidx; - WL_TRACE("Enter\n"); - WL_CONN("key index (%d)\n", key_idx); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CONN, "key index (%d)\n", key_idx); + if (!check_vif_up(ifp->vif)) return -EIO; - if (mac_addr) { - WL_TRACE("Exit"); + if (mac_addr && + (params->cipher != WLAN_CIPHER_SUITE_WEP40) && + (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { + brcmf_dbg(TRACE, "Exit"); return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); } memset(&key, 0, sizeof(key)); @@ -2102,7 +2074,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, key.index = (u32) key_idx; if (key.len > sizeof(key.data)) { - WL_ERR("Too long key length (%u)\n", key.len); + brcmf_err("Too long key length (%u)\n", key.len); err = -EINVAL; goto done; } @@ -2113,59 +2085,58 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, case WLAN_CIPHER_SUITE_WEP40: key.algo = CRYPTO_ALGO_WEP1; val = WEP_ENABLED; - WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); break; case WLAN_CIPHER_SUITE_WEP104: key.algo = CRYPTO_ALGO_WEP128; val = WEP_ENABLED; - WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: - if (cfg->conf->mode != WL_MODE_AP) { - WL_CONN("Swapping key\n"); + if (!brcmf_is_apmode(ifp->vif)) { + brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); memcpy(keybuf, &key.data[24], sizeof(keybuf)); memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); memcpy(&key.data[16], keybuf, sizeof(keybuf)); } key.algo = CRYPTO_ALGO_TKIP; val = TKIP_ENABLED; - WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); break; case WLAN_CIPHER_SUITE_AES_CMAC: key.algo = CRYPTO_ALGO_AES_CCM; val = AES_ENABLED; - WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); break; case WLAN_CIPHER_SUITE_CCMP: key.algo = CRYPTO_ALGO_AES_CCM; val = AES_ENABLED; - WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); break; default: - WL_ERR("Invalid cipher (0x%x)\n", params->cipher); + brcmf_err("Invalid cipher (0x%x)\n", params->cipher); err = -EINVAL; goto done; } - bssidx = brcmf_find_bssidx(cfg, ndev); - err = send_key_to_dongle(cfg, bssidx, ndev, &key); + err = send_key_to_dongle(ndev, &key); if (err) goto done; - err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); + err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); if (err) { - WL_ERR("get wsec error (%d)\n", err); + brcmf_err("get wsec error (%d)\n", err); goto done; } wsec |= val; - err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); if (err) { - WL_ERR("set wsec error (%d)\n", err); + brcmf_err("set wsec error (%d)\n", err); goto done; } done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -2173,37 +2144,32 @@ static s32 brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool pairwise, const u8 *mac_addr) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_wsec_key key; s32 err = 0; - s32 bssidx; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; + if (key_idx >= DOT11_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + brcmf_err("invalid key index (%d)\n", key_idx); + return -EINVAL; + } + memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; key.flags = BRCMF_PRIMARY_KEY; key.algo = CRYPTO_ALGO_OFF; - WL_CONN("key index (%d)\n", key_idx); + brcmf_dbg(CONN, "key index (%d)\n", key_idx); /* Set the new key/index */ - bssidx = brcmf_find_bssidx(cfg, ndev); - err = send_key_to_dongle(cfg, bssidx, ndev, &key); - if (err) { - if (err == -EINVAL) { - if (key.index >= DOT11_MAX_DEFAULT_KEYS) - /* we ignore this key index in this case */ - WL_ERR("invalid key index (%d)\n", key_idx); - } - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - } + err = send_key_to_dongle(ndev, &key); - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -2213,56 +2179,50 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, void (*callback) (void *cookie, struct key_params * params)) { struct key_params params; - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_cfg80211_security *sec; s32 wsec; s32 err = 0; - s32 bssidx; - WL_TRACE("Enter\n"); - WL_CONN("key index (%d)\n", key_idx); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CONN, "key index (%d)\n", key_idx); + if (!check_vif_up(ifp->vif)) return -EIO; memset(¶ms, 0, sizeof(params)); - bssidx = brcmf_find_bssidx(cfg, ndev); - err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); + err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); if (err) { - WL_ERR("WLC_GET_WSEC error (%d)\n", err); + brcmf_err("WLC_GET_WSEC error (%d)\n", err); /* Ignore this error, may happen during DISASSOC */ err = -EAGAIN; goto done; } - switch (wsec & ~SES_OW_ENABLED) { - case WEP_ENABLED: + if (wsec & WEP_ENABLED) { sec = &profile->sec; if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { params.cipher = WLAN_CIPHER_SUITE_WEP40; - WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { params.cipher = WLAN_CIPHER_SUITE_WEP104; - WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); } - break; - case TKIP_ENABLED: + } else if (wsec & TKIP_ENABLED) { params.cipher = WLAN_CIPHER_SUITE_TKIP; - WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); - break; - case AES_ENABLED: + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); + } else if (wsec & AES_ENABLED) { params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; - WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); - break; - default: - WL_ERR("Invalid algo (0x%x)\n", wsec); + brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); + } else { + brcmf_err("Invalid algo (0x%x)\n", wsec); err = -EINVAL; goto done; } callback(cookie, ¶ms); done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -2270,82 +2230,108 @@ static s32 brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx) { - WL_INFO("Not supported\n"); + brcmf_dbg(INFO, "Not supported\n"); return -EOPNOTSUPP; } static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac, struct station_info *sinfo) + const u8 *mac, struct station_info *sinfo) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_scb_val_le scb_val; int rssi; s32 rate; s32 err = 0; u8 *bssid = profile->bssid; - struct brcmf_sta_info_le *sta_info_le; + struct brcmf_sta_info_le sta_info_le; + u32 beacon_period; + u32 dtim_period; - WL_TRACE("Enter, MAC %pM\n", mac); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); + if (!check_vif_up(ifp->vif)) return -EIO; - if (cfg->conf->mode == WL_MODE_AP) { - err = brcmf_dev_iovar_getbuf(ndev, "sta_info", mac, ETH_ALEN, - cfg->dcmd_buf, - WL_DCMD_LEN_MAX); + if (brcmf_is_apmode(ifp->vif)) { + memcpy(&sta_info_le, mac, ETH_ALEN); + err = brcmf_fil_iovar_data_get(ifp, "sta_info", + &sta_info_le, + sizeof(sta_info_le)); if (err < 0) { - WL_ERR("GET STA INFO failed, %d\n", err); + brcmf_err("GET STA INFO failed, %d\n", err); goto done; } - sta_info_le = (struct brcmf_sta_info_le *)cfg->dcmd_buf; - sinfo->filled = STATION_INFO_INACTIVE_TIME; - sinfo->inactive_time = le32_to_cpu(sta_info_le->idle) * 1000; - if (le32_to_cpu(sta_info_le->flags) & BRCMF_STA_ASSOC) { + sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; + if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) { sinfo->filled |= STATION_INFO_CONNECTED_TIME; - sinfo->connected_time = le32_to_cpu(sta_info_le->in); + sinfo->connected_time = le32_to_cpu(sta_info_le.in); } - WL_TRACE("STA idle time : %d ms, connected time :%d sec\n", - sinfo->inactive_time, sinfo->connected_time); - } else if (cfg->conf->mode == WL_MODE_BSS) { + brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", + sinfo->inactive_time, sinfo->connected_time); + } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) { if (memcmp(mac, bssid, ETH_ALEN)) { - WL_ERR("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", - mac, bssid); + brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", + mac, bssid); err = -ENOENT; goto done; } /* Report the current tx rate */ - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate); + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); if (err) { - WL_ERR("Could not get rate (%d)\n", err); + brcmf_err("Could not get rate (%d)\n", err); goto done; } else { sinfo->filled |= STATION_INFO_TX_BITRATE; sinfo->txrate.legacy = rate * 5; - WL_CONN("Rate %d Mbps\n", rate / 2); + brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2); } - if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) { + if (test_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state)) { memset(&scb_val, 0, sizeof(scb_val)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, - sizeof(scb_val)); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, + &scb_val, sizeof(scb_val)); if (err) { - WL_ERR("Could not get rssi (%d)\n", err); + brcmf_err("Could not get rssi (%d)\n", err); goto done; } else { rssi = le32_to_cpu(scb_val.val); sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = rssi; - WL_CONN("RSSI %d dBm\n", rssi); + brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); + } + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD, + &beacon_period); + if (err) { + brcmf_err("Could not get beacon period (%d)\n", + err); + goto done; + } else { + sinfo->bss_param.beacon_interval = + beacon_period; + brcmf_dbg(CONN, "Beacon peroid %d\n", + beacon_period); + } + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD, + &dtim_period); + if (err) { + brcmf_err("Could not get DTIM period (%d)\n", + err); + goto done; + } else { + sinfo->bss_param.dtim_period = dtim_period; + brcmf_dbg(CONN, "DTIM peroid %d\n", + dtim_period); } + sinfo->filled |= STATION_INFO_BSS_PARAM; } } else err = -EPERM; done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -2356,8 +2342,9 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, s32 pm; s32 err = 0; struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); /* * Powersave enable/disable request is coming from the @@ -2367,83 +2354,29 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, * FW later while initializing the dongle */ cfg->pwr_save = enabled; - if (!test_bit(WL_STATUS_READY, &cfg->status)) { + if (!check_vif_up(ifp->vif)) { - WL_INFO("Device is not ready, storing the value in cfg_info struct\n"); + brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n"); goto done; } pm = enabled ? PM_FAST : PM_OFF; - WL_INFO("power save %s\n", (pm ? "enabled" : "disabled")); + /* Do not enable the power save after assoc if it is a p2p interface */ + if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) { + brcmf_dbg(INFO, "Do not enable power save for P2P clients\n"); + pm = PM_OFF; + } + brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled")); - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); if (err) { if (err == -ENODEV) - WL_ERR("net_device is not ready yet\n"); + brcmf_err("net_device is not ready yet\n"); else - WL_ERR("error (%d)\n", err); + brcmf_err("error (%d)\n", err); } done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, - const u8 *addr, - const struct cfg80211_bitrate_mask *mask) -{ - struct brcm_rateset_le rateset_le; - s32 rate; - s32 val; - s32 err_bg; - s32 err_a; - u32 legacy; - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - /* addr param is always NULL. ignore it */ - /* Get current rateset */ - err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le, - sizeof(rateset_le)); - if (err) { - WL_ERR("could not get current rateset (%d)\n", err); - goto done; - } - - legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF); - if (!legacy) - legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy & - 0xFFFF); - - val = wl_g_rates[legacy - 1].bitrate * 100000; - - if (val < le32_to_cpu(rateset_le.count)) - /* Select rate by rateset index */ - rate = rateset_le.rates[val] & 0x7f; - else - /* Specified rate in bps */ - rate = val / 500000; - - WL_CONN("rate %d mbps\n", rate / 2); - - /* - * - * Set rate override, - * Since the is a/b/g-blind, both a/bg_rate are enforced. - */ - err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate); - err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate); - if (err_bg && err_a) { - WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a); - err = err_bg | err_a; - } - -done: - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -2454,6 +2387,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, struct ieee80211_channel *notify_channel; struct cfg80211_bss *bss; struct ieee80211_supported_band *band; + struct brcmu_chan ch; s32 err = 0; u16 channel; u32 freq; @@ -2464,12 +2398,16 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, s32 notify_signal; if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { - WL_ERR("Bss info is larger than buffer. Discarding\n"); + brcmf_err("Bss info is larger than buffer. Discarding\n"); return 0; } - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); + if (!bi->ctl_ch) { + ch.chspec = le16_to_cpu(bi->chanspec); + cfg->d11inf.decchspec(&ch); + bi->ctl_ch = ch.chnum; + } + channel = bi->ctl_ch; if (channel <= CH_MAX_2G_CHANNEL) band = wiphy->bands[IEEE80211_BAND_2GHZ]; @@ -2485,13 +2423,11 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, notify_ielen = le32_to_cpu(bi->ie_length); notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - bi->BSSID[0], bi->BSSID[1], bi->BSSID[2], - bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]); - WL_CONN("Channel: %d(%d)\n", channel, freq); - WL_CONN("Capability: %X\n", notify_capability); - WL_CONN("Beacon interval: %d\n", notify_interval); - WL_CONN("Signal: %d\n", notify_signal); + brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID); + brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq); + brcmf_dbg(CONN, "Capability: %X\n", notify_capability); + brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval); + brcmf_dbg(CONN, "Signal: %d\n", notify_signal); bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, 0, notify_capability, notify_interval, notify_ie, @@ -2500,7 +2436,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, if (!bss) return -ENOMEM; - cfg80211_put_bss(bss); + cfg80211_put_bss(wiphy, bss); return err; } @@ -2522,13 +2458,14 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg) int i; bss_list = cfg->bss_list; - if (bss_list->version != BRCMF_BSS_INFO_VERSION) { - WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", - bss_list->version); + if (bss_list->count != 0 && + bss_list->version != BRCMF_BSS_INFO_VERSION) { + brcmf_err("Version %d != WL_BSS_INFO_VERSION\n", + bss_list->version); return -EOPNOTSUPP; } - WL_SCAN("scanned AP count (%d)\n", bss_list->count); - for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) { + brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count); + for (i = 0; i < bss_list->count; i++) { bi = next_bss_le(bss_list, bi); err = brcmf_inform_single_bss(cfg, bi); if (err) @@ -2545,9 +2482,9 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, struct brcmf_bss_info_le *bi = NULL; struct ieee80211_supported_band *band; struct cfg80211_bss *bss; + struct brcmu_chan ch; u8 *buf = NULL; s32 err = 0; - u16 channel; u32 freq; u16 notify_capability; u16 notify_interval; @@ -2555,7 +2492,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, size_t notify_ielen; s32 notify_signal; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); if (buf == NULL) { @@ -2565,23 +2502,24 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); + err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO, + buf, WL_BSS_INFO_MAX); if (err) { - WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err); + brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err); goto CleanUp; } bi = (struct brcmf_bss_info_le *)(buf + 4); - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); + ch.chspec = le16_to_cpu(bi->chanspec); + cfg->d11inf.decchspec(&ch); - if (channel <= CH_MAX_2G_CHANNEL) + if (ch.band == BRCMU_CHAN_BAND_2G) band = wiphy->bands[IEEE80211_BAND_2GHZ]; else band = wiphy->bands[IEEE80211_BAND_5GHZ]; - freq = ieee80211_channel_to_frequency(channel, band->band); + freq = ieee80211_channel_to_frequency(ch.chnum, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); notify_capability = le16_to_cpu(bi->capability); @@ -2590,10 +2528,10 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, notify_ielen = le32_to_cpu(bi->ie_length); notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - WL_CONN("channel: %d(%d)\n", channel, freq); - WL_CONN("capability: %X\n", notify_capability); - WL_CONN("beacon interval: %d\n", notify_interval); - WL_CONN("signal: %d\n", notify_signal); + brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq); + brcmf_dbg(CONN, "capability: %X\n", notify_capability); + brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval); + brcmf_dbg(CONN, "signal: %d\n", notify_signal); bss = cfg80211_inform_bss(wiphy, notify_channel, bssid, 0, notify_capability, notify_interval, @@ -2604,112 +2542,41 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, goto CleanUp; } - cfg80211_put_bss(bss); + cfg80211_put_bss(wiphy, bss); CleanUp: kfree(buf); - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_info *cfg) -{ - return cfg->conf->mode == WL_MODE_IBSS; -} - -/* - * Traverse a string of 1-byte tag/1-byte length/variable-length value - * triples, returning a pointer to the substring whose first element - * matches tag - */ -static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) -{ - struct brcmf_tlv *elt; - int totlen; - - elt = (struct brcmf_tlv *) buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - int len = elt->len; - - /* validate remaining totlen */ - if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) - return elt; - - elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - - return NULL; -} - -/* Is any of the tlvs the expected entry? If - * not update the tlvs buffer pointer/length. - */ -static bool -brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, - u8 *oui, u32 oui_len, u8 type) -{ - /* If the contents match the OUI and the type */ - if (ie[TLV_LEN_OFF] >= oui_len + 1 && - !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && - type == ie[TLV_BODY_OFF + oui_len]) { - return true; - } - - if (tlvs == NULL) - return false; - /* point to the next ie */ - ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; - /* calculate the length of the rest of the buffer */ - *tlvs_len -= (int)(ie - *tlvs); - /* update the pointer to the start of the buffer */ - *tlvs = ie; - - return false; -} - -struct brcmf_vs_tlv * -brcmf_find_wpaie(u8 *parse, u32 len) -{ - struct brcmf_tlv *ie; - - while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_WPA))) { - if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, - WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) - return (struct brcmf_vs_tlv *)ie; - } - return NULL; -} - -static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) +static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, + struct brcmf_if *ifp) { - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev); struct brcmf_bss_info_le *bi; struct brcmf_ssid *ssid; - struct brcmf_tlv *tim; + const struct brcmf_tlv *tim; u16 beacon_interval; u8 dtim_period; size_t ie_len; u8 *ie; s32 err = 0; - WL_TRACE("Enter\n"); - if (brcmf_is_ibssmode(cfg)) + brcmf_dbg(TRACE, "Enter\n"); + if (brcmf_is_ibssmode(ifp->vif)) return err; ssid = &profile->ssid; *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); - err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_GET_BSS_INFO, - cfg->extra_buf, WL_EXTRA_BUF_MAX); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, + cfg->extra_buf, WL_EXTRA_BUF_MAX); if (err) { - WL_ERR("Could not get bss info %d\n", err); + brcmf_err("Could not get bss info %d\n", err); goto update_bss_info_out; } @@ -2732,252 +2599,30 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) * so we speficially query dtim information to dongle. */ u32 var; - err = brcmf_dev_intvar_get(cfg_to_ndev(cfg), - "dtim_assoc", &var); + err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var); if (err) { - WL_ERR("wl dtim_assoc failed (%d)\n", err); + brcmf_err("wl dtim_assoc failed (%d)\n", err); goto update_bss_info_out; } dtim_period = (u8)var; } - profile->beacon_interval = beacon_interval; - profile->dtim_period = dtim_period; - update_bss_info_out: - WL_TRACE("Exit"); + brcmf_dbg(TRACE, "Exit"); return err; } -static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) +void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); struct escan_info *escan = &cfg->escan_info; - struct brcmf_ssid ssid; - - set_bit(WL_STATUS_SCAN_ABORTING, &cfg->status); - if (cfg->iscan_on) { - iscan->state = WL_ISCAN_STATE_IDLE; - if (iscan->timer_on) { - del_timer_sync(&iscan->timer); - iscan->timer_on = 0; - } - - cancel_work_sync(&iscan->work); - - /* Abort iscan running in FW */ - memset(&ssid, 0, sizeof(ssid)); - brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); - - if (cfg->scan_request) { - /* Indidate scan abort to cfg80211 layer */ - WL_INFO("Terminating scan in progress\n"); - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - } - } - if (cfg->escan_on && cfg->scan_request) { - escan->escan_state = WL_ESCAN_STATE_IDLE; - brcmf_notify_escan_complete(cfg, escan->ndev, true, true); - } - clear_bit(WL_STATUS_SCANNING, &cfg->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &cfg->status); -} - -static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, - bool aborted) -{ - struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan); - struct net_device *ndev = cfg_to_ndev(cfg); - - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { - WL_ERR("Scan complete while device not scanning\n"); - return; - } + set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); if (cfg->scan_request) { - WL_SCAN("ISCAN Completed scan: %s\n", - aborted ? "Aborted" : "Done"); - cfg80211_scan_done(cfg->scan_request, aborted); - brcmf_set_mpc(ndev, 1); - cfg->scan_request = NULL; - } - cfg->iscan_kickstart = false; -} - -static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) -{ - if (iscan->state != WL_ISCAN_STATE_IDLE) { - WL_SCAN("wake up iscan\n"); - schedule_work(&iscan->work); - return 0; - } - - return -EIO; -} - -static s32 -brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, - struct brcmf_scan_results **bss_list) -{ - struct brcmf_iscan_results list; - struct brcmf_scan_results *results; - struct brcmf_scan_results_le *results_le; - struct brcmf_iscan_results *list_buf; - s32 err = 0; - - memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); - list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; - results = &list_buf->results; - results_le = &list_buf->results_le; - results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; - results->version = 0; - results->count = 0; - - memset(&list, 0, sizeof(list)); - list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); - err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list, - BRCMF_ISCAN_RESULTS_FIXED_SIZE, - iscan->scan_buf, WL_ISCAN_BUF_MAX); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - results->buflen = le32_to_cpu(results_le->buflen); - results->version = le32_to_cpu(results_le->version); - results->count = le32_to_cpu(results_le->count); - WL_SCAN("results->count = %d\n", results_le->count); - WL_SCAN("results->buflen = %d\n", results_le->buflen); - *status = le32_to_cpu(list_buf->status_le); - WL_SCAN("status = %d\n", *status); - *bss_list = results; - - return err; -} - -static s32 brcmf_iscan_done(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; - s32 err = 0; - - iscan->state = WL_ISCAN_STATE_IDLE; - brcmf_inform_bss(cfg); - brcmf_notify_iscan_complete(iscan, false); - - return err; -} - -static s32 brcmf_iscan_pending(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; - s32 err = 0; - - /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - - return err; -} - -static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; - s32 err = 0; - - brcmf_inform_bss(cfg); - brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); - /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - - return err; -} - -static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; - s32 err = 0; - - iscan->state = WL_ISCAN_STATE_IDLE; - brcmf_notify_iscan_complete(iscan, true); - - return err; -} - -static void brcmf_cfg80211_iscan_handler(struct work_struct *work) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = - container_of(work, struct brcmf_cfg80211_iscan_ctrl, - work); - struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan); - struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; - u32 status = BRCMF_SCAN_RESULTS_PARTIAL; - - if (iscan->timer_on) { - del_timer_sync(&iscan->timer); - iscan->timer_on = 0; - } - - if (brcmf_get_iscan_results(iscan, &status, &cfg->bss_list)) { - status = BRCMF_SCAN_RESULTS_ABORTED; - WL_ERR("Abort iscan\n"); - } - - el->handler[status](cfg); -} - -static void brcmf_iscan_timer(unsigned long data) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = - (struct brcmf_cfg80211_iscan_ctrl *)data; - - if (iscan) { - iscan->timer_on = 0; - WL_SCAN("timer expired\n"); - brcmf_wakeup_iscan(iscan); - } -} - -static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - - if (cfg->iscan_on) { - iscan->state = WL_ISCAN_STATE_IDLE; - INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); - } - - return 0; -} - -static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) -{ - memset(el, 0, sizeof(*el)); - el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; - el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; - el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; - el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; - el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; -} - -static s32 brcmf_init_iscan(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - int err = 0; - - if (cfg->iscan_on) { - iscan->ndev = cfg_to_ndev(cfg); - brcmf_init_iscan_eloop(&iscan->el); - iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; - init_timer(&iscan->timer); - iscan->timer.data = (unsigned long) iscan; - iscan->timer.function = brcmf_iscan_timer; - err = brcmf_invoke_iscan(cfg); - if (!err) - iscan->data = cfg; + escan->escan_state = WL_ESCAN_STATE_IDLE; + brcmf_notify_escan_complete(cfg, escan->ifp, true, true); } - - return err; + clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); + clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); } static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) @@ -2986,8 +2631,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) container_of(work, struct brcmf_cfg80211_info, escan_timeout_work); - brcmf_notify_escan_complete(cfg, - cfg->escan_info.ndev, true, true); + brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true); } static void brcmf_escan_timeout(unsigned long data) @@ -2996,23 +2640,29 @@ static void brcmf_escan_timeout(unsigned long data) (struct brcmf_cfg80211_info *)data; if (cfg->scan_request) { - WL_ERR("timer expired\n"); - if (cfg->escan_on) - schedule_work(&cfg->escan_timeout_work); + brcmf_err("timer expired\n"); + schedule_work(&cfg->escan_timeout_work); } } static s32 -brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss, +brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg, + struct brcmf_bss_info_le *bss, struct brcmf_bss_info_le *bss_info_le) { + struct brcmu_chan ch_bss, ch_bss_info_le; + + ch_bss.chspec = le16_to_cpu(bss->chanspec); + cfg->d11inf.decchspec(&ch_bss); + ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec); + cfg->d11inf.decchspec(&ch_bss_info_le); + if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) && - (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) == - CHSPEC_BAND(le16_to_cpu(bss->chanspec))) && + ch_bss.band == ch_bss_info_le.band && bss_info_le->SSID_len == bss->SSID_len && !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) { - if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == - (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) { + if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == + (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) { s16 bss_rssi = le16_to_cpu(bss->RSSI); s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI); @@ -3021,13 +2671,13 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss, */ if (bss_info_rssi > bss_rssi) bss->RSSI = bss_info_le->RSSI; - } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && - (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { + } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) && + (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) { /* preserve the on-channel rssi measurement * if the new measurement is off channel */ bss->RSSI = bss_info_le->RSSI; - bss->flags |= WLC_BSS_RSSI_ON_CHANNEL; + bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL; } return 1; } @@ -3035,10 +2685,10 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss, } static s32 -brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 status; s32 err = 0; struct brcmf_escan_result_le *escan_result_le; @@ -3049,40 +2699,40 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, u32 i; bool aborted; - status = be32_to_cpu(e->status); + status = e->status; - if (!ndev || !cfg->escan_on || - !test_bit(WL_STATUS_SCANNING, &cfg->status)) { - WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n", - ndev, cfg->escan_on, - !test_bit(WL_STATUS_SCANNING, &cfg->status)); + if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx); return -EPERM; } if (status == BRCMF_E_STATUS_PARTIAL) { - WL_SCAN("ESCAN Partial result\n"); + brcmf_dbg(SCAN, "ESCAN Partial result\n"); escan_result_le = (struct brcmf_escan_result_le *) data; if (!escan_result_le) { - WL_ERR("Invalid escan result (NULL pointer)\n"); + brcmf_err("Invalid escan result (NULL pointer)\n"); goto exit; } - if (!cfg->scan_request) { - WL_SCAN("result without cfg80211 request\n"); + if (le16_to_cpu(escan_result_le->bss_count) != 1) { + brcmf_err("Invalid bss_count %d: ignoring\n", + escan_result_le->bss_count); goto exit; } + bss_info_le = &escan_result_le->bss_info_le; - if (le16_to_cpu(escan_result_le->bss_count) != 1) { - WL_ERR("Invalid bss_count %d: ignoring\n", - escan_result_le->bss_count); + if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) + goto exit; + + if (!cfg->scan_request) { + brcmf_dbg(SCAN, "result without cfg80211 request\n"); goto exit; } - bss_info_le = &escan_result_le->bss_info_le; bi_length = le32_to_cpu(bss_info_le->length); if (bi_length != (le32_to_cpu(escan_result_le->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { - WL_ERR("Invalid bss_info length %d: ignoring\n", - bi_length); + brcmf_err("Invalid bss_info length %d: ignoring\n", + bi_length); goto exit; } @@ -3090,7 +2740,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, BIT(NL80211_IFTYPE_ADHOC))) { if (le16_to_cpu(bss_info_le->capability) & WLAN_CAPABILITY_IBSS) { - WL_ERR("Ignoring IBSS result\n"); + brcmf_err("Ignoring IBSS result\n"); goto exit; } } @@ -3098,7 +2748,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, list = (struct brcmf_scan_results *) cfg->escan_info.escan_buf; if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) { - WL_ERR("Buffer is too small: ignoring\n"); + brcmf_err("Buffer is too small: ignoring\n"); goto exit; } @@ -3106,7 +2756,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, bss = bss ? (struct brcmf_bss_info_le *) ((unsigned char *)bss + le32_to_cpu(bss->length)) : list->bss_info_le; - if (brcmf_compare_update_same_bss(bss, bss_info_le)) + if (brcmf_compare_update_same_bss(cfg, bss, + bss_info_le)) goto exit; } memcpy(&(cfg->escan_info.escan_buf[list->buflen]), @@ -3116,15 +2767,18 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, list->count++; } else { cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) + goto exit; if (cfg->scan_request) { cfg->bss_list = (struct brcmf_scan_results *) cfg->escan_info.escan_buf; brcmf_inform_bss(cfg); aborted = status != BRCMF_E_STATUS_SUCCESS; - brcmf_notify_escan_complete(cfg, ndev, aborted, + brcmf_notify_escan_complete(cfg, ifp, aborted, false); } else - WL_ERR("Unexpected scan result 0x%x\n", status); + brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n", + status); } exit: return err; @@ -3132,18 +2786,15 @@ exit: static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) { - - if (cfg->escan_on) { - cfg->el.handler[BRCMF_E_ESCAN_RESULT] = - brcmf_cfg80211_escan_handler; - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - /* Init scan_timeout timer */ - init_timer(&cfg->escan_timeout); - cfg->escan_timeout.data = (unsigned long) cfg; - cfg->escan_timeout.function = brcmf_escan_timeout; - INIT_WORK(&cfg->escan_timeout_work, - brcmf_cfg80211_escan_timeout_worker); - } + brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT, + brcmf_cfg80211_escan_handler); + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + /* Init scan_timeout timer */ + init_timer(&cfg->escan_timeout); + cfg->escan_timeout.data = (unsigned long) cfg; + cfg->escan_timeout.function = brcmf_escan_timeout; + INIT_WORK(&cfg->escan_timeout_work, + brcmf_cfg80211_escan_timeout_worker); } static __always_inline void brcmf_delay(u32 ms) @@ -3158,19 +2809,8 @@ static __always_inline void brcmf_delay(u32 ms) static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - - /* - * Check for WL_STATUS_READY before any function call which - * could result is bus access. Don't block the resume for - * any driver error conditions - */ - WL_TRACE("Enter\n"); - - if (test_bit(WL_STATUS_READY, &cfg->status)) - brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); + brcmf_dbg(TRACE, "Enter\n"); - WL_TRACE("Exit\n"); return 0; } @@ -3179,85 +2819,49 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = cfg_to_ndev(cfg); + struct brcmf_cfg80211_vif *vif; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); /* - * Check for WL_STATUS_READY before any function call which - * could result is bus access. Don't block the suspend for - * any driver error conditions + * if the primary net_device is not READY there is nothing + * we can do but pray resume goes smoothly. */ + vif = ((struct brcmf_if *)netdev_priv(ndev))->vif; + if (!check_vif_up(vif)) + goto exit; - /* - * While going to suspend if associated with AP disassociate - * from AP to save power while system is in suspended state - */ - if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) || - test_bit(WL_STATUS_CONNECTING, &cfg->status)) && - test_bit(WL_STATUS_READY, &cfg->status)) { - WL_INFO("Disassociating from AP" - " while entering suspend state\n"); - brcmf_link_down(cfg); - + list_for_each_entry(vif, &cfg->vif_list, list) { + if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) + continue; /* - * Make sure WPA_Supplicant receives all the event + * While going to suspend if associated with AP disassociate + * from AP to save power while system is in suspended state + */ + brcmf_link_down(vif); + + /* 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 */ brcmf_delay(500); } - if (test_bit(WL_STATUS_READY, &cfg->status)) + /* end any scanning */ + if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) brcmf_abort_scanning(cfg); - else - clear_bit(WL_STATUS_SCANNING, &cfg->status); /* Turn off watchdog timer */ - if (test_bit(WL_STATUS_READY, &cfg->status)) - brcmf_set_mpc(ndev, 1); - - WL_TRACE("Exit\n"); + brcmf_set_mpc(netdev_priv(ndev), 1); +exit: + brcmf_dbg(TRACE, "Exit\n"); + /* clear any scanning activity */ + cfg->scan_status = 0; return 0; } static __used s32 -brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len) -{ - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - u32 buflen; - - buflen = brcmf_c_mkiovar(name, buf, len, cfg->dcmd_buf, - WL_DCMD_LEN_MAX); - BUG_ON(!buflen); - - return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg->dcmd_buf, - buflen); -} - -static s32 -brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf, - s32 buf_len) -{ - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - u32 len; - s32 err = 0; - - len = brcmf_c_mkiovar(name, NULL, 0, cfg->dcmd_buf, - WL_DCMD_LEN_MAX); - BUG_ON(!len); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg->dcmd_buf, - WL_DCMD_LEN_MAX); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - memcpy(buf, cfg->dcmd_buf, buf_len); - - return err; -} - -static __used s32 brcmf_update_pmklist(struct net_device *ndev, struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) { @@ -3266,17 +2870,18 @@ brcmf_update_pmklist(struct net_device *ndev, pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid); - WL_CONN("No of elements %d\n", pmkid_len); + brcmf_dbg(CONN, "No of elements %d\n", pmkid_len); for (i = 0; i < pmkid_len; i++) { - WL_CONN("PMKID[%d]: %pM =\n", i, - &pmk_list->pmkids.pmkid[i].BSSID); + brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i, + &pmk_list->pmkids.pmkid[i].BSSID); for (j = 0; j < WLAN_PMKID_LEN; j++) - WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); + brcmf_dbg(CONN, "%02x\n", + pmk_list->pmkids.pmkid[i].PMKID[j]); } if (!err) - brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list, - sizeof(*pmk_list)); + brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info", + (char *)pmk_list, sizeof(*pmk_list)); return err; } @@ -3286,13 +2891,14 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); struct pmkid_list *pmkids = &cfg->pmk_list->pmkids; s32 err = 0; int i; int pmkid_len; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; pmkid_len = le32_to_cpu(pmkids->npmkid); @@ -3309,14 +2915,14 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, } else err = -EINVAL; - WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", - pmkids->pmkid[pmkid_len].BSSID); + brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", + pmkids->pmkid[pmkid_len].BSSID); for (i = 0; i < WLAN_PMKID_LEN; i++) - WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]); + brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]); err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -3325,21 +2931,22 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); struct pmkid_list pmkid; s32 err = 0; int i, pmkid_len; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); - WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", - &pmkid.pmkid[0].BSSID); + brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", + &pmkid.pmkid[0].BSSID); for (i = 0; i < WLAN_PMKID_LEN; i++) - WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]); + brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]); pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid); for (i = 0; i < pmkid_len; i++) @@ -3366,7 +2973,7 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -3375,16 +2982,17 @@ static s32 brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); s32 err = 0; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) + brcmf_dbg(TRACE, "Enter\n"); + if (!check_vif_up(ifp->vif)) return -EIO; memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -3398,10 +3006,10 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) * cfg80211_scan_request one out of the received PNO event. */ static s32 -brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +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_pno_net_info_le *netinfo, *netinfo_start; struct cfg80211_scan_request *request = NULL; struct cfg80211_ssid *ssid = NULL; @@ -3414,10 +3022,10 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, u32 result_count; u32 status; - WL_SCAN("Enter\n"); + brcmf_dbg(SCAN, "Enter\n"); - if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) { - WL_SCAN("PFN NET LOST event. Do Nothing\n"); + if (e->event_code == BRCMF_E_PFN_NET_LOST) { + brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n"); return 0; } @@ -3430,7 +3038,7 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, * multiple NET_FOUND events. For now place a warning here. */ WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE); - WL_SCAN("PFN NET FOUND event. count: %d\n", result_count); + brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count); if (result_count > 0) { int i; @@ -3449,13 +3057,14 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, for (i = 0; i < result_count; i++) { netinfo = &netinfo_start[i]; if (!netinfo) { - WL_ERR("Invalid netinfo ptr. index: %d\n", i); + brcmf_err("Invalid netinfo ptr. index: %d\n", + i); err = -EINVAL; goto out_err; } - WL_SCAN("SSID:%s Channel:%d\n", - netinfo->SSID, netinfo->channel); + brcmf_dbg(SCAN, "SSID:%s Channel:%d\n", + netinfo->SSID, netinfo->channel); memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len); ssid[i].ssid_len = netinfo->SSID_len; request->n_ssids++; @@ -3478,21 +3087,22 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, if (request->n_ssids) request->ssids = &ssid[0]; - if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { + if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { /* Abort any on-going scan */ brcmf_abort_scanning(cfg); } - set_bit(WL_STATUS_SCANNING, &cfg->status); - err = brcmf_do_escan(cfg, wiphy, ndev, request); + set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); + cfg->escan_info.run = brcmf_run_escan; + err = brcmf_do_escan(cfg, wiphy, ifp, request); if (err) { - clear_bit(WL_STATUS_SCANNING, &cfg->status); + clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); goto out_err; } cfg->sched_escan = true; cfg->scan_request = request; } else { - WL_ERR("FALSE PNO Event. (pfn_count == 0)\n"); + brcmf_err("FALSE PNO Event. (pfn_count == 0)\n"); goto out_err; } @@ -3509,21 +3119,19 @@ out_err: return err; } -#ifndef CONFIG_BRCMISCAN static int brcmf_dev_pno_clean(struct net_device *ndev) { - char iovbuf[128]; int ret; /* Disable pfn */ - ret = brcmf_dev_intvar_set(ndev, "pfn", 0); + ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0); if (ret == 0) { /* clear pfn */ - ret = brcmf_dev_iovar_setbuf(ndev, "pfnclear", NULL, 0, - iovbuf, sizeof(iovbuf)); + ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear", + NULL, 0); } if (ret < 0) - WL_ERR("failed code %d\n", ret); + brcmf_err("failed code %d\n", ret); return ret; } @@ -3531,7 +3139,6 @@ static int brcmf_dev_pno_clean(struct net_device *ndev) static int brcmf_dev_pno_config(struct net_device *ndev) { struct brcmf_pno_param_le pfn_param; - char iovbuf[128]; memset(&pfn_param, 0, sizeof(pfn_param)); pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); @@ -3544,9 +3151,8 @@ static int brcmf_dev_pno_config(struct net_device *ndev) /* set up pno scan fr */ pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME); - return brcmf_dev_iovar_setbuf(ndev, "pfn_set", - &pfn_param, sizeof(pfn_param), - iovbuf, sizeof(iovbuf)); + return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set", + &pfn_param, sizeof(pfn_param)); } static int @@ -3554,30 +3160,35 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_sched_scan_request *request) { - char iovbuf[128]; + struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_pno_net_param_le pfn; int i; int ret = 0; - WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n", - request->n_match_sets, request->n_ssids); - if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { - WL_ERR("Scanning already : status (%lu)\n", cfg->status); + brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n", + request->n_match_sets, request->n_ssids); + if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + brcmf_err("Scanning already: 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); return -EAGAIN; } - if (!request || !request->n_ssids || !request->n_match_sets) { - WL_ERR("Invalid sched scan req!! n_ssids:%d\n", - request->n_ssids); + if (!request->n_ssids || !request->n_match_sets) { + brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n", + request->n_ssids); return -EINVAL; } if (request->n_ssids > 0) { for (i = 0; i < request->n_ssids; i++) { /* Active scan req for ssids */ - WL_SCAN(">>> Active scan req for ssid (%s)\n", - request->ssids[i].ssid); + brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n", + request->ssids[i].ssid); /* * match_set ssids is a supert set of n_ssid list, @@ -3590,14 +3201,14 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, /* clean up everything */ ret = brcmf_dev_pno_clean(ndev); if (ret < 0) { - WL_ERR("failed error=%d\n", ret); + brcmf_err("failed error=%d\n", ret); return ret; } /* configure pno */ ret = brcmf_dev_pno_config(ndev); if (ret < 0) { - WL_ERR("PNO setup failed!! ret=%d\n", ret); + brcmf_err("PNO setup failed!! ret=%d\n", ret); return -EINVAL; } @@ -3610,7 +3221,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, ssid_len = ssid->ssid_len; if (!ssid_len) { - WL_ERR("skip broadcast ssid\n"); + brcmf_err("skip broadcast ssid\n"); continue; } pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); @@ -3620,16 +3231,14 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); pfn.ssid.SSID_len = cpu_to_le32(ssid_len); memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len); - ret = brcmf_dev_iovar_setbuf(ndev, "pfn_add", - &pfn, sizeof(pfn), - iovbuf, sizeof(iovbuf)); - WL_SCAN(">>> PNO filter %s for ssid (%s)\n", - ret == 0 ? "set" : "failed", - ssid->ssid); + ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, + sizeof(pfn)); + brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n", + ret == 0 ? "set" : "failed", ssid->ssid); } /* Enable the PNO */ - if (brcmf_dev_intvar_set(ndev, "pfn", 1) < 0) { - WL_ERR("PNO enable failed!! ret=%d\n", ret); + if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) { + brcmf_err("PNO enable failed!! ret=%d\n", ret); return -EINVAL; } } else { @@ -3644,24 +3253,33 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - WL_SCAN("enter\n"); + brcmf_dbg(SCAN, "enter\n"); brcmf_dev_pno_clean(ndev); if (cfg->sched_escan) - brcmf_notify_escan_complete(cfg, ndev, true, true); + brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true); return 0; } -#endif /* CONFIG_BRCMISCAN */ #ifdef CONFIG_NL80211_TESTMODE -static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) +static int brcmf_cfg80211_testmode(struct wiphy *wiphy, + struct wireless_dev *wdev, + void *data, int len) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg->wdev->netdev; + struct net_device *ndev = cfg_to_ndev(cfg); struct brcmf_dcmd *dcmd = data; struct sk_buff *reply; int ret; - ret = brcmf_netlink_dcmd(ndev, dcmd); + brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set, + dcmd->buf, dcmd->len); + + if (dcmd->set) + ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd, + dcmd->buf, dcmd->len); + else + ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd, + dcmd->buf, dcmd->len); if (ret == 0) { reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd)); nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd); @@ -3671,27 +3289,26 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) } #endif -static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx) +static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) { s32 err; /* set auth */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", 0, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0); if (err < 0) { - WL_ERR("auth error %d\n", err); + brcmf_err("auth error %d\n", err); return err; } /* set wsec */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", 0, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0); if (err < 0) { - WL_ERR("wsec error %d\n", err); + brcmf_err("wsec error %d\n", err); return err; } /* set upper-layer auth */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", - WPA_AUTH_NONE, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE); if (err < 0) { - WL_ERR("wpa_auth error %d\n", err); + brcmf_err("wpa_auth error %d\n", err); return err; } @@ -3707,9 +3324,11 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie) } static s32 -brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, - bool is_rsn_ie, s32 bssidx) +brcmf_configure_wpaie(struct net_device *ndev, + const struct brcmf_vs_tlv *wpa_ie, + bool is_rsn_ie) { + struct brcmf_if *ifp = netdev_priv(ndev); u32 auth = 0; /* d11 open authentication */ u16 count; s32 err = 0; @@ -3724,27 +3343,28 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, u16 rsn_cap; u32 wme_bss_disable; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); if (wpa_ie == NULL) goto exit; len = wpa_ie->len + TLV_HDR_LEN; data = (u8 *)wpa_ie; - offset = 0; + offset = TLV_HDR_LEN; if (!is_rsn_ie) offset += VS_IE_FIXED_HDR_LEN; - offset += WPA_IE_VERSION_LEN; + else + offset += WPA_IE_VERSION_LEN; /* check for multicast cipher suite */ if (offset + WPA_IE_MIN_OUI_LEN > len) { err = -EINVAL; - WL_ERR("no multicast cipher suite\n"); + brcmf_err("no multicast cipher suite\n"); goto exit; } if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) { err = -EINVAL; - WL_ERR("ivalid OUI\n"); + brcmf_err("ivalid OUI\n"); goto exit; } offset += TLV_OUI_LEN; @@ -3766,7 +3386,7 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, break; default: err = -EINVAL; - WL_ERR("Invalid multi cast cipher info\n"); + brcmf_err("Invalid multi cast cipher info\n"); goto exit; } @@ -3777,13 +3397,13 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, /* Check for unicast suite(s) */ if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) { err = -EINVAL; - WL_ERR("no unicast cipher suite\n"); + brcmf_err("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; - WL_ERR("ivalid OUI\n"); + brcmf_err("ivalid OUI\n"); goto exit; } offset += TLV_OUI_LEN; @@ -3801,7 +3421,7 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, pval |= AES_ENABLED; break; default: - WL_ERR("Ivalid unicast security info\n"); + brcmf_err("Ivalid unicast security info\n"); } offset++; } @@ -3811,33 +3431,33 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, /* Check for auth key management suite(s) */ if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) { err = -EINVAL; - WL_ERR("no auth key mgmt suite\n"); + brcmf_err("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; - WL_ERR("ivalid OUI\n"); + brcmf_err("ivalid OUI\n"); goto exit; } offset += TLV_OUI_LEN; switch (data[offset]) { case RSN_AKM_NONE: - WL_TRACE("RSN_AKM_NONE\n"); + brcmf_dbg(TRACE, "RSN_AKM_NONE\n"); wpa_auth |= WPA_AUTH_NONE; break; case RSN_AKM_UNSPECIFIED: - WL_TRACE("RSN_AKM_UNSPECIFIED\n"); + brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n"); is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) : (wpa_auth |= WPA_AUTH_UNSPECIFIED); break; case RSN_AKM_PSK: - WL_TRACE("RSN_AKM_PSK\n"); + brcmf_dbg(TRACE, "RSN_AKM_PSK\n"); is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) : (wpa_auth |= WPA_AUTH_PSK); break; default: - WL_ERR("Ivalid key mgmt info\n"); + brcmf_err("Ivalid key mgmt info\n"); } offset++; } @@ -3850,10 +3470,10 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, wme_bss_disable = 0; } /* set wme_bss_disable to sync RSN Capabilities */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "wme_bss_disable", - wme_bss_disable, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable", + wme_bss_disable); if (err < 0) { - WL_ERR("wme_bss_disable error %d\n", err); + brcmf_err("wme_bss_disable error %d\n", err); goto exit; } } @@ -3861,21 +3481,21 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, wsec = (pval | gval | SES_OW_ENABLED); /* set auth */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", auth, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth); if (err < 0) { - WL_ERR("auth error %d\n", err); + brcmf_err("auth error %d\n", err); goto exit; } /* set wsec */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); if (err < 0) { - WL_ERR("wsec error %d\n", err); + brcmf_err("wsec error %d\n", err); goto exit; } /* set upper-layer auth */ - err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", wpa_auth, bssidx); + err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth); if (err < 0) { - WL_ERR("wpa_auth error %d\n", err); + brcmf_err("wpa_auth error %d\n", err); goto exit; } @@ -3884,7 +3504,7 @@ exit: } static s32 -brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len, +brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, struct parsed_vndr_ies *vndr_ies) { s32 err = 0; @@ -3903,15 +3523,15 @@ brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len, vndrie = (struct brcmf_vs_tlv *)ie; /* len should be bigger than OUI length + one */ if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) { - WL_ERR("invalid vndr ie. length is too small %d\n", - vndrie->len); + brcmf_err("invalid vndr ie. length is too small %d\n", + vndrie->len); goto next; } /* if wpa or wme ie, do not add ie */ if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) && ((vndrie->oui_type == WPA_OUI_TYPE) || (vndrie->oui_type == WME_OUI_TYPE))) { - WL_TRACE("Found WPA/WME oui. Do not add it\n"); + brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n"); goto next; } @@ -3924,20 +3544,21 @@ brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len, vndr_ies->count++; - WL_TRACE("** OUI %02x %02x %02x, type 0x%02x\n", - parsed_info->vndrie.oui[0], - parsed_info->vndrie.oui[1], - parsed_info->vndrie.oui[2], - parsed_info->vndrie.oui_type); + 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], + parsed_info->vndrie.oui_type); - if (vndr_ies->count >= MAX_VNDR_IE_NUMBER) + if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT) break; next: - remaining_len -= ie->len; - if (remaining_len <= 2) + remaining_len -= (ie->len + TLV_HDR_LEN); + if (remaining_len <= TLV_HDR_LEN) ie = NULL; else - ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len); + ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len + + TLV_HDR_LEN); } return err; } @@ -3963,17 +3584,17 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) return ie_len + VNDR_IE_HDR_SIZE; } -s32 -brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, s32 bssidx, s32 pktflag, - u8 *vndr_ie_buf, u32 vndr_ie_len) +s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, + const u8 *vndr_ie_buf, u32 vndr_ie_len) { + struct brcmf_if *ifp; + struct vif_saved_ie *saved_ie; s32 err = 0; u8 *iovar_ie_buf; u8 *curr_ie_buf; u8 *mgmt_ie_buf = NULL; - u32 mgmt_ie_buf_len = 0; - u32 *mgmt_ie_len = 0; + int mgmt_ie_buf_len; + u32 *mgmt_ie_len; u32 del_add_ie_buf_len = 0; u32 total_ie_buf_len = 0; u32 parsed_ie_buf_len = 0; @@ -3982,42 +3603,48 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, struct parsed_vndr_ie_info *vndrie_info; s32 i; u8 *ptr; - u32 remained_buf_len; + int remained_buf_len; - WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag); + if (!vif) + return -ENODEV; + ifp = vif->ifp; + saved_ie = &vif->saved_ie; + + brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag); iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (!iovar_ie_buf) return -ENOMEM; curr_ie_buf = iovar_ie_buf; - if (test_bit(WL_STATUS_AP_CREATING, &cfg->status) || - test_bit(WL_STATUS_AP_CREATED, &cfg->status)) { - switch (pktflag) { - case VNDR_IE_PRBRSP_FLAG: - mgmt_ie_buf = cfg->ap_info->probe_res_ie; - mgmt_ie_len = &cfg->ap_info->probe_res_ie_len; - mgmt_ie_buf_len = - sizeof(cfg->ap_info->probe_res_ie); - break; - case VNDR_IE_BEACON_FLAG: - mgmt_ie_buf = cfg->ap_info->beacon_ie; - mgmt_ie_len = &cfg->ap_info->beacon_ie_len; - mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie); - break; - default: - err = -EPERM; - WL_ERR("not suitable type\n"); - goto exit; - } - bssidx = 0; - } else { + switch (pktflag) { + case BRCMF_VNDR_IE_PRBREQ_FLAG: + mgmt_ie_buf = saved_ie->probe_req_ie; + mgmt_ie_len = &saved_ie->probe_req_ie_len; + mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie); + break; + case BRCMF_VNDR_IE_PRBRSP_FLAG: + mgmt_ie_buf = saved_ie->probe_res_ie; + mgmt_ie_len = &saved_ie->probe_res_ie_len; + mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); + break; + case BRCMF_VNDR_IE_BEACON_FLAG: + mgmt_ie_buf = saved_ie->beacon_ie; + mgmt_ie_len = &saved_ie->beacon_ie_len; + mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie); + break; + case BRCMF_VNDR_IE_ASSOCREQ_FLAG: + mgmt_ie_buf = saved_ie->assoc_req_ie; + mgmt_ie_len = &saved_ie->assoc_req_ie_len; + mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie); + break; + default: err = -EPERM; - WL_ERR("not suitable type\n"); + brcmf_err("not suitable type\n"); goto exit; } if (vndr_ie_len > mgmt_ie_buf_len) { err = -ENOMEM; - WL_ERR("extra IE size too big\n"); + brcmf_err("extra IE size too big\n"); goto exit; } @@ -4033,11 +3660,11 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, } } - if (mgmt_ie_buf != NULL) { + if (mgmt_ie_buf && *mgmt_ie_len) { if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { - WL_TRACE("Previous mgmt IE is equals to current IE"); + brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n"); goto exit; } @@ -4048,12 +3675,12 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, for (i = 0; i < old_vndr_ies.count; i++) { vndrie_info = &old_vndr_ies.ie_info[i]; - WL_TRACE("DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", - vndrie_info->vndrie.id, - vndrie_info->vndrie.len, - vndrie_info->vndrie.oui[0], - vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2]); + brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, + vndrie_info->vndrie.len, + vndrie_info->vndrie.oui[0], + vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2]); del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag, vndrie_info->ie_ptr, @@ -4075,24 +3702,27 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, for (i = 0; i < new_vndr_ies.count; i++) { vndrie_info = &new_vndr_ies.ie_info[i]; - WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n", - vndrie_info->vndrie.id, - vndrie_info->vndrie.len, - vndrie_info->vndrie.oui[0], - vndrie_info->vndrie.oui[1], - vndrie_info->vndrie.oui[2]); + /* 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); + 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", + vndrie_info->vndrie.id, + vndrie_info->vndrie.len, + vndrie_info->vndrie.oui[0], + vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2]); del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag, vndrie_info->ie_ptr, vndrie_info->ie_len, "add"); - /* verify remained buf size before copy data */ - remained_buf_len -= vndrie_info->ie_len; - if (remained_buf_len < 0) { - WL_ERR("no space in mgmt_ie_buf: len left %d", - remained_buf_len); - break; - } /* save the parsed IE in wl struct */ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, @@ -4104,13 +3734,10 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, } } if (total_ie_buf_len) { - err = brcmf_dev_iovar_setbuf_bsscfg(ndev, "vndr_ie", - iovar_ie_buf, - total_ie_buf_len, - cfg->extra_buf, - WL_EXTRA_BUF_MAX, bssidx); + err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf, + total_ie_buf_len); if (err) - WL_ERR("vndr ie set error : %d\n", err); + brcmf_err("vndr ie set error : %d\n", err); } exit: @@ -4118,32 +3745,75 @@ exit: return err; } +s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif) +{ + s32 pktflags[] = { + BRCMF_VNDR_IE_PRBREQ_FLAG, + BRCMF_VNDR_IE_PRBRSP_FLAG, + BRCMF_VNDR_IE_BEACON_FLAG + }; + int i; + + for (i = 0; i < ARRAY_SIZE(pktflags); i++) + brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0); + + memset(&vif->saved_ie, 0, sizeof(vif->saved_ie)); + return 0; +} + +static s32 +brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, + struct cfg80211_beacon_data *beacon) +{ + 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"); + return err; + } + brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); + + /* Set Probe Response IEs to FW */ + err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG, + beacon->proberesp_ies, + beacon->proberesp_ies_len); + if (err) + brcmf_err("Set Probe Resp IE Failed\n"); + else + brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); + + return err; +} + static s32 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *settings) { s32 ie_offset; - struct brcmf_tlv *ssid_ie; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); + const struct brcmf_tlv *ssid_ie; struct brcmf_ssid_le ssid_le; - s32 ioctl_value; s32 err = -EPERM; - struct brcmf_tlv *rsn_ie; - struct brcmf_vs_tlv *wpa_ie; + const struct brcmf_tlv *rsn_ie; + const struct brcmf_vs_tlv *wpa_ie; struct brcmf_join_params join_params; - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - s32 bssidx = 0; + enum nl80211_iftype dev_role; + struct brcmf_fil_bss_enable_le bss_enable; + u16 chanspec; - WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", - settings->channel_type, settings->beacon_interval, - settings->dtim_period); - WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n", - settings->ssid, settings->ssid_len, settings->auth_type, - settings->inactivity_timeout); + brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", + settings->chandef.chan->hw_value, + settings->chandef.center_freq1, settings->chandef.width, + settings->beacon_interval, settings->dtim_period); + brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n", + settings->ssid, settings->ssid_len, settings->auth_type, + settings->inactivity_timeout); - if (!test_bit(WL_STATUS_AP_CREATING, &cfg->status)) { - WL_ERR("Not in AP creation mode\n"); - return -EPERM; - } + dev_role = ifp->vif->wdev.iftype; memset(&ssid_le, 0, sizeof(ssid_le)); if (settings->ssid == NULL || settings->ssid_len == 0) { @@ -4157,31 +3827,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len); ssid_le.SSID_len = cpu_to_le32(ssid_ie->len); - WL_TRACE("SSID is (%s) in Head\n", ssid_le.SSID); + brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID); } else { memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len); ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len); } - brcmf_set_mpc(ndev, 0); - ioctl_value = 1; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_DOWN, &ioctl_value); - if (err < 0) { - WL_ERR("BRCMF_C_DOWN error %d\n", err); - goto exit; - } - ioctl_value = 1; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &ioctl_value); - if (err < 0) { - WL_ERR("SET INFRA error %d\n", err); - goto exit; - } - ioctl_value = 1; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value); - if (err < 0) { - WL_ERR("setting AP mode failed %d\n", err); - goto exit; - } + brcmf_set_mpc(ifp, 0); + brcmf_configure_arp_offload(ifp, false); /* find the RSN_IE */ rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, @@ -4191,163 +3844,433 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail, settings->beacon.tail_len); - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = NULL; - kfree(cfg->ap_info->wpa_ie); - cfg->ap_info->wpa_ie = NULL; - if ((wpa_ie != NULL || rsn_ie != NULL)) { - WL_TRACE("WPA(2) IE is found\n"); + brcmf_dbg(TRACE, "WPA(2) IE is found\n"); if (wpa_ie != NULL) { /* WPA IE */ - err = brcmf_configure_wpaie(ndev, wpa_ie, false, - bssidx); + err = brcmf_configure_wpaie(ndev, wpa_ie, false); if (err < 0) goto exit; - cfg->ap_info->wpa_ie = kmemdup(wpa_ie, - wpa_ie->len + - TLV_HDR_LEN, - GFP_KERNEL); } else { /* RSN IE */ err = brcmf_configure_wpaie(ndev, - (struct brcmf_vs_tlv *)rsn_ie, true, bssidx); + (struct brcmf_vs_tlv *)rsn_ie, true); if (err < 0) goto exit; - cfg->ap_info->rsn_ie = kmemdup(rsn_ie, - rsn_ie->len + - TLV_HDR_LEN, - GFP_KERNEL); } - cfg->ap_info->security_mode = true; } else { - WL_TRACE("No WPA(2) IEs found\n"); - brcmf_configure_opensecurity(ndev, bssidx); - cfg->ap_info->security_mode = false; + brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); + brcmf_configure_opensecurity(ifp); } - /* Set Beacon IEs to FW */ - err = brcmf_set_management_ie(cfg, ndev, bssidx, - VNDR_IE_BEACON_FLAG, - (u8 *)settings->beacon.tail, - settings->beacon.tail_len); - if (err) - WL_ERR("Set Beacon IE Failed\n"); - else - WL_TRACE("Applied Vndr IEs for Beacon\n"); - /* Set Probe Response IEs to FW */ - err = brcmf_set_management_ie(cfg, ndev, bssidx, - VNDR_IE_PRBRSP_FLAG, - (u8 *)settings->beacon.proberesp_ies, - settings->beacon.proberesp_ies_len); - if (err) - WL_ERR("Set Probe Resp IE Failed\n"); - else - WL_TRACE("Applied Vndr IEs for Probe Resp\n"); + brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); + + chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef); + err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); + if (err < 0) { + brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err); + goto exit; + } if (settings->beacon_interval) { - ioctl_value = settings->beacon_interval; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_BCNPRD, - &ioctl_value); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, + settings->beacon_interval); if (err < 0) { - WL_ERR("Beacon Interval Set Error, %d\n", err); + brcmf_err("Beacon Interval Set Error, %d\n", err); goto exit; } } if (settings->dtim_period) { - ioctl_value = settings->dtim_period; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_DTIMPRD, - &ioctl_value); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD, + settings->dtim_period); if (err < 0) { - WL_ERR("DTIM Interval Set Error, %d\n", err); + brcmf_err("DTIM Interval Set Error, %d\n", err); goto exit; } } - ioctl_value = 1; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value); - if (err < 0) { - WL_ERR("BRCMF_C_UP error (%d)\n", err); - goto exit; + + if (dev_role == NL80211_IFTYPE_AP) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); + if (err < 0) { + brcmf_err("BRCMF_C_DOWN error %d\n", err); + goto exit; + } + brcmf_fil_iovar_int_set(ifp, "apsta", 0); } - memset(&join_params, 0, sizeof(join_params)); - /* join parameters starts with ssid */ - memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); - /* create softap */ - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, &join_params, - sizeof(join_params)); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); if (err < 0) { - WL_ERR("SET SSID error (%d)\n", err); + brcmf_err("SET INFRA error %d\n", err); goto exit; } - clear_bit(WL_STATUS_AP_CREATING, &cfg->status); - set_bit(WL_STATUS_AP_CREATED, &cfg->status); + if (dev_role == NL80211_IFTYPE_AP) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); + if (err < 0) { + brcmf_err("setting AP mode failed %d\n", 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); + goto exit; + } + + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); + /* create softap */ + 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); + goto exit; + } + brcmf_dbg(TRACE, "AP mode configuration complete\n"); + } else { + err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, + sizeof(ssid_le)); + if (err < 0) { + brcmf_err("setting ssid failed %d\n", err); + goto exit; + } + bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); + bss_enable.enable = cpu_to_le32(1); + 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); + goto exit; + } + + brcmf_dbg(TRACE, "GO mode configuration complete\n"); + } + clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); + set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); exit: - if (err) - brcmf_set_mpc(ndev, 1); + if (err) { + brcmf_set_mpc(ifp, 1); + brcmf_configure_arp_offload(ifp, true); + } return err; } static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - s32 ioctl_value; - s32 err = -EPERM; + struct brcmf_if *ifp = netdev_priv(ndev); + s32 err; + struct brcmf_fil_bss_enable_le bss_enable; + struct brcmf_join_params join_params; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); - if (cfg->conf->mode == WL_MODE_AP) { + if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) { /* Due to most likely deauths outstanding we sleep */ /* first to make sure they get processed by fw. */ msleep(400); - ioctl_value = 0; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value); - if (err < 0) { - WL_ERR("setting AP mode failed %d\n", err); - goto exit; - } - ioctl_value = 0; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value); - if (err < 0) { - WL_ERR("BRCMF_C_UP error %d\n", err); - goto exit; - } - brcmf_set_mpc(ndev, 1); - clear_bit(WL_STATUS_AP_CREATING, &cfg->status); - clear_bit(WL_STATUS_AP_CREATED, &cfg->status); - } -exit: + + memset(&join_params, 0, sizeof(join_params)); + 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); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); + if (err < 0) + brcmf_err("BRCMF_C_UP 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); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); + if (err < 0) + brcmf_err("setting INFRA mode failed %d\n", err); + } else { + bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); + bss_enable.enable = cpu_to_le32(0); + 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); + } + brcmf_set_mpc(ifp, 1); + brcmf_configure_arp_offload(ifp, true); + set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); + clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); + + return err; +} + +static s32 +brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_beacon_data *info) +{ + struct brcmf_if *ifp = netdev_priv(ndev); + s32 err; + + brcmf_dbg(TRACE, "Enter\n"); + + err = brcmf_config_ap_mgmt_ie(ifp->vif, info); + return err; } static int brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac) + const u8 *mac) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_scb_val_le scbval; + struct brcmf_if *ifp = netdev_priv(ndev); s32 err; if (!mac) return -EFAULT; - WL_TRACE("Enter %pM\n", mac); + brcmf_dbg(TRACE, "Enter %pM\n", mac); - if (!check_sys_up(wiphy)) + if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) + ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; + if (!check_vif_up(ifp->vif)) return -EIO; memcpy(&scbval.ea, mac, ETH_ALEN); scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, - &scbval, sizeof(scbval)); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scbval)); if (err) - WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err); + brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err); + + brcmf_dbg(TRACE, "Exit\n"); + return err; +} + + +static void +brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, + struct wireless_dev *wdev, + u16 frame_type, bool reg) +{ + 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); +} + + +static int +brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct ieee80211_channel *chan = params->chan; + const u8 *buf = params->buf; + size_t len = params->len; + const struct ieee80211_mgmt *mgmt; + struct brcmf_cfg80211_vif *vif; + s32 err = 0; + s32 ie_offset; + s32 ie_len; + struct brcmf_fil_action_frame_le *action_frame; + struct brcmf_fil_af_params_le *af_params; + bool ack; + s32 chan_nr; + u32 freq; + + brcmf_dbg(TRACE, "Enter\n"); + + *cookie = 0; + + mgmt = (const struct ieee80211_mgmt *)buf; + + if (!ieee80211_is_mgmt(mgmt->frame_control)) { + brcmf_err("Driver only allows MGMT packet type\n"); + return -EPERM; + } + + vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); + + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + /* Right now the only reason to get a probe response */ + /* is for p2p listen response or for p2p GO from */ + /* wpa_supplicant. Unfortunately the probe is send */ + /* on primary ndev, while dongle wants it on the p2p */ + /* vif. Since this is only reason for a probe */ + /* response to be sent, the vif is taken from cfg. */ + /* If ever desired to send proberesp for non p2p */ + /* response then data should be checked for */ + /* "DIRECT-". Note in future supplicant will take */ + /* dedicated p2p wdev to do this and then this 'hack'*/ + /* is not needed anymore. */ + ie_offset = DOT11_MGMT_HDR_LEN + + DOT11_BCN_PRB_FIXED_LEN; + ie_len = len - ie_offset; + if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) + vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + err = brcmf_vif_set_mgmt_ie(vif, + BRCMF_VNDR_IE_PRBRSP_FLAG, + &buf[ie_offset], + ie_len); + cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, + GFP_KERNEL); + } else if (ieee80211_is_action(mgmt->frame_control)) { + af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); + if (af_params == NULL) { + brcmf_err("unable to allocate frame\n"); + err = -ENOMEM; + goto exit; + } + action_frame = &af_params->action_frame; + /* Add the packet Id */ + action_frame->packet_id = cpu_to_le32(*cookie); + /* Add BSSID */ + memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN); + memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN); + /* Add the length exepted for 802.11 header */ + action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); + /* Add the channel. Use the one specified as parameter if any or + * the current one (got from the firmware) otherwise + */ + if (chan) + freq = chan->center_freq; + else + brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL, + &freq); + chan_nr = ieee80211_frequency_to_channel(freq); + af_params->channel = cpu_to_le32(chan_nr); + + memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], + le16_to_cpu(action_frame->len)); + + brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n", + *cookie, le16_to_cpu(action_frame->len), freq); + + ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg), + af_params); + + cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, + GFP_KERNEL); + kfree(af_params); + } else { + brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); + brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len); + } + +exit: + return err; +} + + +static int +brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_vif *vif; + int err = 0; - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Enter p2p listen cancel\n"); + + vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + if (vif == NULL) { + brcmf_err("No p2p device available for probe response\n"); + err = -ENODEV; + goto exit; + } + brcmf_p2p_cancel_remain_on_channel(vif->ifp); +exit: return err; } +static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_crit_proto_id proto, + u16 duration) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_vif *vif; + + vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); + + /* only DHCP support for now */ + if (proto != NL80211_CRIT_PROTO_DHCP) + return -EINVAL; + + /* suppress and abort scanning */ + set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); + brcmf_abort_scanning(cfg); + + return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration); +} + +static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_vif *vif; + + vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); + + brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0); + clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); +} + +static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper) +{ + int ret; + + switch (oper) { + case NL80211_TDLS_DISCOVERY_REQ: + ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY; + break; + case NL80211_TDLS_SETUP: + ret = BRCMF_TDLS_MANUAL_EP_CREATE; + break; + case NL80211_TDLS_TEARDOWN: + ret = BRCMF_TDLS_MANUAL_EP_DELETE; + break; + default: + brcmf_err("unsupported operation: %d\n", oper); + ret = -EOPNOTSUPP; + } + return ret; +} + +static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *ndev, const u8 *peer, + enum nl80211_tdls_operation oper) +{ + struct brcmf_if *ifp; + struct brcmf_tdls_iovar_le info; + int ret = 0; + + ret = brcmf_convert_nl80211_tdls_oper(oper); + if (ret < 0) + return ret; + + ifp = netdev_priv(ndev); + memset(&info, 0, sizeof(info)); + info.mode = (u8)ret; + if (peer) + memcpy(info.ea, peer, ETH_ALEN); + + 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); + + return ret; +} + static struct cfg80211_ops wl_cfg80211_ops = { + .add_virtual_intf = brcmf_cfg80211_add_iface, + .del_virtual_intf = brcmf_cfg80211_del_iface, .change_virtual_intf = brcmf_cfg80211_change_iface, .scan = brcmf_cfg80211_scan, .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, @@ -4362,7 +4285,6 @@ static struct cfg80211_ops wl_cfg80211_ops = { .set_default_key = brcmf_cfg80211_config_default_key, .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key, .set_power_mgmt = brcmf_cfg80211_set_power_mgmt, - .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask, .connect = brcmf_cfg80211_connect, .disconnect = brcmf_cfg80211_disconnect, .suspend = brcmf_cfg80211_suspend, @@ -4372,135 +4294,197 @@ static struct cfg80211_ops wl_cfg80211_ops = { .flush_pmksa = brcmf_cfg80211_flush_pmksa, .start_ap = brcmf_cfg80211_start_ap, .stop_ap = brcmf_cfg80211_stop_ap, + .change_beacon = brcmf_cfg80211_change_beacon, .del_station = brcmf_cfg80211_del_station, -#ifndef CONFIG_BRCMISCAN - /* scheduled scan need e-scan, which is mutual exclusive with i-scan */ .sched_scan_start = brcmf_cfg80211_sched_scan_start, .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, -#endif -#ifdef CONFIG_NL80211_TESTMODE - .testmode_cmd = brcmf_cfg80211_testmode -#endif + .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, + .mgmt_tx = brcmf_cfg80211_mgmt_tx, + .remain_on_channel = brcmf_p2p_remain_on_channel, + .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, + .start_p2p_device = brcmf_p2p_start_device, + .stop_p2p_device = brcmf_p2p_stop_device, + .crit_proto_start = brcmf_cfg80211_crit_proto_start, + .crit_proto_stop = brcmf_cfg80211_crit_proto_stop, + .tdls_oper = brcmf_cfg80211_tdls_oper, + CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode) }; -static s32 brcmf_mode_to_nl80211_iftype(s32 mode) -{ - s32 err = 0; - - switch (mode) { - case WL_MODE_BSS: - return NL80211_IFTYPE_STATION; - case WL_MODE_IBSS: - return NL80211_IFTYPE_ADHOC; - default: - return NL80211_IFTYPE_UNSPECIFIED; - } - - return err; -} - static void brcmf_wiphy_pno_params(struct wiphy *wiphy) { -#ifndef CONFIG_BRCMFISCAN /* scheduled scan settings */ wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; -#endif } -static struct wireless_dev *brcmf_alloc_wdev(struct device *ndev) +static const struct ieee80211_iface_limit brcmf_iface_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) + } +}; +static const struct ieee80211_iface_combination brcmf_iface_combos[] = { + { + .max_interfaces = BRCMF_IFACE_MAX_CNT, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(brcmf_iface_limits), + .limits = brcmf_iface_limits + } +}; + +static const struct ieee80211_txrx_stypes +brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + } +}; + +static struct wiphy *brcmf_setup_wiphy(struct device *phydev) { - struct wireless_dev *wdev; + struct wiphy *wiphy; s32 err = 0; - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (!wdev) + wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); + if (!wiphy) { + brcmf_err("Could not allocate wiphy device\n"); return ERR_PTR(-ENOMEM); - - wdev->wiphy = wiphy_new(&wl_cfg80211_ops, - sizeof(struct brcmf_cfg80211_info)); - if (!wdev->wiphy) { - WL_ERR("Could not allocate wiphy device\n"); - err = -ENOMEM; - goto wiphy_new_out; - } - set_wiphy_dev(wdev->wiphy, ndev); - wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; - wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; - wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP); - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set - * it as 11a by default. - * This will be updated with - * 11n phy tables in - * "ifconfig up" - * if phy has 11n capability - */ - wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - wdev->wiphy->cipher_suites = __wl_cipher_suites; - wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); - wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power - * save mode - * by default - */ - brcmf_wiphy_pno_params(wdev->wiphy); - err = wiphy_register(wdev->wiphy); + } + set_wiphy_dev(wiphy, phydev); + wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; + wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_DEVICE); + wiphy->iface_combinations = brcmf_iface_combos; + wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); + wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->cipher_suites = __wl_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); + wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | + WIPHY_FLAG_OFFCHAN_TX | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_SUPPORTS_TDLS; + if (!brcmf_roamoff) + wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + wiphy->mgmt_stypes = brcmf_txrx_stypes; + wiphy->max_remain_on_channel_duration = 5000; + brcmf_wiphy_pno_params(wiphy); + brcmf_dbg(INFO, "Registering custom regulatory\n"); + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); + err = wiphy_register(wiphy); if (err < 0) { - WL_ERR("Could not register wiphy device (%d)\n", err); - goto wiphy_register_out; + brcmf_err("Could not register wiphy device (%d)\n", err); + wiphy_free(wiphy); + return ERR_PTR(err); } - return wdev; + return wiphy; +} -wiphy_register_out: - wiphy_free(wdev->wiphy); +struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, + enum nl80211_iftype type, + bool pm_block) +{ + struct brcmf_cfg80211_vif *vif; + + brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", + sizeof(*vif)); + vif = kzalloc(sizeof(*vif), GFP_KERNEL); + if (!vif) + return ERR_PTR(-ENOMEM); + + vif->wdev.wiphy = cfg->wiphy; + vif->wdev.iftype = type; + + vif->pm_block = pm_block; + vif->roam_off = -1; -wiphy_new_out: - kfree(wdev); + brcmf_init_prof(&vif->profile); - return ERR_PTR(err); + list_add_tail(&vif->list, &cfg->vif_list); + return vif; } -static void brcmf_free_wdev(struct brcmf_cfg80211_info *cfg) +void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) { - struct wireless_dev *wdev = cfg->wdev; + list_del(&vif->list); + kfree(vif); +} - if (!wdev) { - WL_ERR("wdev is invalid\n"); - return; - } - wiphy_unregister(wdev->wiphy); - wiphy_free(wdev->wiphy); - kfree(wdev); - cfg->wdev = NULL; +void brcmf_cfg80211_free_netdev(struct net_device *ndev) +{ + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; + + ifp = netdev_priv(ndev); + vif = ifp->vif; + + brcmf_free_vif(vif); + free_netdev(ndev); } -static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, - const struct brcmf_event_msg *e) +static bool brcmf_is_linkup(const struct brcmf_event_msg *e) { - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = e->status; if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { - WL_CONN("Processing set ssid\n"); - cfg->link_up = true; + brcmf_dbg(CONN, "Processing set ssid\n"); return true; } return false; } -static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, - const struct brcmf_event_msg *e) +static bool brcmf_is_linkdown(const struct brcmf_event_msg *e) { - u32 event = be32_to_cpu(e->event_type); - u16 flags = be16_to_cpu(e->flags); + u32 event = e->event_code; + u16 flags = e->flags; - if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { - WL_CONN("Processing link down\n"); + if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) || + (event == BRCMF_E_DISASSOC_IND) || + ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) { + brcmf_dbg(CONN, "Processing link down\n"); return true; } return false; @@ -4509,18 +4493,17 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = e->status; if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) { - WL_CONN("Processing Link %s & no network found\n", - be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ? - "up" : "down"); + brcmf_dbg(CONN, "Processing Link %s & no network found\n", + e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down"); return true; } if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) { - WL_CONN("Processing connecting & no network found\n"); + brcmf_dbg(CONN, "Processing connecting & no network found\n"); return true; } @@ -4539,9 +4522,9 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) conn_info->resp_ie_len = 0; } -static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) +static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, + struct brcmf_if *ifp) { - struct net_device *ndev = cfg_to_ndev(cfg); struct brcmf_cfg80211_assoc_ielen_le *assoc_info; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); u32 req_len; @@ -4550,10 +4533,10 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) brcmf_clear_assoc_ies(cfg); - err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg->extra_buf, - WL_ASSOC_INFO_MAX); + err = brcmf_fil_iovar_data_get(ifp, "assoc_info", + cfg->extra_buf, WL_ASSOC_INFO_MAX); if (err) { - WL_ERR("could not get assoc info (%d)\n", err); + brcmf_err("could not get assoc info (%d)\n", err); return err; } assoc_info = @@ -4561,11 +4544,11 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) req_len = le32_to_cpu(assoc_info->req_len); resp_len = le32_to_cpu(assoc_info->resp_len); if (req_len) { - err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies", - cfg->extra_buf, - WL_ASSOC_INFO_MAX); + err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies", + cfg->extra_buf, + WL_ASSOC_INFO_MAX); if (err) { - WL_ERR("could not get assoc req (%d)\n", err); + brcmf_err("could not get assoc req (%d)\n", err); return err; } conn_info->req_ie_len = req_len; @@ -4577,11 +4560,11 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) conn_info->req_ie = NULL; } if (resp_len) { - err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies", - cfg->extra_buf, - WL_ASSOC_INFO_MAX); + err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies", + cfg->extra_buf, + WL_ASSOC_INFO_MAX); if (err) { - WL_ERR("could not get assoc resp (%d)\n", err); + brcmf_err("could not get assoc resp (%d)\n", err); return err; } conn_info->resp_ie_len = resp_len; @@ -4592,8 +4575,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) conn_info->resp_ie_len = 0; conn_info->resp_ie = NULL; } - WL_CONN("req len (%d) resp len (%d)\n", - conn_info->req_ie_len, conn_info->resp_ie_len); + brcmf_dbg(CONN, "req len (%d) resp len (%d)\n", + conn_info->req_ie_len, conn_info->resp_ie_len); return err; } @@ -4603,43 +4586,59 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e) { - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); struct wiphy *wiphy = cfg_to_wiphy(cfg); - struct brcmf_channel_info_le channel_le; - struct ieee80211_channel *notify_channel; + struct ieee80211_channel *notify_channel = NULL; struct ieee80211_supported_band *band; + struct brcmf_bss_info_le *bi; + struct brcmu_chan ch; u32 freq; s32 err = 0; - u32 target_channel; + u8 *buf; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); - brcmf_get_assoc_ies(cfg); + brcmf_get_assoc_ies(cfg, ifp); memcpy(profile->bssid, e->addr, ETH_ALEN); - brcmf_update_bss_info(cfg); + brcmf_update_bss_info(cfg, ifp); - brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le, - sizeof(channel_le)); + buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto done; + } - target_channel = le32_to_cpu(channel_le.target_channel); - WL_CONN("Roamed to channel %d\n", target_channel); + /* data sent to dongle has to be little endian */ + *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, + buf, WL_BSS_INFO_MAX); - if (target_channel <= CH_MAX_2G_CHANNEL) + if (err) + goto done; + + bi = (struct brcmf_bss_info_le *)(buf + 4); + ch.chspec = le16_to_cpu(bi->chanspec); + cfg->d11inf.decchspec(&ch); + + if (ch.band == BRCMU_CHAN_BAND_2G) band = wiphy->bands[IEEE80211_BAND_2GHZ]; else band = wiphy->bands[IEEE80211_BAND_5GHZ]; - freq = ieee80211_channel_to_frequency(target_channel, band->band); + freq = ieee80211_channel_to_frequency(ch.chnum, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); +done: + kfree(buf); cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid, conn_info->req_ie, conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); - WL_CONN("Report roaming result\n"); + brcmf_dbg(CONN, "Report roaming result\n"); - set_bit(WL_STATUS_CONNECTED, &cfg->status); - WL_TRACE("Exit\n"); + set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -4648,17 +4647,21 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, bool completed) { - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); s32 err = 0; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter\n"); - if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg->status)) { + if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, + &ifp->vif->sme_state)) { if (completed) { - brcmf_get_assoc_ies(cfg); + brcmf_get_assoc_ies(cfg, ifp); memcpy(profile->bssid, e->addr, ETH_ALEN); - brcmf_update_bss_info(cfg); + brcmf_update_bss_info(cfg, ifp); + set_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state); } cfg80211_connect_result(ndev, (u8 *)profile->bssid, @@ -4669,12 +4672,10 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); - if (completed) - set_bit(WL_STATUS_CONNECTED, &cfg->status); - WL_CONN("Report connect result - connection %s\n", - completed ? "succeeded" : "failed"); + brcmf_dbg(CONN, "Report connect result - connection %s\n", + completed ? "succeeded" : "failed"); } - WL_TRACE("Exit\n"); + brcmf_dbg(TRACE, "Exit\n"); return err; } @@ -4683,80 +4684,78 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { - s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 reason = be32_to_cpu(e->reason); - u32 len = be32_to_cpu(e->datalen); static int generation; - + u32 event = e->event_code; + u32 reason = e->reason; struct station_info sinfo; - WL_CONN("event %d, reason %d\n", event, reason); - memset(&sinfo, 0, sizeof(sinfo)); + brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); + if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS && + ndev != cfg_to_ndev(cfg)) { + brcmf_dbg(CONN, "AP mode link down\n"); + complete(&cfg->vif_disabled); + return 0; + } - sinfo.filled = 0; if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && - reason == BRCMF_E_STATUS_SUCCESS) { + (reason == BRCMF_E_STATUS_SUCCESS)) { + memset(&sinfo, 0, sizeof(sinfo)); sinfo.filled = STATION_INFO_ASSOC_REQ_IES; if (!data) { - WL_ERR("No IEs present in ASSOC/REASSOC_IND"); + brcmf_err("No IEs present in ASSOC/REASSOC_IND"); return -EINVAL; } sinfo.assoc_req_ies = data; - sinfo.assoc_req_ies_len = len; + sinfo.assoc_req_ies_len = e->datalen; generation++; sinfo.generation = generation; - cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC); + cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL); } else if ((event == BRCMF_E_DISASSOC_IND) || (event == BRCMF_E_DEAUTH_IND) || (event == BRCMF_E_DEAUTH)) { - generation++; - sinfo.generation = generation; - cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC); + cfg80211_del_sta(ndev, e->addr, GFP_KERNEL); } - return err; + return 0; } static s32 -brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_notify_connect_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct net_device *ndev = ifp->ndev; + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; + struct ieee80211_channel *chan; s32 err = 0; - if (cfg->conf->mode == WL_MODE_AP) { + if (brcmf_is_apmode(ifp->vif)) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); - } else if (brcmf_is_linkup(cfg, e)) { - WL_CONN("Linkup\n"); - if (brcmf_is_ibssmode(cfg)) { + } else if (brcmf_is_linkup(e)) { + brcmf_dbg(CONN, "Linkup\n"); + if (brcmf_is_ibssmode(ifp->vif)) { + chan = ieee80211_get_channel(cfg->wiphy, cfg->channel); memcpy(profile->bssid, e->addr, ETH_ALEN); wl_inform_ibss(cfg, ndev, e->addr); - cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); - clear_bit(WL_STATUS_CONNECTING, &cfg->status); - set_bit(WL_STATUS_CONNECTED, &cfg->status); + cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL); + clear_bit(BRCMF_VIF_STATUS_CONNECTING, + &ifp->vif->sme_state); + set_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state); } else brcmf_bss_connect_done(cfg, ndev, e, true); - } else if (brcmf_is_linkdown(cfg, e)) { - WL_CONN("Linkdown\n"); - if (brcmf_is_ibssmode(cfg)) { - clear_bit(WL_STATUS_CONNECTING, &cfg->status); - if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg->status)) - brcmf_link_down(cfg); - } else { + } else if (brcmf_is_linkdown(e)) { + brcmf_dbg(CONN, "Linkdown\n"); + if (!brcmf_is_ibssmode(ifp->vif)) { brcmf_bss_connect_done(cfg, ndev, e, false); - if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg->status)) { - cfg80211_disconnected(ndev, 0, NULL, 0, - GFP_KERNEL); - brcmf_link_down(cfg); - } } - brcmf_init_prof(cfg->profile); + brcmf_link_down(ifp->vif); + brcmf_init_prof(ndev_to_prof(ndev)); + if (ndev != cfg_to_ndev(cfg)) + complete(&cfg->vif_disabled); } else if (brcmf_is_nonetwork(cfg, e)) { - if (brcmf_is_ibssmode(cfg)) - clear_bit(WL_STATUS_CONNECTING, &cfg->status); + if (brcmf_is_ibssmode(ifp->vif)) + clear_bit(BRCMF_VIF_STATUS_CONNECTING, + &ifp->vif->sme_state); else brcmf_bss_connect_done(cfg, ndev, e, false); } @@ -4765,30 +4764,29 @@ brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg, } static s32 -brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_notify_roaming_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = e->status; if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { - if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) - brcmf_bss_roaming_done(cfg, ndev, e); + if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) + brcmf_bss_roaming_done(cfg, ifp->ndev, e); else - brcmf_bss_connect_done(cfg, ndev, e, true); + brcmf_bss_connect_done(cfg, ifp->ndev, e, true); } return err; } static s32 -brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_notify_mic_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - u16 flags = be16_to_cpu(e->flags); + u16 flags = e->flags; enum nl80211_key_type key_type; if (flags & BRCMF_EVENT_MSG_GROUP) @@ -4796,85 +4794,68 @@ brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg, else key_type = NL80211_KEYTYPE_PAIRWISE; - cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, + cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1, NULL, GFP_KERNEL); return 0; } -static s32 -brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) +static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, + const struct brcmf_event_msg *e, void *data) { - struct brcmf_channel_info_le channel_inform_le; - struct brcmf_scan_results_le *bss_list_le; - u32 len = WL_SCAN_BUF_MAX; - s32 err = 0; - bool scan_abort = false; - u32 scan_channel; + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data; + struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; + struct brcmf_cfg80211_vif *vif; - WL_TRACE("Enter\n"); + brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n", + ifevent->action, ifevent->flags, ifevent->ifidx, + ifevent->bssidx); - if (cfg->iscan_on && cfg->iscan_kickstart) { - WL_TRACE("Exit\n"); - return brcmf_wakeup_iscan(cfg_to_iscan(cfg)); - } + mutex_lock(&event->vif_event_lock); + event->action = ifevent->action; + vif = event->vif; - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { - WL_ERR("Scan complete while device not scanning\n"); - scan_abort = true; - err = -EINVAL; - goto scan_done_out; - } - - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le, - sizeof(channel_inform_le)); - if (err) { - WL_ERR("scan busy (%d)\n", err); - scan_abort = true; - goto scan_done_out; - } - scan_channel = le32_to_cpu(channel_inform_le.scan_channel); - if (scan_channel) - WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel); - cfg->bss_list = cfg->scan_results; - bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list; - - memset(cfg->scan_results, 0, len); - bss_list_le->buflen = cpu_to_le32(len); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS, - cfg->scan_results, len); - if (err) { - WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); - err = -EINVAL; - scan_abort = true; - goto scan_done_out; - } - cfg->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); - cfg->scan_results->version = le32_to_cpu(bss_list_le->version); - cfg->scan_results->count = le32_to_cpu(bss_list_le->count); + switch (ifevent->action) { + case BRCMF_E_IF_ADD: + /* waiting process may have timed out */ + if (!cfg->vif_event.vif) { + mutex_unlock(&event->vif_event_lock); + return -EBADF; + } - err = brcmf_inform_bss(cfg); - if (err) - scan_abort = true; + ifp->vif = vif; + vif->ifp = ifp; + if (ifp->ndev) { + vif->wdev.netdev = ifp->ndev; + ifp->ndev->ieee80211_ptr = &vif->wdev; + SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy)); + } + mutex_unlock(&event->vif_event_lock); + wake_up(&event->vif_wq); + return 0; -scan_done_out: - if (cfg->scan_request) { - WL_SCAN("calling cfg80211_scan_done\n"); - cfg80211_scan_done(cfg->scan_request, scan_abort); - brcmf_set_mpc(ndev, 1); - cfg->scan_request = NULL; - } + case BRCMF_E_IF_DEL: + mutex_unlock(&event->vif_event_lock); + /* event may not be upon user request */ + if (brcmf_cfg80211_vif_event_armed(cfg)) + wake_up(&event->vif_wq); + return 0; - WL_TRACE("Exit\n"); + case BRCMF_E_IF_CHANGE: + mutex_unlock(&event->vif_event_lock); + wake_up(&event->vif_wq); + return 0; - return err; + default: + mutex_unlock(&event->vif_event_lock); + break; + } + return -EINVAL; } static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) { - conf->mode = (u32)-1; conf->frag_threshold = (u32)-1; conf->rts_threshold = (u32)-1; conf->retry_short = (u32)-1; @@ -4882,82 +4863,65 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) conf->tx_power = -1; } -static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) -{ - memset(el, 0, sizeof(*el)); - el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status; - el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; - el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; - el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; - el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results; +static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) +{ + brcmf_fweh_register(cfg->pub, BRCMF_E_LINK, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM, + brcmf_notify_roaming_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR, + brcmf_notify_mic_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, + brcmf_notify_sched_scan_results); + brcmf_fweh_register(cfg->pub, BRCMF_E_IF, + brcmf_notify_vif_event); + brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG, + brcmf_p2p_notify_rx_mgmt_p2p_probereq); + brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE, + brcmf_p2p_notify_listen_complete); + brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX, + brcmf_p2p_notify_action_frame_rx); + brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE, + brcmf_p2p_notify_action_tx_complete); + brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, + brcmf_p2p_notify_action_tx_complete); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) { - kfree(cfg->scan_results); - cfg->scan_results = NULL; - kfree(cfg->bss_info); - cfg->bss_info = NULL; kfree(cfg->conf); cfg->conf = NULL; - kfree(cfg->profile); - cfg->profile = NULL; - kfree(cfg->scan_req_int); - cfg->scan_req_int = NULL; kfree(cfg->escan_ioctl_buf); cfg->escan_ioctl_buf = NULL; - kfree(cfg->dcmd_buf); - cfg->dcmd_buf = NULL; kfree(cfg->extra_buf); cfg->extra_buf = NULL; - kfree(cfg->iscan); - cfg->iscan = NULL; kfree(cfg->pmk_list); cfg->pmk_list = NULL; - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } } static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) { - cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); - if (!cfg->scan_results) - goto init_priv_mem_out; cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL); if (!cfg->conf) goto init_priv_mem_out; - cfg->profile = kzalloc(sizeof(*cfg->profile), GFP_KERNEL); - if (!cfg->profile) - goto init_priv_mem_out; - cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (!cfg->bss_info) - goto init_priv_mem_out; - cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int), - GFP_KERNEL); - if (!cfg->scan_req_int) - goto init_priv_mem_out; cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); if (!cfg->escan_ioctl_buf) goto init_priv_mem_out; - cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); - if (!cfg->dcmd_buf) - goto init_priv_mem_out; cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (!cfg->extra_buf) goto init_priv_mem_out; - cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL); - if (!cfg->iscan) - goto init_priv_mem_out; cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); if (!cfg->pmk_list) goto init_priv_mem_out; @@ -4970,333 +4934,182 @@ init_priv_mem_out: return -ENOMEM; } -/* -* retrieve first queued event from head -*/ - -static struct brcmf_cfg80211_event_q *brcmf_deq_event( - struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_event_q *e = NULL; - - spin_lock_irq(&cfg->evt_q_lock); - if (!list_empty(&cfg->evt_q_list)) { - e = list_first_entry(&cfg->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - } - spin_unlock_irq(&cfg->evt_q_lock); - - return e; -} - -/* -* push event to tail of the queue -* -* remark: this function may not sleep as it is called in atomic context. -*/ - -static s32 -brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event, - const struct brcmf_event_msg *msg, void *data) -{ - struct brcmf_cfg80211_event_q *e; - s32 err = 0; - ulong flags; - u32 data_len; - u32 total_len; - - total_len = sizeof(struct brcmf_cfg80211_event_q); - if (data) - data_len = be32_to_cpu(msg->datalen); - else - data_len = 0; - total_len += data_len; - e = kzalloc(total_len, GFP_ATOMIC); - if (!e) - return -ENOMEM; - - e->etype = event; - memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); - if (data) - memcpy(&e->edata, data, data_len); - - spin_lock_irqsave(&cfg->evt_q_lock, flags); - list_add_tail(&e->evt_q_list, &cfg->evt_q_list); - spin_unlock_irqrestore(&cfg->evt_q_lock, flags); - - return err; -} - -static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) -{ - kfree(e); -} - -static void brcmf_cfg80211_event_handler(struct work_struct *work) -{ - struct brcmf_cfg80211_info *cfg = - container_of(work, struct brcmf_cfg80211_info, - event_work); - struct brcmf_cfg80211_event_q *e; - - e = brcmf_deq_event(cfg); - if (unlikely(!e)) { - WL_ERR("event queue empty...\n"); - return; - } - - do { - WL_INFO("event type (%d)\n", e->etype); - if (cfg->el.handler[e->etype]) - cfg->el.handler[e->etype](cfg, - cfg_to_ndev(cfg), - &e->emsg, e->edata); - else - WL_INFO("Unknown Event (%d): ignoring\n", e->etype); - brcmf_put_event(e); - } while ((e = brcmf_deq_event(cfg))); - -} - -static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg) -{ - spin_lock_init(&cfg->evt_q_lock); - INIT_LIST_HEAD(&cfg->evt_q_list); -} - -static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_event_q *e; - - spin_lock_irq(&cfg->evt_q_lock); - while (!list_empty(&cfg->evt_q_list)) { - e = list_first_entry(&cfg->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - kfree(e); - } - spin_unlock_irq(&cfg->evt_q_lock); -} - static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) { s32 err = 0; cfg->scan_request = NULL; cfg->pwr_save = true; -#ifdef CONFIG_BRCMISCAN - cfg->iscan_on = true; /* iscan on & off switch. - we enable iscan per default */ - cfg->escan_on = false; /* escan on & off switch. - we disable escan per default */ -#else - cfg->iscan_on = false; /* iscan on & off switch. - we disable iscan per default */ - cfg->escan_on = true; /* escan on & off switch. - we enable escan per default */ -#endif - cfg->roam_on = true; /* roam on & off switch. - we enable roam per default */ - - cfg->iscan_kickstart = false; - cfg->active_scan = true; /* we do active scan for - specific scan per default */ - cfg->dongle_up = false; /* dongle is not up yet */ - brcmf_init_eq(cfg); + cfg->active_scan = true; /* we do active scan per default */ + cfg->dongle_up = false; /* dongle is not up yet */ err = brcmf_init_priv_mem(cfg); if (err) return err; - INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler); - brcmf_init_eloop_handler(&cfg->el); + brcmf_register_event_handlers(cfg); mutex_init(&cfg->usr_sync); - err = brcmf_init_iscan(cfg); - if (err) - return err; brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); - brcmf_init_prof(cfg->profile); - brcmf_link_down(cfg); - + init_completion(&cfg->vif_disabled); return err; } static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) { - cancel_work_sync(&cfg->event_work); cfg->dongle_up = false; /* dongle down */ - brcmf_flush_eq(cfg); - brcmf_link_down(cfg); brcmf_abort_scanning(cfg); brcmf_deinit_priv_mem(cfg); } -struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev, - struct device *busdev, - struct brcmf_pub *drvr) +static void init_vif_event(struct brcmf_cfg80211_vif_event *event) { - struct wireless_dev *wdev; + init_waitqueue_head(&event->vif_wq); + mutex_init(&event->vif_event_lock); +} + +static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) +{ + struct brcmf_fil_bwcap_le band_bwcap; + u32 val; + int err; + + /* verify support for bw_cap command */ + val = WLC_BAND_5G; + err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val); + + if (!err) { + /* only set 2G bandwidth using bw_cap command */ + band_bwcap.band = cpu_to_le32(WLC_BAND_2G); + band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ); + err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap, + sizeof(band_bwcap)); + } else { + brcmf_dbg(INFO, "fallback to mimo_bw_cap\n"); + val = WLC_N_BW_40ALL; + err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val); + } + return err; +} + +struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, + struct device *busdev) +{ + struct net_device *ndev = drvr->iflist[0]->ndev; struct brcmf_cfg80211_info *cfg; + struct wiphy *wiphy; + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; s32 err = 0; + s32 io_type; if (!ndev) { - WL_ERR("ndev is invalid\n"); + brcmf_err("ndev is invalid\n"); return NULL; } - wdev = brcmf_alloc_wdev(busdev); - if (IS_ERR(wdev)) { + ifp = netdev_priv(ndev); + wiphy = brcmf_setup_wiphy(busdev); + if (IS_ERR(wiphy)) return NULL; - } - wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); - cfg = wdev_to_cfg(wdev); - cfg->wdev = wdev; + cfg = wiphy_priv(wiphy); + cfg->wiphy = wiphy; cfg->pub = drvr; - ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); - wdev->netdev = ndev; + init_vif_event(&cfg->vif_event); + INIT_LIST_HEAD(&cfg->vif_list); + + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); + if (IS_ERR(vif)) { + wiphy_free(wiphy); + return NULL; + } + + vif->ifp = ifp; + vif->wdev.netdev = ndev; + ndev->ieee80211_ptr = &vif->wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); + err = wl_init_priv(cfg); if (err) { - WL_ERR("Failed to init iwm_priv (%d)\n", err); + brcmf_err("Failed to init iwm_priv (%d)\n", err); goto cfg80211_attach_out; } + ifp->vif = vif; - return cfg; - -cfg80211_attach_out: - brcmf_free_wdev(cfg); - return NULL; -} - -void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) -{ - wl_deinit_priv(cfg); - brcmf_free_wdev(cfg); -} - -void -brcmf_cfg80211_event(struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - u32 event_type = be32_to_cpu(e->event_type); - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - - if (!brcmf_enq_event(cfg, event_type, e, data)) - schedule_work(&cfg->event_work); -} + err = brcmf_p2p_attach(cfg); + if (err) { + brcmf_err("P2P initilisation failed (%d)\n", err); + goto cfg80211_p2p_attach_out; + } + err = brcmf_btcoex_attach(cfg); + if (err) { + brcmf_err("BT-coex initialisation failed (%d)\n", err); + brcmf_p2p_detach(&cfg->p2p); + goto cfg80211_p2p_attach_out; + } -static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) -{ - s32 infra = 0; - s32 err = 0; + /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(), + * setup 40MHz in 2GHz band and enable OBSS scanning. + */ + if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + err = brcmf_enable_bw40_2g(ifp); + if (!err) + err = brcmf_fil_iovar_int_set(ifp, "obss_coex", + BRCMF_OBSS_COEX_AUTO); + } - switch (iftype) { - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_WDS: - WL_ERR("type (%d) : currently we do not support this mode\n", - iftype); - err = -EINVAL; - return err; - case NL80211_IFTYPE_ADHOC: - infra = 0; - break; - case NL80211_IFTYPE_STATION: - infra = 1; - break; - case NL80211_IFTYPE_AP: - infra = 1; - break; - default: - err = -EINVAL; - WL_ERR("invalid type (%d)\n", iftype); - return err; + err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); + if (err) { + brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; } - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); + + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, + &io_type); if (err) { - WL_ERR("WLC_SET_INFRA error (%d)\n", err); - return err; + brcmf_err("Failed to get D11 version (%d)\n", err); + goto cfg80211_p2p_attach_out; } + cfg->d11inf.io_type = (u8)io_type; + brcmu_d11_attach(&cfg->d11inf); - return 0; -} + return cfg; -static s32 brcmf_dongle_eventmsg(struct net_device *ndev) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - s32 err = 0; +cfg80211_p2p_attach_out: + wl_deinit_priv(cfg); - WL_TRACE("Enter\n"); +cfg80211_attach_out: + brcmf_free_vif(vif); + return NULL; +} - /* Setup event_msgs */ - brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, - iovbuf, sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf)); - if (err) { - WL_ERR("Get event_msgs error (%d)\n", err); - goto dongle_eventmsg_out; - } - memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); - - setbit(eventmask, BRCMF_E_SET_SSID); - setbit(eventmask, BRCMF_E_ROAM); - setbit(eventmask, BRCMF_E_PRUNE); - setbit(eventmask, BRCMF_E_AUTH); - setbit(eventmask, BRCMF_E_REASSOC); - setbit(eventmask, BRCMF_E_REASSOC_IND); - setbit(eventmask, BRCMF_E_DEAUTH_IND); - setbit(eventmask, BRCMF_E_DISASSOC_IND); - setbit(eventmask, BRCMF_E_DISASSOC); - setbit(eventmask, BRCMF_E_JOIN); - setbit(eventmask, BRCMF_E_ASSOC_IND); - setbit(eventmask, BRCMF_E_PSK_SUP); - setbit(eventmask, BRCMF_E_LINK); - setbit(eventmask, BRCMF_E_NDIS_LINK); - setbit(eventmask, BRCMF_E_MIC_ERROR); - setbit(eventmask, BRCMF_E_PMKID_CACHE); - setbit(eventmask, BRCMF_E_TXFAIL); - setbit(eventmask, BRCMF_E_JOIN_START); - setbit(eventmask, BRCMF_E_SCAN_COMPLETE); - setbit(eventmask, BRCMF_E_ESCAN_RESULT); - setbit(eventmask, BRCMF_E_PFN_NET_FOUND); - - brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, - iovbuf, sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); - if (err) { - WL_ERR("Set event_msgs error (%d)\n", err); - goto dongle_eventmsg_out; - } +void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) +{ + if (!cfg) + return; -dongle_eventmsg_out: - WL_TRACE("Exit\n"); - return err; + WARN_ON(!list_empty(&cfg->vif_list)); + wiphy_unregister(cfg->wiphy); + brcmf_btcoex_detach(cfg); + wl_deinit_priv(cfg); + wiphy_free(cfg->wiphy); } static s32 -brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) +brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout) { - s8 iovbuf[32]; s32 err = 0; __le32 roamtrigger[2]; __le32 roam_delta[2]; - __le32 bcn_to_le; - __le32 roamvar_le; /* * Setup timeout if Beacons are lost and roam is * off to report link down */ - if (roamvar) { - bcn_to_le = cpu_to_le32(bcn_timeout); - brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le, - sizeof(bcn_to_le), iovbuf, sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, - iovbuf, sizeof(iovbuf)); + if (brcmf_roamoff) { + err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout); if (err) { - WL_ERR("bcn_timeout error (%d)\n", err); + brcmf_err("bcn_timeout error (%d)\n", err); goto dongle_rom_out; } } @@ -5305,31 +5118,29 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) * Enable/Disable built-in roaming to allow supplicant * to take care of roaming */ - WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On"); - roamvar_le = cpu_to_le32(roamvar); - brcmf_c_mkiovar("roam_off", (char *)&roamvar_le, - sizeof(roamvar_le), iovbuf, sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); + brcmf_dbg(INFO, "Internal Roaming = %s\n", + brcmf_roamoff ? "Off" : "On"); + err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff)); if (err) { - WL_ERR("roam_off error (%d)\n", err); + brcmf_err("roam_off error (%d)\n", err); goto dongle_rom_out; } roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL); roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER, - (void *)roamtrigger, sizeof(roamtrigger)); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER, + (void *)roamtrigger, sizeof(roamtrigger)); if (err) { - WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err); + brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err); goto dongle_rom_out; } roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA); roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA, - (void *)roam_delta, sizeof(roam_delta)); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA, + (void *)roam_delta, sizeof(roam_delta)); if (err) { - WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err); + brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err); goto dongle_rom_out; } @@ -5338,40 +5149,37 @@ dongle_rom_out: } static s32 -brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, +brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time, s32 scan_unassoc_time, s32 scan_passive_time) { s32 err = 0; - __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time); - __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time); - __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME, - &scan_assoc_tm_le, sizeof(scan_assoc_tm_le)); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, + scan_assoc_time); if (err) { if (err == -EOPNOTSUPP) - WL_INFO("Scan assoc time is not supported\n"); + brcmf_dbg(INFO, "Scan assoc time is not supported\n"); else - WL_ERR("Scan assoc time error (%d)\n", err); + brcmf_err("Scan assoc time error (%d)\n", err); goto dongle_scantime_out; } - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME, - &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le)); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME, + scan_unassoc_time); if (err) { if (err == -EOPNOTSUPP) - WL_INFO("Scan unassoc time is not supported\n"); + brcmf_dbg(INFO, "Scan unassoc time is not supported\n"); else - WL_ERR("Scan unassoc time error (%d)\n", err); + brcmf_err("Scan unassoc time error (%d)\n", err); goto dongle_scantime_out; } - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME, - &scan_passive_tm_le, sizeof(scan_passive_tm_le)); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME, + scan_passive_time); if (err) { if (err == -EOPNOTSUPP) - WL_INFO("Scan passive time is not supported\n"); + brcmf_dbg(INFO, "Scan passive time is not supported\n"); else - WL_ERR("Scan passive time error (%d)\n", err); + brcmf_err("Scan passive time error (%d)\n", err); goto dongle_scantime_out; } @@ -5379,39 +5187,337 @@ dongle_scantime_out: return err; } -static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg) + +static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, + u32 bw_cap[]) +{ + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct ieee80211_channel *band_chan_arr; + struct brcmf_chanspec_list *list; + struct brcmu_chan ch; + s32 err; + u8 *pbuf; + u32 i, j; + u32 total; + enum ieee80211_band band; + u32 channel; + u32 *n_cnt; + u32 index; + u32 ht40_flag; + bool update; + u32 array_size; + + pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); + + if (pbuf == NULL) + return -ENOMEM; + + list = (struct brcmf_chanspec_list *)pbuf; + + err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf, + BRCMF_DCMD_MEDLEN); + if (err) { + brcmf_err("get chanspecs error (%d)\n", err); + goto exit; + } + + __wl_band_2ghz.n_channels = 0; + __wl_band_5ghz_a.n_channels = 0; + + total = le32_to_cpu(list->count); + for (i = 0; i < total; i++) { + ch.chspec = (u16)le32_to_cpu(list->element[i]); + cfg->d11inf.decchspec(&ch); + + if (ch.band == BRCMU_CHAN_BAND_2G) { + band_chan_arr = __wl_2ghz_channels; + array_size = ARRAY_SIZE(__wl_2ghz_channels); + n_cnt = &__wl_band_2ghz.n_channels; + band = IEEE80211_BAND_2GHZ; + } else if (ch.band == BRCMU_CHAN_BAND_5G) { + band_chan_arr = __wl_5ghz_a_channels; + array_size = ARRAY_SIZE(__wl_5ghz_a_channels); + n_cnt = &__wl_band_5ghz_a.n_channels; + band = IEEE80211_BAND_5GHZ; + } else { + brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec); + continue; + } + if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) && + ch.bw == BRCMU_CHAN_BW_40) + continue; + if (!(bw_cap[band] & WLC_BW_80MHZ_BIT) && + ch.bw == BRCMU_CHAN_BW_80) + continue; + update = false; + for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { + if (band_chan_arr[j].hw_value == ch.chnum) { + update = true; + break; + } + } + if (update) + index = j; + else + index = *n_cnt; + if (index < array_size) { + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(ch.chnum, band); + band_chan_arr[index].hw_value = ch.chnum; + + /* assuming the chanspecs order is HT20, + * HT40 upper, HT40 lower, and VHT80. + */ + if (ch.bw == BRCMU_CHAN_BW_80) { + band_chan_arr[index].flags &= + ~IEEE80211_CHAN_NO_80MHZ; + } else if (ch.bw == BRCMU_CHAN_BW_40) { + ht40_flag = band_chan_arr[index].flags & + IEEE80211_CHAN_NO_HT40; + if (ch.sb == BRCMU_CHAN_SB_U) { + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags &= + ~IEEE80211_CHAN_NO_HT40; + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_HT40PLUS; + } else { + /* It should be one of + * IEEE80211_CHAN_NO_HT40 or + * IEEE80211_CHAN_NO_HT40PLUS + */ + band_chan_arr[index].flags &= + ~IEEE80211_CHAN_NO_HT40; + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_HT40MINUS; + } + } else { + /* disable other bandwidths for now as mentioned + * order assure they are enabled for subsequent + * chanspecs. + */ + band_chan_arr[index].flags = + IEEE80211_CHAN_NO_HT40 | + IEEE80211_CHAN_NO_80MHZ; + ch.bw = BRCMU_CHAN_BW_20; + cfg->d11inf.encchspec(&ch); + channel = ch.chspec; + err = brcmf_fil_bsscfg_int_get(ifp, + "per_chan_info", + &channel); + if (!err) { + if (channel & WL_CHAN_RADAR) + band_chan_arr[index].flags |= + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR); + if (channel & WL_CHAN_PASSIVE) + band_chan_arr[index].flags |= + IEEE80211_CHAN_NO_IR; + } + } + if (!update) + (*n_cnt)++; + } + } +exit: + kfree(pbuf); + return err; +} + +static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[]) { + u32 band, mimo_bwcap; + int err; + + band = WLC_BAND_2G; + err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band); + if (!err) { + bw_cap[IEEE80211_BAND_2GHZ] = band; + band = WLC_BAND_5G; + err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band); + if (!err) { + bw_cap[IEEE80211_BAND_5GHZ] = band; + return; + } + WARN_ON(1); + return; + } + brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n"); + mimo_bwcap = 0; + err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap); + if (err) + /* assume 20MHz if firmware does not give a clue */ + mimo_bwcap = WLC_N_BW_20ALL; + + switch (mimo_bwcap) { + case WLC_N_BW_40ALL: + bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT; + /* fall-thru */ + case WLC_N_BW_20IN2G_40IN5G: + bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT; + /* fall-thru */ + case WLC_N_BW_20ALL: + bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT; + bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT; + break; + default: + brcmf_err("invalid mimo_bw_cap value\n"); + } +} + +static void brcmf_update_ht_cap(struct ieee80211_supported_band *band, + u32 bw_cap[2], u32 nchain) +{ + band->ht_cap.ht_supported = true; + if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) { + band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; + band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; + band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + memset(band->ht_cap.mcs.rx_mask, 0xff, nchain); + band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +} + +static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp) +{ + u16 mcs_map; + int i; + + for (i = 0, mcs_map = 0xFFFF; i < nchain; i++) + mcs_map = (mcs_map << 2) | supp; + + return cpu_to_le16(mcs_map); +} + +static void brcmf_update_vht_cap(struct ieee80211_supported_band *band, + u32 bw_cap[2], u32 nchain) +{ + __le16 mcs_map; + + /* not allowed in 2.4G band */ + if (band->band == IEEE80211_BAND_2GHZ) + return; + + band->vht_cap.vht_supported = true; + /* 80MHz is mandatory */ + band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; + if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) { + band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160; + } + /* all support 256-QAM */ + mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9); + band->vht_cap.vht_mcs.rx_mcs_map = mcs_map; + band->vht_cap.vht_mcs.tx_mcs_map = mcs_map; +} + +static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct wiphy *wiphy; s32 phy_list; + u32 band_list[3]; + u32 nmode = 0; + u32 vhtmode = 0; + u32 bw_cap[2] = { 0, 0 }; + u32 rxchain; + u32 nchain; s8 phy; - s32 err = 0; + s32 err; + u32 nband; + s32 i; + struct ieee80211_supported_band *bands[2] = { NULL, NULL }; + struct ieee80211_supported_band *band; - err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCM_GET_PHYLIST, - &phy_list, sizeof(phy_list)); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST, + &phy_list, sizeof(phy_list)); if (err) { - WL_ERR("error (%d)\n", err); + brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err); return err; } phy = ((char *)&phy_list)[0]; - WL_INFO("%c phy\n", phy); - if (phy == 'n' || phy == 'a') { - wiphy = cfg_to_wiphy(cfg); - wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; + brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy); + + + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, + &band_list, sizeof(band_list)); + if (err) { + brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err); + return err; + } + brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n", + band_list[0], band_list[1], band_list[2]); + + (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); + } else { + brcmf_get_bwcap(ifp, bw_cap); } + brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n", + nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ], + bw_cap[IEEE80211_BAND_5GHZ]); + + err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain); + if (err) { + brcmf_err("rxchain error (%d)\n", err); + nchain = 1; + } else { + for (nchain = 0; rxchain; nchain++) + rxchain = rxchain & (rxchain - 1); + } + brcmf_dbg(INFO, "nchain=%d\n", nchain); + + err = brcmf_construct_reginfo(cfg, bw_cap); + if (err) { + brcmf_err("brcmf_construct_reginfo failed (%d)\n", err); + return err; + } + + nband = band_list[0]; + + for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) { + band = NULL; + if ((band_list[i] == WLC_BAND_5G) && + (__wl_band_5ghz_a.n_channels > 0)) + band = &__wl_band_5ghz_a; + else if ((band_list[i] == WLC_BAND_2G) && + (__wl_band_2ghz.n_channels > 0)) + band = &__wl_band_2ghz; + else + continue; + + if (nmode) + brcmf_update_ht_cap(band, bw_cap, nchain); + if (vhtmode) + brcmf_update_vht_cap(band, bw_cap, nchain); + bands[band->band] = band; + } + + wiphy = cfg_to_wiphy(cfg); + wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; + wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; + wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); return err; } + static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg) { - return wl_update_wiphybands(cfg); + return brcmf_update_wiphybands(cfg); } static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) { struct net_device *ndev; struct wireless_dev *wdev; + struct brcmf_if *ifp; s32 power_mode; s32 err = 0; @@ -5420,104 +5526,58 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) ndev = cfg_to_ndev(cfg); wdev = ndev->ieee80211_ptr; + ifp = netdev_priv(ndev); - brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, - WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); + /* make sure RF is ready for work */ + brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); - err = brcmf_dongle_eventmsg(ndev); - if (err) - goto default_conf_out; + brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME, + WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode); if (err) goto default_conf_out; - WL_INFO("power save set to %s\n", - (power_mode ? "enabled" : "disabled")); + brcmf_dbg(INFO, "power save set to %s\n", + (power_mode ? "enabled" : "disabled")); - err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1), - WL_BEACON_TIMEOUT); + err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT); if (err) goto default_conf_out; - err = brcmf_dongle_mode(ndev, wdev->iftype); - if (err && err != -EINPROGRESS) + err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, + NULL, NULL); + if (err) goto default_conf_out; err = brcmf_dongle_probecap(cfg); if (err) goto default_conf_out; - /* -EINPROGRESS: Call commit handler */ - -default_conf_out: + brcmf_configure_arp_offload(ifp, true); cfg->dongle_up = true; +default_conf_out: return err; } -static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_info *cfg) +static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp) { - char buf[10+IFNAMSIZ]; - struct dentry *fd; - s32 err = 0; - - sprintf(buf, "netdev:%s", cfg_to_ndev(cfg)->name); - cfg->debugfsdir = debugfs_create_dir(buf, - cfg_to_wiphy(cfg)->debugfsdir); - - fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg->debugfsdir, - (u16 *)&cfg->profile->beacon_interval); - if (!fd) { - err = -ENOMEM; - goto err_out; - } + set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); - fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg->debugfsdir, - (u8 *)&cfg->profile->dtim_period); - if (!fd) { - err = -ENOMEM; - goto err_out; - } - -err_out: - return err; + return brcmf_config_dongle(ifp->drvr->config); } -static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_info *cfg) +static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) { - debugfs_remove_recursive(cfg->debugfsdir); - cfg->debugfsdir = NULL; -} - -static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) -{ - s32 err = 0; - - set_bit(WL_STATUS_READY, &cfg->status); - - brcmf_debugfs_add_netdev_params(cfg); - - err = brcmf_config_dongle(cfg); - if (err) - return err; - - brcmf_invoke_iscan(cfg); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - return err; -} - -static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) -{ /* * While going down, if associated with AP disassociate * from AP to save power */ - if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) || - test_bit(WL_STATUS_CONNECTING, &cfg->status)) && - test_bit(WL_STATUS_READY, &cfg->status)) { - WL_INFO("Disassociating from AP"); - brcmf_link_down(cfg); + if (check_vif_up(ifp->vif)) { + brcmf_link_down(ifp->vif); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep @@ -5527,32 +5587,95 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) } brcmf_abort_scanning(cfg); - clear_bit(WL_STATUS_READY, &cfg->status); - - brcmf_debugfs_remove_netdev(cfg); + clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); return 0; } -s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) +s32 brcmf_cfg80211_up(struct net_device *ndev) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; mutex_lock(&cfg->usr_sync); - err = __brcmf_cfg80211_up(cfg); + err = __brcmf_cfg80211_up(ifp); mutex_unlock(&cfg->usr_sync); return err; } -s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) +s32 brcmf_cfg80211_down(struct net_device *ndev) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; mutex_lock(&cfg->usr_sync); - err = __brcmf_cfg80211_down(cfg); + err = __brcmf_cfg80211_down(ifp); mutex_unlock(&cfg->usr_sync); return err; } +enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp) +{ + struct wireless_dev *wdev = &ifp->vif->wdev; + + return wdev->iftype; +} + +u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state) +{ + struct brcmf_cfg80211_vif *vif; + bool result = 0; + + list_for_each_entry(vif, &cfg->vif_list, list) { + if (test_bit(state, &vif->sme_state)) + result++; + } + return result; +} + +static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event, + u8 action) +{ + u8 evt_action; + + mutex_lock(&event->vif_event_lock); + evt_action = event->action; + mutex_unlock(&event->vif_event_lock); + return evt_action == action; +} + +void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, + struct brcmf_cfg80211_vif *vif) +{ + struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; + + mutex_lock(&event->vif_event_lock); + event->vif = vif; + event->action = 0; + mutex_unlock(&event->vif_event_lock); +} + +bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; + bool armed; + + mutex_lock(&event->vif_event_lock); + armed = event->vif != NULL; + mutex_unlock(&event->vif_event_lock); + + return armed; +} +int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, + u8 action, ulong timeout) +{ + struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; + + return wait_event_timeout(event->vif_wq, + vif_event_equals(event, action), timeout); +} + |
