Compare commits
7 Commits
master
...
NBSW_4.5.0
| Author | SHA1 | Date |
|---|---|---|
|
|
a882fa05c6 | |
|
|
c0fbce1571 | |
|
|
3ed0054c18 | |
|
|
8f746d1044 | |
|
|
412dfbc9af | |
|
|
699399f009 | |
|
|
7420bbdc01 |
|
|
@ -14,7 +14,7 @@ inherit pkgconfig
|
|||
|
||||
PACKAGECONFIG = "openssl"
|
||||
|
||||
SRC_URI = "git://w1.fi/hostap.git;protocol=http \
|
||||
SRC_URI = "git://w1.fi/hostap.git;protocol=http;branch=main \
|
||||
file://004-mesh-use-setup-completion-callback-to-complete-mesh-.patch \
|
||||
file://005-mesh-update-ssid-frequency-as-pri-sec-channel-switch.patch \
|
||||
file://006-mesh-inform-kernel-driver-DFS-handler-in-userspace.patch \
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb
|
|||
file://0001-ADD-regdb-EU-section-with-ranges-allowed-for-all-EU-.patch \
|
||||
"
|
||||
|
||||
SRCREV = "f9dfc584fa5c88ced7686917b5bc2bcc67332ced"
|
||||
SRCREV = "90e83fc9933c28c2b231d0efb9d98665ec1d844a"
|
||||
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
SUMMARY = "TI wl18xx firmware for use with Linux kernel"
|
||||
DESCRIPTION = "firmware forTI wl18xx based chipsets like wl1837"
|
||||
HOMEPAGE = "https://git.ti.com/cgit/wilink8-wlan/wl18xx_fw/"
|
||||
SECTION = "base"
|
||||
LICENSE = "Firmware-ti-wl18xx"
|
||||
LIC_FILES_CHKSUM = "file://LICENCE;md5=4977a0fe767ee17765ae63c435a32a9e"
|
||||
|
||||
NO_GENERIC_LICENSE[Firmware-ti-wl18xx]="LICENCE"
|
||||
|
||||
SRC_URI += " \
|
||||
git://git.ti.com/wilink8-wlan/wl18xx_fw.git \
|
||||
"
|
||||
|
||||
SRCREV = "5ec05007f2662f460f881c5868311fd3ab7e6e71"
|
||||
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
do_install () {
|
||||
install -d ${D}${nonarch_base_libdir}/firmware/ti-connectivity/
|
||||
install -m 0644 wl18xx-fw-4.bin ${D}${nonarch_base_libdir}/firmware/ti-connectivity/wl18xx-fw-4-mesh.bin
|
||||
}
|
||||
|
||||
FILES_${PN} = "${nonarch_base_libdir}/firmware"
|
||||
|
|
@ -12,7 +12,7 @@ SRC_URI += " \
|
|||
file://nm-wl18xx-TIInit_11.8.32.bts \
|
||||
"
|
||||
|
||||
SRCREV = "43dbcdfa19342068a023b2b9b07f65f8b11d1bea"
|
||||
SRCREV = "bda5304cc86e9c4029f8101394d2a8b39c640f53"
|
||||
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,952 @@
|
|||
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
|
||||
index 9c8ad11..a7dd616 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/htt.h
|
||||
+++ b/drivers/net/wireless/ath/ath10k/htt.h
|
||||
@@ -836,6 +836,7 @@ enum htt_security_types {
|
||||
|
||||
#define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2
|
||||
#define ATH10K_TXRX_NUM_EXT_TIDS 19
|
||||
+#define ATH10K_TXRX_NON_QOS_TID 16
|
||||
|
||||
enum htt_security_flags {
|
||||
#define HTT_SECURITY_TYPE_MASK 0x7F
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
|
||||
index 9f0e7b4..9e04bc4 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
|
||||
@@ -1725,16 +1725,97 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu)
|
||||
msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu);
|
||||
}
|
||||
|
||||
+static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb,
|
||||
+ u16 offset,
|
||||
+ enum htt_rx_mpdu_encrypt_type enctype)
|
||||
+{
|
||||
+ struct ieee80211_hdr *hdr;
|
||||
+ u64 pn = 0;
|
||||
+ u8 *ehdr;
|
||||
+
|
||||
+ hdr = (struct ieee80211_hdr *)(skb->data + offset);
|
||||
+ ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control);
|
||||
+
|
||||
+ if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) {
|
||||
+ pn = ehdr[0];
|
||||
+ pn |= (u64)ehdr[1] << 8;
|
||||
+ pn |= (u64)ehdr[4] << 16;
|
||||
+ pn |= (u64)ehdr[5] << 24;
|
||||
+ pn |= (u64)ehdr[6] << 32;
|
||||
+ pn |= (u64)ehdr[7] << 40;
|
||||
+ }
|
||||
+ return pn;
|
||||
+}
|
||||
+
|
||||
+static bool ath10k_htt_rx_h_frag_multicast_check(struct ath10k *ar,
|
||||
+ struct sk_buff *skb,
|
||||
+ u16 offset)
|
||||
+{
|
||||
+ struct ieee80211_hdr *hdr;
|
||||
+
|
||||
+ hdr = (struct ieee80211_hdr *)(skb->data + offset);
|
||||
+ return !is_multicast_ether_addr(hdr->addr1);
|
||||
+}
|
||||
+
|
||||
+static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar,
|
||||
+ struct sk_buff *skb,
|
||||
+ u16 peer_id,
|
||||
+ u16 offset,
|
||||
+ enum htt_rx_mpdu_encrypt_type enctype)
|
||||
+{
|
||||
+ struct ath10k_peer *peer;
|
||||
+ union htt_rx_pn_t *last_pn, new_pn = {0};
|
||||
+ struct ieee80211_hdr *hdr;
|
||||
+ bool more_frags;
|
||||
+ u8 tid, frag_number;
|
||||
+ u32 seq;
|
||||
+
|
||||
+ peer = ath10k_peer_find_by_id(ar, peer_id);
|
||||
+ if (!peer) {
|
||||
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ hdr = (struct ieee80211_hdr *)(skb->data + offset);
|
||||
+ if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
+ tid = ieee80211_get_tid(hdr);
|
||||
+ else
|
||||
+ tid = ATH10K_TXRX_NON_QOS_TID;
|
||||
+
|
||||
+ last_pn = &peer->frag_tids_last_pn[tid];
|
||||
+ new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype);
|
||||
+ more_frags = ieee80211_has_morefrags(hdr->frame_control);
|
||||
+ frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
|
||||
+ seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
|
||||
+
|
||||
+ if (frag_number == 0) {
|
||||
+ last_pn->pn48 = new_pn.pn48;
|
||||
+ peer->frag_tids_seq[tid] = seq;
|
||||
+ } else {
|
||||
+ if (seq != peer->frag_tids_seq[tid])
|
||||
+ return false;
|
||||
+
|
||||
+ if (new_pn.pn48 != last_pn->pn48 + 1)
|
||||
+ return false;
|
||||
+
|
||||
+ last_pn->pn48 = new_pn.pn48;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu,
|
||||
struct ieee80211_rx_status *status,
|
||||
bool fill_crypt_header,
|
||||
u8 *rx_hdr,
|
||||
- enum ath10k_pkt_rx_err *err)
|
||||
+ enum ath10k_pkt_rx_err *err,
|
||||
+ u16 peer_id,
|
||||
+ bool frag)
|
||||
{
|
||||
struct sk_buff *first;
|
||||
struct sk_buff *last;
|
||||
- struct sk_buff *msdu;
|
||||
+ struct sk_buff *msdu, *temp;
|
||||
struct htt_rx_desc *rxd;
|
||||
struct ieee80211_hdr *hdr;
|
||||
enum htt_rx_mpdu_encrypt_type enctype;
|
||||
@@ -1747,6 +1828,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
bool is_decrypted;
|
||||
bool is_mgmt;
|
||||
u32 attention;
|
||||
+ bool frag_pn_check = true, multicast_check = true;
|
||||
|
||||
if (skb_queue_empty(amsdu))
|
||||
return;
|
||||
@@ -1845,7 +1927,37 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
}
|
||||
|
||||
skb_queue_walk(amsdu, msdu) {
|
||||
+ if (frag && !fill_crypt_header && is_decrypted &&
|
||||
+ enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
|
||||
+ frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar,
|
||||
+ msdu,
|
||||
+ peer_id,
|
||||
+ 0,
|
||||
+ enctype);
|
||||
+
|
||||
+ if (frag)
|
||||
+ multicast_check = ath10k_htt_rx_h_frag_multicast_check(ar,
|
||||
+ msdu,
|
||||
+ 0);
|
||||
+
|
||||
+ if (!frag_pn_check || !multicast_check) {
|
||||
+ /* Discard the fragment with invalid PN or multicast DA
|
||||
+ */
|
||||
+ temp = msdu->prev;
|
||||
+ __skb_unlink(msdu, amsdu);
|
||||
+ dev_kfree_skb_any(msdu);
|
||||
+ msdu = temp;
|
||||
+ frag_pn_check = true;
|
||||
+ multicast_check = true;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
ath10k_htt_rx_h_csum_offload(msdu);
|
||||
+
|
||||
+ if (frag && !fill_crypt_header &&
|
||||
+ enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
|
||||
+ status->flag &= ~RX_FLAG_MMIC_STRIPPED;
|
||||
+
|
||||
ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
|
||||
is_decrypted);
|
||||
|
||||
@@ -1863,6 +1975,11 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
|
||||
hdr = (void *)msdu->data;
|
||||
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
+
|
||||
+ if (frag && !fill_crypt_header &&
|
||||
+ enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
|
||||
+ status->flag &= ~RX_FLAG_IV_STRIPPED &
|
||||
+ ~RX_FLAG_MMIC_STRIPPED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1970,14 +2087,62 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
|
||||
ath10k_unchain_msdu(amsdu, unchain_cnt);
|
||||
}
|
||||
|
||||
+static bool ath10k_htt_rx_validate_amsdu(struct ath10k *ar,
|
||||
+ struct sk_buff_head *amsdu)
|
||||
+{
|
||||
+ u8 *subframe_hdr;
|
||||
+ struct sk_buff *first;
|
||||
+ bool is_first, is_last;
|
||||
+ struct htt_rx_desc *rxd;
|
||||
+ struct ieee80211_hdr *hdr;
|
||||
+ size_t hdr_len, crypto_len;
|
||||
+ enum htt_rx_mpdu_encrypt_type enctype;
|
||||
+ int bytes_aligned = ar->hw_params.decap_align_bytes;
|
||||
+
|
||||
+ first = skb_peek(amsdu);
|
||||
+
|
||||
+ rxd = (void *)first->data - sizeof(*rxd);
|
||||
+ hdr = (void *)rxd->rx_hdr_status;
|
||||
+
|
||||
+ is_first = !!(rxd->msdu_end.common.info0 &
|
||||
+ __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU));
|
||||
+ is_last = !!(rxd->msdu_end.common.info0 &
|
||||
+ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));
|
||||
+
|
||||
+ /* Return in case of non-aggregated msdu */
|
||||
+ if (is_first && is_last)
|
||||
+ return true;
|
||||
+
|
||||
+ /* First msdu flag is not set for the first msdu of the list */
|
||||
+ if (!is_first)
|
||||
+ return false;
|
||||
+
|
||||
+ enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
|
||||
+ RX_MPDU_START_INFO0_ENCRYPT_TYPE);
|
||||
+
|
||||
+ hdr_len = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
|
||||
+
|
||||
+ subframe_hdr = (u8 *)hdr + round_up(hdr_len, bytes_aligned) +
|
||||
+ crypto_len;
|
||||
+
|
||||
+ /* Validate if the amsdu has a proper first subframe.
|
||||
+ * There are chances a single msdu can be received as amsdu when
|
||||
+ * the unauthenticated amsdu flag of a QoS header
|
||||
+ * gets flipped in non-SPP AMSDU's, in such cases the first
|
||||
+ * subframe has llc/snap header in place of a valid da.
|
||||
+ * return false if the da matches rfc1042 pattern
|
||||
+ */
|
||||
+ if (ether_addr_equal(subframe_hdr, rfc1042_header))
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
- /* FIXME: It might be a good idea to do some fuzzy-testing to drop
|
||||
- * invalid/dangerous frames.
|
||||
- */
|
||||
-
|
||||
if (!rx_status->freq) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "no channel configured; ignoring frame(s)!\n");
|
||||
return false;
|
||||
@@ -1988,6 +2153,11 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
|
||||
return false;
|
||||
}
|
||||
|
||||
+ if (!ath10k_htt_rx_validate_amsdu(ar, amsdu)) {
|
||||
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid amsdu received\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2050,7 +2220,8 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
||||
ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt);
|
||||
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter);
|
||||
- ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err);
|
||||
+ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err, 0,
|
||||
+ false);
|
||||
msdus_to_queue = skb_queue_len(&amsdu);
|
||||
ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
|
||||
|
||||
@@ -2183,6 +2354,11 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
|
||||
fw_desc = &rx->fw_desc;
|
||||
rx_desc_len = fw_desc->len;
|
||||
|
||||
+ if (fw_desc->u.bits.discard) {
|
||||
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt discard mpdu\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
/* I have not yet seen any case where num_mpdu_ranges > 1.
|
||||
* qcacld does not seem handle that case either, so we introduce the
|
||||
* same limitiation here as well.
|
||||
@@ -2483,6 +2659,13 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt,
|
||||
rx_desc = (struct htt_hl_rx_desc *)(skb->data + tot_hdr_len);
|
||||
rx_desc_info = __le32_to_cpu(rx_desc->info);
|
||||
|
||||
+ hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len);
|
||||
+
|
||||
+ if (is_multicast_ether_addr(hdr->addr1)) {
|
||||
+ /* Discard the fragment with multicast DA */
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
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,
|
||||
@@ -2490,8 +2673,6 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt,
|
||||
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;
|
||||
|
||||
@@ -3000,7 +3181,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL,
|
||||
- NULL);
|
||||
+ NULL, peer_id, frag);
|
||||
ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
|
||||
break;
|
||||
case -EAGAIN:
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
|
||||
index dec1582..13a1cae 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
|
||||
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
|
||||
@@ -1282,7 +1282,19 @@ struct fw_rx_desc_base {
|
||||
#define FW_RX_DESC_UDP (1 << 6)
|
||||
|
||||
struct fw_rx_desc_hl {
|
||||
- u8 info0;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ u8 discard:1,
|
||||
+ forward:1,
|
||||
+ any_err:1,
|
||||
+ dup_err:1,
|
||||
+ reserved:1,
|
||||
+ inspect:1,
|
||||
+ extension:2;
|
||||
+ } bits;
|
||||
+ u8 info0;
|
||||
+ } u;
|
||||
+
|
||||
u8 version;
|
||||
u8 len;
|
||||
u8 flags;
|
||||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
|
||||
index 8099b10..75ecfeb 100644
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -5207,7 +5207,7 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
|
||||
*/
|
||||
int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
- u8 data_offset);
|
||||
+ u8 data_offset, bool is_amsdu);
|
||||
|
||||
/**
|
||||
* ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
|
||||
@@ -5219,7 +5219,7 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
- return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype, 0);
|
||||
+ return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype, 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
|
||||
index f75fb7d..60cd5b0 100644
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -50,12 +50,6 @@ struct ieee80211_local;
|
||||
#define IEEE80211_ENCRYPT_HEADROOM 8
|
||||
#define IEEE80211_ENCRYPT_TAILROOM 18
|
||||
|
||||
-/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
|
||||
- * reception of at least three fragmented frames. This limit can be increased
|
||||
- * by changing this define, at the cost of slower frame reassembly and
|
||||
- * increased memory use (about 2 kB of RAM per entry). */
|
||||
-#define IEEE80211_FRAGMENT_MAX 4
|
||||
-
|
||||
/* power level hasn't been configured (or set to automatic) */
|
||||
#define IEEE80211_UNSET_POWER_LEVEL INT_MIN
|
||||
|
||||
@@ -88,18 +82,6 @@ extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS];
|
||||
|
||||
#define IEEE80211_MAX_NAN_INSTANCE_ID 255
|
||||
|
||||
-struct ieee80211_fragment_entry {
|
||||
- struct sk_buff_head skb_list;
|
||||
- unsigned long first_frag_time;
|
||||
- u16 seq;
|
||||
- u16 extra_len;
|
||||
- u16 last_frag;
|
||||
- u8 rx_queue;
|
||||
- bool check_sequential_pn; /* needed for CCMP/GCMP */
|
||||
- u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
|
||||
-};
|
||||
-
|
||||
-
|
||||
struct ieee80211_bss {
|
||||
u32 device_ts_beacon, device_ts_presp;
|
||||
|
||||
@@ -240,8 +222,15 @@ struct ieee80211_rx_data {
|
||||
*/
|
||||
int security_idx;
|
||||
|
||||
- u32 tkip_iv32;
|
||||
- u16 tkip_iv16;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ u32 iv32;
|
||||
+ u16 iv16;
|
||||
+ } tkip;
|
||||
+ struct {
|
||||
+ u8 pn[IEEE80211_CCMP_PN_LEN];
|
||||
+ } ccm_gcm;
|
||||
+ };
|
||||
};
|
||||
|
||||
struct ieee80211_csa_settings {
|
||||
@@ -894,9 +883,7 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
- /* Fragment table for host-based reassembly */
|
||||
- struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
|
||||
- unsigned int fragment_next;
|
||||
+ struct ieee80211_fragment_cache frags;
|
||||
|
||||
/* TID bitmap for NoAck policy */
|
||||
u16 noack_map;
|
||||
@@ -2268,4 +2255,7 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
|
||||
#define debug_noinline
|
||||
#endif
|
||||
|
||||
+void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache);
|
||||
+void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache);
|
||||
+
|
||||
#endif /* IEEE80211_I_H */
|
||||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
|
||||
index 1c6bb17..a88795c 100644
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1108,16 +1108,12 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
|
||||
*/
|
||||
static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
- int i;
|
||||
-
|
||||
/* free extra data */
|
||||
ieee80211_free_keys(sdata, false);
|
||||
|
||||
ieee80211_debugfs_remove_netdev(sdata);
|
||||
|
||||
- for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
|
||||
- __skb_queue_purge(&sdata->fragments[i].skb_list);
|
||||
- sdata->fragment_next = 0;
|
||||
+ ieee80211_destroy_frag_cache(&sdata->frags);
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
ieee80211_mesh_teardown_sdata(sdata);
|
||||
@@ -1893,8 +1889,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
sdata->wdev.wiphy = local->hw.wiphy;
|
||||
sdata->local = local;
|
||||
|
||||
- for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
|
||||
- skb_queue_head_init(&sdata->fragments[i].skb_list);
|
||||
+ ieee80211_init_frag_cache(&sdata->frags);
|
||||
|
||||
INIT_LIST_HEAD(&sdata->key_list);
|
||||
|
||||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
|
||||
index efc1acc..fff7efc 100644
|
||||
--- a/net/mac80211/key.c
|
||||
+++ b/net/mac80211/key.c
|
||||
@@ -764,6 +764,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
+ static atomic_t key_color = ATOMIC_INIT(0);
|
||||
struct ieee80211_key *old_key;
|
||||
int idx = key->conf.keyidx;
|
||||
bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
@@ -815,6 +816,12 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
||||
key->sdata = sdata;
|
||||
key->sta = sta;
|
||||
|
||||
+ /*
|
||||
+ * Assign a unique ID to every key so we can easily prevent mixed
|
||||
+ * key and fragment cache attacks.
|
||||
+ */
|
||||
+ key->color = atomic_inc_return(&key_color);
|
||||
+
|
||||
increment_tailroom_need_count(sdata);
|
||||
|
||||
ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
|
||||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
|
||||
index cbc219d..39a50ba 100644
|
||||
--- a/net/mac80211/key.h
|
||||
+++ b/net/mac80211/key.h
|
||||
@@ -127,6 +127,8 @@ struct ieee80211_key {
|
||||
} debugfs;
|
||||
#endif
|
||||
|
||||
+ unsigned int color;
|
||||
+
|
||||
/*
|
||||
* key config, must be last because it contains key
|
||||
* material as variable length member
|
||||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
|
||||
index cd3e241..77463a8 100644
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -2084,19 +2084,34 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
return result;
|
||||
}
|
||||
|
||||
+void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
|
||||
+ skb_queue_head_init(&cache->entries[i].skb_list);
|
||||
+}
|
||||
+
|
||||
+void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(cache->entries); i++)
|
||||
+ __skb_queue_purge(&cache->entries[i].skb_list);
|
||||
+}
|
||||
+
|
||||
static inline struct ieee80211_fragment_entry *
|
||||
-ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
|
||||
+ieee80211_reassemble_add(struct ieee80211_fragment_cache *cache,
|
||||
unsigned int frag, unsigned int seq, int rx_queue,
|
||||
struct sk_buff **skb)
|
||||
{
|
||||
struct ieee80211_fragment_entry *entry;
|
||||
|
||||
- entry = &sdata->fragments[sdata->fragment_next++];
|
||||
- if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
|
||||
- sdata->fragment_next = 0;
|
||||
+ entry = &cache->entries[cache->next++];
|
||||
+ if (cache->next >= IEEE80211_FRAGMENT_MAX)
|
||||
+ cache->next = 0;
|
||||
|
||||
- if (!skb_queue_empty(&entry->skb_list))
|
||||
- __skb_queue_purge(&entry->skb_list);
|
||||
+ __skb_queue_purge(&entry->skb_list);
|
||||
|
||||
__skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
|
||||
*skb = NULL;
|
||||
@@ -2111,14 +2126,14 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
static inline struct ieee80211_fragment_entry *
|
||||
-ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
|
||||
+ieee80211_reassemble_find(struct ieee80211_fragment_cache *cache,
|
||||
unsigned int frag, unsigned int seq,
|
||||
int rx_queue, struct ieee80211_hdr *hdr)
|
||||
{
|
||||
struct ieee80211_fragment_entry *entry;
|
||||
int i, idx;
|
||||
|
||||
- idx = sdata->fragment_next;
|
||||
+ idx = cache->next;
|
||||
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
|
||||
struct ieee80211_hdr *f_hdr;
|
||||
struct sk_buff *f_skb;
|
||||
@@ -2127,7 +2142,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
|
||||
if (idx < 0)
|
||||
idx = IEEE80211_FRAGMENT_MAX - 1;
|
||||
|
||||
- entry = &sdata->fragments[idx];
|
||||
+ entry = &cache->entries[idx];
|
||||
if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
|
||||
entry->rx_queue != rx_queue ||
|
||||
entry->last_frag + 1 != frag)
|
||||
@@ -2155,15 +2170,27 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc)
|
||||
+{
|
||||
+ return rx->key &&
|
||||
+ (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
|
||||
+ rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
|
||||
+ rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
|
||||
+ rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
|
||||
+ ieee80211_has_protected(fc);
|
||||
+}
|
||||
+
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
+ struct ieee80211_fragment_cache *cache = &rx->sdata->frags;
|
||||
struct ieee80211_hdr *hdr;
|
||||
u16 sc;
|
||||
__le16 fc;
|
||||
unsigned int frag, seq;
|
||||
struct ieee80211_fragment_entry *entry;
|
||||
struct sk_buff *skb;
|
||||
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
fc = hdr->frame_control;
|
||||
@@ -2179,6 +2206,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
goto out_no_led;
|
||||
}
|
||||
|
||||
+ if (rx->sta)
|
||||
+ cache = &rx->sta->frags;
|
||||
+
|
||||
if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
|
||||
goto out;
|
||||
|
||||
@@ -2197,20 +2227,17 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
|
||||
if (frag == 0) {
|
||||
/* This is the first fragment of a new frame. */
|
||||
- entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
|
||||
+ entry = ieee80211_reassemble_add(cache, frag, seq,
|
||||
rx->seqno_idx, &(rx->skb));
|
||||
- if (rx->key &&
|
||||
- (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
|
||||
- rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
|
||||
- rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
|
||||
- rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
|
||||
- ieee80211_has_protected(fc)) {
|
||||
+ if (requires_sequential_pn(rx, fc)) {
|
||||
int queue = rx->security_idx;
|
||||
|
||||
/* Store CCMP/GCMP PN so that we can verify that the
|
||||
* next fragment has a sequential PN value.
|
||||
*/
|
||||
entry->check_sequential_pn = true;
|
||||
+ entry->is_protected = true;
|
||||
+ entry->key_color = rx->key->color;
|
||||
memcpy(entry->last_pn,
|
||||
rx->key->u.ccmp.rx_pn[queue],
|
||||
IEEE80211_CCMP_PN_LEN);
|
||||
@@ -2222,6 +2249,11 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
sizeof(rx->key->u.gcmp.rx_pn[queue]));
|
||||
BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
|
||||
IEEE80211_GCMP_PN_LEN);
|
||||
+ } else if (rx->key &&
|
||||
+ (ieee80211_has_protected(fc) ||
|
||||
+ (status->flag & RX_FLAG_DECRYPTED))) {
|
||||
+ entry->is_protected = true;
|
||||
+ entry->key_color = rx->key->color;
|
||||
}
|
||||
return RX_QUEUED;
|
||||
}
|
||||
@@ -2229,7 +2261,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
/* This is a fragment for a frame that should already be pending in
|
||||
* fragment cache. Add this fragment to the end of the pending entry.
|
||||
*/
|
||||
- entry = ieee80211_reassemble_find(rx->sdata, frag, seq,
|
||||
+ entry = ieee80211_reassemble_find(cache, frag, seq,
|
||||
rx->seqno_idx, hdr);
|
||||
if (!entry) {
|
||||
I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
|
||||
@@ -2244,25 +2276,39 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
if (entry->check_sequential_pn) {
|
||||
int i;
|
||||
u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
|
||||
- int queue;
|
||||
|
||||
- if (!rx->key ||
|
||||
- (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP &&
|
||||
- rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 &&
|
||||
- rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP &&
|
||||
- rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256))
|
||||
+ if (!requires_sequential_pn(rx, fc))
|
||||
+ return RX_DROP_UNUSABLE;
|
||||
+
|
||||
+ /* Prevent mixed key and fragment cache attacks */
|
||||
+ if (entry->key_color != rx->key->color)
|
||||
return RX_DROP_UNUSABLE;
|
||||
+
|
||||
memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
|
||||
for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
|
||||
pn[i]++;
|
||||
if (pn[i])
|
||||
break;
|
||||
}
|
||||
- queue = rx->security_idx;
|
||||
- rpn = rx->key->u.ccmp.rx_pn[queue];
|
||||
+
|
||||
+ rpn = rx->ccm_gcm.pn;
|
||||
if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN))
|
||||
return RX_DROP_UNUSABLE;
|
||||
memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN);
|
||||
+ } else if (entry->is_protected &&
|
||||
+ (!rx->key ||
|
||||
+ (!ieee80211_has_protected(fc) &&
|
||||
+ !(status->flag & RX_FLAG_DECRYPTED)) ||
|
||||
+ rx->key->color != entry->key_color)) {
|
||||
+ /* Drop this as a mixed key or fragment cache attack, even
|
||||
+ * if for TKIP Michael MIC should protect us, and WEP is a
|
||||
+ * lost cause anyway.
|
||||
+ */
|
||||
+ return RX_DROP_UNUSABLE;
|
||||
+ } else if (entry->is_protected && rx->key &&
|
||||
+ entry->key_color != rx->key->color &&
|
||||
+ (status->flag & RX_FLAG_DECRYPTED)) {
|
||||
+ return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
||||
skb_pull(rx->skb, ieee80211_hdrlen(fc));
|
||||
@@ -2422,13 +2468,13 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
|
||||
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
|
||||
|
||||
/*
|
||||
- * Allow EAPOL frames to us/the PAE group address regardless
|
||||
- * of whether the frame was encrypted or not.
|
||||
+ * Allow EAPOL frames to us/the PAE group address regardless of
|
||||
+ * whether the frame was encrypted or not, and always disallow
|
||||
+ * all other destination addresses for them.
|
||||
*/
|
||||
- if (ehdr->h_proto == rx->sdata->control_port_protocol &&
|
||||
- (ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
|
||||
- ether_addr_equal(ehdr->h_dest, pae_group_addr)))
|
||||
- return true;
|
||||
+ if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol))
|
||||
+ return ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
|
||||
+ ether_addr_equal(ehdr->h_dest, pae_group_addr);
|
||||
|
||||
if (ieee80211_802_1x_port_control(rx) ||
|
||||
ieee80211_drop_unencrypted(rx, fc))
|
||||
@@ -2452,8 +2498,28 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
|
||||
cfg80211_rx_control_port(dev, skb, noencrypt);
|
||||
dev_kfree_skb(skb);
|
||||
} else {
|
||||
+ struct ethhdr *ehdr = (void *)skb_mac_header(skb);
|
||||
+
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
|
||||
+ /*
|
||||
+ * 802.1X over 802.11 requires that the authenticator address
|
||||
+ * be used for EAPOL frames. However, 802.1X allows the use of
|
||||
+ * the PAE group address instead. If the interface is part of
|
||||
+ * a bridge and we pass the frame with the PAE group address,
|
||||
+ * then the bridge will forward it to the network (even if the
|
||||
+ * client was not associated yet), which isn't supposed to
|
||||
+ * happen.
|
||||
+ * To avoid that, rewrite the destination address to our own
|
||||
+ * address, so that the authenticator (e.g. hostapd) will see
|
||||
+ * the frame, but bridge won't forward it anywhere else. Note
|
||||
+ * that due to earlier filtering, the only other address can
|
||||
+ * be the PAE group address.
|
||||
+ */
|
||||
+ if (unlikely(skb->protocol == sdata->control_port_protocol &&
|
||||
+ !ether_addr_equal(ehdr->h_dest, sdata->vif.addr)))
|
||||
+ ether_addr_copy(ehdr->h_dest, sdata->vif.addr);
|
||||
+
|
||||
/* deliver to local stack */
|
||||
if (rx->napi)
|
||||
napi_gro_receive(rx->napi, skb);
|
||||
@@ -2493,6 +2559,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
||||
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
|
||||
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
|
||||
+ ehdr->h_proto != rx->sdata->control_port_protocol &&
|
||||
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
|
||||
if (is_multicast_ether_addr(ehdr->h_dest) &&
|
||||
ieee80211_vif_get_num_mcast_if(sdata) != 0) {
|
||||
@@ -2602,7 +2669,7 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
|
||||
if (ieee80211_data_to_8023_exthdr(skb, ðhdr,
|
||||
rx->sdata->vif.addr,
|
||||
rx->sdata->vif.type,
|
||||
- data_offset))
|
||||
+ data_offset, true))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
||||
@@ -2659,6 +2726,23 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
||||
if (is_multicast_ether_addr(hdr->addr1))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
+ if (rx->key) {
|
||||
+ /*
|
||||
+ * We should not receive A-MSDUs on pre-HT connections,
|
||||
+ * and HT connections cannot use old ciphers. Thus drop
|
||||
+ * them, as in those cases we couldn't even have SPP
|
||||
+ * A-MSDUs or such.
|
||||
+ */
|
||||
+ switch (rx->key->conf.cipher) {
|
||||
+ case WLAN_CIPHER_SUITE_WEP40:
|
||||
+ case WLAN_CIPHER_SUITE_WEP104:
|
||||
+ case WLAN_CIPHER_SUITE_TKIP:
|
||||
+ return RX_DROP_UNUSABLE;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return __ieee80211_rx_h_amsdu(rx, 0);
|
||||
}
|
||||
|
||||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
|
||||
index ee72428..b506f2a 100644
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -374,6 +374,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
u64_stats_init(&sta->rx_stats.syncp);
|
||||
|
||||
+ ieee80211_init_frag_cache(&sta->frags);
|
||||
+
|
||||
sta->sta_state = IEEE80211_STA_NONE;
|
||||
|
||||
/* Mark TID as unreserved */
|
||||
@@ -1085,6 +1087,8 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
|
||||
|
||||
ieee80211_sta_debugfs_remove(sta);
|
||||
|
||||
+ ieee80211_destroy_frag_cache(&sta->frags);
|
||||
+
|
||||
cleanup_single_sta(sta);
|
||||
}
|
||||
|
||||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
|
||||
index 768000d..6611eae 100644
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -432,6 +432,34 @@ struct ieee80211_sta_rx_stats {
|
||||
u64 msdu[IEEE80211_NUM_TIDS + 1];
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * IEEE 802.11-2016 (10.6 "Defragmentation") recommends support for "concurrent
|
||||
+ * reception of at least one MSDU per access category per associated STA"
|
||||
+ * on APs, or "at least one MSDU per access category" on other interface types.
|
||||
+ *
|
||||
+ * This limit can be increased by changing this define, at the cost of slower
|
||||
+ * frame reassembly and increased memory use while fragments are pending.
|
||||
+ */
|
||||
+#define IEEE80211_FRAGMENT_MAX 4
|
||||
+
|
||||
+struct ieee80211_fragment_entry {
|
||||
+ struct sk_buff_head skb_list;
|
||||
+ unsigned long first_frag_time;
|
||||
+ u16 seq;
|
||||
+ u16 extra_len;
|
||||
+ u16 last_frag;
|
||||
+ u8 rx_queue;
|
||||
+ u8 check_sequential_pn:1, /* needed for CCMP/GCMP */
|
||||
+ is_protected:1;
|
||||
+ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
|
||||
+ unsigned int key_color;
|
||||
+};
|
||||
+
|
||||
+struct ieee80211_fragment_cache {
|
||||
+ struct ieee80211_fragment_entry entries[IEEE80211_FRAGMENT_MAX];
|
||||
+ unsigned int next;
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* The bandwidth threshold below which the per-station CoDel parameters will be
|
||||
* scaled to be more lenient (to prevent starvation of slow stations). This
|
||||
@@ -525,6 +553,7 @@ struct ieee80211_sta_rx_stats {
|
||||
* @status_stats.last_ack_signal: last ACK signal
|
||||
* @status_stats.ack_signal_filled: last ACK signal validity
|
||||
* @status_stats.avg_ack_signal: average ACK signal
|
||||
+ * @frags: fragment cache
|
||||
*/
|
||||
struct sta_info {
|
||||
/* General information, mostly static */
|
||||
@@ -630,6 +659,8 @@ struct sta_info {
|
||||
|
||||
struct cfg80211_chan_def tdls_chandef;
|
||||
|
||||
+ struct ieee80211_fragment_cache frags;
|
||||
+
|
||||
/* keep last! */
|
||||
struct ieee80211_sta sta;
|
||||
};
|
||||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
|
||||
index 690fe47..eb42d18 100644
|
||||
--- a/net/mac80211/wpa.c
|
||||
+++ b/net/mac80211/wpa.c
|
||||
@@ -3,6 +3,7 @@
|
||||
* Copyright 2002-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
+ * Copyright (C) 2020-2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
@@ -167,8 +168,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
||||
|
||||
update_iv:
|
||||
/* update IV in key information to be able to detect replays */
|
||||
- rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32;
|
||||
- rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16;
|
||||
+ rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip.iv32;
|
||||
+ rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip.iv16;
|
||||
|
||||
return RX_CONTINUE;
|
||||
|
||||
@@ -294,8 +295,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
|
||||
key, skb->data + hdrlen,
|
||||
skb->len - hdrlen, rx->sta->sta.addr,
|
||||
hdr->addr1, hwaccel, rx->security_idx,
|
||||
- &rx->tkip_iv32,
|
||||
- &rx->tkip_iv16);
|
||||
+ &rx->tkip.iv32,
|
||||
+ &rx->tkip.iv16);
|
||||
if (res != TKIP_DECRYPT_OK)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
@@ -552,6 +553,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
|
||||
}
|
||||
|
||||
memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN);
|
||||
+ if (unlikely(ieee80211_is_frag(hdr)))
|
||||
+ memcpy(rx->ccm_gcm.pn, pn, IEEE80211_CCMP_PN_LEN);
|
||||
}
|
||||
|
||||
/* Remove CCMP header and MIC */
|
||||
@@ -782,6 +785,8 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx)
|
||||
}
|
||||
|
||||
memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN);
|
||||
+ if (unlikely(ieee80211_is_frag(hdr)))
|
||||
+ memcpy(rx->ccm_gcm.pn, pn, IEEE80211_CCMP_PN_LEN);
|
||||
}
|
||||
|
||||
/* Remove GCMP header and MIC */
|
||||
diff --git a/net/wireless/util.c b/net/wireless/util.c
|
||||
index 734c4d0..981a225 100644
|
||||
--- a/net/wireless/util.c
|
||||
+++ b/net/wireless/util.c
|
||||
@@ -449,7 +449,7 @@ EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
|
||||
|
||||
int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
- u8 data_offset)
|
||||
+ u8 data_offset, bool is_amsdu)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct {
|
||||
@@ -537,7 +537,7 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
|
||||
tmp.h_proto = payload.proto;
|
||||
|
||||
- if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
|
||||
+ if (likely((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) &&
|
||||
tmp.h_proto != htons(ETH_P_AARP) &&
|
||||
tmp.h_proto != htons(ETH_P_IPX)) ||
|
||||
ether_addr_equal(payload.hdr, bridge_tunnel_header)))
|
||||
@@ -683,6 +683,9 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||
remaining = skb->len - offset;
|
||||
if (subframe_len > remaining)
|
||||
goto purge;
|
||||
+ /* mitigate A-MSDU aggregation injection attacks */
|
||||
+ if (ether_addr_equal(eth.h_dest, rfc1042_header))
|
||||
+ goto purge;
|
||||
|
||||
offset += sizeof(struct ethhdr);
|
||||
last = remaining <= subframe_len + padding;
|
||||
|
|
@ -1,30 +1,30 @@
|
|||
From 570a5113d096abd20168f93b3ab3ed3625fda840 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Walther <patrick.walther@netmodule.com>
|
||||
Date: Fri, 24 Jul 2020 18:56:44 +0200
|
||||
Subject: [PATCH] backport of netmodule patches from openwrt
|
||||
commit 775f8efe32011d6efc55d383a1c88fb173c80246
|
||||
Author: Patrick Walther <patrick.walther@netmodule.com>
|
||||
Date: Fri Jul 24 18:56:44 2020 +0200
|
||||
|
||||
---
|
||||
drivers/net/wireless/ath/ath10k/mac.c | 2 +-
|
||||
drivers/net/wireless/ath/ath10k/pci.c | 2 +-
|
||||
drivers/net/wireless/ath/regd.c | 2 +-
|
||||
drivers/net/wireless/ath/regd.h | 3 +-
|
||||
drivers/net/wireless/ath/regd_common.h | 1 +
|
||||
drivers/net/wireless/ti/wlcore/cmd.c | 13 +++-----
|
||||
drivers/net/wireless/ti/wlcore/cmd.h | 2 +-
|
||||
drivers/net/wireless/ti/wlcore/conf.h | 3 ++
|
||||
drivers/net/wireless/ti/wlcore/init.c | 22 ++++++++++---
|
||||
drivers/net/wireless/ti/wlcore/main.c | 54 +++++++++++++++++++------------
|
||||
drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 +
|
||||
include/net/cfg80211.h | 10 ++++--
|
||||
include/net/mac80211.h | 7 ++--
|
||||
include/uapi/linux/nl80211.h | 3 ++
|
||||
net/mac80211/cfg.c | 13 ++++++++
|
||||
net/mac80211/main.c | 4 +--
|
||||
net/wireless/core.c | 41 +++++++++++++++++++----
|
||||
net/wireless/nl80211.c | 13 ++++++++
|
||||
net/wireless/reg.c | 23 ++++++++++---
|
||||
19 files changed, 162 insertions(+), 57 deletions(-)
|
||||
backport of netmodule patches from openwrt
|
||||
|
||||
%% original patch: 0009-backport-of-netmodule-patches-from-openwrt.patch
|
||||
|
||||
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
|
||||
index 2a18e2e..bb30fd7 100644
|
||||
--- a/drivers/net/wireless/ath/ath.h
|
||||
+++ b/drivers/net/wireless/ath/ath.h
|
||||
@@ -198,12 +198,13 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
||||
bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr);
|
||||
|
||||
void ath_hw_setbssidmask(struct ath_common *common);
|
||||
-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
|
||||
+void ath_key_delete(struct ath_common *common, u8 hw_key_idx);
|
||||
int ath_key_config(struct ath_common *common,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
bool ath_hw_keyreset(struct ath_common *common, u16 entry);
|
||||
+bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac);
|
||||
void ath_hw_cycle_counters_update(struct ath_common *common);
|
||||
int32_t ath_hw_get_listen_time(struct ath_common *common);
|
||||
|
||||
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
index 7946d3b..ba289ad 100644
|
||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
||||
|
|
@ -51,6 +51,263 @@ index d7435c9..57ec879 100644
|
|||
static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
|
||||
|
||||
module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
|
||||
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
|
||||
index 47dd580..0b890db 100644
|
||||
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
|
||||
@@ -516,7 +516,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
}
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
- ath_key_delete(common, key);
|
||||
+ ath_key_delete(common, key->->hw_key_idx);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||||
index b647a32..c3892a9 100644
|
||||
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||||
@@ -1460,7 +1460,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
|
||||
}
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
- ath_key_delete(common, key);
|
||||
+ ath_key_delete(common, key->hw_key_idx);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
|
||||
index 015fe02..9b2e6d8 100644
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||
@@ -830,6 +830,7 @@ struct ath_hw {
|
||||
struct ath9k_pacal_info pacal_info;
|
||||
struct ar5416Stats stats;
|
||||
struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
|
||||
+ DECLARE_BITMAP(pending_del_keymap, ATH_KEYMAX);
|
||||
|
||||
enum ath9k_int imask;
|
||||
u32 imrs2_reg;
|
||||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
|
||||
index 17418f9..5efd45c 100644
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -831,12 +831,80 @@ exit:
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
}
|
||||
|
||||
+static bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix)
|
||||
+{
|
||||
+ struct ath_buf *bf;
|
||||
+ struct ieee80211_tx_info *txinfo;
|
||||
+ struct ath_frame_info *fi;
|
||||
+
|
||||
+ list_for_each_entry(bf, txq_list, list) {
|
||||
+ if (bf->bf_state.stale || !bf->bf_mpdu)
|
||||
+ continue;
|
||||
+
|
||||
+ txinfo = IEEE80211_SKB_CB(bf->bf_mpdu);
|
||||
+ fi = (struct ath_frame_info *)&txinfo->rate_driver_data[0];
|
||||
+ if (fi->keyix == keyix)
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix)
|
||||
+{
|
||||
+ struct ath_hw *ah = sc->sc_ah;
|
||||
+ int i;
|
||||
+ struct ath_txq *txq;
|
||||
+ bool key_in_use = false;
|
||||
+
|
||||
+ for (i = 0; !key_in_use && i < ATH9K_NUM_TX_QUEUES; i++) {
|
||||
+ if (!ATH_TXQ_SETUP(sc, i))
|
||||
+ continue;
|
||||
+ txq = &sc->tx.txq[i];
|
||||
+ if (!txq->axq_depth)
|
||||
+ continue;
|
||||
+ if (!ath9k_hw_numtxpending(ah, txq->axq_qnum))
|
||||
+ continue;
|
||||
+
|
||||
+ ath_txq_lock(sc, txq);
|
||||
+ key_in_use = ath9k_txq_list_has_key(&txq->axq_q, keyix);
|
||||
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
||||
+ int idx = txq->txq_tailidx;
|
||||
+
|
||||
+ while (!key_in_use &&
|
||||
+ !list_empty(&txq->txq_fifo[idx])) {
|
||||
+ key_in_use = ath9k_txq_list_has_key(
|
||||
+ &txq->txq_fifo[idx], keyix);
|
||||
+ INCR(idx, ATH_TXFIFO_DEPTH);
|
||||
+ }
|
||||
+ }
|
||||
+ ath_txq_unlock(sc, txq);
|
||||
+ }
|
||||
+
|
||||
+ return key_in_use;
|
||||
+}
|
||||
+
|
||||
+static void ath9k_pending_key_del(struct ath_softc *sc, u8 keyix)
|
||||
+{
|
||||
+ struct ath_hw *ah = sc->sc_ah;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+
|
||||
+ if (!test_bit(keyix, ah->pending_del_keymap) ||
|
||||
+ ath9k_txq_has_key(sc, keyix))
|
||||
+ return;
|
||||
+
|
||||
+ /* No more TXQ frames point to this key cache entry, so delete it. */
|
||||
+ clear_bit(keyix, ah->pending_del_keymap);
|
||||
+ ath_key_delete(common, keyix);
|
||||
+}
|
||||
+
|
||||
static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
bool prev_idle;
|
||||
+ int i;
|
||||
|
||||
ath9k_deinit_channel_context(sc);
|
||||
|
||||
@@ -904,6 +972,14 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
+ for (i = 0; i < ATH_KEYMAX; i++)
|
||||
+ ath9k_pending_key_del(sc, i);
|
||||
+
|
||||
+ /* Clear key cache entries explicitly to get rid of any potentially
|
||||
+ * remaining keys.
|
||||
+ */
|
||||
+ ath9k_cmn_init_crypto(sc->sc_ah);
|
||||
+
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
sc->ps_idle = prev_idle;
|
||||
@@ -1546,12 +1622,11 @@ static void ath9k_del_ps_key(struct ath_softc *sc,
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_node *an = (struct ath_node *) sta->drv_priv;
|
||||
- struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
|
||||
|
||||
if (!an->ps_key)
|
||||
return;
|
||||
|
||||
- ath_key_delete(common, &ps_key);
|
||||
+ ath_key_delete(common, an->ps_key);
|
||||
an->ps_key = 0;
|
||||
an->key_idx[0] = 0;
|
||||
}
|
||||
@@ -1713,6 +1788,12 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
||||
if (sta)
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
+ /* Delete pending key cache entries if no more frames are pointing to
|
||||
+ * them in TXQs.
|
||||
+ */
|
||||
+ for (i = 0; i < ATH_KEYMAX; i++)
|
||||
+ ath9k_pending_key_del(sc, i);
|
||||
+
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
if (sta)
|
||||
@@ -1742,7 +1823,15 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
||||
}
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
- ath_key_delete(common, key);
|
||||
+ if (ath9k_txq_has_key(sc, key->hw_key_idx)) {
|
||||
+ /* Delay key cache entry deletion until there are no
|
||||
+ * remaining TXQ frames pointing to this entry.
|
||||
+ */
|
||||
+ set_bit(key->hw_key_idx, sc->sc_ah->pending_del_keymap);
|
||||
+ ath_hw_keysetmac(common, key->hw_key_idx, NULL);
|
||||
+ } else {
|
||||
+ ath_key_delete(common, key->hw_key_idx);
|
||||
+ }
|
||||
if (an) {
|
||||
for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
|
||||
if (an->key_idx[i] != key->hw_key_idx)
|
||||
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
|
||||
index 1816b4e..61b59a8 100644
|
||||
--- a/drivers/net/wireless/ath/key.c
|
||||
+++ b/drivers/net/wireless/ath/key.c
|
||||
@@ -84,8 +84,7 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
|
||||
}
|
||||
EXPORT_SYMBOL(ath_hw_keyreset);
|
||||
|
||||
-static bool ath_hw_keysetmac(struct ath_common *common,
|
||||
- u16 entry, const u8 *mac)
|
||||
+bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
|
||||
{
|
||||
u32 macHi, macLo;
|
||||
u32 unicast_flag = AR_KEYTABLE_VALID;
|
||||
@@ -125,6 +124,7 @@ static bool ath_hw_keysetmac(struct ath_common *common,
|
||||
|
||||
return true;
|
||||
}
|
||||
+EXPORT_SYMBOL(ath_hw_keysetmac);
|
||||
|
||||
static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
|
||||
const struct ath_keyval *k,
|
||||
@@ -581,29 +581,38 @@ EXPORT_SYMBOL(ath_key_config);
|
||||
/*
|
||||
* Delete Key.
|
||||
*/
|
||||
-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
|
||||
+void ath_key_delete(struct ath_common *common, u8 hw_key_idx)
|
||||
{
|
||||
- ath_hw_keyreset(common, key->hw_key_idx);
|
||||
- if (key->hw_key_idx < IEEE80211_WEP_NKID)
|
||||
+ /* Leave CCMP and TKIP (main key) configured to avoid disabling
|
||||
+ * encryption for potentially pending frames already in a TXQ with the
|
||||
+ * keyix pointing to this key entry. Instead, only clear the MAC address
|
||||
+ * to prevent RX processing from using this key cache entry.
|
||||
+ */
|
||||
+ if (test_bit(hw_key_idx, common->ccmp_keymap) ||
|
||||
+ test_bit(hw_key_idx, common->tkip_keymap))
|
||||
+ ath_hw_keysetmac(common, hw_key_idx, NULL);
|
||||
+ else
|
||||
+ ath_hw_keyreset(common, hw_key_idx);
|
||||
+ if (hw_key_idx < IEEE80211_WEP_NKID)
|
||||
return;
|
||||
|
||||
- clear_bit(key->hw_key_idx, common->keymap);
|
||||
- clear_bit(key->hw_key_idx, common->ccmp_keymap);
|
||||
- if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
|
||||
+ clear_bit(hw_key_idx, common->keymap);
|
||||
+ clear_bit(hw_key_idx, common->ccmp_keymap);
|
||||
+ if (!test_bit(hw_key_idx, common->tkip_keymap))
|
||||
return;
|
||||
|
||||
- clear_bit(key->hw_key_idx + 64, common->keymap);
|
||||
+ clear_bit(hw_key_idx + 64, common->keymap);
|
||||
|
||||
- clear_bit(key->hw_key_idx, common->tkip_keymap);
|
||||
- clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
|
||||
+ clear_bit(hw_key_idx, common->tkip_keymap);
|
||||
+ clear_bit(hw_key_idx + 64, common->tkip_keymap);
|
||||
|
||||
if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
|
||||
- ath_hw_keyreset(common, key->hw_key_idx + 32);
|
||||
- clear_bit(key->hw_key_idx + 32, common->keymap);
|
||||
- clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
|
||||
+ ath_hw_keyreset(common, hw_key_idx + 32);
|
||||
+ clear_bit(hw_key_idx + 32, common->keymap);
|
||||
+ clear_bit(hw_key_idx + 64 + 32, common->keymap);
|
||||
|
||||
- clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
|
||||
- clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
|
||||
+ clear_bit(hw_key_idx + 32, common->tkip_keymap);
|
||||
+ clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath_key_delete);
|
||||
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
|
||||
index e263400..c242f00 100644
|
||||
--- a/drivers/net/wireless/ath/regd.c
|
||||
|
|
@ -130,7 +387,7 @@ index 2a48fc6..888cfd7 100644
|
|||
cmd->supported_rates, sta->uapsd_queues);
|
||||
|
||||
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
|
||||
index 084375b..bfad7b5 100644
|
||||
index 084375b..24ee7ab 100644
|
||||
--- a/drivers/net/wireless/ti/wlcore/cmd.h
|
||||
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
|
||||
@@ -65,7 +65,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
|
|
@ -142,6 +399,14 @@ index 084375b..bfad7b5 100644
|
|||
int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 hlid);
|
||||
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,
|
||||
@@ -458,6 +458,7 @@ enum wl1271_cmd_key_type {
|
||||
KEY_TKIP = 2,
|
||||
KEY_AES = 3,
|
||||
KEY_GEM = 4,
|
||||
+ KEY_IGTK = 5,
|
||||
};
|
||||
|
||||
struct wl1271_cmd_set_keys {
|
||||
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
|
||||
index 6116383..e33f577 100644
|
||||
--- a/drivers/net/wireless/ti/wlcore/conf.h
|
||||
|
|
@ -202,7 +467,7 @@ index 03b49ba..6334351 100644
|
|||
rc.long_retry_limit = 10;
|
||||
rc.aflags = 0;
|
||||
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
|
||||
index 6d36cbf..355d186 100644
|
||||
index 6d36cbf..aa6f22c 100644
|
||||
--- a/drivers/net/wireless/ti/wlcore/main.c
|
||||
+++ b/drivers/net/wireless/ti/wlcore/main.c
|
||||
@@ -2213,12 +2213,13 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
|
|
@ -301,7 +566,17 @@ index 6d36cbf..355d186 100644
|
|||
|
||||
wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
|
||||
|
||||
@@ -3551,12 +3556,14 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
@@ -3538,6 +3543,9 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
key_type = KEY_TKIP;
|
||||
key_conf->hw_key_idx = key_conf->keyidx;
|
||||
break;
|
||||
+ case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
+ key_type = KEY_IGTK;
|
||||
+ break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
key_type = KEY_AES;
|
||||
key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||
@@ -3551,12 +3559,14 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +592,7 @@ index 6d36cbf..355d186 100644
|
|||
if (ret < 0) {
|
||||
wl1271_error("Could not add or replace key");
|
||||
return ret;
|
||||
@@ -3582,7 +3589,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
@@ -3582,7 +3592,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
|
||||
key_conf->keyidx, key_type,
|
||||
key_conf->keylen, key_conf->key,
|
||||
|
|
@ -326,7 +601,7 @@ index 6d36cbf..355d186 100644
|
|||
if (ret < 0) {
|
||||
wl1271_error("Could not remove key");
|
||||
return ret;
|
||||
@@ -5216,11 +5223,6 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
|
||||
@@ -5216,11 +5226,6 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -338,7 +613,7 @@ index 6d36cbf..355d186 100644
|
|||
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
|
||||
wl_sta->hlid);
|
||||
if (ret)
|
||||
@@ -5794,9 +5796,16 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
|
||||
@@ -5794,9 +5799,16 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
|
|
@ -355,7 +630,15 @@ index 6d36cbf..355d186 100644
|
|||
wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
@@ -6224,6 +6233,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
@@ -6210,6 +6222,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
WLAN_CIPHER_SUITE_TKIP,
|
||||
WLAN_CIPHER_SUITE_CCMP,
|
||||
WL1271_CIPHER_SUITE_GEM,
|
||||
+ WLAN_CIPHER_SUITE_AES_CMAC,
|
||||
};
|
||||
|
||||
/* The tx descriptor buffer */
|
||||
@@ -6224,6 +6237,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
|
||||
ieee80211_hw_set(wl->hw, SUPPORT_FAST_XMIT);
|
||||
ieee80211_hw_set(wl->hw, CHANCTX_STA_CSA);
|
||||
|
|
@ -363,7 +646,7 @@ index 6d36cbf..355d186 100644
|
|||
ieee80211_hw_set(wl->hw, QUEUE_CONTROL);
|
||||
ieee80211_hw_set(wl->hw, TX_AMPDU_SETUP_IN_HW);
|
||||
ieee80211_hw_set(wl->hw, AMPDU_AGGREGATION);
|
||||
@@ -6268,9 +6278,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
@@ -6268,9 +6282,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
|
||||
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
|
||||
|
|
@ -389,7 +672,7 @@ index 6fab60b..eefae3f 100644
|
|||
|
||||
enum wl12xx_flags {
|
||||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
|
||||
index 8099b10..4849bab 100644
|
||||
index 75ecfeb..3b4b4e2 100644
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -112,6 +112,7 @@ enum ieee80211_channel_flags {
|
||||
|
|
@ -20,7 +20,8 @@ SRC_URI = "http://www.kernel.org/pub/linux/kernel/projects/backports/stable/v${S
|
|||
file://0004-backport-of-rt2x00-patches-from-openwrt.patch \
|
||||
file://0005-backport-of-mwl-patches-from-openwrt.patch \
|
||||
file://0006-backport-of-brcm-patches-from-openwrt.patch \
|
||||
file://0007-backport-of-netmodule-patches-from-openwrt.patch \
|
||||
file://0008-fragattack.patch \
|
||||
file://0009-backport-of-netmodule-patches-from-openwrt.patch \
|
||||
file://config.${NM_TARGET} \
|
||||
"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue