aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ieee80211.h30
-rw-r--r--net/mac80211/tx.c23
-rw-r--r--net/mac80211/wpa.c18
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 */
1193static 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
333static 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
333static ieee80211_tx_result 349static ieee80211_tx_result
334ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) 350ieee80211_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;