|
@@ -550,6 +550,11 @@ static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar,
|
|
|
return IEEE80211_TKIP_IV_LEN;
|
|
|
case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2:
|
|
|
return IEEE80211_CCMP_HDR_LEN;
|
|
|
+ case HTT_RX_MPDU_ENCRYPT_AES_CCM256_WPA2:
|
|
|
+ return IEEE80211_CCMP_256_HDR_LEN;
|
|
|
+ case HTT_RX_MPDU_ENCRYPT_AES_GCMP_WPA2:
|
|
|
+ case HTT_RX_MPDU_ENCRYPT_AES_GCMP256_WPA2:
|
|
|
+ return IEEE80211_GCMP_HDR_LEN;
|
|
|
case HTT_RX_MPDU_ENCRYPT_WEP128:
|
|
|
case HTT_RX_MPDU_ENCRYPT_WAPI:
|
|
|
break;
|
|
@@ -575,6 +580,11 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
|
|
|
return IEEE80211_TKIP_ICV_LEN;
|
|
|
case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2:
|
|
|
return IEEE80211_CCMP_MIC_LEN;
|
|
|
+ case HTT_RX_MPDU_ENCRYPT_AES_CCM256_WPA2:
|
|
|
+ return IEEE80211_CCMP_256_MIC_LEN;
|
|
|
+ case HTT_RX_MPDU_ENCRYPT_AES_GCMP_WPA2:
|
|
|
+ case HTT_RX_MPDU_ENCRYPT_AES_GCMP256_WPA2:
|
|
|
+ return IEEE80211_GCMP_MIC_LEN;
|
|
|
case HTT_RX_MPDU_ENCRYPT_WEP128:
|
|
|
case HTT_RX_MPDU_ENCRYPT_WAPI:
|
|
|
break;
|
|
@@ -1051,9 +1061,21 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
|
|
|
hdr = (void *)msdu->data;
|
|
|
|
|
|
/* Tail */
|
|
|
- if (status->flag & RX_FLAG_IV_STRIPPED)
|
|
|
+ if (status->flag & RX_FLAG_IV_STRIPPED) {
|
|
|
skb_trim(msdu, msdu->len -
|
|
|
ath10k_htt_rx_crypto_tail_len(ar, enctype));
|
|
|
+ } else {
|
|
|
+ /* MIC */
|
|
|
+ if ((status->flag & RX_FLAG_MIC_STRIPPED) &&
|
|
|
+ enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
|
|
|
+ skb_trim(msdu, msdu->len - 8);
|
|
|
+
|
|
|
+ /* ICV */
|
|
|
+ if (status->flag & RX_FLAG_ICV_STRIPPED &&
|
|
|
+ enctype != HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
|
|
|
+ skb_trim(msdu, msdu->len -
|
|
|
+ ath10k_htt_rx_crypto_tail_len(ar, enctype));
|
|
|
+ }
|
|
|
|
|
|
/* MMIC */
|
|
|
if ((status->flag & RX_FLAG_MMIC_STRIPPED) &&
|
|
@@ -1075,7 +1097,8 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
|
|
|
static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
|
|
|
struct sk_buff *msdu,
|
|
|
struct ieee80211_rx_status *status,
|
|
|
- const u8 first_hdr[64])
|
|
|
+ const u8 first_hdr[64],
|
|
|
+ enum htt_rx_mpdu_encrypt_type enctype)
|
|
|
{
|
|
|
struct ieee80211_hdr *hdr;
|
|
|
struct htt_rx_desc *rxd;
|
|
@@ -1083,6 +1106,7 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
|
|
|
u8 da[ETH_ALEN];
|
|
|
u8 sa[ETH_ALEN];
|
|
|
int l3_pad_bytes;
|
|
|
+ int bytes_aligned = ar->hw_params.decap_align_bytes;
|
|
|
|
|
|
/* Delivered decapped frame:
|
|
|
* [nwifi 802.11 header] <-- replaced with 802.11 hdr
|
|
@@ -1111,6 +1135,14 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
|
|
|
/* push original 802.11 header */
|
|
|
hdr = (struct ieee80211_hdr *)first_hdr;
|
|
|
hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
|
|
+
|
|
|
+ if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
|
|
|
+ memcpy(skb_push(msdu,
|
|
|
+ ath10k_htt_rx_crypto_param_len(ar, enctype)),
|
|
|
+ (void *)hdr + round_up(hdr_len, bytes_aligned),
|
|
|
+ ath10k_htt_rx_crypto_param_len(ar, enctype));
|
|
|
+ }
|
|
|
+
|
|
|
memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
|
|
|
|
|
|
/* original 802.11 header has a different DA and in
|
|
@@ -1171,6 +1203,7 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar,
|
|
|
u8 sa[ETH_ALEN];
|
|
|
int l3_pad_bytes;
|
|
|
struct htt_rx_desc *rxd;
|
|
|
+ int bytes_aligned = ar->hw_params.decap_align_bytes;
|
|
|
|
|
|
/* Delivered decapped frame:
|
|
|
* [eth header] <-- replaced with 802.11 hdr & rfc1042/llc
|
|
@@ -1199,6 +1232,14 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar,
|
|
|
/* push original 802.11 header */
|
|
|
hdr = (struct ieee80211_hdr *)first_hdr;
|
|
|
hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
|
|
+
|
|
|
+ if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
|
|
|
+ memcpy(skb_push(msdu,
|
|
|
+ ath10k_htt_rx_crypto_param_len(ar, enctype)),
|
|
|
+ (void *)hdr + round_up(hdr_len, bytes_aligned),
|
|
|
+ ath10k_htt_rx_crypto_param_len(ar, enctype));
|
|
|
+ }
|
|
|
+
|
|
|
memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
|
|
|
|
|
|
/* original 802.11 header has a different DA and in
|
|
@@ -1212,12 +1253,14 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar,
|
|
|
static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
|
|
|
struct sk_buff *msdu,
|
|
|
struct ieee80211_rx_status *status,
|
|
|
- const u8 first_hdr[64])
|
|
|
+ const u8 first_hdr[64],
|
|
|
+ enum htt_rx_mpdu_encrypt_type enctype)
|
|
|
{
|
|
|
struct ieee80211_hdr *hdr;
|
|
|
size_t hdr_len;
|
|
|
int l3_pad_bytes;
|
|
|
struct htt_rx_desc *rxd;
|
|
|
+ int bytes_aligned = ar->hw_params.decap_align_bytes;
|
|
|
|
|
|
/* Delivered decapped frame:
|
|
|
* [amsdu header] <-- replaced with 802.11 hdr
|
|
@@ -1233,6 +1276,14 @@ static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *)first_hdr;
|
|
|
hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
|
|
+
|
|
|
+ if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
|
|
|
+ memcpy(skb_push(msdu,
|
|
|
+ ath10k_htt_rx_crypto_param_len(ar, enctype)),
|
|
|
+ (void *)hdr + round_up(hdr_len, bytes_aligned),
|
|
|
+ ath10k_htt_rx_crypto_param_len(ar, enctype));
|
|
|
+ }
|
|
|
+
|
|
|
memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
|
|
|
}
|
|
|
|
|
@@ -1267,13 +1318,15 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar,
|
|
|
is_decrypted);
|
|
|
break;
|
|
|
case RX_MSDU_DECAP_NATIVE_WIFI:
|
|
|
- ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr);
|
|
|
+ ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr,
|
|
|
+ enctype);
|
|
|
break;
|
|
|
case RX_MSDU_DECAP_ETHERNET2_DIX:
|
|
|
ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype);
|
|
|
break;
|
|
|
case RX_MSDU_DECAP_8023_SNAP_LLC:
|
|
|
- ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr);
|
|
|
+ ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr,
|
|
|
+ enctype);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -1316,7 +1369,8 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu)
|
|
|
|
|
|
static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|
|
struct sk_buff_head *amsdu,
|
|
|
- struct ieee80211_rx_status *status)
|
|
|
+ struct ieee80211_rx_status *status,
|
|
|
+ bool fill_crypt_header)
|
|
|
{
|
|
|
struct sk_buff *first;
|
|
|
struct sk_buff *last;
|
|
@@ -1326,7 +1380,6 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|
|
enum htt_rx_mpdu_encrypt_type enctype;
|
|
|
u8 first_hdr[64];
|
|
|
u8 *qos;
|
|
|
- size_t hdr_len;
|
|
|
bool has_fcs_err;
|
|
|
bool has_crypto_err;
|
|
|
bool has_tkip_err;
|
|
@@ -1351,15 +1404,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|
|
* decapped header. It'll be used for undecapping of each MSDU.
|
|
|
*/
|
|
|
hdr = (void *)rxd->rx_hdr_status;
|
|
|
- hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
|
|
- memcpy(first_hdr, hdr, hdr_len);
|
|
|
+ memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
|
|
|
|
|
|
/* Each A-MSDU subframe will use the original header as the base and be
|
|
|
* reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
|
|
|
*/
|
|
|
hdr = (void *)first_hdr;
|
|
|
- qos = ieee80211_get_qos_ctl(hdr);
|
|
|
- qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
|
|
|
+
|
|
|
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
|
|
|
+ qos = ieee80211_get_qos_ctl(hdr);
|
|
|
+ qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
|
|
|
+ }
|
|
|
|
|
|
/* Some attention flags are valid only in the last MSDU. */
|
|
|
last = skb_peek_tail(amsdu);
|
|
@@ -1406,9 +1461,14 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|
|
status->flag |= RX_FLAG_DECRYPTED;
|
|
|
|
|
|
if (likely(!is_mgmt))
|
|
|
- status->flag |= RX_FLAG_IV_STRIPPED |
|
|
|
- RX_FLAG_MMIC_STRIPPED;
|
|
|
-}
|
|
|
+ status->flag |= RX_FLAG_MMIC_STRIPPED;
|
|
|
+
|
|
|
+ if (fill_crypt_header)
|
|
|
+ status->flag |= RX_FLAG_MIC_STRIPPED |
|
|
|
+ RX_FLAG_ICV_STRIPPED;
|
|
|
+ else
|
|
|
+ status->flag |= RX_FLAG_IV_STRIPPED;
|
|
|
+ }
|
|
|
|
|
|
skb_queue_walk(amsdu, msdu) {
|
|
|
ath10k_htt_rx_h_csum_offload(msdu);
|
|
@@ -1424,6 +1484,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|
|
if (is_mgmt)
|
|
|
continue;
|
|
|
|
|
|
+ if (fill_crypt_header)
|
|
|
+ continue;
|
|
|
+
|
|
|
hdr = (void *)msdu->data;
|
|
|
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
|
|
}
|
|
@@ -1434,6 +1497,9 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
|
|
|
struct ieee80211_rx_status *status)
|
|
|
{
|
|
|
struct sk_buff *msdu;
|
|
|
+ struct sk_buff *first_subframe;
|
|
|
+
|
|
|
+ first_subframe = skb_peek(amsdu);
|
|
|
|
|
|
while ((msdu = __skb_dequeue(amsdu))) {
|
|
|
/* Setup per-MSDU flags */
|
|
@@ -1442,6 +1508,13 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
|
|
|
else
|
|
|
status->flag |= RX_FLAG_AMSDU_MORE;
|
|
|
|
|
|
+ if (msdu == first_subframe) {
|
|
|
+ first_subframe = NULL;
|
|
|
+ status->flag &= ~RX_FLAG_ALLOW_SAME_PN;
|
|
|
+ } else {
|
|
|
+ status->flag |= RX_FLAG_ALLOW_SAME_PN;
|
|
|
+ }
|
|
|
+
|
|
|
ath10k_process_rx(ar, status, msdu);
|
|
|
}
|
|
|
}
|
|
@@ -1584,7 +1657,7 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|
|
ath10k_htt_rx_h_unchain(ar, &amsdu);
|
|
|
|
|
|
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
|
|
- ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
|
|
|
+ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
|
|
|
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
|
|
|
|
|
|
return num_msdus;
|
|
@@ -1745,8 +1818,7 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
|
|
|
}
|
|
|
|
|
|
static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,
|
|
|
- struct sk_buff_head *amsdu,
|
|
|
- int budget_left)
|
|
|
+ struct sk_buff_head *amsdu)
|
|
|
{
|
|
|
struct sk_buff *msdu;
|
|
|
struct htt_rx_desc *rxd;
|
|
@@ -1757,9 +1829,8 @@ static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,
|
|
|
if (WARN_ON(!skb_queue_empty(amsdu)))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- while ((msdu = __skb_dequeue(list)) && budget_left) {
|
|
|
+ while ((msdu = __skb_dequeue(list))) {
|
|
|
__skb_queue_tail(amsdu, msdu);
|
|
|
- budget_left--;
|
|
|
|
|
|
rxd = (void *)msdu->data - sizeof(*rxd);
|
|
|
if (rxd->msdu_end.common.info0 &
|
|
@@ -1850,8 +1921,7 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
|
|
return num_msdu;
|
|
|
}
|
|
|
|
|
|
-static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb,
|
|
|
- int budget_left)
|
|
|
+static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|
|
{
|
|
|
struct ath10k_htt *htt = &ar->htt;
|
|
|
struct htt_resp *resp = (void *)skb->data;
|
|
@@ -1908,9 +1978,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb,
|
|
|
if (offload)
|
|
|
num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list);
|
|
|
|
|
|
- while (!skb_queue_empty(&list) && budget_left) {
|
|
|
+ while (!skb_queue_empty(&list)) {
|
|
|
__skb_queue_head_init(&amsdu);
|
|
|
- ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu, budget_left);
|
|
|
+ ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu);
|
|
|
switch (ret) {
|
|
|
case 0:
|
|
|
/* Note: The in-order indication may report interleaved
|
|
@@ -1920,10 +1990,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb,
|
|
|
* should still give an idea about rx rate to the user.
|
|
|
*/
|
|
|
num_msdus += skb_queue_len(&amsdu);
|
|
|
- budget_left -= skb_queue_len(&amsdu);
|
|
|
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
|
|
|
ath10k_htt_rx_h_filter(ar, &amsdu, status);
|
|
|
- ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
|
|
|
+ ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
|
|
|
ath10k_htt_rx_h_deliver(ar, &amsdu, status);
|
|
|
break;
|
|
|
case -EAGAIN:
|
|
@@ -2563,8 +2632,7 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
|
|
|
}
|
|
|
|
|
|
spin_lock_bh(&htt->rx_ring.lock);
|
|
|
- num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb,
|
|
|
- (budget - quota));
|
|
|
+ num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb);
|
|
|
spin_unlock_bh(&htt->rx_ring.lock);
|
|
|
if (num_rx_msdus < 0) {
|
|
|
resched_napi = true;
|