summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorKalle Valo <kvalo@codeaurora.org>2019-05-27 15:15:29 +0300
committerKalle Valo <kvalo@codeaurora.org>2019-05-27 15:15:29 +0300
commit889ca18093423af7bf224416fe7548a7e13e82fc (patch)
treed762982fd593bb797d3df49a462276c1fc37c161 /drivers/net
parentf4aa80129ff71909380ee0bde8be36c5cc031d4c (diff)
parent9e7251fa38978b85108c44743e1436d48e8d0d76 (diff)
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 5.3. Major changes: ath10k * enable SDIO support, first one being QCA6174 hw3.2
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath10k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c48
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h12
-rw-r--r--drivers/net/wireless/ath/ath10k/coredump.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c50
-rw-r--r--drivers/net/wireless/ath/ath10k/debugfs_sta.c7
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h60
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c387
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c29
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h6
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c15
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c18
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c28
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h12
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c37
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h7
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_pipe.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c18
-rw-r--r--drivers/net/wireless/ath/carl9170/mac.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/rx.c2
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c2
-rw-r--r--drivers/net/wireless/ath/regd.h1
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c70
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.h11
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c148
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c67
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c18
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c26
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.c10
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h33
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c14
48 files changed, 1017 insertions, 250 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index 0bf726c55736..f80854180e21 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -740,7 +740,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev)
enum ath10k_hw_rev hw_rev;
size_t size;
int ret;
- struct ath10k_bus_params bus_params;
+ struct ath10k_bus_params bus_params = {};
of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev);
if (!of_id) {
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index aff585658fc0..61ef90329788 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -154,6 +154,33 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.fw_diag_ce_download = false,
},
{
+ .id = QCA6174_HW_3_2_VERSION,
+ .dev_id = QCA6174_3_2_DEVICE_ID,
+ .bus = ATH10K_BUS_SDIO,
+ .name = "qca6174 hw3.2 sdio",
+ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
+ .uart_pin = 19,
+ .otp_exe_param = 0,
+ .channel_counters_freq_hz = 88000,
+ .max_probe_resp_desc_thres = 0,
+ .cal_data_len = 0,
+ .fw = {
+ .dir = QCA6174_HW_3_0_FW_DIR,
+ .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
+ .board_size = QCA6174_BOARD_DATA_SZ,
+ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
+ },
+ .hw_ops = &qca6174_ops,
+ .hw_clk = qca6174_clk,
+ .target_cpu_freq = 176000000,
+ .decap_align_bytes = 4,
+ .n_cipher_suites = 8,
+ .num_peers = 10,
+ .ast_skid_limit = 0x10,
+ .num_wds_entries = 0x20,
+ .uart_pin_workaround = true,
+ },
+ {
.id = QCA6174_HW_2_1_VERSION,
.dev_id = QCA6164_2_1_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
@@ -629,7 +656,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
complete(&ar->target_suspend);
}
-static void ath10k_init_sdio(struct ath10k *ar)
+static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
{
u32 param = 0;
@@ -646,7 +673,12 @@ static void ath10k_init_sdio(struct ath10k *ar)
* not big enough for mac80211 / native wifi frames. disable it
*/
param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
- param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
+
+ if (mode == ATH10K_FIRMWARE_MODE_UTF)
+ param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
+ else
+ param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
+
ath10k_bmi_write32(ar, hi_acs_flags, param);
/* Explicitly set fwlog prints to zero as target may turn it on
@@ -2065,8 +2097,16 @@ static int ath10k_init_uart(struct ath10k *ar)
return ret;
}
- if (!uart_print)
+ if (!uart_print && ar->hw_params.uart_pin_workaround) {
+ ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin,
+ ar->hw_params.uart_pin);
+ if (ret) {
+ ath10k_warn(ar, "failed to set UART TX pin: %d", ret);
+ return ret;
+ }
+
return 0;
+ }
ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);
if (ret) {
@@ -2501,7 +2541,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
goto err;
if (ar->hif.bus == ATH10K_BUS_SDIO)
- ath10k_init_sdio(ar);
+ ath10k_init_sdio(ar, mode);
}
ar->htc.htc_ops.target_send_suspend_complete =
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index e35aae5146f1..2d109c030ec4 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -196,7 +196,7 @@ struct ath10k_fw_extd_stats_peer {
struct list_head list;
u8 peer_macaddr[ETH_ALEN];
- u32 rx_duration;
+ u64 rx_duration;
};
struct ath10k_fw_stats_vdev {
@@ -400,6 +400,14 @@ struct ath10k_peer {
/* protected by ar->data_lock */
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
+ union htt_rx_pn_t tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS];
+ bool tids_last_pn_valid[ATH10K_TXRX_NUM_EXT_TIDS];
+ union htt_rx_pn_t frag_tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS];
+ u32 frag_tids_seq[ATH10K_TXRX_NUM_EXT_TIDS];
+ struct {
+ enum htt_security_types sec_type;
+ int pn_len;
+ } rx_pn[ATH10K_HTT_TXRX_PEER_SECURITY_MAX];
};
struct ath10k_txq {
@@ -614,6 +622,7 @@ struct ath10k_debug {
bool fw_stats_done;
unsigned long htt_stats_mask;
+ unsigned long reset_htt_stats;
struct delayed_work htt_stats_dwork;
struct ath10k_dfs_stats dfs_stats;
struct ath_dfs_pool_stats dfs_pool_stats;
@@ -919,6 +928,7 @@ struct ath10k_bus_params {
u32 chip_id;
enum ath10k_dev_type dev_type;
bool link_can_suspend;
+ bool hl_msdu_ids;
};
struct ath10k {
diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c
index 45a355fb62b9..b6d2932383cf 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.c
+++ b/drivers/net/wireless/ath/ath10k/coredump.c
@@ -1192,8 +1192,8 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar)
if (test_bit(ATH10K_FW_CRASH_DUMP_CE_DATA, &ath10k_coredump_mask)) {
dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA);
- dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) +
- CE_COUNT * sizeof(ce_hdr->entries[0]));
+ dump_tlv->tlv_len = cpu_to_le32(struct_size(ce_hdr, entries,
+ CE_COUNT));
ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data);
ce_hdr->ce_count = cpu_to_le32(CE_COUNT);
memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved));
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 32d967a31c65..740781fe80f8 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -305,6 +305,9 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
if (is_end)
ar->debug.fw_stats_done = true;
+ if (stats.extended)
+ ar->debug.fw_stats.extended = true;
+
is_started = !list_empty(&ar->debug.fw_stats.pdevs);
if (is_started && !is_end) {
@@ -873,7 +876,7 @@ static int ath10k_debug_htt_stats_req(struct ath10k *ar)
cookie = get_jiffies_64();
ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
- cookie);
+ ar->debug.reset_htt_stats, cookie);
if (ret) {
ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
return ret;
@@ -922,8 +925,8 @@ static ssize_t ath10k_write_htt_stats_mask(struct file *file,
if (ret)
return ret;
- /* max 8 bit masks (for now) */
- if (mask > 0xff)
+ /* max 17 bit masks (for now) */
+ if (mask > HTT_STATS_BIT_MASK)
return -E2BIG;
mutex_lock(&ar->conf_mutex);
@@ -2469,6 +2472,44 @@ static const struct file_operations fops_ps_state_enable = {
.llseek = default_llseek,
};
+static ssize_t ath10k_write_reset_htt_stats(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned long reset;
+ int ret;
+
+ ret = kstrtoul_from_user(user_buf, count, 0, &reset);
+ if (ret)
+ return ret;
+
+ if (reset == 0 || reset > 0x1ffff)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ar->debug.reset_htt_stats = reset;
+
+ ret = ath10k_debug_htt_stats_req(ar);
+ if (ret)
+ goto out;
+
+ ar->debug.reset_htt_stats = 0;
+ ret = count;
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static const struct file_operations fops_reset_htt_stats = {
+ .write = ath10k_write_reset_htt_stats,
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
@@ -2609,6 +2650,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar,
&fops_ps_state_enable);
+ debugfs_create_file("reset_htt_stats", 0200, ar->debug.debugfs_phy, ar,
+ &fops_reset_htt_stats);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index c704ae371c4d..42931a669b02 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -663,6 +663,13 @@ static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
mutex_lock(&ar->conf_mutex);
+ if (!arsta->tx_stats) {
+ ath10k_warn(ar, "failed to get tx stats");
+ mutex_unlock(&ar->conf_mutex);
+ kfree(buf);
+ return 0;
+ }
+
spin_lock_bh(&ar->data_lock);
for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {
for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 805a7f8a04f2..1d4d1a1992fe 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -73,6 +73,7 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
struct ath10k_htc_hdr *hdr;
hdr = (struct ath10k_htc_hdr *)skb->data;
+ memset(hdr, 0, sizeof(struct ath10k_htc_hdr));
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 4cee5492abc8..19cd0cb5875f 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -315,6 +315,7 @@ struct htt_stats_req {
} __packed;
#define HTT_STATS_REQ_CFG_STAT_TYPE_INVALID 0xff
+#define HTT_STATS_BIT_MASK GENMASK(16, 0)
/*
* htt_oob_sync_req - request out-of-band sync
@@ -733,6 +734,20 @@ struct htt_rx_indication_hl {
struct htt_rx_indication_mpdu_range mpdu_ranges[0];
} __packed;
+struct htt_hl_rx_desc {
+ __le32 info;
+ __le32 pn_31_0;
+ union {
+ struct {
+ __le16 pn_47_32;
+ __le16 pn_63_48;
+ } pn16;
+ __le32 pn_63_32;
+ } u0;
+ __le32 pn_95_64;
+ __le32 pn_127_96;
+} __packed;
+
static inline struct htt_rx_indication_mpdu_range *
htt_rx_ind_get_mpdu_ranges(struct htt_rx_indication *rx_ind)
{
@@ -790,6 +805,21 @@ struct htt_rx_peer_unmap {
__le16 peer_id;
} __packed;
+enum htt_txrx_sec_cast_type {
+ HTT_TXRX_SEC_MCAST = 0,
+ HTT_TXRX_SEC_UCAST
+};
+
+enum htt_rx_pn_check_type {
+ HTT_RX_NON_PN_CHECK = 0,
+ HTT_RX_PN_CHECK
+};
+
+enum htt_rx_tkip_demic_type {
+ HTT_RX_NON_TKIP_MIC = 0,
+ HTT_RX_TKIP_MIC
+};
+
enum htt_security_types {
HTT_SECURITY_NONE,
HTT_SECURITY_WEP128,
@@ -803,6 +833,9 @@ enum htt_security_types {
HTT_NUM_SECURITY_TYPES /* keep this last! */
};
+#define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2
+#define ATH10K_TXRX_NUM_EXT_TIDS 19
+
enum htt_security_flags {
#define HTT_SECURITY_TYPE_MASK 0x7F
#define HTT_SECURITY_TYPE_LSB 0
@@ -1010,6 +1043,11 @@ struct htt_rx_fragment_indication {
u8 fw_msdu_rx_desc[0];
} __packed;
+#define ATH10K_IEEE80211_EXTIV BIT(5)
+#define ATH10K_IEEE80211_TKIP_MICLEN 8 /* trailing MIC */
+
+#define HTT_RX_FRAG_IND_INFO0_HEADER_LEN 16
+
#define HTT_RX_FRAG_IND_INFO0_EXT_TID_MASK 0x1F
#define HTT_RX_FRAG_IND_INFO0_EXT_TID_LSB 0
#define HTT_RX_FRAG_IND_INFO0_FLUSH_VALID_MASK 0x20
@@ -2055,6 +2093,9 @@ struct ath10k_htt_rx_ops {
int idx);
void* (*htt_get_vaddr_ring)(struct ath10k_htt *htt);
void (*htt_reset_paddrs_ring)(struct ath10k_htt *htt, int idx);
+ bool (*htt_rx_proc_rx_frag_ind)(struct ath10k_htt *htt,
+ struct htt_rx_fragment_indication *rx,
+ struct sk_buff *skb);
};
static inline size_t ath10k_htt_get_rx_ring_size(struct ath10k_htt *htt)
@@ -2094,6 +2135,16 @@ static inline void ath10k_htt_reset_paddrs_ring(struct ath10k_htt *htt, int idx)
htt->rx_ops->htt_reset_paddrs_ring(htt, idx);
}
+static inline bool ath10k_htt_rx_proc_rx_frag_ind(struct ath10k_htt *htt,
+ struct htt_rx_fragment_indication *rx,
+ struct sk_buff *skb)
+{
+ if (!htt->rx_ops->htt_rx_proc_rx_frag_ind)
+ return true;
+
+ return htt->rx_ops->htt_rx_proc_rx_frag_ind(htt, rx, skb);
+}
+
#define RX_HTT_HDR_STATUS_LEN 64
/* This structure layout is programmed via rx ring setup
@@ -2128,10 +2179,8 @@ struct htt_rx_desc {
#define HTT_RX_DESC_HL_INFO_ENCRYPTED_LSB 12
#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_MASK 0x00002000
#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_LSB 13
-#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00008000
-#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 15
-#define HTT_RX_DESC_HL_INFO_FRAGMENT_MASK 0x00010000
-#define HTT_RX_DESC_HL_INFO_FRAGMENT_LSB 16
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00010000
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 16
#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_MASK 0x01fe0000
#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_LSB 17
@@ -2195,7 +2244,8 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
-int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
+int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u32 mask, u32 reset_mask,
+ u64 cookie);
int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_ampdu,
u8 max_subfrms_amsdu);
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 1acc622d2183..0c18c58de71d 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2061,9 +2061,91 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
return 0;
}
+static void ath10k_htt_rx_mpdu_desc_pn_hl(struct htt_hl_rx_desc *rx_desc,
+ union htt_rx_pn_t *pn,
+ int pn_len_bits)
+{
+ switch (pn_len_bits) {
+ case 48:
+ pn->pn48 = __le32_to_cpu(rx_desc->pn_31_0) +
+ ((u64)(__le32_to_cpu(rx_desc->u0.pn_63_32) & 0xFFFF) << 32);
+ break;
+ case 24:
+ pn->pn24 = __le32_to_cpu(rx_desc->pn_31_0);
+ break;
+ };
+}
+
+static bool ath10k_htt_rx_pn_cmp48(union htt_rx_pn_t *new_pn,
+ union htt_rx_pn_t *old_pn)
+{
+ return ((new_pn->pn48 & 0xffffffffffffULL) <=
+ (old_pn->pn48 & 0xffffffffffffULL));
+}
+
+static bool ath10k_htt_rx_pn_check_replay_hl(struct ath10k *ar,
+ struct ath10k_peer *peer,
+ struct htt_rx_indication_hl *rx)
+{
+ bool last_pn_valid, pn_invalid = false;
+ enum htt_txrx_sec_cast_type sec_index;
+ enum htt_security_types sec_type;
+ union htt_rx_pn_t new_pn = {0};
+ struct htt_hl_rx_desc *rx_desc;
+ union htt_rx_pn_t *last_pn;
+ u32 rx_desc_info, tid;
+ int num_mpdu_ranges;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!peer)
+ return false;
+
+ if (!(rx->fw_desc.flags & FW_RX_DESC_FLAGS_FIRST_MSDU))
+ return false;
+
+ num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
+ HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
+
+ rx_desc = (struct htt_hl_rx_desc *)&rx->mpdu_ranges[num_mpdu_ranges];
+ rx_desc_info = __le32_to_cpu(rx_desc->info);
+
+ if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED))
+ return false;
+
+ tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
+ last_pn_valid = peer->tids_last_pn_valid[tid];
+ last_pn = &peer->tids_last_pn[tid];
+
+ if (MS(rx_desc_info, HTT_RX_DESC_HL_INFO_MCAST_BCAST))
+ sec_index = HTT_TXRX_SEC_MCAST;
+ else
+ sec_index = HTT_TXRX_SEC_UCAST;
+
+ sec_type = peer->rx_pn[sec_index].sec_type;
+ ath10k_htt_rx_mpdu_desc_pn_hl(rx_desc, &new_pn, peer->rx_pn[sec_index].pn_len);
+
+ if (sec_type != HTT_SECURITY_AES_CCMP &&
+ sec_type != HTT_SECURITY_TKIP &&
+ sec_type != HTT_SECURITY_TKIP_NOMIC)
+ return false;
+
+ if (last_pn_valid)
+ pn_invalid = ath10k_htt_rx_pn_cmp48(&new_pn, last_pn);
+ else
+ peer->tids_last_pn_valid[tid] = 1;
+
+ if (!pn_invalid)
+ last_pn->pn48 = new_pn.pn48;
+
+ return pn_invalid;
+}
+
static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
struct htt_rx_indication_hl *rx,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ enum htt_rx_pn_check_type check_pn_type,
+ enum htt_rx_tkip_demic_type tkip_mic_type)
{
struct ath10k *ar = htt->ar;
struct ath10k_peer *peer;
@@ -2107,6 +2189,10 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
goto err;
}
+ if (check_pn_type == HTT_RX_PN_CHECK &&
+ ath10k_htt_rx_pn_check_replay_hl(ar, peer, rx))
+ goto err;
+
/* Strip off all headers before the MAC header before delivery to
* mac80211
*/
@@ -2114,6 +2200,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
sizeof(rx->ppdu) + sizeof(rx->prefix) +
sizeof(rx->fw_desc) +
sizeof(*mpdu_ranges) * num_mpdu_ranges + rx_desc_len;
+
skb_pull(skb, tot_hdr_len);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -2162,6 +2249,10 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
RX_FLAG_MMIC_STRIPPED;
}
+ if (tkip_mic_type == HTT_RX_TKIP_MIC)
+ rx_status->flag &= ~RX_FLAG_IV_STRIPPED &
+ ~RX_FLAG_MMIC_STRIPPED;
+
ieee80211_rx_ni(ar->hw, skb);
/* We have delivered the skb to the upper layers (mac80211) so we
@@ -2175,6 +2266,231 @@ err:
return true;
}
+static int ath10k_htt_rx_frag_tkip_decap_nomic(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *ivp, *orig_hdr;
+
+ orig_hdr = skb->data;
+ ivp = orig_hdr + hdr_len + head_len;
+
+ /* the ExtIV bit is always set to 1 for TKIP */
+ if (!(ivp[IEEE80211_WEP_IV_LEN - 1] & ATH10K_IEEE80211_EXTIV))
+ return -EINVAL;
+
+ memmove(orig_hdr + IEEE80211_TKIP_IV_LEN, orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_TKIP_IV_LEN);
+ skb_trim(skb, skb->len - ATH10K_IEEE80211_TKIP_MICLEN);
+ return 0;
+}
+
+static int ath10k_htt_rx_frag_tkip_decap_withmic(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *ivp, *orig_hdr;
+
+ orig_hdr = skb->data;
+ ivp = orig_hdr + hdr_len + head_len;
+
+ /* the ExtIV bit is always set to 1 for TKIP */
+ if (!(ivp[IEEE80211_WEP_IV_LEN - 1] & ATH10K_IEEE80211_EXTIV))
+ return -EINVAL;
+
+ memmove(orig_hdr + IEEE80211_TKIP_IV_LEN, orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_TKIP_IV_LEN);
+ skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
+ return 0;
+}
+
+static int ath10k_htt_rx_frag_ccmp_decap(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *ivp, *orig_hdr;
+
+ orig_hdr = skb->data;
+ ivp = orig_hdr + hdr_len + head_len;
+
+ /* the ExtIV bit is always set to 1 for CCMP */
+ if (!(ivp[IEEE80211_WEP_IV_LEN - 1] & ATH10K_IEEE80211_EXTIV))
+ return -EINVAL;
+
+ skb_trim(skb, skb->len - IEEE80211_CCMP_MIC_LEN);
+ memmove(orig_hdr + IEEE80211_CCMP_HDR_LEN, orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_CCMP_HDR_LEN);
+ return 0;
+}
+
+static int ath10k_htt_rx_frag_wep_decap(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *orig_hdr;
+
+ orig_hdr = skb->data;
+
+ memmove(orig_hdr + IEEE80211_WEP_IV_LEN,
+ orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_WEP_IV_LEN);
+ skb_trim(skb, skb->len - IEEE80211_WEP_ICV_LEN);
+ return 0;
+}
+
+static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt,
+ struct htt_rx_fragment_indication *rx,
+ struct sk_buff *skb)
+{
+ struct ath10k *ar = htt->ar;
+ enum htt_rx_tkip_demic_type tkip_mic = HTT_RX_NON_TKIP_MIC;
+ enum htt_txrx_sec_cast_type sec_index;
+ struct htt_rx_indication_hl *rx_hl;
+ enum htt_security_types sec_type;
+ u32 tid, frag, seq, rx_desc_info;
+ union htt_rx_pn_t new_pn = {0};
+ struct htt_hl_rx_desc *rx_desc;
+ u16 peer_id, sc, hdr_space;
+ union htt_rx_pn_t *last_pn;
+ struct ieee80211_hdr *hdr;
+ int ret, num_mpdu_ranges;
+ struct ath10k_peer *peer;
+ struct htt_resp *resp;
+ size_t tot_hdr_len;
+
+ resp = (struct htt_resp *)(skb->data + HTT_RX_FRAG_IND_INFO0_HEADER_LEN);
+ skb_pull(skb, HTT_RX_FRAG_IND_INFO0_HEADER_LEN);
+ skb_trim(skb, skb->len - FCS_LEN);
+
+ peer_id = __le16_to_cpu(rx->peer_id);
+ rx_hl = (struct htt_rx_indication_hl *)(&resp->rx_ind_hl);
+
+ spin_lock_bh(&ar->data_lock);
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer) {
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer: %u\n", peer_id);
+ goto err;
+ }
+
+ num_mpdu_ranges = MS(__le32_to_cpu(rx_hl->hdr.info1),
+ HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
+
+ tot_hdr_len = sizeof(struct htt_resp_hdr) +
+ sizeof(rx_hl->hdr) +
+ sizeof(rx_hl->ppdu) +
+ sizeof(rx_hl->prefix) +
+ sizeof(rx_hl->fw_desc) +
+ sizeof(struct htt_rx_indication_mpdu_range) * num_mpdu_ranges;
+
+ tid = MS(rx_hl->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
+ rx_desc = (struct htt_hl_rx_desc *)(skb->data + tot_hdr_len);
+ rx_desc_info = __le32_to_cpu(rx_desc->info);
+
+ if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED)) {
+ spin_unlock_bh(&ar->data_lock);
+ return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb,
+ HTT_RX_NON_PN_CHECK,
+ HTT_RX_NON_TKIP_MIC);
+ }
+
+ hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len);
+
+ if (ieee80211_has_retry(hdr->frame_control))
+ goto err;
+
+ hdr_space = ieee80211_hdrlen(hdr->frame_control);
+ sc = __le16_to_cpu(hdr->seq_ctrl);
+ seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+ frag = sc & IEEE80211_SCTL_FRAG;
+
+ sec_index = MS(rx_desc_info, HTT_RX_DESC_HL_INFO_MCAST_BCAST) ?
+ HTT_TXRX_SEC_MCAST : HTT_TXRX_SEC_UCAST;</