Commit 5cbee557 authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2016-10-18' of...

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 6bc80629 f4a067f9
...@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, ...@@ -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)); skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, 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)) { while (!skb_queue_empty(&list)) {
struct rx_packet_hdr *rx_hdr; struct rx_packet_hdr *rx_hdr;
......
...@@ -4039,6 +4039,18 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); ...@@ -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. * 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 * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
* @skb: the 802.11 data frame * @skb: the 802.11 data frame
...@@ -4046,8 +4058,11 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); ...@@ -4046,8 +4058,11 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
* @iftype: the virtual interface type * @iftype: the virtual interface type
* Return: 0 on success. Non-zero on error. * Return: 0 on success. Non-zero on error.
*/ */
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
enum nl80211_iftype iftype); 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 * 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, ...@@ -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 * 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 * Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames.
* 802.3 frames. The @list will be empty if the decode fails. The * The @list will be empty if the decode fails. The @skb must be fully
* @skb is consumed after the function returns. * 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 * @list: The output list of 802.3 frames. It must be allocated and
* initialized by by the caller. * initialized by by the caller.
* @addr: The device MAC address. * @addr: The device MAC address.
* @iftype: The device interface type. * @iftype: The device interface type.
* @extra_headroom: The hardware extra headroom for SKBs in the @list. * @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, void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype, const u8 *addr, enum nl80211_iftype iftype,
const unsigned int extra_headroom, 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 * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
......
...@@ -18,21 +18,24 @@ ...@@ -18,21 +18,24 @@
#include "key.h" #include "key.h"
#include "aes_ccm.h" #include "aes_ccm.h"
void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
u8 *data, size_t data_len, u8 *mic, u8 *data, size_t data_len, u8 *mic,
size_t mic_len) size_t mic_len)
{ {
struct scatterlist sg[3]; 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) + aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
crypto_aead_reqsize(tfm)] if (!aead_req)
__aligned(__alignof__(struct aead_request)); return -ENOMEM;
struct aead_request *aead_req = (void *) aead_req_data;
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_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[1], data, data_len);
sg_set_buf(&sg[2], mic, mic_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, ...@@ -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); aead_request_set_ad(aead_req, sg[0].length);
crypto_aead_encrypt(aead_req); crypto_aead_encrypt(aead_req);
kzfree(aead_req);
return 0;
} }
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, 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, ...@@ -48,18 +54,23 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
size_t mic_len) size_t mic_len)
{ {
struct scatterlist sg[3]; struct scatterlist sg[3];
char aead_req_data[sizeof(struct aead_request) + struct aead_request *aead_req;
crypto_aead_reqsize(tfm)] int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
__aligned(__alignof__(struct aead_request)); u8 *__aad;
struct aead_request *aead_req = (void *) aead_req_data; int err;
if (data_len == 0) if (data_len == 0)
return -EINVAL; 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_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[1], data, data_len);
sg_set_buf(&sg[2], mic, mic_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, ...@@ -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_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
aead_request_set_ad(aead_req, sg[0].length); 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[], struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
......
...@@ -12,10 +12,12 @@ ...@@ -12,10 +12,12 @@
#include <linux/crypto.h> #include <linux/crypto.h>
#define CCM_AAD_LEN 32
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
size_t key_len, size_t key_len,
size_t mic_len); size_t mic_len);
void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
u8 *data, size_t data_len, u8 *mic, u8 *data, size_t data_len, u8 *mic,
size_t mic_len); size_t mic_len);
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
......
...@@ -15,20 +15,23 @@ ...@@ -15,20 +15,23 @@
#include "key.h" #include "key.h"
#include "aes_gcm.h" #include "aes_gcm.h"
void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
u8 *data, size_t data_len, u8 *mic) u8 *data, size_t data_len, u8 *mic)
{ {
struct scatterlist sg[3]; 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) + aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
crypto_aead_reqsize(tfm)] if (!aead_req)
__aligned(__alignof__(struct aead_request)); return -ENOMEM;
struct aead_request *aead_req = (void *)aead_req_data;
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_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[1], data, data_len);
sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_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, ...@@ -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); aead_request_set_ad(aead_req, sg[0].length);
crypto_aead_encrypt(aead_req); crypto_aead_encrypt(aead_req);
kzfree(aead_req);
return 0;
} }
int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
u8 *data, size_t data_len, u8 *mic) u8 *data, size_t data_len, u8 *mic)
{ {
struct scatterlist sg[3]; struct scatterlist sg[3];
char aead_req_data[sizeof(struct aead_request) + struct aead_request *aead_req;
crypto_aead_reqsize(tfm)] int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
__aligned(__alignof__(struct aead_request)); u8 *__aad;
struct aead_request *aead_req = (void *)aead_req_data; int err;
if (data_len == 0) if (data_len == 0)
return -EINVAL; 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_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[1], data, data_len);
sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_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, ...@@ -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); data_len + IEEE80211_GCMP_MIC_LEN, j_0);
aead_request_set_ad(aead_req, sg[0].length); 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[], struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
#include <linux/crypto.h> #include <linux/crypto.h>
void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, #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); u8 *data, size_t data_len, u8 *mic);
int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
u8 *data, size_t data_len, u8 *mic); u8 *data, size_t data_len, u8 *mic);
......
...@@ -17,28 +17,27 @@ ...@@ -17,28 +17,27 @@
#include "key.h" #include "key.h"
#include "aes_gmac.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, int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
const u8 *data, size_t data_len, u8 *mic) const u8 *data, size_t data_len, u8 *mic)
{ {
struct scatterlist sg[4]; struct scatterlist sg[4];
char aead_req_data[sizeof(struct aead_request) + u8 *zero, *__aad, iv[AES_BLOCK_SIZE];
crypto_aead_reqsize(tfm)] struct aead_request *aead_req;
__aligned(__alignof__(struct aead_request)); int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
struct aead_request *aead_req = (void *)aead_req_data;
u8 zero[GMAC_MIC_LEN], iv[AES_BLOCK_SIZE];
if (data_len < GMAC_MIC_LEN) if (data_len < GMAC_MIC_LEN)
return -EINVAL; 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_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[1], data, data_len - GMAC_MIC_LEN);
sg_set_buf(&sg[2], zero, GMAC_MIC_LEN); sg_set_buf(&sg[2], zero, GMAC_MIC_LEN);
sg_set_buf(&sg[3], mic, 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, ...@@ -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_tfm(aead_req, tfm);
aead_request_set_crypt(aead_req, sg, sg, 0, iv); 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); crypto_aead_encrypt(aead_req);
kzfree(aead_req);
return 0; return 0;
} }
......
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
#include <linux/crypto.h> #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[], struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
size_t key_len); size_t key_len);
int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, 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, ...@@ -820,7 +820,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
break; break;
rcu_read_lock(); rcu_read_lock();
sta = sta_info_get(sdata, mgmt->da); sta = sta_info_get_bss(sdata, mgmt->da);
rcu_read_unlock(); rcu_read_unlock();
if (!sta) if (!sta)
return -ENOLINK; return -ENOLINK;
......
...@@ -2298,6 +2298,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) ...@@ -2298,6 +2298,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;
struct sk_buff_head frame_list; struct sk_buff_head frame_list;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 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))) if (unlikely(!ieee80211_is_data(fc)))
return RX_CONTINUE; return RX_CONTINUE;
...@@ -2308,24 +2310,53 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) ...@@ -2308,24 +2310,53 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
if (!(status->rx_flags & IEEE80211_RX_AMSDU)) if (!(status->rx_flags & IEEE80211_RX_AMSDU))
return RX_CONTINUE; return RX_CONTINUE;
if (ieee80211_has_a4(hdr->frame_control) && if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && switch (rx->sdata->vif.type) {
!rx->sdata->u.vlan.sta) 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; 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) && 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)))
return RX_DROP_UNUSABLE; return RX_DROP_UNUSABLE;
skb->dev = dev; skb->dev = dev;
__skb_queue_head_init(&frame_list); __skb_queue_head_init(&frame_list);
if (ieee80211_data_to_8023_exthdr(skb, &ethhdr,
rx->sdata->vif.addr,
rx->sdata->vif.type))
return RX_DROP_UNUSABLE;
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
rx->sdata->vif.type, 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)) { while (!skb_queue_empty(&frame_list)) {
rx->skb = __skb_dequeue(&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, ...@@ -405,7 +405,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
u8 *pos; u8 *pos;
u8 pn[6]; u8 pn[6];
u64 pn64; u64 pn64;
u8 aad[2 * AES_BLOCK_SIZE]; u8 aad[CCM_AAD_LEN];
u8 b_0[AES_BLOCK_SIZE]; u8 b_0[AES_BLOCK_SIZE];
if (info->control.hw_key && if (info->control.hw_key &&
...@@ -461,10 +461,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb, ...@@ -461,10 +461,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
pos += IEEE80211_CCMP_HDR_LEN; pos += IEEE80211_CCMP_HDR_LEN;
ccmp_special_blocks(skb, pn, b_0, aad); ccmp_special_blocks(skb, pn, b_0, aad);
ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
skb_put(skb, mic_len), mic_len); skb_put(skb, mic_len), mic_len);
return 0;
} }
...@@ -639,7 +637,7 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ...@@ -639,7 +637,7 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
u8 *pos; u8 *pos;
u8 pn[6]; u8 pn[6];
u64 pn64; u64 pn64;
u8 aad[2 * AES_BLOCK_SIZE]; u8 aad[GCM_AAD_LEN];
u8 j_0[AES_BLOCK_SIZE]; u8 j_0[AES_BLOCK_SIZE];
if (info->control.hw_key && if (info->control.hw_key &&
...@@ -696,10 +694,8 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ...@@ -696,10 +694,8 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
pos += IEEE80211_GCMP_HDR_LEN; pos += IEEE80211_GCMP_HDR_LEN;
gcmp_special_blocks(skb, pn, j_0, aad); gcmp_special_blocks(skb, pn, j_0, aad);
ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
skb_put(skb, IEEE80211_GCMP_MIC_LEN)); skb_put(skb, IEEE80211_GCMP_MIC_LEN));
return 0;
} }
ieee80211_tx_result ieee80211_tx_result
...@@ -1123,9 +1119,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx) ...@@ -1123,9 +1119,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx)
struct ieee80211_key *key = tx->key; struct ieee80211_key *key = tx->key;
struct ieee80211_mmie_16 *mmie; struct ieee80211_mmie_16 *mmie;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
u8 aad[20]; u8 aad[GMAC_AAD_LEN];
u64 pn64; u64 pn64;
u8 nonce[12]; u8 nonce[GMAC_NONCE_LEN];
if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
return TX_DROP; return TX_DROP;
...@@ -1171,7 +1167,7 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx) ...@@ -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_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_key *key = rx->key; struct ieee80211_key *key = rx->key;
struct ieee80211_mmie_16 *mmie; 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; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (!ieee80211_is_mgmt(hdr->frame_control)) if (!ieee80211_is_mgmt(hdr->frame_control))
......
...@@ -420,7 +420,7 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) ...@@ -420,7 +420,7 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
} }
EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr, int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
const u8 *addr, enum nl80211_iftype iftype) const u8 *addr, enum nl80211_iftype iftype)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
...@@ -525,13 +525,7 @@ static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr, ...@@ -525,13 +525,7 @@ static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
return 0; return 0;
} }
EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
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);
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
enum nl80211_iftype iftype, enum nl80211_iftype iftype,
...@@ -746,24 +740,18 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, ...@@ -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, void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype, const u8 *addr, enum nl80211_iftype iftype,
const unsigned int extra_headroom, const unsigned int extra_headroom,
bool has_80211_header) const u8 *check_da, const u8 *check_sa)
{ {
unsigned int hlen = ALIGN(extra_headroom, 4); unsigned int hlen = ALIGN(extra_headroom, 4);
struct sk_buff *frame = NULL; struct sk_buff *frame = NULL;
u16 ethertype; u16 ethertype;
u8 *payload; u8 *payload;
int offset = 0, remaining, err; int offset = 0, remaining;
struct ethhdr eth; struct ethhdr eth;
bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
bool reuse_skb = false; bool reuse_skb = false;
bool last = false; bool last = false;
if (has_80211_header) {
err = __ieee80211_data_to_8023(skb, &eth, addr, iftype);
if (err)
goto out;
}
while (!last) { while (!last) {
unsigned int subframe_len; unsigned int subframe_len;
int len; int len;
...@@ -780,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, ...@@ -780,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
goto purge; goto purge;
offset += sizeof(struct ethhdr); offset += sizeof(struct ethhdr);
/* reuse skb for the last subframe */
last = remaining <= subframe_len + padding; 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) { if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
skb_pull(skb, offset); skb_pull(skb, offset);
frame = skb; frame = skb;
...@@ -819,7 +816,6 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, ...@@ -819,7 +816,6 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
purge: purge:
__skb_queue_purge(list); __skb_queue_purge(list);
out:
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment