Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 4.20. Major changes: ath10k * limit available channels via DT ieee80211-freq-limit wil6210 * add 802.11r Fast Roaming support for AP and station modes * add support for channel 4
This commit is contained in:
commit
9cac6a9b62
@ -655,10 +655,10 @@ static void ath10k_ahb_hif_stop(struct ath10k *ar)
|
||||
ath10k_ahb_irq_disable(ar);
|
||||
synchronize_irq(ar_ahb->irq);
|
||||
|
||||
ath10k_pci_flush(ar);
|
||||
|
||||
napi_synchronize(&ar->napi);
|
||||
napi_disable(&ar->napi);
|
||||
|
||||
ath10k_pci_flush(ar);
|
||||
}
|
||||
|
||||
static int ath10k_ahb_hif_power_up(struct ath10k *ar)
|
||||
|
@ -1416,10 +1416,8 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
|
||||
|
||||
nentries = roundup_pow_of_two(nentries);
|
||||
|
||||
src_ring = kzalloc(sizeof(*src_ring) +
|
||||
(nentries *
|
||||
sizeof(*src_ring->per_transfer_context)),
|
||||
GFP_KERNEL);
|
||||
src_ring = kzalloc(struct_size(src_ring, per_transfer_context,
|
||||
nentries), GFP_KERNEL);
|
||||
if (src_ring == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -1476,10 +1474,8 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id,
|
||||
|
||||
nentries = roundup_pow_of_two(nentries);
|
||||
|
||||
src_ring = kzalloc(sizeof(*src_ring) +
|
||||
(nentries *
|
||||
sizeof(*src_ring->per_transfer_context)),
|
||||
GFP_KERNEL);
|
||||
src_ring = kzalloc(struct_size(src_ring, per_transfer_context,
|
||||
nentries), GFP_KERNEL);
|
||||
if (!src_ring)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -1534,10 +1530,8 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
|
||||
|
||||
nentries = roundup_pow_of_two(attr->dest_nentries);
|
||||
|
||||
dest_ring = kzalloc(sizeof(*dest_ring) +
|
||||
(nentries *
|
||||
sizeof(*dest_ring->per_transfer_context)),
|
||||
GFP_KERNEL);
|
||||
dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context,
|
||||
nentries), GFP_KERNEL);
|
||||
if (dest_ring == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -1580,10 +1574,8 @@ ath10k_ce_alloc_dest_ring_64(struct ath10k *ar, unsigned int ce_id,
|
||||
|
||||
nentries = roundup_pow_of_two(attr->dest_nentries);
|
||||
|
||||
dest_ring = kzalloc(sizeof(*dest_ring) +
|
||||
(nentries *
|
||||
sizeof(*dest_ring->per_transfer_context)),
|
||||
GFP_KERNEL);
|
||||
dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context,
|
||||
nentries), GFP_KERNEL);
|
||||
if (!dest_ring)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
@ -91,6 +91,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA988X_HW_2_0_VERSION,
|
||||
@ -124,6 +125,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA9887_HW_1_0_VERSION,
|
||||
@ -157,6 +159,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_2_1_VERSION,
|
||||
@ -189,6 +192,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_2_1_VERSION,
|
||||
@ -221,6 +225,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_3_0_VERSION,
|
||||
@ -253,6 +258,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_3_2_VERSION,
|
||||
@ -288,6 +294,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA99X0_HW_2_0_DEV_VERSION,
|
||||
@ -326,6 +333,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA9984_HW_1_0_DEV_VERSION,
|
||||
@ -369,6 +377,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA9888_HW_2_0_DEV_VERSION,
|
||||
@ -411,6 +420,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA9377_HW_1_0_DEV_VERSION,
|
||||
@ -443,6 +453,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA9377_HW_1_1_DEV_VERSION,
|
||||
@ -477,6 +488,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = QCA4019_HW_1_0_DEV_VERSION,
|
||||
@ -516,6 +528,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = false,
|
||||
.shadow_reg_support = false,
|
||||
.rri_on_ddr = false,
|
||||
.hw_filter_reset_required = true,
|
||||
},
|
||||
{
|
||||
.id = WCN3990_HW_1_0_DEV_VERSION,
|
||||
@ -539,6 +552,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.per_ce_irq = true,
|
||||
.shadow_reg_support = true,
|
||||
.rri_on_ddr = true,
|
||||
.hw_filter_reset_required = false,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2405,7 +2419,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
||||
* possible to implicitly make it correct by creating a dummy vdev and
|
||||
* then deleting it.
|
||||
*/
|
||||
if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
|
||||
if (ar->hw_params.hw_filter_reset_required &&
|
||||
mode == ATH10K_FIRMWARE_MODE_NORMAL) {
|
||||
status = ath10k_core_reset_rx_filter(ar);
|
||||
if (status) {
|
||||
ath10k_err(ar,
|
||||
|
@ -589,6 +589,11 @@ struct ath10k_hw_params {
|
||||
|
||||
/* Number of bytes to be the offset for each FFT sample */
|
||||
int spectral_bin_offset;
|
||||
|
||||
/* targets which require hw filter reset during boot up,
|
||||
* to avoid it sending spurious acks.
|
||||
*/
|
||||
bool hw_filter_reset_required;
|
||||
};
|
||||
|
||||
struct htt_rx_desc;
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "mac.h"
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/acpi.h>
|
||||
@ -8359,6 +8360,7 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
|
||||
}
|
||||
|
||||
wiphy_read_of_freq_limits(ar->hw->wiphy);
|
||||
ath10k_mac_setup_ht_vht_cap(ar);
|
||||
|
||||
ar->hw->wiphy->interface_modes =
|
||||
|
@ -2068,9 +2068,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
|
||||
|
||||
ath10k_pci_irq_disable(ar);
|
||||
ath10k_pci_irq_sync(ar);
|
||||
ath10k_pci_flush(ar);
|
||||
napi_synchronize(&ar->napi);
|
||||
napi_disable(&ar->napi);
|
||||
ath10k_pci_flush(ar);
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
WARN_ON(ar_pci->ps_wake_refcount > 0);
|
||||
|
@ -1869,6 +1869,12 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
|
||||
if (ret)
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n",
|
||||
cmd_id);
|
||||
queue_work(ar->workqueue, &ar->restart_work);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -638,7 +638,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
|
||||
memcpy(vif->bssid, bssid, sizeof(vif->bssid));
|
||||
vif->bss_ch = channel;
|
||||
|
||||
if ((vif->nw_type == INFRA_NETWORK)) {
|
||||
if (vif->nw_type == INFRA_NETWORK) {
|
||||
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
vif->listen_intvl_t, 0);
|
||||
ath6kl_check_ch_switch(ar, channel);
|
||||
|
@ -37,10 +37,6 @@
|
||||
#define AR5008_11NG_HT_SS_SHIFT 12
|
||||
#define AR5008_11NG_HT_DS_SHIFT 20
|
||||
|
||||
static const int firstep_table[] =
|
||||
/* level: 0 1 2 3 4 5 6 7 8 */
|
||||
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
|
||||
|
||||
/*
|
||||
* register values to turn OFDM weak signal detection OFF
|
||||
*/
|
||||
|
@ -1074,7 +1074,6 @@ struct ath_softc {
|
||||
|
||||
struct ath_spec_scan_priv spec_priv;
|
||||
|
||||
struct ieee80211_vif *tx99_vif;
|
||||
struct sk_buff *tx99_skb;
|
||||
bool tx99_state;
|
||||
s16 tx99_power;
|
||||
|
@ -116,7 +116,7 @@ void ath_debug_rate_stats(struct ath_softc *sc,
|
||||
if (rxs->rate_idx >= ARRAY_SIZE(rstats->ht_stats))
|
||||
goto exit;
|
||||
|
||||
if ((rxs->bw == RATE_INFO_BW_40))
|
||||
if (rxs->bw == RATE_INFO_BW_40)
|
||||
rstats->ht_stats[rxs->rate_idx].ht40_cnt++;
|
||||
else
|
||||
rstats->ht_stats[rxs->rate_idx].ht20_cnt++;
|
||||
|
@ -1251,15 +1251,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
struct ath_node *an = &avp->mcast_node;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
if (IS_ENABLED(CONFIG_ATH9K_TX99))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ATH9K_TX99)) {
|
||||
if (sc->cur_chan->nvifs >= 1) {
|
||||
mutex_unlock(&sc->mutex);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
sc->tx99_vif = vif;
|
||||
}
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
|
||||
sc->cur_chan->nvifs++;
|
||||
@ -1342,7 +1337,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
|
||||
ath9k_p2p_remove_vif(sc, vif);
|
||||
|
||||
sc->cur_chan->nvifs--;
|
||||
sc->tx99_vif = NULL;
|
||||
if (!ath9k_is_chanctx_enabled())
|
||||
list_del(&avp->list);
|
||||
|
||||
|
@ -54,12 +54,6 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct sk_buff *skb;
|
||||
struct ath_vif *avp;
|
||||
|
||||
if (!sc->tx99_vif)
|
||||
return NULL;
|
||||
|
||||
avp = (struct ath_vif *)sc->tx99_vif->drv_priv;
|
||||
|
||||
skb = alloc_skb(len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
@ -77,14 +71,11 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
|
||||
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
|
||||
|
||||
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
rate = &tx_info->control.rates[0];
|
||||
tx_info->band = sc->cur_chan->chandef.chan->band;
|
||||
tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
|
||||
tx_info->control.vif = sc->tx99_vif;
|
||||
rate->count = 1;
|
||||
if (ah->curchan && IS_CHAN_HT(ah->curchan)) {
|
||||
rate->flags |= IEEE80211_TX_RC_MCS;
|
||||
|
@ -2973,7 +2973,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ath_set_rates(sc->tx99_vif, NULL, bf);
|
||||
ath_set_rates(NULL, NULL, bf);
|
||||
|
||||
ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
|
||||
ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
|
||||
|
@ -174,13 +174,12 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn
|
||||
int i;
|
||||
|
||||
size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc);
|
||||
wcn_ch->cpu_addr = dma_alloc_coherent(dev, size, &wcn_ch->dma_addr,
|
||||
GFP_KERNEL);
|
||||
wcn_ch->cpu_addr = dma_zalloc_coherent(dev, size,
|
||||
&wcn_ch->dma_addr,
|
||||
GFP_KERNEL);
|
||||
if (!wcn_ch->cpu_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(wcn_ch->cpu_addr, 0, size);
|
||||
|
||||
cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr;
|
||||
cur_ctl = wcn_ch->head_blk_ctl;
|
||||
|
||||
@ -628,13 +627,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
|
||||
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
|
||||
|
||||
s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H;
|
||||
cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->mgmt_mem_pool.phy_addr,
|
||||
GFP_KERNEL);
|
||||
cpu_addr = dma_zalloc_coherent(wcn->dev, s,
|
||||
&wcn->mgmt_mem_pool.phy_addr,
|
||||
GFP_KERNEL);
|
||||
if (!cpu_addr)
|
||||
goto out_err;
|
||||
|
||||
wcn->mgmt_mem_pool.virt_addr = cpu_addr;
|
||||
memset(cpu_addr, 0, s);
|
||||
|
||||
/* Allocate BD headers for DATA frames */
|
||||
|
||||
@ -643,13 +642,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
|
||||
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
|
||||
|
||||
s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L;
|
||||
cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->data_mem_pool.phy_addr,
|
||||
GFP_KERNEL);
|
||||
cpu_addr = dma_zalloc_coherent(wcn->dev, s,
|
||||
&wcn->data_mem_pool.phy_addr,
|
||||
GFP_KERNEL);
|
||||
if (!cpu_addr)
|
||||
goto out_err;
|
||||
|
||||
wcn->data_mem_pool.virt_addr = cpu_addr;
|
||||
memset(cpu_addr, 0, s);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -792,10 +792,10 @@ static int wcn36xx_smd_process_ptt_msg_rsp(void *buf, size_t len,
|
||||
rsp->header.len - sizeof(rsp->ptt_msg_resp_status));
|
||||
|
||||
if (rsp->header.len > 0) {
|
||||
*p_ptt_rsp_msg = kmalloc(rsp->header.len, GFP_ATOMIC);
|
||||
*p_ptt_rsp_msg = kmemdup(rsp->ptt_msg, rsp->header.len,
|
||||
GFP_ATOMIC);
|
||||
if (!*p_ptt_rsp_msg)
|
||||
return -ENOMEM;
|
||||
memcpy(*p_ptt_rsp_msg, rsp->ptt_msg, rsp->header.len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -48,9 +48,29 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
|
||||
CHAN60G(1, 0),
|
||||
CHAN60G(2, 0),
|
||||
CHAN60G(3, 0),
|
||||
/* channel 4 not supported yet */
|
||||
CHAN60G(4, 0),
|
||||
};
|
||||
|
||||
static int wil_num_supported_channels(struct wil6210_priv *wil)
|
||||
{
|
||||
int num_channels = ARRAY_SIZE(wil_60ghz_channels);
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities))
|
||||
num_channels--;
|
||||
|
||||
return num_channels;
|
||||
}
|
||||
|
||||
void update_supported_bands(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
|
||||
wil_dbg_misc(wil, "update supported bands");
|
||||
|
||||
wiphy->bands[NL80211_BAND_60GHZ]->n_channels =
|
||||
wil_num_supported_channels(wil);
|
||||
}
|
||||
|
||||
/* Vendor id to be used in vendor specific command and events
|
||||
* to user space.
|
||||
* NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
|
||||
@ -199,7 +219,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
|
||||
BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
|
||||
BIT(IEEE80211_STYPE_DISASSOC >> 4),
|
||||
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
||||
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
||||
BIT(IEEE80211_STYPE_REASSOC_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
||||
BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
||||
@ -871,6 +893,26 @@ static void wil_print_crypto(struct wil6210_priv *wil,
|
||||
c->control_port_no_encrypt);
|
||||
}
|
||||
|
||||
static const char *
|
||||
wil_get_auth_type_name(enum nl80211_auth_type auth_type)
|
||||
{
|
||||
switch (auth_type) {
|
||||
case NL80211_AUTHTYPE_OPEN_SYSTEM:
|
||||
return "OPEN_SYSTEM";
|
||||
case NL80211_AUTHTYPE_SHARED_KEY:
|
||||
return "SHARED_KEY";
|
||||
case NL80211_AUTHTYPE_FT:
|
||||
return "FT";
|
||||
case NL80211_AUTHTYPE_NETWORK_EAP:
|
||||
return "NETWORK_EAP";
|
||||
case NL80211_AUTHTYPE_SAE:
|
||||
return "SAE";
|
||||
case NL80211_AUTHTYPE_AUTOMATIC:
|
||||
return "AUTOMATIC";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
static void wil_print_connect_params(struct wil6210_priv *wil,
|
||||
struct cfg80211_connect_params *sme)
|
||||
{
|
||||
@ -884,11 +926,73 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
|
||||
if (sme->ssid)
|
||||
print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
|
||||
16, 1, sme->ssid, sme->ssid_len, true);
|
||||
if (sme->prev_bssid)
|
||||
wil_info(wil, " Previous BSSID=%pM\n", sme->prev_bssid);
|
||||
wil_info(wil, " Auth Type: %s\n",
|
||||
wil_get_auth_type_name(sme->auth_type));
|
||||
wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
|
||||
wil_info(wil, " PBSS: %d\n", sme->pbss);
|
||||
wil_print_crypto(wil, &sme->crypto);
|
||||
}
|
||||
|
||||
static int wil_ft_connect(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_connect_params *sme)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
struct wmi_ft_auth_cmd auth_cmd;
|
||||
int rc;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
|
||||
wil_err(wil, "FT: FW does not support FT roaming\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!sme->prev_bssid) {
|
||||
wil_err(wil, "FT: prev_bssid was not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ether_addr_equal(sme->prev_bssid, sme->bssid)) {
|
||||
wil_err(wil, "FT: can not roam to same AP\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!test_bit(wil_vif_fwconnected, vif->status)) {
|
||||
wil_err(wil, "FT: roam while not connected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vif->privacy != sme->privacy) {
|
||||
wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n",
|
||||
vif->privacy, sme->privacy);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sme->pbss) {
|
||||
wil_err(wil, "FT: roam is not valid for PBSS\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&auth_cmd, 0, sizeof(auth_cmd));
|
||||
auth_cmd.channel = sme->channel->hw_value - 1;
|
||||
ether_addr_copy(auth_cmd.bssid, sme->bssid);
|
||||
|
||||
wil_info(wil, "FT: roaming\n");
|
||||
|
||||
set_bit(wil_vif_ft_roam, vif->status);
|
||||
rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid,
|
||||
&auth_cmd, sizeof(auth_cmd));
|
||||
if (rc == 0)
|
||||
mod_timer(&vif->connect_timer,
|
||||
jiffies + msecs_to_jiffies(5000));
|
||||
else
|
||||
clear_bit(wil_vif_ft_roam, vif->status);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_connect_params *sme)
|
||||
@ -901,14 +1005,23 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
const u8 *rsn_eid;
|
||||
int ch;
|
||||
int rc = 0;
|
||||
bool is_ft_roam = false;
|
||||
u8 network_type;
|
||||
enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
|
||||
|
||||
wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
|
||||
wil_print_connect_params(wil, sme);
|
||||
|
||||
if (test_bit(wil_vif_fwconnecting, vif->status) ||
|
||||
if (sme->auth_type == NL80211_AUTHTYPE_FT)
|
||||
is_ft_roam = true;
|
||||
if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC &&
|
||||
test_bit(wil_vif_fwconnected, vif->status))
|
||||
return -EALREADY;
|
||||
is_ft_roam = true;
|
||||
|
||||
if (!is_ft_roam)
|
||||
if (test_bit(wil_vif_fwconnecting, vif->status) ||
|
||||
test_bit(wil_vif_fwconnected, vif->status))
|
||||
return -EALREADY;
|
||||
|
||||
if (sme->ie_len > WMI_MAX_IE_LEN) {
|
||||
wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len);
|
||||
@ -918,8 +1031,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
rsn_eid = sme->ie ?
|
||||
cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
|
||||
NULL;
|
||||
if (sme->privacy && !rsn_eid)
|
||||
if (sme->privacy && !rsn_eid) {
|
||||
wil_info(wil, "WSC connection\n");
|
||||
if (is_ft_roam) {
|
||||
wil_err(wil, "No WSC with FT roam\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sme->pbss)
|
||||
bss_type = IEEE80211_BSS_TYPE_PBSS;
|
||||
@ -941,6 +1059,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
vif->privacy = sme->privacy;
|
||||
vif->pbss = sme->pbss;
|
||||
|
||||
rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
|
||||
case WLAN_CAPABILITY_DMG_TYPE_AP:
|
||||
network_type = WMI_NETTYPE_INFRA;
|
||||
break;
|
||||
case WLAN_CAPABILITY_DMG_TYPE_PBSS:
|
||||
network_type = WMI_NETTYPE_P2P;
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
|
||||
bss->capability);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ch = bss->channel->hw_value;
|
||||
if (ch == 0) {
|
||||
wil_err(wil, "BSS at unknown frequency %dMhz\n",
|
||||
bss->channel->center_freq);
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_ft_roam) {
|
||||
if (network_type != WMI_NETTYPE_INFRA) {
|
||||
wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n",
|
||||
bss->capability);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
rc = wil_ft_connect(wiphy, ndev, sme);
|
||||
if (rc == 0)
|
||||
vif->bss = bss;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (vif->privacy) {
|
||||
/* For secure assoc, remove old keys */
|
||||
rc = wmi_del_cipher_key(vif, 0, bss->bssid,
|
||||
@ -957,28 +1114,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
}
|
||||
}
|
||||
|
||||
/* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
|
||||
* elements. Send it also in case it's empty, to erase previously set
|
||||
* ies in FW.
|
||||
*/
|
||||
rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* WMI_CONNECT_CMD */
|
||||
memset(&conn, 0, sizeof(conn));
|
||||
switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
|
||||
case WLAN_CAPABILITY_DMG_TYPE_AP:
|
||||
conn.network_type = WMI_NETTYPE_INFRA;
|
||||
break;
|
||||
case WLAN_CAPABILITY_DMG_TYPE_PBSS:
|
||||
conn.network_type = WMI_NETTYPE_P2P;
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
|
||||
bss->capability);
|
||||
goto out;
|
||||
}
|
||||
conn.network_type = network_type;
|
||||
if (vif->privacy) {
|
||||
if (rsn_eid) { /* regular secure connection */
|
||||
conn.dot11_auth_mode = WMI_AUTH11_SHARED;
|
||||
@ -998,14 +1136,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
|
||||
conn.ssid_len = min_t(u8, ssid_eid[1], 32);
|
||||
memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
|
||||
|
||||
ch = bss->channel->hw_value;
|
||||
if (ch == 0) {
|
||||
wil_err(wil, "BSS at unknown frequency %dMhz\n",
|
||||
bss->channel->center_freq);
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
conn.channel = ch - 1;
|
||||
|
||||
ether_addr_copy(conn.bssid, bss->bssid);
|
||||
@ -1201,9 +1331,9 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid,
|
||||
return &wil->sta[cid];
|
||||
}
|
||||
|
||||
static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
|
||||
struct wil_sta_info *cs,
|
||||
struct key_params *params)
|
||||
void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
|
||||
struct wil_sta_info *cs,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct wil_tid_crypto_rx_single *cc;
|
||||
int tid;
|
||||
@ -1286,13 +1416,19 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
||||
params->seq_len, params->seq);
|
||||
|
||||
if (IS_ERR(cs)) {
|
||||
wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
|
||||
mac_addr, key_usage_str[key_usage], key_index,
|
||||
params->seq_len, params->seq);
|
||||
return -EINVAL;
|
||||
/* in FT, sta info may not be available as add_key may be
|
||||
* sent by host before FW sends WMI_CONNECT_EVENT
|
||||
*/
|
||||
if (!test_bit(wil_vif_ft_roam, vif->status)) {
|
||||
wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
|
||||
mac_addr, key_usage_str[key_usage], key_index,
|
||||
params->seq_len, params->seq);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
wil_del_rx_key(key_index, key_usage, cs);
|
||||
if (!IS_ERR(cs))
|
||||
wil_del_rx_key(key_index, key_usage, cs);
|
||||
|
||||
if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
|
||||
wil_err(wil,
|
||||
@ -1305,7 +1441,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
||||
|
||||
rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
|
||||
params->key, key_usage);
|
||||
if (!rc)
|
||||
if (!rc && !IS_ERR(cs))
|
||||
/* in FT set crypto will take place upon receiving
|
||||
* WMI_RING_EN_EVENTID event
|
||||
*/
|
||||
wil_set_crypto_rx(key_index, key_usage, cs, params);
|
||||
|
||||
return rc;
|
||||
@ -1468,21 +1607,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
|
||||
}
|
||||
|
||||
/* internal functions for device reset and starting AP */
|
||||
static u8 *
|
||||
_wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len,
|
||||
u16 *ies_len)
|
||||
{
|
||||
u8 *ies = NULL;
|
||||
|
||||
if (proberesp) {
|
||||
struct ieee80211_mgmt *f =
|
||||
(struct ieee80211_mgmt *)proberesp;
|
||||
size_t hlen = offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
|
||||
ies = f->u.probe_resp.variable;
|
||||
if (ies_len)
|
||||
*ies_len = proberesp_len - hlen;
|
||||
}
|
||||
|
||||
return ies;
|
||||
}
|
||||
|
||||
static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
|
||||
struct cfg80211_beacon_data *bcon)
|
||||
{
|
||||
int rc;
|
||||
u16 len = 0, proberesp_len = 0;
|
||||
u8 *ies = NULL, *proberesp = NULL;
|
||||
u8 *ies = NULL, *proberesp;
|
||||
|
||||
if (bcon->probe_resp) {
|
||||
struct ieee80211_mgmt *f =
|
||||
(struct ieee80211_mgmt *)bcon->probe_resp;
|
||||
size_t hlen = offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
proberesp = f->u.probe_resp.variable;
|
||||
proberesp_len = bcon->probe_resp_len - hlen;
|
||||
}
|
||||
proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
|
||||
bcon->probe_resp_len,
|
||||
&proberesp_len);
|
||||
rc = _wil_cfg80211_merge_extra_ies(proberesp,
|
||||
proberesp_len,
|
||||
bcon->proberesp_ies,
|
||||
@ -1526,6 +1680,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
|
||||
u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
|
||||
u16 proberesp_len = 0;
|
||||
u8 *proberesp;
|
||||
bool ft = false;
|
||||
|
||||
if (pbss)
|
||||
wmi_nettype = WMI_NETTYPE_P2P;
|
||||
@ -1538,6 +1695,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
|
||||
wil_set_recovery_state(wil, fw_recovery_idle);
|
||||
|
||||
proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
|
||||
bcon->probe_resp_len,
|
||||
&proberesp_len);
|
||||
/* check that the probe response IEs has a MDE */
|
||||
if ((proberesp && proberesp_len > 0 &&
|
||||
cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN,
|
||||
proberesp,
|
||||
proberesp_len)))
|
||||
ft = true;
|
||||
|
||||
if (ft) {
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING,
|
||||
wil->fw_capabilities)) {
|
||||
wil_err(wil, "FW does not support FT roaming\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
set_bit(wil_vif_ft_roam, vif->status);
|
||||
}
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
|
||||
@ -1699,6 +1875,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
wmi_pcp_stop(vif);
|
||||
clear_bit(wil_vif_ft_roam, vif->status);
|
||||
|
||||
if (last)
|
||||
__wil_down(wil);
|
||||
@ -1718,8 +1895,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
|
||||
struct wil6210_vif *vif = ndev_to_vif(dev);
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "add station %pM aid %d mid %d\n",
|
||||
mac, params->aid, vif->mid);
|
||||
wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n",
|
||||
mac, params->aid, vif->mid,
|
||||
params->sta_flags_mask, params->sta_flags_set);
|
||||
|
||||
if (!disable_ap_sme) {
|
||||
wil_err(wil, "not supported with AP SME enabled\n");
|
||||
@ -2040,6 +2218,54 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_update_ft_ies_params *ftie)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wil6210_vif *vif = ndev_to_vif(dev);
|
||||
struct cfg80211_bss *bss;
|
||||
struct wmi_ft_reassoc_cmd reassoc;
|
||||
int rc = 0;
|
||||
|
||||
wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid);
|
||||
wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
ftie->ie, ftie->ie_len, true);
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
|
||||
wil_err(wil, "FW does not support FT roaming\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!test_bit(wil_vif_ft_roam, vif->status))
|
||||
/* vif is not roaming */
|
||||
return 0;
|
||||
|
||||
/* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as
|
||||
* a trigger for reassoc
|
||||
*/
|
||||
|
||||
bss = vif->bss;
|
||||
if (!bss) {
|
||||
wil_err(wil, "FT: bss is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&reassoc, 0, sizeof(reassoc));
|
||||
ether_addr_copy(reassoc.bssid, bss->bssid);
|
||||
|
||||
rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid,
|
||||
&reassoc, sizeof(reassoc));
|
||||
if (rc)
|
||||
wil_err(wil, "FT: reassoc failed (%d)\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct cfg80211_ops wil_cfg80211_ops = {
|
||||
.add_virtual_intf = wil_cfg80211_add_iface,
|
||||
.del_virtual_intf = wil_cfg80211_del_iface,
|
||||
@ -2075,6 +2301,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
|
||||
.resume = wil_cfg80211_resume,
|
||||
.sched_scan_start = wil_cfg80211_sched_scan_start,
|
||||
.sched_scan_stop = wil_cfg80211_sched_scan_stop,
|
||||
.update_ft_ies = wil_cfg80211_update_ft_ies,
|
||||
};
|
||||
|
||||
static void wil_wiphy_init(struct wiphy *wiphy)
|
||||
|
@ -725,32 +725,6 @@ struct dentry *wil_debugfs_create_ioblob(const char *name,
|
||||
return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
|
||||
}
|
||||
|
||||
/*---reset---*/
|
||||
static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
|
||||
/**
|
||||
* BUG:
|
||||
* this code does NOT sync device state with the rest of system
|
||||
* use with care, debug only!!!
|
||||
*/
|
||||
rtnl_lock();
|
||||
dev_close(ndev);
|
||||
ndev->flags &= ~IFF_UP;
|
||||
rtnl_unlock();
|
||||
wil_reset(wil, true);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_reset = {
|
||||
.write = wil_write_file_reset,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
|
||||
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
@ -1263,6 +1237,9 @@ static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data)
|
||||
int num_active;
|
||||
int num_free;
|
||||
|
||||
if (!rbm->buff_arr)
|
||||
return -EINVAL;
|
||||
|
||||
seq_printf(s, " size = %zu\n", rbm->size);
|
||||
seq_printf(s, " free_list_empty_cnt = %lu\n",
|
||||
rbm->free_list_empty_cnt);
|
||||
@ -1695,6 +1672,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
||||
char *status = "unknown";
|
||||
u8 aid = 0;
|
||||
u8 mid;
|
||||
bool sta_connected = false;
|
||||
|
||||
switch (p->status) {
|
||||
case wil_sta_unused:
|
||||
@ -1709,8 +1687,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
||||
break;
|
||||
}
|
||||
mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
|
||||
seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
|
||||
mid, aid);
|
||||
if (mid < wil->max_vifs) {
|
||||
struct wil6210_vif *vif = wil->vifs[mid];
|
||||
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
|
||||
p->status == wil_sta_connected)
|
||||
sta_connected = true;
|
||||
}
|
||||
/* print roam counter only for connected stations */
|
||||
if (sta_connected)
|
||||
seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
|
||||
i, p->addr, p->stats.ft_roams, mid, aid);
|
||||
else
|
||||
seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i,
|
||||
p->addr, status, mid, aid);
|
||||
|
||||
if (p->status == wil_sta_connected) {
|
||||
spin_lock_bh(&p->tid_rx_lock);
|
||||
@ -2451,7 +2441,6 @@ static const struct {
|
||||
{"desc", 0444, &fops_txdesc},
|
||||
{"bf", 0444, &fops_bf},
|
||||
{"mem_val", 0644, &fops_memread},
|
||||
{"reset", 0244, &fops_reset},
|
||||
{"rxon", 0244, &fops_rxon},
|
||||
{"tx_mgmt", 0244, &fops_txmgmt},
|
||||
{"wmi_send", 0244, &fops_wmi},
|
||||
|
@ -223,6 +223,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
int min_ring_id = wil_get_min_tx_ring_id(wil);
|
||||
|
||||
might_sleep();
|
||||
wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
|
||||
@ -273,7 +274,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx));
|
||||
memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx));
|
||||
/* release vrings */
|
||||
for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) {
|
||||
for (i = min_ring_id; i < ARRAY_SIZE(wil->ring_tx); i++) {
|
||||
if (wil->ring2cid_tid[i][0] == cid)
|
||||
wil_ring_fini_tx(wil, i);
|
||||
}
|
||||
@ -360,6 +361,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
vif->bss = NULL;
|
||||
}
|
||||
clear_bit(wil_vif_fwconnecting, vif->status);
|
||||
clear_bit(wil_vif_ft_roam, vif->status);
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
@ -604,8 +607,10 @@ int wil_priv_init(struct wil6210_priv *wil)
|
||||
wil->sta[i].mid = U8_MAX;
|
||||
}
|
||||
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
spin_lock_init(&wil->ring_tx_data[i].lock);
|
||||
wil->ring2cid_tid[i][0] = WIL6210_MAX_CID;
|
||||
}
|
||||
|
||||
mutex_init(&wil->mutex);
|
||||
mutex_init(&wil->vif_mutex);
|
||||
@ -653,8 +658,6 @@ int wil_priv_init(struct wil6210_priv *wil)
|
||||
|
||||
/* edma configuration can be updated via debugfs before allocation */
|
||||
wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS;
|
||||
wil->use_compressed_rx_status = true;
|
||||
wil->use_rx_hw_reordering = true;
|
||||
wil->tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT;
|
||||
|
||||
/* Rx status ring size should be bigger than the number of RX buffers
|
||||
@ -1154,6 +1157,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
|
||||
wil->max_agg_wsize = WIL_MAX_AGG_WSIZE;
|
||||
wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE;
|
||||
}
|
||||
|
||||
update_supported_bands(wil);
|
||||
}
|
||||
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
|
||||
|
@ -108,6 +108,7 @@ int wil_set_capabilities(struct wil6210_priv *wil)
|
||||
set_bit(hw_capa_no_flash, wil->hw_capa);
|
||||
wil->use_enhanced_dma_hw = true;
|
||||
wil->use_rx_hw_reordering = true;
|
||||
wil->use_compressed_rx_status = true;
|
||||
wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
|
||||
WIL_FW_NAME_TALYN;
|
||||
if (wil_fw_verify_file_exists(wil, wil_fw_name))
|
||||
|
@ -382,11 +382,13 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
}
|
||||
|
||||
/* apply */
|
||||
r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
|
||||
spin_lock_bh(&sta->tid_rx_lock);
|
||||
wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
|
||||
sta->tid_rx[tid] = r;
|
||||
spin_unlock_bh(&sta->tid_rx_lock);
|
||||
if (!wil->use_rx_hw_reordering) {
|
||||
r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
|
||||
spin_lock_bh(&sta->tid_rx_lock);
|
||||
wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
|
||||
sta->tid_rx[tid] = r;
|
||||
spin_unlock_bh(&sta->tid_rx_lock);
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
@ -77,8 +77,9 @@ bool wil_is_tx_idle(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
unsigned long data_comp_to;
|
||||
int min_ring_id = wil_get_min_tx_ring_id(wil);
|
||||
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
struct wil_ring *vring = &wil->ring_tx[i];
|
||||
int vring_index = vring - wil->ring_tx;
|
||||
struct wil_ring_tx_data *txdata =
|
||||
@ -765,7 +766,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
return;
|
||||
}
|
||||
|
||||
if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
|
||||
if (wdev->iftype == NL80211_IFTYPE_STATION) {
|
||||
if (mcast && ether_addr_equal(eth->h_source, ndev->dev_addr)) {
|
||||
/* mcast packet looped back to us */
|
||||
rc = GRO_DROP;
|
||||
dev_kfree_skb(skb);
|
||||
goto stats;
|
||||
}
|
||||
} else if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
|
||||
if (mcast) {
|
||||
/* send multicast frames both to higher layers in
|
||||
* local net stack and back to the wireless medium
|
||||
@ -1051,6 +1059,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid,
|
||||
int tid)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
struct wmi_vring_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(WMI_VRING_CMD_MODIFY),
|
||||
.vring_cfg = {
|
||||
.tx_sw_ring = {
|
||||
.max_mpdu_size =
|
||||
cpu_to_le16(wil_mtu2macbuf(mtu_max)),
|
||||
.ring_size = 0,
|
||||
},
|
||||
.ringid = ring_id,
|
||||
.cidxtid = mk_cidxtid(cid, tid),
|
||||
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
|
||||
.mac_ctrl = 0,
|
||||
.to_resolution = 0,
|
||||
.agg_max_wsize = 0,
|
||||
.schd_params = {
|
||||
.priority = cpu_to_le16(0),
|
||||
.timeslot_us = cpu_to_le16(0xfff),
|
||||
},
|
||||
},
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_vring_cfg_done_event cmd;
|
||||
} __packed reply = {
|
||||
.cmd = {.status = WMI_FW_STATUS_FAILURE},
|
||||
};
|
||||
struct wil_ring *vring = &wil->ring_tx[ring_id];
|
||||
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
|
||||
|
||||
wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id,
|
||||
cid, tid);
|
||||
lockdep_assert_held(&wil->mutex);
|
||||
|
||||
if (!vring->va) {
|
||||
wil_err(wil, "Tx ring [%d] not allocated\n", ring_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wil->ring2cid_tid[ring_id][0] != cid ||
|
||||
wil->ring2cid_tid[ring_id][1] != tid) {
|
||||
wil_err(wil, "ring info does not match cid=%u tid=%u\n",
|
||||
wil->ring2cid_tid[ring_id][0],
|
||||
wil->ring2cid_tid[ring_id][1]);
|
||||
}
|
||||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
|
||||
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
|
||||
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "Tx modify failed, status 0x%02x\n",
|
||||
reply.cmd.status);
|
||||
rc = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* set BA aggregation window size to 0 to force a new BA with the
|
||||
* new AP
|
||||
*/
|
||||
txdata->agg_wsize = 0;
|
||||
if (txdata->dot1x_open && agg_wsize >= 0)
|
||||
wil_addba_tx_request(wil, ring_id, agg_wsize);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
spin_lock_bh(&txdata->lock);
|
||||
txdata->dot1x_open = false;
|
||||
txdata->enabled = 0;
|
||||
spin_unlock_bh(&txdata->lock);
|
||||
wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID;
|
||||
wil->ring2cid_tid[ring_id][1] = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
@ -1935,6 +2025,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
|
||||
bool check_stop)
|
||||
{
|
||||
int i;
|
||||
int min_ring_id = wil_get_min_tx_ring_id(wil);
|
||||
|
||||
if (unlikely(!vif))
|
||||
return;
|
||||
@ -1967,7 +2058,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
|
||||
return;
|
||||
|
||||
/* check wake */
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
struct wil_ring *cur_ring = &wil->ring_tx[i];
|
||||
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];
|
||||
|
||||
@ -2272,6 +2363,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
|
||||
wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast;
|
||||
wil->txrx_ops.tx_init = wil_tx_init;
|
||||
wil->txrx_ops.tx_fini = wil_tx_fini;
|
||||
wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify;
|
||||
/* RX ops */
|
||||
wil->txrx_ops.rx_init = wil_rx_init;
|
||||
wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp;
|
||||
|
@ -279,9 +279,6 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
|
||||
u16 buff_id;
|
||||
|
||||
*d = *_d;
|
||||
pa = wil_rx_desc_get_addr_edma(&d->dma);
|
||||
dmalen = le16_to_cpu(d->dma.length);
|
||||
dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
|
||||
|
||||
/* Extract the SKB from the rx_buff management array */
|
||||
buff_id = __le16_to_cpu(d->mac.buff_id);
|
||||
@ -291,10 +288,15 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
|
||||
}
|
||||
skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
|
||||
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
|
||||
if (unlikely(!skb))
|
||||
if (unlikely(!skb)) {
|
||||
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
|
||||
else
|
||||
} else {
|
||||
pa = wil_rx_desc_get_addr_edma(&d->dma);
|
||||
dmalen = le16_to_cpu(d->dma.length);
|
||||
dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* Move the buffer from the active to the free list */
|
||||
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
|
||||
@ -745,6 +747,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id,
|
||||
int cid, int tid)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
|
||||
wil_err(wil, "ring modify is not supported for EDMA\n");
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* This function is used only for RX SW reorder */
|
||||
static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
|
||||
struct sk_buff *skb, struct wil_net_stats *stats)
|
||||
@ -906,6 +918,9 @@ again:
|
||||
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
|
||||
if (!skb) {
|
||||
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
|
||||
/* Move the buffer from the active list to the free list */
|
||||
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
|
||||
&wil->rx_buff_mgmt.free);
|
||||
goto again;
|
||||
}
|
||||
|
||||
@ -1595,6 +1610,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil)
|
||||
wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma;
|
||||
wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma;
|
||||
wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma;
|
||||
wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma;
|
||||
/* RX ops */
|
||||
wil->txrx_ops.rx_init = wil_rx_init_edma;
|
||||
wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma;
|
||||
|
@ -449,6 +449,15 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid)
|
||||
*tid = (cidxtid >> 4) & 0xf;
|
||||
}
|
||||
|
||||
/**
|
||||
* wil_cid_valid - check cid is valid
|
||||
* @cid: CID value
|
||||
*/
|
||||
static inline bool wil_cid_valid(u8 cid)
|
||||
{
|
||||
return (cid >= 0 && cid < WIL6210_MAX_CID);
|
||||
}
|
||||
|
||||
struct wil6210_mbox_ring {
|
||||
u32 base;
|
||||
u16 entry_size; /* max. size of mbox entry, incl. all headers */
|
||||
@ -577,6 +586,7 @@ struct wil_net_stats {
|
||||
unsigned long rx_csum_err;
|
||||
u16 last_mcs_rx;
|
||||
u64 rx_per_mcs[WIL_MCS_MAX + 1];
|
||||
u32 ft_roams; /* relevant in STA mode */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -599,6 +609,8 @@ struct wil_txrx_ops {
|
||||
struct wil_ctx *ctx);
|
||||
int (*tx_ring_tso)(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct wil_ring *ring, struct sk_buff *skb);
|
||||
int (*tx_ring_modify)(struct wil6210_vif *vif, int ring_id,
|
||||
int cid, int tid);
|
||||
irqreturn_t (*irq_tx)(int irq, void *cookie);
|
||||
/* RX ops */
|
||||
int (*rx_init)(struct wil6210_priv *wil, u16 ring_size);
|
||||
@ -821,6 +833,7 @@ extern u8 led_polarity;
|
||||
enum wil6210_vif_status {
|
||||
wil_vif_fwconnecting,
|
||||
wil_vif_fwconnected,
|
||||
wil_vif_ft_roam,
|
||||
wil_vif_status_last /* keep last */
|
||||
};
|
||||
|
||||
@ -1204,6 +1217,7 @@ int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
|
||||
int wmi_echo(struct wil6210_priv *wil);
|
||||
int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie);
|
||||
int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring);
|
||||
int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie);
|
||||
int wmi_rxon(struct wil6210_priv *wil, bool on);
|
||||
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
|
||||
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
|
||||
@ -1319,6 +1333,9 @@ void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil);
|
||||
void wil_rx_handle(struct wil6210_priv *wil, int *quota);
|
||||
void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
|
||||
void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil);
|
||||
void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
|
||||
struct wil_sta_info *cs,
|
||||
struct key_params *params);
|
||||
|
||||
int wil_iftype_nl2wmi(enum nl80211_iftype type);
|
||||
|
||||
@ -1370,4 +1387,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid,
|
||||
u8 tid, u8 token, u16 status, bool amsdu,
|
||||
u16 agg_wsize, u16 timeout);
|
||||
|
||||
void update_supported_bands(struct wil6210_priv *wil);
|
||||
|
||||
#endif /* __WIL6210_H__ */
|
||||
|
@ -227,6 +227,14 @@ struct blink_on_off_time led_blink_time[] = {
|
||||
{WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
|
||||
};
|
||||
|
||||
struct auth_no_hdr {
|
||||
__le16 auth_alg;
|
||||
__le16 auth_transaction;
|
||||
__le16 status_code;
|
||||
/* possibly followed by Challenge text */
|
||||
u8 variable[0];
|
||||
} __packed;
|
||||
|
||||
u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
|
||||
|
||||
/**
|
||||
@ -468,6 +476,12 @@ static const char *cmdid2name(u16 cmdid)
|
||||
return "WMI_LINK_STATS_CMD";
|
||||
case WMI_SW_TX_REQ_EXT_CMDID:
|
||||
return "WMI_SW_TX_REQ_EXT_CMDID";
|
||||
case WMI_FT_AUTH_CMDID:
|
||||
return "WMI_FT_AUTH_CMD";
|
||||
case WMI_FT_REASSOC_CMDID:
|
||||
return "WMI_FT_REASSOC_CMD";
|
||||
case WMI_UPDATE_FT_IES_CMDID:
|
||||
return "WMI_UPDATE_FT_IES_CMD";
|
||||
default:
|
||||
return "Untracked CMD";
|
||||
}
|
||||
@ -606,6 +620,12 @@ static const char *eventid2name(u16 eventid)
|
||||
return "WMI_LINK_STATS_CONFIG_DONE_EVENT";
|
||||
case WMI_LINK_STATS_EVENTID:
|
||||
return "WMI_LINK_STATS_EVENT";
|
||||
case WMI_COMMAND_NOT_SUPPORTED_EVENTID:
|
||||
return "WMI_COMMAND_NOT_SUPPORTED_EVENT";
|
||||
case WMI_FT_AUTH_STATUS_EVENTID:
|
||||
return "WMI_FT_AUTH_STATUS_EVENT";
|
||||
case WMI_FT_REASSOC_STATUS_EVENTID:
|
||||
return "WMI_FT_REASSOC_STATUS_EVENT";
|
||||
default:
|
||||
return "Untracked EVENT";
|
||||
}
|
||||
@ -1156,6 +1176,9 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
struct wmi_ring_en_event *evt = d;
|
||||
u8 vri = evt->ring_index;
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
struct wil_sta_info *sta;
|
||||
int cid;
|
||||
struct key_params params;
|
||||
|
||||
wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid);
|
||||
|
||||
@ -1164,13 +1187,33 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
|
||||
/* in AP mode with disable_ap_sme, this is done by
|
||||
* wil_cfg80211_change_station()
|
||||
if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme ||
|
||||
test_bit(wil_vif_ft_roam, vif->status))
|
||||
/* in AP mode with disable_ap_sme that is not FT,
|
||||
* this is done by wil_cfg80211_change_station()
|
||||
*/
|
||||
wil->ring_tx_data[vri].dot1x_open = true;
|
||||
if (vri == vif->bcast_ring) /* no BA for bcast */
|
||||
return;
|
||||
|
||||
cid = wil->ring2cid_tid[vri][0];
|
||||
if (!wil_cid_valid(cid)) {
|
||||
wil_err(wil, "invalid cid %d for vring %d\n", cid, vri);
|
||||
return;
|
||||
}
|
||||
|
||||
/* In FT mode we get key but not store it as it is received
|
||||
* before WMI_CONNECT_EVENT received from FW.
|
||||
* wil_set_crypto_rx is called here to reset the security PN
|
||||
*/
|
||||
sta = &wil->sta[cid];
|
||||
if (test_bit(wil_vif_ft_roam, vif->status)) {
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
wil_set_crypto_rx(0, WMI_KEY_USE_PAIRWISE, sta, ¶ms);
|
||||
if (wdev->iftype != NL80211_IFTYPE_AP)
|
||||
clear_bit(wil_vif_ft_roam, vif->status);
|
||||
}
|
||||
|
||||
if (agg_wsize >= 0)
|
||||
wil_addba_tx_request(wil, vri, agg_wsize);
|
||||
}
|
||||
@ -1461,6 +1504,271 @@ wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
evt->payload, payload_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* find cid and ringid for the station vif
|
||||
*
|
||||
* return error, if other interfaces are used or ring was not found
|
||||
*/
|
||||
static int wil_find_cid_ringid_sta(struct wil6210_priv *wil,
|
||||
struct wil6210_vif *vif,
|
||||
int *cid,
|
||||
int *ringid)
|
||||
{
|
||||
struct wil_ring *ring;
|
||||
struct wil_ring_tx_data *txdata;
|
||||
int min_ring_id = wil_get_min_tx_ring_id(wil);
|
||||
int i;
|
||||
u8 lcid;
|
||||
|
||||
if (!(vif->wdev.iftype == NL80211_IFTYPE_STATION ||
|
||||
vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
|
||||
wil_err(wil, "invalid interface type %d\n", vif->wdev.iftype);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* In the STA mode, it is expected to have only one ring
|
||||
* for the AP we are connected to.
|
||||
* find it and return the cid associated with it.
|
||||
*/
|
||||
for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
ring = &wil->ring_tx[i];
|
||||
txdata = &wil->ring_tx_data[i];
|
||||
if (!ring->va || !txdata->enabled || txdata->mid != vif->mid)
|
||||
continue;
|
||||
|
||||
lcid = wil->ring2cid_tid[i][0];
|
||||
if (lcid >= WIL6210_MAX_CID) /* skip BCAST */
|
||||
continue;
|
||||
|
||||
wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid);
|
||||
*cid = lcid;
|
||||
*ringid = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil, "find sta cid while no rings active?\n");
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void
|
||||
wmi_evt_auth_status(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
struct wmi_ft_auth_status_event *data = d;
|
||||
int ie_len = len - offsetof(struct wmi_ft_auth_status_event, ie_info);
|
||||
int rc, cid = 0, ringid = 0;
|
||||
struct cfg80211_ft_event_params ft;
|
||||
u16 d_len;
|
||||
/* auth_alg(u16) + auth_transaction(u16) + status_code(u16) */
|
||||
const size_t auth_ie_offset = sizeof(u16) * 3;
|
||||
struct auth_no_hdr *auth = (struct auth_no_hdr *)data->ie_info;
|
||||
|
||||
/* check the status */
|
||||
if (ie_len >= 0 && data->status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "FT: auth failed. status %d\n", data->status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ie_len < auth_ie_offset) {
|
||||
wil_err(wil, "FT: auth event too short, len %d\n", len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
d_len = le16_to_cpu(data->ie_len);
|
||||
if (d_len != ie_len) {
|
||||
wil_err(wil,
|
||||
"FT: auth ie length mismatch, d_len %d should be %d\n",
|
||||
d_len, ie_len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!test_bit(wil_vif_ft_roam, wil->status)) {
|
||||
wil_err(wil, "FT: Not in roaming state\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(auth->auth_transaction) != 2) {
|
||||
wil_err(wil, "FT: auth error. auth_transaction %d\n",
|
||||
le16_to_cpu(auth->auth_transaction));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(auth->auth_alg) != WLAN_AUTH_FT) {
|
||||
wil_err(wil, "FT: auth error. auth_alg %d\n",
|
||||
le16_to_cpu(auth->auth_alg));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil, "FT: Auth to %pM successfully\n", data->mac_addr);
|
||||
wil_hex_dump_wmi("FT Auth ies : ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data->ie_info, d_len, true);
|
||||
|
||||
/* find cid and ringid */
|
||||
rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
|
||||
if (rc) {
|
||||
wil_err(wil, "No valid cid found\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (vif->privacy) {
|
||||
/* For secure assoc, remove old keys */
|
||||
rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
|
||||
WMI_KEY_USE_PAIRWISE);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
|
||||
goto fail;
|
||||
}
|
||||
rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
|
||||
WMI_KEY_USE_RX_GROUP);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&ft, 0, sizeof(ft));
|
||||
ft.ies = data->ie_info + auth_ie_offset;
|
||||
ft.ies_len = d_len - auth_ie_offset;
|
||||
ft.target_ap = data->mac_addr;
|
||||
cfg80211_ft_event(ndev, &ft);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
|
||||
}
|
||||
|
||||
static void
|
||||
wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
struct wmi_ft_reassoc_status_event *data = d;
|
||||
int ies_len = len - offsetof(struct wmi_ft_reassoc_status_event,
|
||||
ie_info);
|
||||
int rc = -ENOENT, cid = 0, ringid = 0;
|
||||
int ch; /* channel number (primary) */
|
||||
size_t assoc_req_ie_len = 0, assoc_resp_ie_len = 0;
|
||||
u8 *assoc_req_ie = NULL, *assoc_resp_ie = NULL;
|
||||
/* capinfo(u16) + listen_interval(u16) + current_ap mac addr + IEs */
|
||||
const size_t assoc_req_ie_offset = sizeof(u16) * 2 + ETH_ALEN;
|
||||
/* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
|
||||
const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
|
||||
u16 d_len;
|
||||
int freq;
|
||||
struct cfg80211_roam_info info;
|
||||
|
||||
if (ies_len < 0) {
|
||||
wil_err(wil, "ft reassoc event too short, len %d\n", len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil, "Reasoc Status event: status=%d, aid=%d",
|
||||
data->status, data->aid);
|
||||
wil_dbg_wmi(wil, " mac_addr=%pM, beacon_ie_len=%d",
|
||||
data->mac_addr, data->beacon_ie_len);
|
||||
wil_dbg_wmi(wil, " reassoc_req_ie_len=%d, reassoc_resp_ie_len=%d",
|
||||
le16_to_cpu(data->reassoc_req_ie_len),
|
||||
le16_to_cpu(data->reassoc_resp_ie_len));
|
||||
|
||||
d_len = le16_to_cpu(data->beacon_ie_len) +
|
||||
le16_to_cpu(data->reassoc_req_ie_len) +
|
||||
le16_to_cpu(data->reassoc_resp_ie_len);
|
||||
if (d_len != ies_len) {
|
||||
wil_err(wil,
|
||||
"ft reassoc ie length mismatch, d_len %d should be %d\n",
|
||||
d_len, ies_len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check the status */
|
||||
if (data->status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "ft reassoc failed. status %d\n", data->status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* find cid and ringid */
|
||||
rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
|
||||
if (rc) {
|
||||
wil_err(wil, "No valid cid found\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ch = data->channel + 1;
|
||||
wil_info(wil, "FT: Roam %pM channel [%d] cid %d aid %d\n",
|
||||
data->mac_addr, ch, cid, data->aid);
|
||||
|
||||
wil_hex_dump_wmi("reassoc AI : ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data->ie_info, len - sizeof(*data), true);
|
||||
|
||||
/* figure out IE's */
|
||||
if (le16_to_cpu(data->reassoc_req_ie_len) > assoc_req_ie_offset) {
|
||||
assoc_req_ie = &data->ie_info[assoc_req_ie_offset];
|
||||
assoc_req_ie_len = le16_to_cpu(data->reassoc_req_ie_len) -
|
||||
assoc_req_ie_offset;
|
||||
}
|
||||
if (le16_to_cpu(data->reassoc_resp_ie_len) <= assoc_resp_ie_offset) {
|
||||
wil_err(wil, "FT: reassoc resp ie len is too short, len %d\n",
|
||||
le16_to_cpu(data->reassoc_resp_ie_len));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
assoc_resp_ie = &data->ie_info[le16_to_cpu(data->reassoc_req_ie_len) +
|
||||
assoc_resp_ie_offset];
|
||||
assoc_resp_ie_len = le16_to_cpu(data->reassoc_resp_ie_len) -
|
||||
assoc_resp_ie_offset;
|
||||
|
||||
if (test_bit(wil_status_resetting, wil->status) ||
|
||||
!test_bit(wil_status_fwready, wil->status)) {
|
||||
wil_err(wil, "FT: status_resetting, cancel reassoc event\n");
|
||||
/* no need for cleanup, wil_reset will do that */
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
/* ring modify to set the ring for the roamed AP settings */
|
||||
wil_dbg_wmi(wil,
|
||||
"ft modify tx config for connection CID %d ring %d\n",
|
||||
cid, ringid);
|
||||
|
||||
rc = wil->txrx_ops.tx_ring_modify(vif, ringid, cid, 0);
|
||||
if (rc) {
|
||||
wil_err(wil, "modify TX for CID %d MID %d ring %d failed (%d)\n",
|
||||
cid, vif->mid, ringid, rc);
|
||||
mutex_unlock(&wil->mutex);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Update the driver STA members with the new bss */
|
||||
wil->sta[cid].aid = data->aid;
|
||||
wil->sta[cid].stats.ft_roams++;
|
||||
ether_addr_copy(wil->sta[cid].addr, vif->bss->bssid);
|
||||
mutex_unlock(&wil->mutex);
|
||||
del_timer_sync(&vif->connect_timer);
|
||||
|
||||
cfg80211_ref_bss(wiphy, vif->bss);
|
||||
freq = ieee80211_channel_to_frequency(ch, NL80211_BAND_60GHZ);
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.channel = ieee80211_get_channel(wiphy, freq);
|
||||
info.bss = vif->bss;
|
||||
info.req_ie = assoc_req_ie;
|
||||
info.req_ie_len = assoc_req_ie_len;
|
||||
info.resp_ie = assoc_resp_ie;
|
||||
info.resp_ie_len = assoc_resp_ie_len;
|
||||
cfg80211_roamed(ndev, &info, GFP_KERNEL);
|
||||
vif->bss = NULL;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some events are ignored for purpose; and need not be interpreted as
|
||||
* "unhandled events"
|
||||
@ -1492,6 +1800,8 @@ static const struct {
|
||||
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
|
||||
{WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result},
|
||||
{WMI_LINK_STATS_EVENTID, wmi_evt_link_stats},
|
||||
{WMI_FT_AUTH_STATUS_EVENTID, wmi_evt_auth_status},
|
||||
{WMI_FT_REASSOC_STATUS_EVENTID, wmi_evt_reassoc_status},
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2086,6 +2396,40 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
u16 len;
|
||||
struct wmi_update_ft_ies_cmd *cmd;
|
||||
int rc;
|
||||
|
||||
if (!ie)
|
||||
ie_len = 0;
|
||||
|
||||
len = sizeof(struct wmi_update_ft_ies_cmd) + ie_len;
|
||||
if (len < ie_len) {
|
||||
wil_err(wil, "wraparound. ie len %d\n", ie_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd = kzalloc(len, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->ie_len = cpu_to_le16(ie_len);
|
||||
memcpy(cmd->ie_info, ie, ie_len);
|
||||
rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len);
|
||||
kfree(cmd);
|
||||
|
||||
out:
|
||||
if (rc)
|
||||
wil_err(wil, "update ft ies failed : %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* wmi_rxon - turn radio on/off
|
||||
* @on: turn on if true, off otherwise
|
||||
|
@ -103,6 +103,7 @@ enum wmi_fw_capability {
|
||||
WMI_FW_CAPABILITY_AMSDU = 23,
|
||||
WMI_FW_CAPABILITY_RAW_MODE = 24,
|
||||
WMI_FW_CAPABILITY_TX_REQ_EXT = 25,
|
||||
WMI_FW_CAPABILITY_CHANNEL_4 = 26,
|
||||
WMI_FW_CAPABILITY_MAX,
|
||||
};
|
||||
|
||||
@ -2369,6 +2370,7 @@ struct wmi_ft_reassoc_status_event {
|
||||
__le16 beacon_ie_len;
|
||||
__le16 reassoc_req_ie_len;
|
||||
__le16 reassoc_resp_ie_len;
|
||||
u8 reserved[4];
|
||||
u8 ie_info[0];
|
||||
} __packed;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user