diff options
| author | Jouni Malinen <j@w1.fi> | 2009-01-08 06:32:00 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:00:01 -0500 |
| commit | fb7333367632c67d8b6b06fb8d906cdabb11b02a (patch) | |
| tree | 337d89f2c8c033b00dfcefbbcbded3f914d51661 | |
| parent | 5394af4d86ae51b369ff243c3f75b6f9a74e164b (diff) | |
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>
| -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; |
