diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_rx.c | 91 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_tx.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/sdio.c | 29 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 8 |
8 files changed, 151 insertions, 30 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index dc45d16e8d21..383d4fa555a8 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2118,12 +2118,15 @@ static int ath10k_init_uart(struct ath10k *ar) return ret; } - 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; + if (!uart_print) { + if (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; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 83a7fb68fd24..53f1095de8ff 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2151,6 +2151,10 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, struct ath10k_peer *peer; struct htt_rx_indication_mpdu_range *mpdu_ranges; struct fw_rx_desc_hl *fw_desc; + 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; struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; u16 peer_id; @@ -2158,9 +2162,11 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, int num_mpdu_ranges; size_t tot_hdr_len; struct ieee80211_channel *ch; - bool pn_invalid; + bool pn_invalid, qos, first_msdu; + u32 tid, rx_desc_info; peer_id = __le16_to_cpu(rx->hdr.peer_id); + tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID); spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, peer_id); @@ -2168,6 +2174,9 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, if (!peer && peer_id != HTT_INVALID_PEERID) ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id); + if (!peer) + return true; + num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1), HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); mpdu_ranges = htt_rx_ind_get_mpdu_ranges_hl(rx); @@ -2192,10 +2201,24 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, goto err; } - if (check_pn_type == HTT_RX_PN_CHECK) { + 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_MCAST_BCAST)) + sec_index = HTT_TXRX_SEC_MCAST; + else + sec_index = HTT_TXRX_SEC_UCAST; + + sec_type = peer->rx_pn[sec_index].sec_type; + first_msdu = rx->fw_desc.flags & FW_RX_DESC_FLAGS_FIRST_MSDU; + + ath10k_htt_rx_mpdu_desc_pn_hl(rx_desc, &new_pn, peer->rx_pn[sec_index].pn_len); + + if (check_pn_type == HTT_RX_PN_CHECK && tid >= IEEE80211_NUM_TIDS) { spin_lock_bh(&ar->data_lock); pn_invalid = ath10k_htt_rx_pn_check_replay_hl(ar, peer, rx); spin_unlock_bh(&ar->data_lock); + if (pn_invalid) goto err; } @@ -2211,6 +2234,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, skb_pull(skb, tot_hdr_len); hdr = (struct ieee80211_hdr *)skb->data; + qos = ieee80211_is_data_qos(hdr->frame_control); rx_status = IEEE80211_SKB_RXCB(skb); rx_status->chains |= BIT(0); if (rx->ppdu.combined_rssi == 0) { @@ -2254,6 +2278,55 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (tid < IEEE80211_NUM_TIDS && + first_msdu && + check_pn_type == HTT_RX_PN_CHECK && + (sec_type == HTT_SECURITY_AES_CCMP || + sec_type == HTT_SECURITY_TKIP || + sec_type == HTT_SECURITY_TKIP_NOMIC)) { + u8 offset, *ivp, i; + s8 keyidx = 0; + __le64 pn48 = cpu_to_le64(new_pn.pn48); + + hdr = (struct ieee80211_hdr *)skb->data; + offset = ieee80211_hdrlen(hdr->frame_control); + hdr->frame_control |= __cpu_to_le16(IEEE80211_FCTL_PROTECTED); + rx_status->flag &= ~RX_FLAG_IV_STRIPPED; + + memmove(skb->data - IEEE80211_CCMP_HDR_LEN, + skb->data, offset); + skb_push(skb, IEEE80211_CCMP_HDR_LEN); + ivp = skb->data + offset; + memset(skb->data + offset, 0, IEEE80211_CCMP_HDR_LEN); + /* Ext IV */ + ivp[IEEE80211_WEP_IV_LEN - 1] |= ATH10K_IEEE80211_EXTIV; + + for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { + if (peer->keys[i] && + peer->keys[i]->flags & IEEE80211_KEY_FLAG_PAIRWISE) + keyidx = peer->keys[i]->keyidx; + } + + /* Key ID */ + ivp[IEEE80211_WEP_IV_LEN - 1] |= keyidx << 6; + + if (sec_type == HTT_SECURITY_AES_CCMP) { + rx_status->flag |= RX_FLAG_MIC_STRIPPED; + /* pn 0, pn 1 */ + memcpy(skb->data + offset, &pn48, 2); + /* pn 1, pn 3 , pn 34 , pn 5 */ + memcpy(skb->data + offset + 4, ((u8 *)&pn48) + 2, 4); + } else { + rx_status->flag |= RX_FLAG_ICV_STRIPPED; + /* TSC 0 */ + memcpy(skb->data + offset + 2, &pn48, 1); + /* TSC 1 */ + memcpy(skb->data + offset, ((u8 *)&pn48) + 1, 1); + /* TSC 2 , TSC 3 , TSC 4 , TSC 5*/ + memcpy(skb->data + offset + 4, ((u8 *)&pn48) + 2, 4); + } + } } if (tkip_mic_type == HTT_RX_TKIP_MIC) @@ -2263,6 +2336,20 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR) rx_status->flag |= RX_FLAG_MMIC_ERROR; + if (!qos && tid < IEEE80211_NUM_TIDS) { + u8 offset; + __le16 qos_ctrl = 0; + + hdr = (struct ieee80211_hdr *)skb->data; + offset = ieee80211_hdrlen(hdr->frame_control); + + hdr->frame_control |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + memmove(skb->data - IEEE80211_QOS_CTL_LEN, skb->data, offset); + skb_push(skb, IEEE80211_QOS_CTL_LEN); + qos_ctrl = cpu_to_le16(tid); + memcpy(skb->data + offset, &qos_ctrl, IEEE80211_QOS_CTL_LEN); + } + ieee80211_rx_ni(ar->hw, skb); /* We have delivered the skb to the upper layers (mac80211) so we diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 2ef717f18795..a182c0944cc7 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1237,6 +1237,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm struct ath10k *ar = htt->ar; int res, data_len; struct htt_cmd_hdr *cmd_hdr; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct htt_data_tx_desc *tx_desc; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); struct sk_buff *tmp_skb; @@ -1247,6 +1248,13 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm u16 flags1 = 0; u16 msdu_id = 0; + if ((ieee80211_is_action(hdr->frame_control) || + ieee80211_is_deauth(hdr->frame_control) || + ieee80211_is_disassoc(hdr->frame_control)) && + ieee80211_has_protected(hdr->frame_control)) { + skb_put(msdu, IEEE80211_CCMP_MIC_LEN); + } + data_len = msdu->len; switch (txmode) { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0606416dc971..a6d21856b7e7 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5503,10 +5503,6 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); - spin_lock_bh(&ar->data_lock); - ath10k_mac_vif_beacon_cleanup(arvif); - spin_unlock_bh(&ar->data_lock); - ret = ath10k_spectral_vif_stop(arvif); if (ret) ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n", @@ -5575,6 +5571,11 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, peer->vif = NULL; } } + + /* Clean this up late, less opportunity for firmware to access + * DMA memory we have deleted. + */ + ath10k_mac_vif_beacon_cleanup(arvif); spin_unlock_bh(&ar->data_lock); ath10k_peer_cleanup(ar, arvif->vdev_id); @@ -6970,7 +6971,8 @@ exit: return ret; } -static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) +static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath10k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 8ed4fbd8d6c3..9870d2d095c8 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -381,16 +381,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar, struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data; bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; enum ath10k_htc_ep_id eid; - u16 payload_len; u8 *trailer; int ret; - payload_len = le16_to_cpu(htc_hdr->len); - skb->len = payload_len + sizeof(struct ath10k_htc_hdr); - if (trailer_present) { - trailer = skb->data + sizeof(*htc_hdr) + - payload_len - htc_hdr->trailer_len; + trailer = skb->data + skb->len - htc_hdr->trailer_len; eid = pipe_id_to_eid(htc_hdr->eid); @@ -632,13 +627,31 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar, { struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); struct sk_buff *skb = pkt->skb; + struct ath10k_htc_hdr *htc_hdr; int ret; ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr, skb->data, pkt->alloc_len); + if (ret) + goto out; + + /* Update actual length. The original length may be incorrect, + * as the FW will bundle multiple packets as long as their sizes + * fit within the same aligned length (pkt->alloc_len). + */ + htc_hdr = (struct ath10k_htc_hdr *)skb->data; + pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr); + if (pkt->act_len > pkt->alloc_len) { + ath10k_warn(ar, "rx packet too large (%zu > %zu)\n", + pkt->act_len, pkt->alloc_len); + ret = -EMSGSIZE; + goto out; + } + + skb_put(skb, pkt->act_len); + +out: pkt->status = ret; - if (!ret) - skb_put(skb, pkt->act_len); return ret; } diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 2985bb17decd..4d5d10c01064 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -841,7 +841,7 @@ static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar, struct wmi_ch_info_ev_arg *arg) { const void **tb; - const struct wmi_chan_info_event *ev; + const struct wmi_tlv_chan_info_event *ev; int ret; tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index d691f06e58f2..649b229a41e9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1615,6 +1615,22 @@ struct chan_info_params { #define WMI_TLV_FLAG_MGMT_BUNDLE_TX_COMPL BIT(9) +struct wmi_tlv_chan_info_event { + __le32 err_code; + __le32 freq; + __le32 cmd_flags; + __le32 noise_floor; + __le32 rx_clear_count; + __le32 cycle_count; + __le32 chan_tx_pwr_range; + __le32 chan_tx_pwr_tp; + __le32 rx_frame_count; + __le32 my_bss_rx_cycle_count; + __le32 rx_11b_mode_data_duration; + __le32 tx_frame_cnt; + __le32 mac_clk_mhz; +} __packed; + struct wmi_tlv_mgmt_tx_compl_ev { __le32 desc_id; __le32 status; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 838768c98adc..e80dbe7e8f4c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6533,14 +6533,6 @@ struct wmi_chan_info_event { __le32 noise_floor; __le32 rx_clear_count; __le32 cycle_count; - __le32 chan_tx_pwr_range; - __le32 chan_tx_pwr_tp; - __le32 rx_frame_count; - __le32 my_bss_rx_cycle_count; - __le32 rx_11b_mode_data_duration; - __le32 tx_frame_cnt; - __le32 mac_clk_mhz; - } __packed; struct wmi_10_4_chan_info_event { |