mac80211: 802.11w - CCMP for management frames
Extend CCMP to support encryption and decryption of unicast management frames. Signed-off-by: Jouni Malinen <j@w1.fi> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
5394af4d86
commit
fb73333676
3 changed files with 64 additions and 7 deletions
|
@ -1030,6 +1030,7 @@ enum ieee80211_category {
|
|||
WLAN_CATEGORY_QOS = 1,
|
||||
WLAN_CATEGORY_DLS = 2,
|
||||
WLAN_CATEGORY_BACK = 3,
|
||||
WLAN_CATEGORY_PUBLIC = 4,
|
||||
WLAN_CATEGORY_WMM = 17,
|
||||
};
|
||||
|
||||
|
@ -1185,6 +1186,35 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
|
|||
return hdr->addr1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
|
||||
* @hdr: the frame (buffer must include at least the first octet of payload)
|
||||
*/
|
||||
static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
if (ieee80211_is_disassoc(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control))
|
||||
return true;
|
||||
|
||||
if (ieee80211_is_action(hdr->frame_control)) {
|
||||
u8 *category;
|
||||
|
||||
/*
|
||||
* Action frames, excluding Public Action frames, are Robust
|
||||
* Management Frames. However, if we are looking at a Protected
|
||||
* frame, skip the check since the data may be encrypted and
|
||||
* the frame has already been found to be a Robust Management
|
||||
* Frame (by the other end).
|
||||
*/
|
||||
if (ieee80211_has_protected(hdr->frame_control))
|
||||
return true;
|
||||
category = ((u8 *) hdr) + 24;
|
||||
return *category != WLAN_CATEGORY_PUBLIC;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_fhss_chan_to_freq - get channel frequency
|
||||
* @channel: the FHSS channel
|
||||
|
|
|
@ -330,6 +330,22 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
|
|||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (!ieee80211_is_mgmt(fc))
|
||||
return 0;
|
||||
|
||||
if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP))
|
||||
return 0;
|
||||
|
||||
if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
|
||||
skb->data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result
|
||||
ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
@ -428,10 +444,15 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
if (ieee80211_is_auth(hdr->frame_control))
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
case ALG_CCMP:
|
||||
if (!ieee80211_is_data_present(hdr->frame_control))
|
||||
tx->key = NULL;
|
||||
break;
|
||||
case ALG_CCMP:
|
||||
if (!ieee80211_is_data_present(hdr->frame_control) &&
|
||||
!ieee80211_use_mfp(hdr->frame_control, tx->sta,
|
||||
tx->skb))
|
||||
tx->key = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -266,7 +266,7 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
|
|||
int encrypted)
|
||||
{
|
||||
__le16 mask_fc;
|
||||
int a4_included;
|
||||
int a4_included, mgmt;
|
||||
u8 qos_tid;
|
||||
u8 *b_0, *aad;
|
||||
u16 data_len, len_a;
|
||||
|
@ -277,12 +277,15 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
|
|||
aad = scratch + 4 * AES_BLOCK_LEN;
|
||||
|
||||
/*
|
||||
* Mask FC: zero subtype b4 b5 b6
|
||||
* Mask FC: zero subtype b4 b5 b6 (if not mgmt)
|
||||
* Retry, PwrMgt, MoreData; set Protected
|
||||
*/
|
||||
mgmt = ieee80211_is_mgmt(hdr->frame_control);
|
||||
mask_fc = hdr->frame_control;
|
||||
mask_fc &= ~cpu_to_le16(0x0070 | IEEE80211_FCTL_RETRY |
|
||||
mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY |
|
||||
IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
|
||||
if (!mgmt)
|
||||
mask_fc &= ~cpu_to_le16(0x0070);
|
||||
mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
@ -300,8 +303,10 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
|
|||
|
||||
/* First block, b_0 */
|
||||
b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
|
||||
/* Nonce: QoS Priority | A2 | PN */
|
||||
b_0[1] = qos_tid;
|
||||
/* Nonce: Nonce Flags | A2 | PN
|
||||
* Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
|
||||
*/
|
||||
b_0[1] = qos_tid | (mgmt << 4);
|
||||
memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
|
||||
memcpy(&b_0[8], pn, CCMP_PN_LEN);
|
||||
/* l(m) */
|
||||
|
@ -446,7 +451,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
|
|||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
if (!ieee80211_is_data(hdr->frame_control) &&
|
||||
!ieee80211_is_robust_mgmt_frame(hdr))
|
||||
return RX_CONTINUE;
|
||||
|
||||
data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
|
||||
|
|
Loading…
Reference in a new issue