diff options
-rw-r--r-- | include/linux/ieee80211.h | 30 | ||||
-rw-r--r-- | net/mac80211/tx.c | 23 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 18 |
3 files changed, 64 insertions, 7 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index cade2556af0e..d5165895f316 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1030,6 +1030,7 @@ enum ieee80211_category { | |||
1030 | WLAN_CATEGORY_QOS = 1, | 1030 | WLAN_CATEGORY_QOS = 1, |
1031 | WLAN_CATEGORY_DLS = 2, | 1031 | WLAN_CATEGORY_DLS = 2, |
1032 | WLAN_CATEGORY_BACK = 3, | 1032 | WLAN_CATEGORY_BACK = 3, |
1033 | WLAN_CATEGORY_PUBLIC = 4, | ||
1033 | WLAN_CATEGORY_WMM = 17, | 1034 | WLAN_CATEGORY_WMM = 17, |
1034 | }; | 1035 | }; |
1035 | 1036 | ||
@@ -1186,6 +1187,35 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) | |||
1186 | } | 1187 | } |
1187 | 1188 | ||
1188 | /** | 1189 | /** |
1190 | * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame | ||
1191 | * @hdr: the frame (buffer must include at least the first octet of payload) | ||
1192 | */ | ||
1193 | static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) | ||
1194 | { | ||
1195 | if (ieee80211_is_disassoc(hdr->frame_control) || | ||
1196 | ieee80211_is_deauth(hdr->frame_control)) | ||
1197 | return true; | ||
1198 | |||
1199 | if (ieee80211_is_action(hdr->frame_control)) { | ||
1200 | u8 *category; | ||
1201 | |||
1202 | /* | ||
1203 | * Action frames, excluding Public Action frames, are Robust | ||
1204 | * Management Frames. However, if we are looking at a Protected | ||
1205 | * frame, skip the check since the data may be encrypted and | ||
1206 | * the frame has already been found to be a Robust Management | ||
1207 | * Frame (by the other end). | ||
1208 | */ | ||
1209 | if (ieee80211_has_protected(hdr->frame_control)) | ||
1210 | return true; | ||
1211 | category = ((u8 *) hdr) + 24; | ||
1212 | return *category != WLAN_CATEGORY_PUBLIC; | ||
1213 | } | ||
1214 | |||
1215 | return false; | ||
1216 | } | ||
1217 | |||
1218 | /** | ||
1189 | * ieee80211_fhss_chan_to_freq - get channel frequency | 1219 | * ieee80211_fhss_chan_to_freq - get channel frequency |
1190 | * @channel: the FHSS channel | 1220 | * @channel: the FHSS channel |
1191 | * | 1221 | * |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cd6bc87eec73..50c6c4fabea5 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -330,6 +330,22 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
330 | return TX_CONTINUE; | 330 | return TX_CONTINUE; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, | ||
334 | struct sk_buff *skb) | ||
335 | { | ||
336 | if (!ieee80211_is_mgmt(fc)) | ||
337 | return 0; | ||
338 | |||
339 | if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP)) | ||
340 | return 0; | ||
341 | |||
342 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) | ||
343 | skb->data)) | ||
344 | return 0; | ||
345 | |||
346 | return 1; | ||
347 | } | ||
348 | |||
333 | static ieee80211_tx_result | 349 | static ieee80211_tx_result |
334 | ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | 350 | ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) |
335 | { | 351 | { |
@@ -428,10 +444,15 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
428 | if (ieee80211_is_auth(hdr->frame_control)) | 444 | if (ieee80211_is_auth(hdr->frame_control)) |
429 | break; | 445 | break; |
430 | case ALG_TKIP: | 446 | case ALG_TKIP: |
431 | case ALG_CCMP: | ||
432 | if (!ieee80211_is_data_present(hdr->frame_control)) | 447 | if (!ieee80211_is_data_present(hdr->frame_control)) |
433 | tx->key = NULL; | 448 | tx->key = NULL; |
434 | break; | 449 | break; |
450 | case ALG_CCMP: | ||
451 | if (!ieee80211_is_data_present(hdr->frame_control) && | ||
452 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, | ||
453 | tx->skb)) | ||
454 | tx->key = NULL; | ||
455 | break; | ||
435 | } | 456 | } |
436 | } | 457 | } |
437 | 458 | ||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 7aa63caf8d50..aff46adde3f0 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -266,7 +266,7 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
266 | int encrypted) | 266 | int encrypted) |
267 | { | 267 | { |
268 | __le16 mask_fc; | 268 | __le16 mask_fc; |
269 | int a4_included; | 269 | int a4_included, mgmt; |
270 | u8 qos_tid; | 270 | u8 qos_tid; |
271 | u8 *b_0, *aad; | 271 | u8 *b_0, *aad; |
272 | u16 data_len, len_a; | 272 | u16 data_len, len_a; |
@@ -277,12 +277,15 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
277 | aad = scratch + 4 * AES_BLOCK_LEN; | 277 | aad = scratch + 4 * AES_BLOCK_LEN; |
278 | 278 | ||
279 | /* | 279 | /* |
280 | * Mask FC: zero subtype b4 b5 b6 | 280 | * Mask FC: zero subtype b4 b5 b6 (if not mgmt) |
281 | * Retry, PwrMgt, MoreData; set Protected | 281 | * Retry, PwrMgt, MoreData; set Protected |
282 | */ | 282 | */ |
283 | mgmt = ieee80211_is_mgmt(hdr->frame_control); | ||
283 | mask_fc = hdr->frame_control; | 284 | mask_fc = hdr->frame_control; |
284 | mask_fc &= ~cpu_to_le16(0x0070 | IEEE80211_FCTL_RETRY | | 285 | mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | |
285 | IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); | 286 | IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); |
287 | if (!mgmt) | ||
288 | mask_fc &= ~cpu_to_le16(0x0070); | ||
286 | mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 289 | mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
287 | 290 | ||
288 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 291 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
@@ -300,8 +303,10 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
300 | 303 | ||
301 | /* First block, b_0 */ | 304 | /* First block, b_0 */ |
302 | b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ | 305 | b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ |
303 | /* Nonce: QoS Priority | A2 | PN */ | 306 | /* Nonce: Nonce Flags | A2 | PN |
304 | b_0[1] = qos_tid; | 307 | * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) |
308 | */ | ||
309 | b_0[1] = qos_tid | (mgmt << 4); | ||
305 | memcpy(&b_0[2], hdr->addr2, ETH_ALEN); | 310 | memcpy(&b_0[2], hdr->addr2, ETH_ALEN); |
306 | memcpy(&b_0[8], pn, CCMP_PN_LEN); | 311 | memcpy(&b_0[8], pn, CCMP_PN_LEN); |
307 | /* l(m) */ | 312 | /* l(m) */ |
@@ -446,7 +451,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
446 | 451 | ||
447 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 452 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
448 | 453 | ||
449 | if (!ieee80211_is_data(hdr->frame_control)) | 454 | if (!ieee80211_is_data(hdr->frame_control) && |
455 | !ieee80211_is_robust_mgmt_frame(hdr)) | ||
450 | return RX_CONTINUE; | 456 | return RX_CONTINUE; |
451 | 457 | ||
452 | data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; | 458 | data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; |