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