All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 46f6b060 authored by Masashi Honma's avatar Masashi Honma Committed by Johannes Berg

mac80211: Encrypt "Group addressed privacy" action frames

Previously, the action frames to group address was not encrypted. But
[1] "Table 8-38 Category values" indicates "Mesh" and "Multihop" category
action frames should be encrypted (Group addressed privacy == yes). And the
encyption key should be MGTK ([1] 10.13 Group addressed robust management frame
procedures). So this patch modifies the code to make it suitable for spec.

[1] IEEE Std 802.11-2012
Signed-off-by: default avatarMasashi Honma <masashi.honma@gmail.com>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
parent 49708e37
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -2486,6 +2487,35 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr, ...@@ -2486,6 +2487,35 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC; return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC;
} }
/**
* _ieee80211_is_group_privacy_action - check if frame is a group addressed
* privacy action frame
* @hdr: the frame
*/
static inline bool _ieee80211_is_group_privacy_action(struct ieee80211_hdr *hdr)
{
struct ieee80211_mgmt *mgmt = (void *)hdr;
if (!ieee80211_is_action(hdr->frame_control) ||
!is_multicast_ether_addr(hdr->addr1))
return false;
return mgmt->u.action.category == WLAN_CATEGORY_MESH_ACTION ||
mgmt->u.action.category == WLAN_CATEGORY_MULTIHOP_ACTION;
}
/**
* ieee80211_is_group_privacy_action - check if frame is a group addressed
* privacy action frame
* @skb: the skb containing the frame, length will be checked
*/
static inline bool ieee80211_is_group_privacy_action(struct sk_buff *skb)
{
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
return false;
return _ieee80211_is_group_privacy_action((void *)skb->data);
}
/** /**
* ieee80211_tu_to_usec - convert time units (TU) to microseconds * ieee80211_tu_to_usec - convert time units (TU) to microseconds
* @tu: the TUs * @tu: the TUs
......
...@@ -1624,8 +1624,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) ...@@ -1624,8 +1624,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (mmie_keyidx < NUM_DEFAULT_KEYS || if (mmie_keyidx < NUM_DEFAULT_KEYS ||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */ return RX_DROP_MONITOR; /* unexpected BIP keyidx */
if (rx->sta) if (rx->sta) {
if (ieee80211_is_group_privacy_action(skb) &&
test_sta_flag(rx->sta, WLAN_STA_MFP))
return RX_DROP_MONITOR;
rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]); rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
}
if (!rx->key) if (!rx->key)
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
} else if (!ieee80211_has_protected(fc)) { } else if (!ieee80211_has_protected(fc)) {
......
...@@ -593,6 +593,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) ...@@ -593,6 +593,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
else if (tx->sta && else if (tx->sta &&
(key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
tx->key = key; tx->key = key;
else if (ieee80211_is_group_privacy_action(tx->skb) &&
(key = rcu_dereference(tx->sdata->default_multicast_key)))
tx->key = key;
else if (ieee80211_is_mgmt(hdr->frame_control) && else if (ieee80211_is_mgmt(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) && is_multicast_ether_addr(hdr->addr1) &&
ieee80211_is_robust_mgmt_frame(tx->skb) && ieee80211_is_robust_mgmt_frame(tx->skb) &&
...@@ -625,7 +628,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) ...@@ -625,7 +628,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_GCMP_256:
if (!ieee80211_is_data_present(hdr->frame_control) && if (!ieee80211_is_data_present(hdr->frame_control) &&
!ieee80211_use_mfp(hdr->frame_control, tx->sta, !ieee80211_use_mfp(hdr->frame_control, tx->sta,
tx->skb)) tx->skb) &&
!ieee80211_is_group_privacy_action(tx->skb))
tx->key = NULL; tx->key = NULL;
else else
skip_hw = (tx->key->conf.flags & skip_hw = (tx->key->conf.flags &
......
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