This is relatively small, mostly to get the SG/crypto
from stack removal fix that crashes things when VMAP stack is used in conjunction with software crypto. Aside from that, we have: * a fix for AP_VLAN usage with the nl80211 frame command * two fixes (and two preparation patches) for A-MSDU, one to discard group-addressed (multicast) and unexpected 4-address A-MSDUs, the other to validate A-MSDU inner MAC addresses properly to prevent controlled port bypass -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJYBcgKAAoJEGt7eEactAAdhUkP/jMVQbLMZ1Jcc9+lsPVGUIga I9GeQ4lcnD+4ASeJUhTtemC1IMNL4zMVqaIxbznDXKP7rZRrODVvCPk2TYIw9c5S rzF/TRierMFttLu3xY757nAsYg6T7F03JdOQ3SKIb3xOD8pXCWQoVRN14ldroRno 4stOAtDrpD5wvK2JhlWv1EYlxGVLqLcakZt/BwgDX/cJGkAx49Q/s29FUnesB9Ep sCH5chffeQskOL9CrSwboNmucgt4HGQORc4UL/KtPOEBtyfu/LCXEKSqAKVyQZtZ OerouOHWqQE5lT2K6qD/KKFW4lV2t1h+xzqsvZk4ZR5o3s+PAGai6D/wf+JgY9Hk uor9ju/e0htcI9m0aFdHDnltV0OOwIhR2bxWTuBBUkyFVtdQQY+1MRTTtuunWIB4 SDYv6LrNL/0HAIuTlPQH99rnsFNnRZCtTpdbT7GRckAMeWMvy19bF2ZB1FXuSn+h 5dxIo0qkw8nv4Y9wQ6QmgOcSzYyidUrCgLTO516qXVAKY0kl/u4q/zPr0Fmx/qfY oxspelDv0qd2NMQwJ/AmwjAjkQBulv5DVLu+cDXdOMkc/EbhzWyvetcHiNukxjHn mukCBxTlLoDLug2LFkAPIddEutj+VUEefkf/pD/js8uYuyd9ZnPjiIh6fG25il9a cHbMYtANt2EnZjwI9Z74 =T6t1 -----END PGP SIGNATURE----- Merge tag 'mac80211-for-davem-2016-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211 Johannes Berg says: ==================== This is relatively small, mostly to get the SG/crypto from stack removal fix that crashes things when VMAP stack is used in conjunction with software crypto. Aside from that, we have: * a fix for AP_VLAN usage with the nl80211 frame command * two fixes (and two preparation patches) for A-MSDU, one to discard group-addressed (multicast) and unexpected 4-address A-MSDUs, the other to validate A-MSDU inner MAC addresses properly to prevent controlled port bypass ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
5cbee55736
|
@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
|
|||
skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
|
||||
|
||||
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
|
||||
priv->wdev.iftype, 0, false);
|
||||
priv->wdev.iftype, 0, NULL, NULL);
|
||||
|
||||
while (!skb_queue_empty(&list)) {
|
||||
struct rx_packet_hdr *rx_hdr;
|
||||
|
|
|
@ -4039,6 +4039,18 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
|
|||
* that do not do the 802.11/802.3 conversion on the device.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ieee80211_data_to_8023_exthdr - convert an 802.11 data frame to 802.3
|
||||
* @skb: the 802.11 data frame
|
||||
* @ehdr: pointer to a &struct ethhdr that will get the header, instead
|
||||
* of it being pushed into the SKB
|
||||
* @addr: the device MAC address
|
||||
* @iftype: the virtual interface type
|
||||
* Return: 0 on success. Non-zero on error.
|
||||
*/
|
||||
int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
const u8 *addr, enum nl80211_iftype iftype);
|
||||
|
||||
/**
|
||||
* ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
|
||||
* @skb: the 802.11 data frame
|
||||
|
@ -4046,8 +4058,11 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
|
|||
* @iftype: the virtual interface type
|
||||
* Return: 0 on success. Non-zero on error.
|
||||
*/
|
||||
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_data_from_8023 - convert an 802.3 frame to 802.11
|
||||
|
@ -4065,22 +4080,23 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
|||
/**
|
||||
* ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
|
||||
*
|
||||
* Decode an IEEE 802.11n A-MSDU frame and convert it to a list of
|
||||
* 802.3 frames. The @list will be empty if the decode fails. The
|
||||
* @skb is consumed after the function returns.
|
||||
* Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames.
|
||||
* The @list will be empty if the decode fails. The @skb must be fully
|
||||
* header-less before being passed in here; it is freed in this function.
|
||||
*
|
||||
* @skb: The input IEEE 802.11n A-MSDU frame.
|
||||
* @skb: The input A-MSDU frame without any headers.
|
||||
* @list: The output list of 802.3 frames. It must be allocated and
|
||||
* initialized by by the caller.
|
||||
* @addr: The device MAC address.
|
||||
* @iftype: The device interface type.
|
||||
* @extra_headroom: The hardware extra headroom for SKBs in the @list.
|
||||
* @has_80211_header: Set it true if SKB is with IEEE 802.11 header.
|
||||
* @check_da: DA to check in the inner ethernet header, or NULL
|
||||
* @check_sa: SA to check in the inner ethernet header, or NULL
|
||||
*/
|
||||
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
const unsigned int extra_headroom,
|
||||
bool has_80211_header);
|
||||
const u8 *check_da, const u8 *check_sa);
|
||||
|
||||
/**
|
||||
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
|
||||
|
|
|
@ -18,21 +18,24 @@
|
|||
#include "key.h"
|
||||
#include "aes_ccm.h"
|
||||
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len)
|
||||
int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len)
|
||||
{
|
||||
struct scatterlist sg[3];
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
u8 *__aad;
|
||||
|
||||
char aead_req_data[sizeof(struct aead_request) +
|
||||
crypto_aead_reqsize(tfm)]
|
||||
__aligned(__alignof__(struct aead_request));
|
||||
struct aead_request *aead_req = (void *) aead_req_data;
|
||||
aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(aead_req, 0, sizeof(aead_req_data));
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, CCM_AAD_LEN);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, mic_len);
|
||||
|
||||
|
@ -41,6 +44,9 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
|||
aead_request_set_ad(aead_req, sg[0].length);
|
||||
|
||||
crypto_aead_encrypt(aead_req);
|
||||
kzfree(aead_req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
|
@ -48,18 +54,23 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
|||
size_t mic_len)
|
||||
{
|
||||
struct scatterlist sg[3];
|
||||
char aead_req_data[sizeof(struct aead_request) +
|
||||
crypto_aead_reqsize(tfm)]
|
||||
__aligned(__alignof__(struct aead_request));
|
||||
struct aead_request *aead_req = (void *) aead_req_data;
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
u8 *__aad;
|
||||
int err;
|
||||
|
||||
if (data_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(aead_req, 0, sizeof(aead_req_data));
|
||||
aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, CCM_AAD_LEN);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, mic_len);
|
||||
|
||||
|
@ -67,7 +78,10 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
|||
aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
|
||||
aead_request_set_ad(aead_req, sg[0].length);
|
||||
|
||||
return crypto_aead_decrypt(aead_req);
|
||||
err = crypto_aead_decrypt(aead_req);
|
||||
kzfree(aead_req);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#define CCM_AAD_LEN 32
|
||||
|
||||
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
|
||||
size_t key_len,
|
||||
size_t mic_len);
|
||||
void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len);
|
||||
int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len);
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len);
|
||||
|
|
|
@ -15,20 +15,23 @@
|
|||
#include "key.h"
|
||||
#include "aes_gcm.h"
|
||||
|
||||
void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
struct scatterlist sg[3];
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
u8 *__aad;
|
||||
|
||||
char aead_req_data[sizeof(struct aead_request) +
|
||||
crypto_aead_reqsize(tfm)]
|
||||
__aligned(__alignof__(struct aead_request));
|
||||
struct aead_request *aead_req = (void *)aead_req_data;
|
||||
aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(aead_req, 0, sizeof(aead_req_data));
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, GCM_AAD_LEN);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
|
||||
|
||||
|
@ -37,24 +40,31 @@ void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
|||
aead_request_set_ad(aead_req, sg[0].length);
|
||||
|
||||
crypto_aead_encrypt(aead_req);
|
||||
kzfree(aead_req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
struct scatterlist sg[3];
|
||||
char aead_req_data[sizeof(struct aead_request) +
|
||||
crypto_aead_reqsize(tfm)]
|
||||
__aligned(__alignof__(struct aead_request));
|
||||
struct aead_request *aead_req = (void *)aead_req_data;
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
u8 *__aad;
|
||||
int err;
|
||||
|
||||
if (data_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(aead_req, 0, sizeof(aead_req_data));
|
||||
aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, GCM_AAD_LEN);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
|
||||
|
||||
|
@ -63,7 +73,10 @@ int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
|||
data_len + IEEE80211_GCMP_MIC_LEN, j_0);
|
||||
aead_request_set_ad(aead_req, sg[0].length);
|
||||
|
||||
return crypto_aead_decrypt(aead_req);
|
||||
err = crypto_aead_decrypt(aead_req);
|
||||
kzfree(aead_req);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
#define GCM_AAD_LEN 32
|
||||
|
||||
int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
|
||||
|
|
|
@ -17,28 +17,27 @@
|
|||
#include "key.h"
|
||||
#include "aes_gmac.h"
|
||||
|
||||
#define GMAC_MIC_LEN 16
|
||||
#define GMAC_NONCE_LEN 12
|
||||
#define AAD_LEN 20
|
||||
|
||||
int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
|
||||
const u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
struct scatterlist sg[4];
|
||||
char aead_req_data[sizeof(struct aead_request) +
|
||||
crypto_aead_reqsize(tfm)]
|
||||
__aligned(__alignof__(struct aead_request));
|
||||
struct aead_request *aead_req = (void *)aead_req_data;
|
||||
u8 zero[GMAC_MIC_LEN], iv[AES_BLOCK_SIZE];
|
||||
u8 *zero, *__aad, iv[AES_BLOCK_SIZE];
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
|
||||
if (data_len < GMAC_MIC_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
memset(aead_req, 0, sizeof(aead_req_data));
|
||||
aead_req = kzalloc(reqsize + GMAC_MIC_LEN + GMAC_AAD_LEN, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
zero = (u8 *)aead_req + reqsize;
|
||||
__aad = zero + GMAC_MIC_LEN;
|
||||
memcpy(__aad, aad, GMAC_AAD_LEN);
|
||||
|
||||
memset(zero, 0, GMAC_MIC_LEN);
|
||||
sg_init_table(sg, 4);
|
||||
sg_set_buf(&sg[0], aad, AAD_LEN);
|
||||
sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
|
||||
sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN);
|
||||
sg_set_buf(&sg[2], zero, GMAC_MIC_LEN);
|
||||
sg_set_buf(&sg[3], mic, GMAC_MIC_LEN);
|
||||
|
@ -49,9 +48,10 @@ int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
|
|||
|
||||
aead_request_set_tfm(aead_req, tfm);
|
||||
aead_request_set_crypt(aead_req, sg, sg, 0, iv);
|
||||
aead_request_set_ad(aead_req, AAD_LEN + data_len);
|
||||
aead_request_set_ad(aead_req, GMAC_AAD_LEN + data_len);
|
||||
|
||||
crypto_aead_encrypt(aead_req);
|
||||
kzfree(aead_req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
#define GMAC_AAD_LEN 20
|
||||
#define GMAC_MIC_LEN 16
|
||||
#define GMAC_NONCE_LEN 12
|
||||
|
||||
struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
|
||||
size_t key_len);
|
||||
int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
|
||||
|
|
|
@ -820,7 +820,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
|
||||
break;
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(sdata, mgmt->da);
|
||||
sta = sta_info_get_bss(sdata, mgmt->da);
|
||||
rcu_read_unlock();
|
||||
if (!sta)
|
||||
return -ENOLINK;
|
||||
|
|
|
@ -2298,6 +2298,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
|||
__le16 fc = hdr->frame_control;
|
||||
struct sk_buff_head frame_list;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
struct ethhdr ethhdr;
|
||||
const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
|
||||
|
||||
if (unlikely(!ieee80211_is_data(fc)))
|
||||
return RX_CONTINUE;
|
||||
|
@ -2308,24 +2310,53 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
|||
if (!(status->rx_flags & IEEE80211_RX_AMSDU))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (ieee80211_has_a4(hdr->frame_control) &&
|
||||
rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||
!rx->sdata->u.vlan.sta)
|
||||
return RX_DROP_UNUSABLE;
|
||||
if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
|
||||
switch (rx->sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
if (!rx->sdata->u.vlan.sta)
|
||||
return RX_DROP_UNUSABLE;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!rx->sdata->u.mgd.use_4addr)
|
||||
return RX_DROP_UNUSABLE;
|
||||
break;
|
||||
default:
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
check_da = NULL;
|
||||
check_sa = NULL;
|
||||
} else switch (rx->sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
check_da = NULL;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!rx->sta ||
|
||||
!test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
|
||||
check_sa = NULL;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
check_sa = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_multicast_ether_addr(hdr->addr1) &&
|
||||
((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||
rx->sdata->u.vlan.sta) ||
|
||||
(rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
rx->sdata->u.mgd.use_4addr)))
|
||||
if (is_multicast_ether_addr(hdr->addr1))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
skb->dev = dev;
|
||||
__skb_queue_head_init(&frame_list);
|
||||
|
||||
if (ieee80211_data_to_8023_exthdr(skb, ðhdr,
|
||||
rx->sdata->vif.addr,
|
||||
rx->sdata->vif.type))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
||||
rx->sdata->vif.type,
|
||||
rx->local->hw.extra_tx_headroom, true);
|
||||
rx->local->hw.extra_tx_headroom,
|
||||
check_da, check_sa);
|
||||
|
||||
while (!skb_queue_empty(&frame_list)) {
|
||||
rx->skb = __skb_dequeue(&frame_list);
|
||||
|
|
|
@ -405,7 +405,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
|
|||
u8 *pos;
|
||||
u8 pn[6];
|
||||
u64 pn64;
|
||||
u8 aad[2 * AES_BLOCK_SIZE];
|
||||
u8 aad[CCM_AAD_LEN];
|
||||
u8 b_0[AES_BLOCK_SIZE];
|
||||
|
||||
if (info->control.hw_key &&
|
||||
|
@ -461,10 +461,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
|
|||
|
||||
pos += IEEE80211_CCMP_HDR_LEN;
|
||||
ccmp_special_blocks(skb, pn, b_0, aad);
|
||||
ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
|
||||
skb_put(skb, mic_len), mic_len);
|
||||
|
||||
return 0;
|
||||
return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
|
||||
skb_put(skb, mic_len), mic_len);
|
||||
}
|
||||
|
||||
|
||||
|
@ -639,7 +637,7 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
|||
u8 *pos;
|
||||
u8 pn[6];
|
||||
u64 pn64;
|
||||
u8 aad[2 * AES_BLOCK_SIZE];
|
||||
u8 aad[GCM_AAD_LEN];
|
||||
u8 j_0[AES_BLOCK_SIZE];
|
||||
|
||||
if (info->control.hw_key &&
|
||||
|
@ -696,10 +694,8 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
|||
|
||||
pos += IEEE80211_GCMP_HDR_LEN;
|
||||
gcmp_special_blocks(skb, pn, j_0, aad);
|
||||
ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
|
||||
skb_put(skb, IEEE80211_GCMP_MIC_LEN));
|
||||
|
||||
return 0;
|
||||
return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
|
||||
skb_put(skb, IEEE80211_GCMP_MIC_LEN));
|
||||
}
|
||||
|
||||
ieee80211_tx_result
|
||||
|
@ -1123,9 +1119,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx)
|
|||
struct ieee80211_key *key = tx->key;
|
||||
struct ieee80211_mmie_16 *mmie;
|
||||
struct ieee80211_hdr *hdr;
|
||||
u8 aad[20];
|
||||
u8 aad[GMAC_AAD_LEN];
|
||||
u64 pn64;
|
||||
u8 nonce[12];
|
||||
u8 nonce[GMAC_NONCE_LEN];
|
||||
|
||||
if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
|
||||
return TX_DROP;
|
||||
|
@ -1171,7 +1167,7 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx)
|
|||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_key *key = rx->key;
|
||||
struct ieee80211_mmie_16 *mmie;
|
||||
u8 aad[20], mic[16], ipn[6], nonce[12];
|
||||
u8 aad[GMAC_AAD_LEN], mic[GMAC_MIC_LEN], ipn[6], nonce[GMAC_NONCE_LEN];
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
if (!ieee80211_is_mgmt(hdr->frame_control))
|
||||
|
|
|
@ -420,8 +420,8 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
|
||||
|
||||
static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
const u8 *addr, enum nl80211_iftype iftype)
|
||||
int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
const u8 *addr, enum nl80211_iftype iftype)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct {
|
||||
|
@ -525,13 +525,7 @@ static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_data_to_8023);
|
||||
EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
|
||||
|
||||
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype,
|
||||
|
@ -746,24 +740,18 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
|
|||
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
const unsigned int extra_headroom,
|
||||
bool has_80211_header)
|
||||
const u8 *check_da, const u8 *check_sa)
|
||||
{
|
||||
unsigned int hlen = ALIGN(extra_headroom, 4);
|
||||
struct sk_buff *frame = NULL;
|
||||
u16 ethertype;
|
||||
u8 *payload;
|
||||
int offset = 0, remaining, err;
|
||||
int offset = 0, remaining;
|
||||
struct ethhdr eth;
|
||||
bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
|
||||
bool reuse_skb = false;
|
||||
bool last = false;
|
||||
|
||||
if (has_80211_header) {
|
||||
err = __ieee80211_data_to_8023(skb, ð, addr, iftype);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!last) {
|
||||
unsigned int subframe_len;
|
||||
int len;
|
||||
|
@ -780,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
|||
goto purge;
|
||||
|
||||
offset += sizeof(struct ethhdr);
|
||||
/* reuse skb for the last subframe */
|
||||
last = remaining <= subframe_len + padding;
|
||||
|
||||
/* FIXME: should we really accept multicast DA? */
|
||||
if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
|
||||
!ether_addr_equal(check_da, eth.h_dest)) ||
|
||||
(check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
|
||||
offset += len + padding;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reuse skb for the last subframe */
|
||||
if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
|
||||
skb_pull(skb, offset);
|
||||
frame = skb;
|
||||
|
@ -819,7 +816,6 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
|||
|
||||
purge:
|
||||
__skb_queue_purge(list);
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
|
||||
|
|
Loading…
Reference in a new issue