* [PATCHv2 01/16] mac80211: 802.11w - STA flag for MFP
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
@ 2009-01-08 11:31 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 02/16] mac80211: 802.11w - CCMP for management frames Jouni Malinen
` (15 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:31 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Add flags for setting STA entries and struct ieee80211_if_sta to
indicate whether management frame protection (MFP) is used.
Signed-off-by: Jouni Malinen <j@w1.fi>
---
include/linux/nl80211.h | 2 ++
include/net/cfg80211.h | 2 ++
net/mac80211/cfg.c | 4 ++++
net/mac80211/debugfs_sta.c | 5 +++--
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 7 +++++--
net/mac80211/sta_info.h | 2 ++
7 files changed, 19 insertions(+), 4 deletions(-)
--- wireless-testing.orig/net/mac80211/mlme.c 2009-01-08 13:05:41.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c 2009-01-08 13:06:19.000000000 +0200
@@ -1,6 +1,6 @@
/*
* BSS client mode implementation
- * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
* Copyright 2004, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
@@ -472,7 +472,7 @@ static void ieee80211_send_deauth_disass
/* u.deauth.reason_code == u.disassoc.reason_code */
mgmt->u.deauth.reason_code = cpu_to_le16(reason);
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED);
}
/* MLME */
@@ -1421,6 +1421,9 @@ static void ieee80211_rx_mgmt_assoc_resp
rate_control_rate_init(sta);
+ if (ifsta->flags & IEEE80211_STA_MFP_ENABLED)
+ set_sta_flags(sta, WLAN_STA_MFP);
+
if (elems.wmm_param)
set_sta_flags(sta, WLAN_STA_WME);
--- wireless-testing.orig/include/linux/nl80211.h 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h 2009-01-08 13:06:19.000000000 +0200
@@ -412,12 +412,14 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
* with short barker preamble
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
*/
enum nl80211_sta_flags {
__NL80211_STA_FLAG_INVALID,
NL80211_STA_FLAG_AUTHORIZED,
NL80211_STA_FLAG_SHORT_PREAMBLE,
NL80211_STA_FLAG_WME,
+ NL80211_STA_FLAG_MFP,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
--- wireless-testing.orig/include/net/cfg80211.h 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h 2009-01-08 13:06:19.000000000 +0200
@@ -112,12 +112,14 @@ struct beacon_parameters {
* @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
* with short preambles
* @STATION_FLAG_WME: station is WME/QoS capable
+ * @STATION_FLAG_MFP: station uses management frame protection
*/
enum station_flags {
STATION_FLAG_CHANGED = 1<<0,
STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
+ STATION_FLAG_MFP = 1<<NL80211_STA_FLAG_MFP,
};
/**
--- wireless-testing.orig/net/mac80211/cfg.c 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c 2009-01-08 13:06:19.000000000 +0200
@@ -630,6 +630,10 @@ static void sta_apply_parameters(struct
sta->flags &= ~WLAN_STA_WME;
if (params->station_flags & STATION_FLAG_WME)
sta->flags |= WLAN_STA_WME;
+
+ sta->flags &= ~WLAN_STA_MFP;
+ if (params->station_flags & STATION_FLAG_MFP)
+ sta->flags |= WLAN_STA_MFP;
spin_unlock_bh(&sta->lock);
}
--- wireless-testing.orig/net/mac80211/debugfs_sta.c 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_sta.c 2009-01-08 13:06:19.000000000 +0200
@@ -67,14 +67,15 @@ static ssize_t sta_flags_read(struct fil
char buf[100];
struct sta_info *sta = file->private_data;
u32 staflags = get_sta_flags(sta);
- int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
+ int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s",
staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
staflags & WLAN_STA_PS ? "PS\n" : "",
staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
staflags & WLAN_STA_WME ? "WME\n" : "",
- staflags & WLAN_STA_WDS ? "WDS\n" : "");
+ staflags & WLAN_STA_WDS ? "WDS\n" : "",
+ staflags & WLAN_STA_MFP ? "MFP\n" : "");
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
STA_OPS(flags);
--- wireless-testing.orig/net/mac80211/sta_info.h 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/sta_info.h 2009-01-08 13:06:19.000000000 +0200
@@ -34,6 +34,7 @@
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
* frame to this station is transmitted.
+ * @WLAN_STA_MFP: Management frame protection is used with this STA.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH = 1<<0,
@@ -46,6 +47,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_WDS = 1<<7,
WLAN_STA_PSPOLL = 1<<8,
WLAN_STA_CLEAR_PS_FILT = 1<<9,
+ WLAN_STA_MFP = 1<<10,
};
#define STA_TID_NUM 16
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-01-08 13:05:38.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-01-08 13:06:19.000000000 +0200
@@ -260,6 +260,7 @@ struct mesh_preq_queue {
#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
#define IEEE80211_STA_TKIP_WEP_USED BIT(14)
#define IEEE80211_STA_CSA_RECEIVED BIT(15)
+#define IEEE80211_STA_MFP_ENABLED BIT(16)
/* flags for MLME request */
#define IEEE80211_STA_REQ_SCAN 0
#define IEEE80211_STA_REQ_DIRECT_PROBE 1
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 02/16] mac80211: 802.11w - CCMP for management frames
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
2009-01-08 11:31 ` [PATCHv2 01/16] mac80211: 802.11w - STA flag for MFP Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 03/16] mac80211: 802.11w - Add BIP (AES-128-CMAC) Jouni Malinen
` (14 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Extend CCMP to support encryption and decryption of unicast management
frames.
Signed-off-by: Jouni Malinen <j@w1.fi>
---
include/linux/ieee80211.h | 30 ++++++++++++++++++++++++++++++
net/mac80211/tx.c | 23 ++++++++++++++++++++++-
net/mac80211/wpa.c | 18 ++++++++++++------
3 files changed, 64 insertions(+), 7 deletions(-)
--- wireless-testing.orig/net/mac80211/tx.c 2009-01-08 13:05:41.000000000 +0200
+++ wireless-testing/net/mac80211/tx.c 2009-01-08 13:06:22.000000000 +0200
@@ -331,6 +331,22 @@ ieee80211_tx_h_multicast_ps_buf(struct i
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)
{
@@ -430,10 +446,15 @@ ieee80211_tx_h_select_key(struct ieee802
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;
}
}
--- wireless-testing.orig/net/mac80211/wpa.c 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/wpa.c 2009-01-08 13:06:22.000000000 +0200
@@ -268,7 +268,7 @@ static void ccmp_special_blocks(struct s
int encrypted)
{
__le16 mask_fc;
- int a4_included;
+ int a4_included, mgmt;
u8 qos_tid;
u8 *b_0, *aad;
u16 data_len, len_a;
@@ -279,12 +279,15 @@ static void ccmp_special_blocks(struct s
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);
@@ -302,8 +305,10 @@ static void ccmp_special_blocks(struct s
/* 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) */
@@ -449,7 +454,8 @@ ieee80211_crypto_ccmp_decrypt(struct iee
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;
--- wireless-testing.orig/include/linux/ieee80211.h 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h 2009-01-08 13:06:22.000000000 +0200
@@ -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,
};
@@ -1186,6 +1187,35 @@ static inline u8 *ieee80211_get_DA(struc
}
/**
+ * 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
*
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 03/16] mac80211: 802.11w - Add BIP (AES-128-CMAC)
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
2009-01-08 11:31 ` [PATCHv2 01/16] mac80211: 802.11w - STA flag for MFP Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 02/16] mac80211: 802.11w - CCMP for management frames Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 04/16] mac80211: 802.11w - Use " Jouni Malinen
` (13 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Implement Broadcast/Multicast Integrity Protocol for management frame
protection. This patch adds the needed definitions for the new
information element (MMIE) and implementation for the new "encryption"
type (though, BIP is actually not encrypting data, it provides only
integrity protection). These routines will be used by a follow-on patch
that enables BIP for multicast/broadcast robust management frames.
Signed-off-by: Jouni Malinen <j@w1.fi>
---
include/linux/ieee80211.h | 10 +++
net/mac80211/Makefile | 1
net/mac80211/aes_cmac.c | 135 +++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/aes_cmac.h | 19 ++++++
net/mac80211/ieee80211_i.h | 2
net/mac80211/key.h | 10 +++
net/mac80211/wpa.c | 125 +++++++++++++++++++++++++++++++++++++++++
net/mac80211/wpa.h | 5 +
8 files changed, 306 insertions(+), 1 deletion(-)
--- wireless-testing.orig/include/linux/ieee80211.h 2009-01-08 13:06:22.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h 2009-01-08 13:06:24.000000000 +0200
@@ -655,6 +655,15 @@ struct ieee80211_mgmt {
#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
+/* Management MIC information element (IEEE 802.11w) */
+struct ieee80211_mmie {
+ u8 element_id;
+ u8 length;
+ __le16 key_id;
+ u8 sequence_number[6];
+ u8 mic[8];
+} __attribute__ ((packed));
+
/* Control frames */
struct ieee80211_rts {
__le16 frame_control;
@@ -1018,6 +1027,7 @@ enum ieee80211_eid {
WLAN_EID_HT_INFORMATION = 61,
/* 802.11i */
WLAN_EID_RSN = 48,
+ WLAN_EID_MMIE = 76 /* 802.11w */,
WLAN_EID_WPA = 221,
WLAN_EID_GENERIC = 221,
WLAN_EID_VENDOR_SPECIFIC = 221,
--- wireless-testing.orig/net/mac80211/key.h 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/key.h 2009-01-08 13:06:24.000000000 +0200
@@ -96,6 +96,16 @@ struct ieee80211_key {
u8 tx_crypto_buf[6 * AES_BLOCK_LEN];
u8 rx_crypto_buf[6 * AES_BLOCK_LEN];
} ccmp;
+ struct {
+ u8 tx_pn[6];
+ u8 rx_pn[6];
+ struct crypto_cipher *tfm;
+ u32 replays; /* dot11RSNAStatsCMACReplays */
+ u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
+ /* scratch buffers for virt_to_page() (crypto API) */
+ u8 tx_crypto_buf[2 * AES_BLOCK_LEN];
+ u8 rx_crypto_buf[2 * AES_BLOCK_LEN];
+ } aes_cmac;
} u;
/* number of times this key has been used */
--- wireless-testing.orig/net/mac80211/wpa.c 2009-01-08 13:06:22.000000000 +0200
+++ wireless-testing/net/mac80211/wpa.c 2009-01-08 13:06:24.000000000 +0200
@@ -1,5 +1,6 @@
/*
* Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2008, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,7 @@
#include "michael.h"
#include "tkip.h"
#include "aes_ccm.h"
+#include "aes_cmac.h"
#include "wpa.h"
ieee80211_tx_result
@@ -494,3 +496,126 @@ ieee80211_crypto_ccmp_decrypt(struct iee
return RX_CONTINUE;
}
+
+
+static void bip_aad(struct sk_buff *skb, u8 *aad)
+{
+ /* BIP AAD: FC(masked) || A1 || A2 || A3 */
+
+ /* FC type/subtype */
+ aad[0] = skb->data[0];
+ /* Mask FC Retry, PwrMgt, MoreData flags to zero */
+ aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6));
+ /* A1 || A2 || A3 */
+ memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN);
+}
+
+
+static inline void bip_ipn_swap(u8 *d, const u8 *s)
+{
+ *d++ = s[5];
+ *d++ = s[4];
+ *d++ = s[3];
+ *d++ = s[2];
+ *d++ = s[1];
+ *d = s[0];
+}
+
+
+ieee80211_tx_result
+ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
+{
+ struct sk_buff *skb = tx->skb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_key *key = tx->key;
+ struct ieee80211_mmie *mmie;
+ u8 *pn, aad[20];
+ int i;
+
+ if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
+ /* hwaccel */
+ info->control.hw_key = &tx->key->conf;
+ return 0;
+ }
+
+ if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
+ return TX_DROP;
+
+ mmie = (struct ieee80211_mmie *) skb_put(skb, sizeof(*mmie));
+ mmie->element_id = WLAN_EID_MMIE;
+ mmie->length = sizeof(*mmie) - 2;
+ mmie->key_id = cpu_to_le16(key->conf.keyidx);
+
+ /* PN = PN + 1 */
+ pn = key->u.aes_cmac.tx_pn;
+
+ for (i = sizeof(key->u.aes_cmac.tx_pn) - 1; i >= 0; i--) {
+ pn[i]++;
+ if (pn[i])
+ break;
+ }
+ bip_ipn_swap(mmie->sequence_number, pn);
+
+ bip_aad(skb, aad);
+
+ /*
+ * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
+ */
+ ieee80211_aes_cmac(key->u.aes_cmac.tfm, key->u.aes_cmac.tx_crypto_buf,
+ aad, skb->data + 24, skb->len - 24, mmie->mic);
+
+ return TX_CONTINUE;
+}
+
+
+ieee80211_rx_result
+ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
+{
+ struct sk_buff *skb = rx->skb;
+ struct ieee80211_key *key = rx->key;
+ struct ieee80211_mmie *mmie;
+ u8 aad[20], mic[8], ipn[6];
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (!ieee80211_is_mgmt(hdr->frame_control))
+ return RX_CONTINUE;
+
+ if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
+ (rx->status->flag & RX_FLAG_IV_STRIPPED))
+ return RX_CONTINUE;
+
+ if (skb->len < 24 + sizeof(*mmie))
+ return RX_DROP_UNUSABLE;
+
+ mmie = (struct ieee80211_mmie *)
+ (skb->data + skb->len - sizeof(*mmie));
+ if (mmie->element_id != WLAN_EID_MMIE ||
+ mmie->length != sizeof(*mmie) - 2)
+ return RX_DROP_UNUSABLE; /* Invalid MMIE */
+
+ bip_ipn_swap(ipn, mmie->sequence_number);
+
+ if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
+ key->u.aes_cmac.replays++;
+ return RX_DROP_UNUSABLE;
+ }
+
+ if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
+ /* hardware didn't decrypt/verify MIC */
+ bip_aad(skb, aad);
+ ieee80211_aes_cmac(key->u.aes_cmac.tfm,
+ key->u.aes_cmac.rx_crypto_buf, aad,
+ skb->data + 24, skb->len - 24, mic);
+ if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
+ key->u.aes_cmac.icverrors++;
+ return RX_DROP_UNUSABLE;
+ }
+ }
+
+ memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
+
+ /* Remove MMIE */
+ skb_trim(skb, skb->len - sizeof(*mmie));
+
+ return RX_CONTINUE;
+}
--- wireless-testing.orig/net/mac80211/wpa.h 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/wpa.h 2009-01-08 13:06:24.000000000 +0200
@@ -28,4 +28,9 @@ ieee80211_crypto_ccmp_encrypt(struct iee
ieee80211_rx_result
ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx);
+
#endif /* WPA_H */
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/net/mac80211/aes_cmac.c 2009-01-08 13:06:24.000000000 +0200
@@ -0,0 +1,135 @@
+/*
+ * AES-128-CMAC with TLen 16 for IEEE 802.11w BIP
+ * Copyright 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+
+#include <net/mac80211.h>
+#include "key.h"
+#include "aes_cmac.h"
+
+#define AES_BLOCK_SIZE 16
+#define AES_CMAC_KEY_LEN 16
+#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
+#define AAD_LEN 20
+
+
+static void gf_mulx(u8 *pad)
+{
+ int i, carry;
+
+ carry = pad[0] & 0x80;
+ for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+ pad[AES_BLOCK_SIZE - 1] <<= 1;
+ if (carry)
+ pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+static void aes_128_cmac_vector(struct crypto_cipher *tfm, u8 *scratch,
+ size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ u8 *cbc, *pad;
+ const u8 *pos, *end;
+ size_t i, e, left, total_len;
+
+ cbc = scratch;
+ pad = scratch + AES_BLOCK_SIZE;
+
+ memset(cbc, 0, AES_BLOCK_SIZE);
+
+ total_len = 0;
+ for (e = 0; e < num_elem; e++)
+ total_len += len[e];
+ left = total_len;
+
+ e = 0;
+ pos = addr[0];
+ end = pos + len[0];
+
+ while (left >= AES_BLOCK_SIZE) {
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
+ cbc[i] ^= *pos++;
+ if (pos >= end) {
+ e++;
+ pos = addr[e];
+ end = pos + len[e];
+ }
+ }
+ if (left > AES_BLOCK_SIZE)
+ crypto_cipher_encrypt_one(tfm, cbc, cbc);
+ left -= AES_BLOCK_SIZE;
+ }
+
+ memset(pad, 0, AES_BLOCK_SIZE);
+ crypto_cipher_encrypt_one(tfm, pad, pad);
+ gf_mulx(pad);
+
+ if (left || total_len == 0) {
+ for (i = 0; i < left; i++) {
+ cbc[i] ^= *pos++;
+ if (pos >= end) {
+ e++;
+ pos = addr[e];
+ end = pos + len[e];
+ }
+ }
+ cbc[left] ^= 0x80;
+ gf_mulx(pad);
+ }
+
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ pad[i] ^= cbc[i];
+ crypto_cipher_encrypt_one(tfm, pad, pad);
+ memcpy(mac, pad, CMAC_TLEN);
+}
+
+
+void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad,
+ const u8 *data, size_t data_len, u8 *mic)
+{
+ const u8 *addr[3];
+ size_t len[3];
+ u8 zero[CMAC_TLEN];
+
+ memset(zero, 0, CMAC_TLEN);
+ addr[0] = aad;
+ len[0] = AAD_LEN;
+ addr[1] = data;
+ len[1] = data_len - CMAC_TLEN;
+ addr[2] = zero;
+ len[2] = CMAC_TLEN;
+
+ aes_128_cmac_vector(tfm, scratch, 3, addr, len, mic);
+}
+
+
+struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[])
+{
+ struct crypto_cipher *tfm;
+
+ tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm))
+ return NULL;
+
+ crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN);
+
+ return tfm;
+}
+
+
+void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm)
+{
+ if (tfm)
+ crypto_free_cipher(tfm);
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/net/mac80211/aes_cmac.h 2009-01-08 13:06:24.000000000 +0200
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef AES_CMAC_H
+#define AES_CMAC_H
+
+#include <linux/crypto.h>
+
+struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]);
+void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad,
+ const u8 *data, size_t data_len, u8 *mic);
+void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm);
+
+#endif /* AES_CMAC_H */
--- wireless-testing.orig/net/mac80211/Makefile 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/Makefile 2009-01-08 13:06:24.000000000 +0200
@@ -15,6 +15,7 @@ mac80211-y := \
michael.o \
tkip.o \
aes_ccm.o \
+ aes_cmac.o \
cfg.o \
rx.o \
spectmgmt.o \
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-01-08 13:06:19.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-01-08 13:06:24.000000000 +0200
@@ -43,7 +43,7 @@ struct ieee80211_local;
/* Required encryption head and tailroom */
#define IEEE80211_ENCRYPT_HEADROOM 8
-#define IEEE80211_ENCRYPT_TAILROOM 12
+#define IEEE80211_ENCRYPT_TAILROOM 18
/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
* reception of at least three fragmented frames. This limit can be increased
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 04/16] mac80211: 802.11w - Use BIP (AES-128-CMAC)
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (2 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 03/16] mac80211: 802.11w - Add BIP (AES-128-CMAC) Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 05/16] mac80211: 802.11w - WEXT parameter for setting mgmt cipher Jouni Malinen
` (12 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Add mechanism for managing BIP keys (IGTK) and integrate BIP into the
TX/RX paths.
Signed-off-by: Jouni Malinen <j@w1.fi>
---
drivers/net/wireless/ath5k/pcu.c | 3 +
include/linux/ieee80211.h | 1
include/linux/nl80211.h | 6 +-
include/net/cfg80211.h | 5 ++
include/net/mac80211.h | 2
net/mac80211/cfg.c | 31 +++++++++++++
net/mac80211/debugfs_key.c | 79 +++++++++++++++++++++++++++++++++-
net/mac80211/debugfs_key.h | 10 ++++
net/mac80211/ieee80211_i.h | 5 +-
net/mac80211/key.c | 62 ++++++++++++++++++++++++++
net/mac80211/key.h | 6 ++
net/mac80211/rx.c | 90 +++++++++++++++++++++++++++++++++++----
net/mac80211/tx.c | 9 +++
net/wireless/nl80211.c | 29 +++++++++---
14 files changed, 317 insertions(+), 21 deletions(-)
--- wireless-testing.orig/include/linux/ieee80211.h 2009-01-08 13:06:24.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h 2009-01-08 13:06:27.000000000 +0200
@@ -1139,6 +1139,7 @@ enum ieee80211_back_parties {
/* reserved: 0x000FAC03 */
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
+#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
#define WLAN_MAX_KEY_LEN 32
--- wireless-testing.orig/include/net/mac80211.h 2009-01-08 13:05:41.000000000 +0200
+++ wireless-testing/include/net/mac80211.h 2009-01-08 13:06:27.000000000 +0200
@@ -658,11 +658,13 @@ struct ieee80211_if_conf {
* @ALG_WEP: WEP40 or WEP104
* @ALG_TKIP: TKIP
* @ALG_CCMP: CCMP (AES)
+ * @ALG_AES_CMAC: AES-128-CMAC
*/
enum ieee80211_key_alg {
ALG_WEP,
ALG_TKIP,
ALG_CCMP,
+ ALG_AES_CMAC,
};
/**
--- wireless-testing.orig/net/mac80211/cfg.c 2009-01-08 13:06:19.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c 2009-01-08 13:06:27.000000000 +0200
@@ -133,6 +133,9 @@ static int ieee80211_add_key(struct wiph
case WLAN_CIPHER_SUITE_CCMP:
alg = ALG_CCMP;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ alg = ALG_AES_CMAC;
+ break;
default:
return -EINVAL;
}
@@ -275,6 +278,17 @@ static int ieee80211_get_key(struct wiph
else
params.cipher = WLAN_CIPHER_SUITE_WEP104;
break;
+ case ALG_AES_CMAC:
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ seq[0] = key->u.aes_cmac.tx_pn[5];
+ seq[1] = key->u.aes_cmac.tx_pn[4];
+ seq[2] = key->u.aes_cmac.tx_pn[3];
+ seq[3] = key->u.aes_cmac.tx_pn[2];
+ seq[4] = key->u.aes_cmac.tx_pn[1];
+ seq[5] = key->u.aes_cmac.tx_pn[0];
+ params.seq = seq;
+ params.seq_len = 6;
+ break;
}
params.key = key->conf.key;
@@ -304,6 +318,22 @@ static int ieee80211_config_default_key(
return 0;
}
+static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 key_idx)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ rcu_read_lock();
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ieee80211_set_default_mgmt_key(sdata, key_idx);
+
+ rcu_read_unlock();
+
+ return 0;
+}
+
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -1153,6 +1183,7 @@ struct cfg80211_ops mac80211_config_ops
.del_key = ieee80211_del_key,
.get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
+ .set_default_mgmt_key = ieee80211_config_default_mgmt_key,
.add_beacon = ieee80211_add_beacon,
.set_beacon = ieee80211_set_beacon,
.del_beacon = ieee80211_del_beacon,
--- wireless-testing.orig/net/mac80211/debugfs_key.c 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_key.c 2009-01-08 13:06:27.000000000 +0200
@@ -76,6 +76,9 @@ static ssize_t key_algorithm_read(struct
case ALG_CCMP:
alg = "CCMP\n";
break;
+ case ALG_AES_CMAC:
+ alg = "AES-128-CMAC\n";
+ break;
default:
return 0;
}
@@ -105,6 +108,12 @@ static ssize_t key_tx_spec_read(struct f
len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
break;
+ case ALG_AES_CMAC:
+ tpn = key->u.aes_cmac.tx_pn;
+ len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
+ tpn[0], tpn[1], tpn[2], tpn[3], tpn[4],
+ tpn[5]);
+ break;
default:
return 0;
}
@@ -142,6 +151,14 @@ static ssize_t key_rx_spec_read(struct f
}
len = p - buf;
break;
+ case ALG_AES_CMAC:
+ rpn = key->u.aes_cmac.rx_pn;
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "%02x%02x%02x%02x%02x%02x\n",
+ rpn[0], rpn[1], rpn[2],
+ rpn[3], rpn[4], rpn[5]);
+ len = p - buf;
+ break;
default:
return 0;
}
@@ -156,13 +173,40 @@ static ssize_t key_replays_read(struct f
char buf[20];
int len;
- if (key->conf.alg != ALG_CCMP)
+ switch (key->conf.alg) {
+ case ALG_CCMP:
+ len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
+ break;
+ case ALG_AES_CMAC:
+ len = scnprintf(buf, sizeof(buf), "%u\n",
+ key->u.aes_cmac.replays);
+ break;
+ default:
return 0;
- len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
+ }
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
KEY_OPS(replays);
+static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_key *key = file->private_data;
+ char buf[20];
+ int len;
+
+ switch (key->conf.alg) {
+ case ALG_AES_CMAC:
+ len = scnprintf(buf, sizeof(buf), "%u\n",
+ key->u.aes_cmac.icverrors);
+ break;
+ default:
+ return 0;
+ }
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(icverrors);
+
static ssize_t key_key_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -224,6 +268,7 @@ void ieee80211_debugfs_key_add(struct ie
DEBUGFS_ADD(tx_spec);
DEBUGFS_ADD(rx_spec);
DEBUGFS_ADD(replays);
+ DEBUGFS_ADD(icverrors);
DEBUGFS_ADD(key);
DEBUGFS_ADD(ifindex);
};
@@ -245,6 +290,7 @@ void ieee80211_debugfs_key_remove(struct
DEBUGFS_DEL(tx_spec);
DEBUGFS_DEL(rx_spec);
DEBUGFS_DEL(replays);
+ DEBUGFS_DEL(icverrors);
DEBUGFS_DEL(key);
DEBUGFS_DEL(ifindex);
@@ -282,6 +328,35 @@ void ieee80211_debugfs_key_remove_defaul
sdata->common_debugfs.default_key = NULL;
}
+void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
+{
+ char buf[50];
+ struct ieee80211_key *key;
+
+ if (!sdata->debugfsdir)
+ return;
+
+ /* this is running under the key lock */
+
+ key = sdata->default_mgmt_key;
+ if (key) {
+ sprintf(buf, "../keys/%d", key->debugfs.cnt);
+ sdata->common_debugfs.default_mgmt_key =
+ debugfs_create_symlink("default_mgmt_key",
+ sdata->debugfsdir, buf);
+ } else
+ ieee80211_debugfs_key_remove_mgmt_default(sdata);
+}
+
+void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata)
+{
+ if (!sdata)
+ return;
+
+ debugfs_remove(sdata->common_debugfs.default_mgmt_key);
+ sdata->common_debugfs.default_mgmt_key = NULL;
+}
+
void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
struct sta_info *sta)
{
--- wireless-testing.orig/net/mac80211/key.h 2009-01-08 13:06:24.000000000 +0200
+++ wireless-testing/net/mac80211/key.h 2009-01-08 13:06:27.000000000 +0200
@@ -46,6 +46,8 @@ struct sta_info;
* acceleration.
* @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
* @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
+ * @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs
+ * to be updated.
*/
enum ieee80211_internal_key_flags {
KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
@@ -54,6 +56,7 @@ enum ieee80211_internal_key_flags {
KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3),
KEY_FLAG_TODO_DEFKEY = BIT(4),
KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
+ KEY_FLAG_TODO_DEFMGMTKEY = BIT(6),
};
struct tkip_ctx {
@@ -124,6 +127,7 @@ struct ieee80211_key {
struct dentry *tx_spec;
struct dentry *rx_spec;
struct dentry *replays;
+ struct dentry *icverrors;
struct dentry *key;
struct dentry *ifindex;
int cnt;
@@ -150,6 +154,8 @@ void ieee80211_key_link(struct ieee80211
struct sta_info *sta);
void ieee80211_key_free(struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
+void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
+ int idx);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
--- wireless-testing.orig/net/mac80211/rx.c 2009-01-08 13:04:01.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c 2009-01-08 13:06:27.000000000 +0200
@@ -435,6 +435,52 @@ ieee80211_rx_h_passive_scan(struct ieee8
return RX_CONTINUE;
}
+
+static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1))
+ return 0;
+
+ return ieee80211_is_robust_mgmt_frame(hdr);
+}
+
+
+static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1))
+ return 0;
+
+ return ieee80211_is_robust_mgmt_frame(hdr);
+}
+
+
+/* Get the BIP key index from MMIE; return -1 if this is not a BIP frame */
+static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
+{
+ struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
+ struct ieee80211_mmie *mmie;
+
+ if (skb->len < 24 + sizeof(*mmie) ||
+ !is_multicast_ether_addr(hdr->da))
+ return -1;
+
+ if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
+ return -1; /* not a robust management frame */
+
+ mmie = (struct ieee80211_mmie *)
+ (skb->data + skb->len - sizeof(*mmie));
+ if (mmie->element_id != WLAN_EID_MMIE ||
+ mmie->length != sizeof(*mmie) - 2)
+ return -1;
+
+ return le16_to_cpu(mmie->key_id);
+}
+
+
static ieee80211_rx_result
ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
{
@@ -550,21 +596,23 @@ ieee80211_rx_h_decrypt(struct ieee80211_
int hdrlen;
ieee80211_rx_result result = RX_DROP_UNUSABLE;
struct ieee80211_key *stakey = NULL;
+ int mmie_keyidx = -1;
/*
* Key selection 101
*
- * There are three types of keys:
+ * There are four types of keys:
* - GTK (group keys)
+ * - IGTK (group keys for management frames)
* - PTK (pairwise keys)
* - STK (station-to-station pairwise keys)
*
* When selecting a key, we have to distinguish between multicast
* (including broadcast) and unicast frames, the latter can only
- * use PTKs and STKs while the former always use GTKs. Unless, of
- * course, actual WEP keys ("pre-RSNA") are used, then unicast
- * frames can also use key indizes like GTKs. Hence, if we don't
- * have a PTK/STK we check the key index for a WEP key.
+ * use PTKs and STKs while the former always use GTKs and IGTKs.
+ * Unless, of course, actual WEP keys ("pre-RSNA") are used, then
+ * unicast frames can also use key indices like GTKs. Hence, if we
+ * don't have a PTK/STK we check the key index for a WEP key.
*
* Note that in a regular BSS, multicast frames are sent by the
* AP only, associated stations unicast the frame to the AP first
@@ -577,8 +625,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_
* possible.
*/
- if (!ieee80211_has_protected(hdr->frame_control))
- return RX_CONTINUE;
+ if (!ieee80211_has_protected(hdr->frame_control)) {
+ if (!ieee80211_is_mgmt(hdr->frame_control) ||
+ rx->sta == NULL || !test_sta_flags(rx->sta, WLAN_STA_MFP))
+ return RX_CONTINUE;
+ mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
+ if (mmie_keyidx < 0)
+ return RX_CONTINUE;
+ }
/*
* No point in finding a key and decrypting if the frame is neither
@@ -592,6 +646,16 @@ ieee80211_rx_h_decrypt(struct ieee80211_
if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
rx->key = stakey;
+ } else if (mmie_keyidx >= 0) {
+ /* Broadcast/multicast robust management frame / BIP */
+ if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
+ (rx->status->flag & RX_FLAG_IV_STRIPPED))
+ return RX_CONTINUE;
+
+ if (mmie_keyidx < NUM_DEFAULT_KEYS ||
+ mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
+ return RX_DROP_MONITOR; /* unexpected BIP keyidx */
+ rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
} else {
/*
* The device doesn't give us the IV so we won't be
@@ -654,6 +718,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_
case ALG_CCMP:
result = ieee80211_crypto_ccmp_decrypt(rx);
break;
+ case ALG_AES_CMAC:
+ result = ieee80211_crypto_aes_cmac_decrypt(rx);
+ break;
}
/* either the frame has been decrypted or will be dropped */
@@ -1108,6 +1175,15 @@ ieee80211_drop_unencrypted(struct ieee80
/* Drop unencrypted frames if key is set. */
if (unlikely(!ieee80211_has_protected(fc) &&
!ieee80211_is_nullfunc(fc) &&
+ (!ieee80211_is_mgmt(fc) ||
+ (ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
+ rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP))) &&
+ (rx->key || rx->sdata->drop_unencrypted)))
+ return -EACCES;
+ /* BIP does not use Protected field, so need to check MMIE */
+ if (unlikely(rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP) &&
+ ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
+ ieee80211_get_mmie_keyidx(rx->skb) < 0 &&
(rx->key || rx->sdata->drop_unencrypted)))
return -EACCES;
--- wireless-testing.orig/net/mac80211/tx.c 2009-01-08 13:06:22.000000000 +0200
+++ wireless-testing/net/mac80211/tx.c 2009-01-08 13:06:27.000000000 +0200
@@ -427,6 +427,9 @@ ieee80211_tx_h_select_key(struct ieee802
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
tx->key = key;
+ else if (ieee80211_is_mgmt(hdr->frame_control) &&
+ (key = rcu_dereference(tx->sdata->default_mgmt_key)))
+ tx->key = key;
else if ((key = rcu_dereference(tx->sdata->default_key)))
tx->key = key;
else if (tx->sdata->drop_unencrypted &&
@@ -455,6 +458,10 @@ ieee80211_tx_h_select_key(struct ieee802
tx->skb))
tx->key = NULL;
break;
+ case ALG_AES_CMAC:
+ if (!ieee80211_is_mgmt(hdr->frame_control))
+ tx->key = NULL;
+ break;
}
}
@@ -810,6 +817,8 @@ ieee80211_tx_h_encrypt(struct ieee80211_
return ieee80211_crypto_tkip_encrypt(tx);
case ALG_CCMP:
return ieee80211_crypto_ccmp_encrypt(tx);
+ case ALG_AES_CMAC:
+ return ieee80211_crypto_aes_cmac_encrypt(tx);
}
/* not reached */
--- wireless-testing.orig/net/mac80211/key.c 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/key.c 2009-01-08 13:06:27.000000000 +0200
@@ -18,6 +18,7 @@
#include "ieee80211_i.h"
#include "debugfs_key.h"
#include "aes_ccm.h"
+#include "aes_cmac.h"
/**
@@ -219,13 +220,38 @@ void ieee80211_set_default_key(struct ie
spin_unlock_irqrestore(&sdata->local->key_lock, flags);
}
+static void
+__ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
+{
+ struct ieee80211_key *key = NULL;
+
+ if (idx >= NUM_DEFAULT_KEYS &&
+ idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
+ key = sdata->keys[idx];
+
+ rcu_assign_pointer(sdata->default_mgmt_key, key);
+
+ if (key)
+ add_todo(key, KEY_FLAG_TODO_DEFMGMTKEY);
+}
+
+void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
+ int idx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdata->local->key_lock, flags);
+ __ieee80211_set_default_mgmt_key(sdata, idx);
+ spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+}
+
static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_key *old,
struct ieee80211_key *new)
{
- int idx, defkey;
+ int idx, defkey, defmgmtkey;
if (new)
list_add(&new->list, &sdata->key_list);
@@ -241,13 +267,19 @@ static void __ieee80211_key_replace(stru
idx = new->conf.keyidx;
defkey = old && sdata->default_key == old;
+ defmgmtkey = old && sdata->default_mgmt_key == old;
if (defkey && !new)
__ieee80211_set_default_key(sdata, -1);
+ if (defmgmtkey && !new)
+ __ieee80211_set_default_mgmt_key(sdata, -1);
rcu_assign_pointer(sdata->keys[idx], new);
if (defkey && new)
__ieee80211_set_default_key(sdata, new->conf.keyidx);
+ if (defmgmtkey && new)
+ __ieee80211_set_default_mgmt_key(sdata,
+ new->conf.keyidx);
}
if (old) {
@@ -266,7 +298,7 @@ struct ieee80211_key *ieee80211_key_allo
{
struct ieee80211_key *key;
- BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS);
+ BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
if (!key)
@@ -295,6 +327,10 @@ struct ieee80211_key *ieee80211_key_allo
key->conf.iv_len = CCMP_HDR_LEN;
key->conf.icv_len = CCMP_MIC_LEN;
break;
+ case ALG_AES_CMAC:
+ key->conf.iv_len = 0;
+ key->conf.icv_len = sizeof(struct ieee80211_mmie);
+ break;
}
memcpy(key->conf.key, key_data, key_len);
INIT_LIST_HEAD(&key->list);
@@ -312,6 +348,19 @@ struct ieee80211_key *ieee80211_key_allo
}
}
+ if (alg == ALG_AES_CMAC) {
+ /*
+ * Initialize AES key state here as an optimization so that
+ * it does not need to be initialized for every packet.
+ */
+ key->u.aes_cmac.tfm =
+ ieee80211_aes_cmac_key_setup(key_data);
+ if (!key->u.aes_cmac.tfm) {
+ kfree(key);
+ return NULL;
+ }
+ }
+
return key;
}
@@ -465,6 +514,8 @@ static void __ieee80211_key_destroy(stru
if (key->conf.alg == ALG_CCMP)
ieee80211_aes_key_free(key->u.ccmp.tfm);
+ if (key->conf.alg == ALG_AES_CMAC)
+ ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
ieee80211_debugfs_key_remove(key);
kfree(key);
@@ -487,6 +538,7 @@ static void __ieee80211_key_todo(void)
list_del_init(&key->todo);
todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
KEY_FLAG_TODO_DEFKEY |
+ KEY_FLAG_TODO_DEFMGMTKEY |
KEY_FLAG_TODO_HWACCEL_ADD |
KEY_FLAG_TODO_HWACCEL_REMOVE |
KEY_FLAG_TODO_DELETE);
@@ -504,6 +556,11 @@ static void __ieee80211_key_todo(void)
ieee80211_debugfs_key_add_default(key->sdata);
work_done = true;
}
+ if (todoflags & KEY_FLAG_TODO_DEFMGMTKEY) {
+ ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
+ ieee80211_debugfs_key_add_mgmt_default(key->sdata);
+ work_done = true;
+ }
if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
ieee80211_key_enable_hw_accel(key);
work_done = true;
@@ -539,6 +596,7 @@ void ieee80211_free_keys(struct ieee8021
ieee80211_key_lock();
ieee80211_debugfs_key_remove_default(sdata);
+ ieee80211_debugfs_key_remove_mgmt_default(sdata);
spin_lock_irqsave(&sdata->local->key_lock, flags);
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-01-08 13:06:24.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-01-08 13:06:27.000000000 +0200
@@ -409,8 +409,10 @@ struct ieee80211_sub_if_data {
unsigned int fragment_next;
#define NUM_DEFAULT_KEYS 4
- struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
+#define NUM_DEFAULT_MGMT_KEYS 2
+ struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
struct ieee80211_key *default_key;
+ struct ieee80211_key *default_mgmt_key;
u16 sequence_number;
@@ -482,6 +484,7 @@ struct ieee80211_sub_if_data {
} debugfs;
struct {
struct dentry *default_key;
+ struct dentry *default_mgmt_key;
} common_debugfs;
#ifdef CONFIG_MAC80211_MESH
--- wireless-testing.orig/include/net/cfg80211.h 2009-01-08 13:06:19.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h 2009-01-08 13:06:27.000000000 +0200
@@ -473,6 +473,8 @@ struct ieee80211_channel;
*
* @set_default_key: set the default key on an interface
*
+ * @set_default_mgmt_key: set the default management frame key on an interface
+ *
* @add_beacon: Add a beacon with given parameters, @head, @interval
* and @dtim_period will be valid, @tail is optional.
* @set_beacon: Change the beacon parameters for an access point mode
@@ -520,6 +522,9 @@ struct cfg80211_ops {
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
+ int (*set_default_mgmt_key)(struct wiphy *wiphy,
+ struct net_device *netdev,
+ u8 key_index);
int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info);
--- wireless-testing.orig/net/mac80211/debugfs_key.h 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_key.h 2009-01-08 13:06:27.000000000 +0200
@@ -6,6 +6,10 @@ void ieee80211_debugfs_key_add(struct ie
void ieee80211_debugfs_key_remove(struct ieee80211_key *key);
void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_key_add_mgmt_default(
+ struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_key_remove_mgmt_default(
+ struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
struct sta_info *sta);
#else
@@ -19,6 +23,12 @@ static inline void ieee80211_debugfs_key
static inline void ieee80211_debugfs_key_remove_default(
struct ieee80211_sub_if_data *sdata)
{}
+static inline void ieee80211_debugfs_key_add_mgmt_default(
+ struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_key_remove_mgmt_default(
+ struct ieee80211_sub_if_data *sdata)
+{}
static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
struct sta_info *sta)
{}
--- wireless-testing.orig/net/wireless/nl80211.c 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c 2009-01-08 13:06:27.000000000 +0200
@@ -738,7 +738,7 @@ static int nl80211_get_key(struct sk_buf
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
@@ -804,30 +804,41 @@ static int nl80211_set_key(struct sk_buf
int err;
struct net_device *dev;
u8 key_idx;
+ int (*func)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index);
if (!info->attrs[NL80211_ATTR_KEY_IDX])
return -EINVAL;
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
+ if (key_idx < 4 || key_idx > 5)
+ return -EINVAL;
+ } else if (key_idx > 3)
return -EINVAL;
/* currently only support setting default key */
- if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
+ !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
return -EINVAL;
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err)
return err;
- if (!drv->ops->set_default_key) {
+ if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ func = drv->ops->set_default_key;
+ else
+ func = drv->ops->set_default_mgmt_key;
+
+ if (!func) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
- err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
+ err = func(&drv->wiphy, dev, key_idx);
rtnl_unlock();
out:
@@ -863,7 +874,7 @@ static int nl80211_new_key(struct sk_buf
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
/*
@@ -894,6 +905,10 @@ static int nl80211_new_key(struct sk_buf
if (params.key_len != 13)
return -EINVAL;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ if (params.key_len != 16)
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -928,7 +943,7 @@ static int nl80211_del_key(struct sk_buf
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
--- wireless-testing.orig/include/linux/nl80211.h 2009-01-08 13:06:19.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h 2009-01-08 13:06:27.000000000 +0200
@@ -72,8 +72,8 @@
*
* @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
* by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
- * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
- * %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
* @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
* %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
* attributes.
@@ -346,6 +346,8 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_FREQ,
NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_ATTR_KEY_DEFAULT_MGMT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
--- wireless-testing.orig/drivers/net/wireless/ath5k/pcu.c 2009-01-08 13:03:44.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath5k/pcu.c 2009-01-08 13:06:27.000000000 +0200
@@ -1026,6 +1026,9 @@ int ath5k_keycache_type(const struct iee
return AR5K_KEYTABLE_TYPE_40;
else if (key->keylen == LEN_WEP104)
return AR5K_KEYTABLE_TYPE_104;
+ return -EINVAL;
+ default:
+ return -EINVAL;
}
return -EINVAL;
}
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 05/16] mac80211: 802.11w - WEXT parameter for setting mgmt cipher
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (3 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 04/16] mac80211: 802.11w - Use " Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 06/16] mac80211: 802.11w - WEXT configuration for IGTK Jouni Malinen
` (11 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Add a new IW_AUTH parameter for setting cipher suite for
multicast/broadcast management frames. This is for full-mac drivers
that take care of RSN IE generation for (re)association request frames.
Signed-off-by: Jouni Malinen <j@w1.fi>
---
include/linux/wireless.h | 5 ++++-
net/mac80211/wext.c | 1 +
2 files changed, 5 insertions(+), 1 deletion(-)
--- wireless-testing.orig/include/linux/wireless.h 2009-01-08 13:03:43.000000000 +0200
+++ wireless-testing/include/linux/wireless.h 2009-01-08 13:06:29.000000000 +0200
@@ -577,18 +577,21 @@
#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8
#define IW_AUTH_ROAMING_CONTROL 9
#define IW_AUTH_PRIVACY_INVOKED 10
+#define IW_AUTH_CIPHER_GROUP_MGMT 11
/* IW_AUTH_WPA_VERSION values (bit field) */
#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001
#define IW_AUTH_WPA_VERSION_WPA 0x00000002
#define IW_AUTH_WPA_VERSION_WPA2 0x00000004
-/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */
+/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT
+ * values (bit field) */
#define IW_AUTH_CIPHER_NONE 0x00000001
#define IW_AUTH_CIPHER_WEP40 0x00000002
#define IW_AUTH_CIPHER_TKIP 0x00000004
#define IW_AUTH_CIPHER_CCMP 0x00000008
#define IW_AUTH_CIPHER_WEP104 0x00000010
+#define IW_AUTH_CIPHER_AES_CMAC 0x00000020
/* IW_AUTH_KEY_MGMT values (bit field) */
#define IW_AUTH_KEY_MGMT_802_1X 1
--- wireless-testing.orig/net/mac80211/wext.c 2009-01-08 13:05:41.000000000 +0200
+++ wireless-testing/net/mac80211/wext.c 2009-01-08 13:06:29.000000000 +0200
@@ -922,6 +922,7 @@ static int ieee80211_ioctl_siwauth(struc
case IW_AUTH_WPA_ENABLED:
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
case IW_AUTH_KEY_MGMT:
+ case IW_AUTH_CIPHER_GROUP_MGMT:
break;
case IW_AUTH_CIPHER_PAIRWISE:
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 06/16] mac80211: 802.11w - WEXT configuration for IGTK
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (4 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 05/16] mac80211: 802.11w - WEXT parameter for setting mgmt cipher Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 07/16] mac80211: 802.11w - Configuration of MFP disabled/optional/required Jouni Malinen
` (10 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Added new SIOCSIWENCODEEXT algorithm for configuring BIP (AES-CMAC)
keys (IGTK).
Signed-off-by: Jouni Malinen <j@w1.fi>
---
include/linux/wireless.h | 1
net/mac80211/wext.c | 62 ++++++++++++++++++++++++++++++++++++-----------
2 files changed, 49 insertions(+), 14 deletions(-)
--- wireless-testing.orig/include/linux/wireless.h 2009-01-08 13:06:29.000000000 +0200
+++ wireless-testing/include/linux/wireless.h 2009-01-08 13:06:33.000000000 +0200
@@ -615,6 +615,7 @@
#define IW_ENCODE_ALG_TKIP 2
#define IW_ENCODE_ALG_CCMP 3
#define IW_ENCODE_ALG_PMK 4
+#define IW_ENCODE_ALG_AES_CMAC 5
/* struct iw_encode_ext ->ext_flags */
#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001
#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002
--- wireless-testing.orig/net/mac80211/wext.c 2009-01-08 13:06:29.000000000 +0200
+++ wireless-testing/net/mac80211/wext.c 2009-01-08 13:06:33.000000000 +0200
@@ -37,7 +37,14 @@ static int ieee80211_set_encryption(stru
struct ieee80211_key *key;
int err;
- if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
+ if (alg == ALG_AES_CMAC) {
+ if (idx < NUM_DEFAULT_KEYS ||
+ idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
+ printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d "
+ "(BIP)\n", sdata->dev->name, idx);
+ return -EINVAL;
+ }
+ } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
sdata->dev->name, idx);
return -EINVAL;
@@ -103,6 +110,9 @@ static int ieee80211_set_encryption(stru
if (set_tx_key || (!sta && !sdata->default_key && key))
ieee80211_set_default_key(sdata, idx);
+ if (alg == ALG_AES_CMAC &&
+ (set_tx_key || (!sta && !sdata->default_mgmt_key && key)))
+ ieee80211_set_default_mgmt_key(sdata, idx);
}
out_unlock:
@@ -1043,6 +1053,9 @@ static int ieee80211_ioctl_siwencodeext(
case IW_ENCODE_ALG_CCMP:
alg = ALG_CCMP;
break;
+ case IW_ENCODE_ALG_AES_CMAC:
+ alg = ALG_AES_CMAC;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -1051,20 +1064,41 @@ static int ieee80211_ioctl_siwencodeext(
remove = 1;
idx = erq->flags & IW_ENCODE_INDEX;
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!sdata->default_key)
- idx = 0;
- else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (sdata->default_key == sdata->keys[i]) {
- idx = i;
- break;
+ if (alg == ALG_AES_CMAC) {
+ if (idx < NUM_DEFAULT_KEYS + 1 ||
+ idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
+ idx = -1;
+ if (!sdata->default_mgmt_key)
+ idx = 0;
+ else for (i = NUM_DEFAULT_KEYS;
+ i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
+ i++) {
+ if (sdata->default_mgmt_key == sdata->keys[i])
+ {
+ idx = i;
+ break;
+ }
}
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ } else {
+ if (idx < 1 || idx > 4) {
+ idx = -1;
+ if (!sdata->default_key)
+ idx = 0;
+ else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ if (sdata->default_key == sdata->keys[i]) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ }
return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg,
remove,
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 07/16] mac80211: 802.11w - Configuration of MFP disabled/optional/required
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (5 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 06/16] mac80211: 802.11w - WEXT configuration for IGTK Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 08/16] mac80211: 802.11w - SA Query processing Jouni Malinen
` (9 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Add new WEXT IW_AUTH_* parameter for setting MFP
disabled/optional/required.
Signed-off-by: Jouni Malinen <j@w1.fi>
---
include/linux/wireless.h | 6 ++++++
net/mac80211/ieee80211_i.h | 6 ++++++
net/mac80211/mlme.c | 4 ++++
net/mac80211/wext.c | 7 +++++++
4 files changed, 23 insertions(+)
--- wireless-testing.orig/include/linux/wireless.h 2009-01-08 13:06:33.000000000 +0200
+++ wireless-testing/include/linux/wireless.h 2009-01-08 13:06:36.000000000 +0200
@@ -578,6 +578,7 @@
#define IW_AUTH_ROAMING_CONTROL 9
#define IW_AUTH_PRIVACY_INVOKED 10
#define IW_AUTH_CIPHER_GROUP_MGMT 11
+#define IW_AUTH_MFP 12
/* IW_AUTH_WPA_VERSION values (bit field) */
#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001
@@ -607,6 +608,11 @@
#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming
* control */
+/* IW_AUTH_MFP (management frame protection) values */
+#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */
+#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */
+#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */
+
/* SIOCSIWENCODEEXT definitions */
#define IW_ENCODE_SEQ_MAX_SIZE 8
/* struct iw_encode_ext ->alg */
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-01-08 13:06:27.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-01-08 13:06:36.000000000 +0200
@@ -320,6 +320,12 @@ struct ieee80211_if_sta {
int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
int auth_transaction;
+ enum {
+ IEEE80211_MFP_DISABLED,
+ IEEE80211_MFP_OPTIONAL,
+ IEEE80211_MFP_REQUIRED
+ } mfp; /* management frame protection */
+
unsigned long ibss_join_req;
struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
u32 supp_rates_bits[IEEE80211_NUM_BANDS];
--- wireless-testing.orig/net/mac80211/wext.c 2009-01-08 13:06:33.000000000 +0200
+++ wireless-testing/net/mac80211/wext.c 2009-01-08 13:06:36.000000000 +0200
@@ -970,6 +970,13 @@ static int ieee80211_ioctl_siwauth(struc
else
ret = -EOPNOTSUPP;
break;
+ case IW_AUTH_MFP:
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ sdata->u.sta.mfp = data->value;
+ else
+ ret = -EOPNOTSUPP;
+ break;
default:
ret = -EOPNOTSUPP;
break;
--- wireless-testing.orig/net/mac80211/mlme.c 2009-01-08 13:06:19.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c 2009-01-08 13:06:36.000000000 +0200
@@ -2340,6 +2340,10 @@ static int ieee80211_sta_config_auth(str
selected->ssid_len);
ieee80211_sta_set_bssid(sdata, selected->bssid);
ieee80211_sta_def_wmm_params(sdata, selected);
+ if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED)
+ sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED;
+ else
+ sdata->u.sta.flags &= ~IEEE80211_STA_MFP_ENABLED;
/* Send out direct probe if no probe resp was received or
* the one we have is outdated
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 08/16] mac80211: 802.11w - SA Query processing
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (6 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 07/16] mac80211: 802.11w - Configuration of MFP disabled/optional/required Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 09/16] mac80211: 802.11w - Do not force Action frames to disable encryption Jouni Malinen
` (8 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Process SA Query Requests for client mode in mac80211. AP side
processing of SA Query Response frames is in user space (hostapd).
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
include/linux/ieee80211.h | 14 +++++++++
net/mac80211/rx.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+)
--- wireless-testing.orig/include/linux/ieee80211.h 2009-01-08 13:06:27.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h 2009-01-08 13:06:38.000000000 +0200
@@ -527,6 +527,8 @@ struct ieee80211_tim_ie {
u8 virtual_map[0];
} __attribute__ ((packed));
+#define WLAN_SA_QUERY_TR_ID_LEN 16
+
struct ieee80211_mgmt {
__le16 frame_control;
__le16 duration;
@@ -646,6 +648,10 @@ struct ieee80211_mgmt {
u8 action_code;
u8 variable[0];
} __attribute__((packed)) mesh_action;
+ struct {
+ u8 action;
+ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+ } __attribute__ ((packed)) sa_query;
} u;
} __attribute__ ((packed)) action;
} u;
@@ -1041,6 +1047,7 @@ enum ieee80211_category {
WLAN_CATEGORY_DLS = 2,
WLAN_CATEGORY_BACK = 3,
WLAN_CATEGORY_PUBLIC = 4,
+ WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_WMM = 17,
};
@@ -1129,6 +1136,13 @@ enum ieee80211_back_parties {
WLAN_BACK_TIMER = 2,
};
+/* SA Query action */
+enum ieee80211_sa_query_action {
+ WLAN_ACTION_SA_QUERY_REQUEST = 0,
+ WLAN_ACTION_SA_QUERY_RESPONSE = 1,
+};
+
+
/* A-MSDU 802.11n */
#define IEEE80211_QOS_CONTROL_A_MSDU_PRESENT 0x0080
--- wireless-testing.orig/net/mac80211/rx.c 2009-01-08 13:06:27.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c 2009-01-08 13:06:38.000000000 +0200
@@ -1635,6 +1635,57 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_
return RX_CONTINUE;
}
+void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *resp;
+
+ if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) {
+ /* Not to own unicast address */
+ return;
+ }
+
+ if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 ||
+ compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) {
+ /* Not from the current AP. */
+ return;
+ }
+
+ if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) {
+ /* Association in progress; ignore SA Query */
+ return;
+ }
+
+ if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) {
+ /* Too short SA Query request frame */
+ return;
+ }
+
+ skb = dev_alloc_skb(sizeof(*resp) + local->hw.extra_tx_headroom);
+ if (skb == NULL)
+ return;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ resp = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(resp, 0, 24);
+ memcpy(resp->da, mgmt->sa, ETH_ALEN);
+ memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN);
+ resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+ skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
+ resp->u.action.category = WLAN_CATEGORY_SA_QUERY;
+ resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE;
+ memcpy(resp->u.action.u.sa_query.trans_id,
+ mgmt->u.action.u.sa_query.trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN);
+
+ ieee80211_tx_skb(sdata, skb, 1);
+}
+
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
{
@@ -1708,6 +1759,24 @@ ieee80211_rx_h_action(struct ieee80211_r
break;
}
break;
+ case WLAN_CATEGORY_SA_QUERY:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.sa_query)))
+ return RX_DROP_MONITOR;
+ switch (mgmt->u.action.u.sa_query.action) {
+ case WLAN_ACTION_SA_QUERY_REQUEST:
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return RX_DROP_MONITOR;
+ ieee80211_process_sa_query_req(sdata, mgmt, len);
+ break;
+ case WLAN_ACTION_SA_QUERY_RESPONSE:
+ /*
+ * SA Query response is currently only used in AP mode
+ * and it is processed in user space.
+ */
+ return RX_CONTINUE;
+ }
+ break;
default:
return RX_CONTINUE;
}
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 09/16] mac80211: 802.11w - Do not force Action frames to disable encryption
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (7 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 08/16] mac80211: 802.11w - SA Query processing Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 10/16] mac80211: 802.11w - Drop unprotected robust management frames if MFP is used Jouni Malinen
` (7 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
When sending out Action frames, allow ieee80211_tx_skb() to send them
without enforcing do_not_encrypt. These frames will be encrypted if
MFP has been negotiated.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
net/mac80211/ht.c | 6 +++---
net/mac80211/mesh_hwmp.c | 4 ++--
net/mac80211/mesh_plink.c | 2 +-
net/mac80211/spectmgmt.c | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
--- wireless-testing.orig/net/mac80211/ht.c 2009-01-08 13:03:43.000000000 +0200
+++ wireless-testing/net/mac80211/ht.c 2009-01-08 13:06:41.000000000 +0200
@@ -200,7 +200,7 @@ static void ieee80211_send_addba_request
mgmt->u.action.u.addba_req.start_seq_num =
cpu_to_le16(start_seq_num << 4);
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 1);
}
static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
@@ -246,7 +246,7 @@ static void ieee80211_send_addba_resp(st
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 1);
}
static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
@@ -289,7 +289,7 @@ static void ieee80211_send_delba(struct
mgmt->u.action.u.delba.params = cpu_to_le16(params);
mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 1);
}
void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
--- wireless-testing.orig/net/mac80211/mesh_hwmp.c 2009-01-08 13:03:43.000000000 +0200
+++ wireless-testing/net/mac80211/mesh_hwmp.c 2009-01-08 13:06:41.000000000 +0200
@@ -149,7 +149,7 @@ static int mesh_path_sel_frame_tx(enum m
pos += ETH_ALEN;
memcpy(pos, &dst_dsn, 4);
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 1);
return 0;
}
@@ -198,7 +198,7 @@ int mesh_path_error_tx(u8 *dst, __le32 d
pos += ETH_ALEN;
memcpy(pos, &dst_dsn, 4);
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 1);
return 0;
}
--- wireless-testing.orig/net/mac80211/mesh_plink.c 2009-01-08 13:03:43.000000000 +0200
+++ wireless-testing/net/mac80211/mesh_plink.c 2009-01-08 13:06:41.000000000 +0200
@@ -218,7 +218,7 @@ static int mesh_plink_frame_tx(struct ie
memcpy(pos, &reason, 2);
}
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 1);
return 0;
}
--- wireless-testing.orig/net/mac80211/spectmgmt.c 2009-01-08 13:04:01.000000000 +0200
+++ wireless-testing/net/mac80211/spectmgmt.c 2009-01-08 13:06:41.000000000 +0200
@@ -65,7 +65,7 @@ static void ieee80211_send_refuse_measur
IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb, 1);
}
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 10/16] mac80211: 802.11w - Drop unprotected robust management frames if MFP is used
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (8 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 09/16] mac80211: 802.11w - Do not force Action frames to disable encryption Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 11/16] mac80211: 802.11w - Implement Association Comeback processing Jouni Malinen
` (6 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Use ieee80211_drop_unencrypted() to decide whether a received frame
should be dropped with management frames, too. If MFP is negotiated,
unprotected robust management frames will be dropped.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
net/mac80211/rx.c | 7 +++++++
1 file changed, 7 insertions(+)
--- wireless-testing.orig/net/mac80211/rx.c 2009-01-08 13:06:38.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c 2009-01-08 13:06:43.000000000 +0200
@@ -1705,6 +1705,9 @@ ieee80211_rx_h_action(struct ieee80211_r
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
+ if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
+ return RX_DROP_MONITOR;
+
/* all categories we currently handle have action_code */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
return RX_DROP_MONITOR;
@@ -1790,10 +1793,14 @@ static ieee80211_rx_result debug_noinlin
ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
+ if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
+ return RX_DROP_MONITOR;
+
if (ieee80211_vif_is_mesh(&sdata->vif))
return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 11/16] mac80211: 802.11w - Implement Association Comeback processing
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (9 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 10/16] mac80211: 802.11w - Drop unprotected robust management frames if MFP is used Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 12/16] mac80211: 802.11w - Optional software CCMP for management frames Jouni Malinen
` (5 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
When MFP is enabled, the AP does not allow a STA to associate if an
existing security association exists without first going through SA
Query process. When this happens, the association request is denied
with a new status code ("temporarily rejected") ans Association
Comeback IE is used to notify when the association may be tried again
(i.e., when the SA Query procedure has timed out).
Use the comeback time to update the mac80211 client MLME timer for
next association attempt to minimize waiting time if association is
temporarily rejected.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
include/linux/ieee80211.h | 4 ++++
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mlme.c | 20 +++++++++++++++++---
net/mac80211/util.c | 4 ++++
4 files changed, 27 insertions(+), 3 deletions(-)
--- wireless-testing.orig/include/linux/ieee80211.h 2009-01-08 13:06:38.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h 2009-01-08 13:06:45.000000000 +0200
@@ -914,6 +914,9 @@ enum ieee80211_statuscode {
/* 802.11g */
WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
+ /* 802.11w */
+ WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY = 30,
+ WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION = 31,
/* 802.11i */
WLAN_STATUS_INVALID_IE = 40,
WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
@@ -1034,6 +1037,7 @@ enum ieee80211_eid {
/* 802.11i */
WLAN_EID_RSN = 48,
WLAN_EID_MMIE = 76 /* 802.11w */,
+ WLAN_EID_ASSOC_COMEBACK_TIME = 77,
WLAN_EID_WPA = 221,
WLAN_EID_GENERIC = 221,
WLAN_EID_VENDOR_SPECIFIC = 221,
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-01-08 13:06:36.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-01-08 13:06:45.000000000 +0200
@@ -821,6 +821,7 @@ struct ieee802_11_elems {
u8 *country_elem;
u8 *pwr_constr_elem;
u8 *quiet_elem; /* first quite element */
+ u8 *assoc_comeback;
/* length of them, respectively */
u8 ssid_len;
@@ -848,6 +849,7 @@ struct ieee802_11_elems {
u8 pwr_constr_elem_len;
u8 quiet_elem_len;
u8 num_of_quiet_elem; /* can be more the one */
+ u8 assoc_comeback_len;
};
static inline struct ieee80211_local *hw_to_local(
--- wireless-testing.orig/net/mac80211/mlme.c 2009-01-08 13:06:36.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c 2009-01-08 13:06:45.000000000 +0200
@@ -1288,6 +1288,23 @@ static void ieee80211_rx_mgmt_assoc_resp
sdata->dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa),
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
+ pos = mgmt->u.assoc_resp.variable;
+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+
+ if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
+ elems.assoc_comeback && elems.assoc_comeback_len == 4) {
+ u32 tu, ms;
+ tu = get_unaligned_le32(elems.assoc_comeback);
+ ms = tu * 1024 / 1000;
+ printk(KERN_DEBUG "%s: AP rejected association temporarily; "
+ "comeback duration %u TU (%u ms)\n",
+ sdata->dev->name, tu, ms);
+ if (ms > IEEE80211_ASSOC_TIMEOUT)
+ mod_timer(&ifsta->timer,
+ jiffies + msecs_to_jiffies(ms));
+ return;
+ }
+
if (status_code != WLAN_STATUS_SUCCESS) {
printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
sdata->dev->name, status_code);
@@ -1303,9 +1320,6 @@ static void ieee80211_rx_mgmt_assoc_resp
"set\n", sdata->dev->name, aid);
aid &= ~(BIT(15) | BIT(14));
- pos = mgmt->u.assoc_resp.variable;
- ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-
if (!elems.supp_rates) {
printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
sdata->dev->name);
--- wireless-testing.orig/net/mac80211/util.c 2009-01-08 13:03:43.000000000 +0200
+++ wireless-testing/net/mac80211/util.c 2009-01-08 13:06:45.000000000 +0200
@@ -653,6 +653,10 @@ void ieee802_11_parse_elems(u8 *start, s
elems->pwr_constr_elem = pos;
elems->pwr_constr_elem_len = elen;
break;
+ case WLAN_EID_ASSOC_COMEBACK_TIME:
+ elems->assoc_comeback = pos;
+ elems->assoc_comeback_len = elen;
+ break;
default:
break;
}
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 12/16] mac80211: 802.11w - Optional software CCMP for management frames
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (10 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 11/16] mac80211: 802.11w - Implement Association Comeback processing Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 13/16] mac80211: 802.11w - Add driver capability flag for MFP Jouni Malinen
` (4 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
If driver/firmware/hardware does not support CCMP for management
frames, it can now request mac80211 to take care of encrypting and
decrypting management frames (when MFP is enabled) in software. The
will need to add this new IEEE80211_KEY_FLAG_SW_MGMT flag when a CCMP
key is being configured for TX side and return the undecrypted frames
on RX side without RX_FLAG_DECRYPTED flag to use software CCMP for
management frames (but hardware for data frames).
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
include/net/mac80211.h | 4 ++++
net/mac80211/wpa.c | 9 +++++++--
2 files changed, 11 insertions(+), 2 deletions(-)
--- wireless-testing.orig/include/net/mac80211.h 2009-01-08 13:06:27.000000000 +0200
+++ wireless-testing/include/net/mac80211.h 2009-01-08 13:06:48.000000000 +0200
@@ -693,12 +693,16 @@ enum ieee80211_key_len {
* generation in software.
* @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates
* that the key is pairwise rather then a shared key.
+ * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a
+ * CCMP key if it requires CCMP encryption of management frames (MFP) to
+ * be done in software.
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_WMM_STA = 1<<0,
IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
IEEE80211_KEY_FLAG_PAIRWISE = 1<<3,
+ IEEE80211_KEY_FLAG_SW_MGMT = 1<<4,
};
/**
--- wireless-testing.orig/net/mac80211/wpa.c 2009-01-08 13:06:24.000000000 +0200
+++ wireless-testing/net/mac80211/wpa.c 2009-01-08 13:06:48.000000000 +0200
@@ -369,9 +369,14 @@ static int ccmp_encrypt_skb(struct ieee8
int hdrlen, len, tail;
u8 *pos, *pn;
int i;
+ bool skip_hw;
+
+ skip_hw = (tx->key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT) &&
+ ieee80211_is_mgmt(hdr->frame_control);
if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
- !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+ !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
+ !skip_hw) {
/* hwaccel - with no need for preallocated room for CCMP
* header or MIC fields */
info->control.hw_key = &tx->key->conf;
@@ -406,7 +411,7 @@ static int ccmp_encrypt_skb(struct ieee8
ccmp_pn2hdr(pos, pn, key->conf.keyidx);
- if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
+ if ((key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !skip_hw) {
/* hwaccel - with preallocated room for CCMP header */
info->control.hw_key = &tx->key->conf;
return 0;
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 13/16] mac80211: 802.11w - Add driver capability flag for MFP
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (11 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 12/16] mac80211: 802.11w - Optional software CCMP for management frames Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 14/16] ath9k: Fix set_key error codes Jouni Malinen
` (3 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
This allows user space to determine whether a driver supports MFP and
behave properly without having to ask user to configure this in
MFP-optional mode.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
include/net/mac80211.h | 4 ++++
net/mac80211/wext.c | 4 ++++
2 files changed, 8 insertions(+)
--- wireless-testing.orig/net/mac80211/wext.c 2009-01-08 13:06:36.000000000 +0200
+++ wireless-testing/net/mac80211/wext.c 2009-01-08 13:07:22.000000000 +0200
@@ -971,6 +971,10 @@ static int ieee80211_ioctl_siwauth(struc
ret = -EOPNOTSUPP;
break;
case IW_AUTH_MFP:
+ if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
if (sdata->vif.type == NL80211_IFTYPE_STATION ||
sdata->vif.type == NL80211_IFTYPE_ADHOC)
sdata->u.sta.mfp = data->value;
--- wireless-testing.orig/include/net/mac80211.h 2009-01-08 13:07:29.000000000 +0200
+++ wireless-testing/include/net/mac80211.h 2009-01-08 13:08:12.000000000 +0200
@@ -872,6 +872,9 @@ enum ieee80211_tkip_key_type {
*
* @IEEE80211_HW_SUPPORTS_DYNAMIC_PS:
* Hardware has support for dynamic PS.
+ *
+ * @IEEE80211_HW_MFP_CAPABLE:
+ * Hardware supports management frame protection (MFP, IEEE 802.11w).
*/
enum ieee80211_hw_flags {
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
@@ -887,6 +890,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_PS = 1<<11,
IEEE80211_HW_PS_NULLFUNC_STACK = 1<<12,
IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<13,
+ IEEE80211_HW_MFP_CAPABLE = 1<<14,
};
/**
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 14/16] ath9k: Fix set_key error codes
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (12 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 13/16] mac80211: 802.11w - Add driver capability flag for MFP Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 15/16] ath9k: Setup MFP options for CCMP Jouni Malinen
` (2 subsequent siblings)
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Return -EOPNOTSUPP if the algorithm is not supported and -ENOSPC if
there is no room in the key cache. This avoids KERN_ERR printk in
mac80211 for "errors" that are actually expected to happen in normal
operating conditions.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
drivers/net/wireless/ath9k/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- wireless-testing.orig/drivers/net/wireless/ath9k/main.c 2009-01-08 13:03:42.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath9k/main.c 2009-01-08 13:08:51.000000000 +0200
@@ -815,7 +815,7 @@ static int ath_key_config(struct ath_sof
hk.kv_type = ATH9K_CIPHER_AES_CCM;
break;
default:
- return -EINVAL;
+ return -EOPNOTSUPP;
}
hk.kv_len = key->keylen;
@@ -849,7 +849,7 @@ static int ath_key_config(struct ath_sof
else
idx = ath_reserve_key_cache_slot(sc);
if (idx < 0)
- return -EIO; /* no free key cache entries */
+ return -ENOSPC; /* no free key cache entries */
}
if (key->alg == ALG_TKIP)
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 15/16] ath9k: Setup MFP options for CCMP
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (13 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 14/16] ath9k: Fix set_key error codes Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 11:32 ` [PATCHv2 16/16] mac80211_hwsim: Report driver as MFP capable Jouni Malinen
2009-01-08 12:07 ` [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Johannes Berg
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
Configure hardware CCMP for management frame protection and use
software crypto when needed.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
drivers/net/wireless/ath9k/ath9k.h | 2 ++
drivers/net/wireless/ath9k/hw.c | 17 +++++++++++++++++
drivers/net/wireless/ath9k/main.c | 5 +++++
drivers/net/wireless/ath9k/recv.c | 6 ++++++
drivers/net/wireless/ath9k/reg.h | 6 ++++++
5 files changed, 36 insertions(+)
--- wireless-testing.orig/drivers/net/wireless/ath9k/hw.c 2009-01-08 13:03:42.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath9k/hw.c 2009-01-08 13:08:54.000000000 +0200
@@ -2266,6 +2266,23 @@ int ath9k_hw_reset(struct ath_hal *ah, s
if (r)
return r;
+ /* Setup MFP options for CCMP */
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
+ * frames when constructing CCMP AAD. */
+ REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
+ 0xc7ff);
+ ah->sw_mgmt_crypto = false;
+ } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+ /* Disable hardware crypto for management frames */
+ REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
+ AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
+ REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+ AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
+ ah->sw_mgmt_crypto = true;
+ } else
+ ah->sw_mgmt_crypto = true;
+
if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
ath9k_hw_set_delta_slope(ah, chan);
--- wireless-testing.orig/drivers/net/wireless/ath9k/reg.h 2009-01-08 13:03:42.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath9k/reg.h 2009-01-08 13:08:54.000000000 +0200
@@ -1243,6 +1243,8 @@ enum {
#define AR_AES_MUTE_MASK1 0x8060
#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF
+#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S 16
#define AR_GATED_CLKS 0x8064
#define AR_GATED_CLKS_TX 0x00000002
@@ -1467,6 +1469,10 @@ enum {
#define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700
#define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380
+#define AR_PCU_MISC_MODE2 0x8344
+#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002
+#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004
+
#define AR_KEYTABLE_0 0x8800
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
#define AR_KEY_CACHE_SIZE 128
--- wireless-testing.orig/drivers/net/wireless/ath9k/main.c 2009-01-08 13:08:51.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath9k/main.c 2009-01-08 13:08:54.000000000 +0200
@@ -1554,6 +1554,9 @@ static int ath_attach(u16 devid, struct
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_AMPDU_AGGREGATION;
+ if (AR_SREV_9160_10_OR_LATER(sc->sc_ah))
+ hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
@@ -2348,6 +2351,8 @@ static int ath9k_set_key(struct ieee8021
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (key->alg == ALG_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
+ key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
ret = 0;
}
break;
--- wireless-testing.orig/drivers/net/wireless/ath9k/recv.c 2009-01-08 13:03:42.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath9k/recv.c 2009-01-08 13:08:54.000000000 +0200
@@ -593,6 +593,12 @@ int ath_rx_tasklet(struct ath_softc *sc,
if (test_bit(keyix, sc->sc_keymap))
rx_status.flag |= RX_FLAG_DECRYPTED;
}
+ if (ah->sw_mgmt_crypto &&
+ (rx_status.flag & RX_FLAG_DECRYPTED) &&
+ ieee80211_is_mgmt(hdr->frame_control)) {
+ /* Use software decrypt for management frames. */
+ rx_status.flag &= ~RX_FLAG_DECRYPTED;
+ }
/* Send the frame to mac80211 */
__ieee80211_rx(sc->hw, skb, &rx_status);
--- wireless-testing.orig/drivers/net/wireless/ath9k/ath9k.h 2009-01-08 13:03:42.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath9k/ath9k.h 2009-01-08 13:08:54.000000000 +0200
@@ -805,6 +805,8 @@ struct ath_hal {
#ifndef ATH_NF_PER_CHAN
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
#endif
+
+ bool sw_mgmt_crypto;
};
struct chan_centers {
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCHv2 16/16] mac80211_hwsim: Report driver as MFP capable
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (14 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 15/16] ath9k: Setup MFP options for CCMP Jouni Malinen
@ 2009-01-08 11:32 ` Jouni Malinen
2009-01-08 12:07 ` [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Johannes Berg
16 siblings, 0 replies; 18+ messages in thread
From: Jouni Malinen @ 2009-01-08 11:32 UTC (permalink / raw)
To: John W. Linville, Johannes Berg; +Cc: linux-wireless, Jouni Malinen
mac80211_hwsim has no problems with MFP, so report it as MFP capable.
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
---
drivers/net/wireless/mac80211_hwsim.c | 2 ++
1 file changed, 2 insertions(+)
--- wireless-testing.orig/drivers/net/wireless/mac80211_hwsim.c 2009-01-08 13:12:12.000000000 +0200
+++ wireless-testing/drivers/net/wireless/mac80211_hwsim.c 2009-01-08 13:17:36.000000000 +0200
@@ -784,6 +784,8 @@ static int __init init_mac80211_hwsim(vo
BIT(NL80211_IFTYPE_MESH_POINT);
hw->ampdu_queues = 1;
+ hw->flags = IEEE80211_HW_MFP_CAPABLE;
+
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
hw->sta_data_size = sizeof(struct hwsim_sta_priv);
--
--
Jouni Malinen PGP id EFC895FA
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection)
2009-01-08 11:31 [PATCHv2 00/16] mac80211: IEEE 802.11w (management frame protection) Jouni Malinen
` (15 preceding siblings ...)
2009-01-08 11:32 ` [PATCHv2 16/16] mac80211_hwsim: Report driver as MFP capable Jouni Malinen
@ 2009-01-08 12:07 ` Johannes Berg
16 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2009-01-08 12:07 UTC (permalink / raw)
To: Jouni Malinen; +Cc: John W. Linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 1026 bytes --]
On Thu, 2009-01-08 at 13:31 +0200, Jouni Malinen wrote:
> This set of patches adds support for IEEE 802.11w (management frame
> protection) into mac80211. It is up-to-date with the latest IEEE 802.11w
> draft (D7.0) and I do not expect any major changes to IEEE 802.11w
> anymore.
>
> This version is ready to be applied into wireless-testing. It is against
> wireless-testing + CSA patch from Sujith + PS patches from Johannes.
>
> Differences to PATCH v1:
> - introduce a mechanism for drivers to indicate that they are MFP capable
> and allow user space programs to figure out whether MFP can be used
> - mark ath9k MFP capable
> - mark mac80211_hwsim MFP capable
> - rebase against PS patches from Johannes (one of them allocated a new
> driver hw flag that would have conflicted with an allocation for MFP)
Looks all good to me, thanks for doing the flag and rebasing.
For the mac80211 part (haven't looked at ath9k in detail):
Acked-by: Johannes Berg <johannes@sipsolutions.net>
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread