linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP)
@ 2008-12-31 15:38 Jouni Malinen
  2008-12-31 15:38 ` [RFC 01/11] mac80211: 802.11w - STA flag for MFP Jouni Malinen
                   ` (11 more replies)
  0 siblings, 12 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

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.

The main differences to the last RFC round:
- resync with current mac80211
- update to latest IEEE 802.11w draft (D6.0 -> D7.0)
  (protection against unauthorized (re)association attacks with
   SA Query procedure and Association Comeback notification;
   exclude Public Action frames from MFP)

-- 
Jouni Malinen                                            PGP id EFC895FA

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC 01/11] mac80211: 802.11w - STA flag for MFP
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 02/11] mac80211: 802.11w - CCMP for management frames Jouni Malinen
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 16:47:22.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2008-12-31 16:48:01.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	2008-12-31 16:47:22.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2008-12-31 16:48:01.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	2008-12-31 16:47:22.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h	2008-12-31 16:48:01.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	2008-12-31 16:47:22.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c	2008-12-31 16:48:01.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	2008-12-31 16:47:22.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_sta.c	2008-12-31 16:48:01.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	2008-12-31 16:47:22.000000000 +0200
+++ wireless-testing/net/mac80211/sta_info.h	2008-12-31 16:48:01.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	2008-12-31 16:47:22.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2008-12-31 16:48:01.000000000 +0200
@@ -259,6 +259,7 @@ struct mesh_preq_queue {
 #define IEEE80211_STA_AUTO_CHANNEL_SEL	BIT(12)
 #define IEEE80211_STA_PRIVACY_INVOKED	BIT(13)
 #define IEEE80211_STA_TKIP_WEP_USED	BIT(14)
+#define IEEE80211_STA_MFP_ENABLED	BIT(15)
 /* 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] 15+ messages in thread

* [RFC 02/11] mac80211: 802.11w - CCMP for management frames
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
  2008-12-31 15:38 ` [RFC 01/11] mac80211: 802.11w - STA flag for MFP Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2009-01-02 10:04   ` Johannes Berg
  2008-12-31 15:38 ` [RFC 03/11] mac80211: 802.11w - Add BIP (AES-128-CMAC) Jouni Malinen
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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 |   23 +++++++++++++++++++++++
 net/mac80211/tx.c         |   23 ++++++++++++++++++++++-
 net/mac80211/wpa.c        |   18 ++++++++++++------
 3 files changed, 57 insertions(+), 7 deletions(-)

--- wireless-testing.orig/net/mac80211/tx.c	2008-12-31 16:46:11.000000000 +0200
+++ wireless-testing/net/mac80211/tx.c	2008-12-31 16:54:08.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	2008-12-31 16:46:11.000000000 +0200
+++ wireless-testing/net/mac80211/wpa.c	2008-12-31 16:54:27.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	2008-12-31 16:46:11.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h	2008-12-31 17:00:34.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,28 @@ 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)) {
+		/*
+		 * Action frames, excluding Public Action frames, are Robust
+		 * Management Frames.
+		 */
+		u8 *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] 15+ messages in thread

* [RFC 03/11] mac80211: 802.11w - Add BIP (AES-128-CMAC)
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
  2008-12-31 15:38 ` [RFC 01/11] mac80211: 802.11w - STA flag for MFP Jouni Malinen
  2008-12-31 15:38 ` [RFC 02/11] mac80211: 802.11w - CCMP for management frames Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 04/11] mac80211: 802.11w - Use " Jouni Malinen
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:00:34.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h	2008-12-31 17:03:09.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/mac80211/key.h	2008-12-31 17:03:09.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	2008-12-31 16:54:27.000000000 +0200
+++ wireless-testing/net/mac80211/wpa.c	2008-12-31 17:03:09.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/mac80211/wpa.h	2008-12-31 17:03:09.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	2008-12-31 17:03:09.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	2008-12-31 17:03:09.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/mac80211/Makefile	2008-12-31 17:03:09.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	2008-12-31 16:48:01.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2008-12-31 17:03:09.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] 15+ messages in thread

* [RFC 04/11] mac80211: 802.11w - Use BIP (AES-128-CMAC)
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (2 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 03/11] mac80211: 802.11w - Add BIP (AES-128-CMAC) Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 05/11] mac80211: 802.11w - WEXT parameter for setting mgmt cipher Jouni Malinen
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:03:09.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h	2008-12-31 17:04:36.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/include/net/mac80211.h	2008-12-31 17:04:36.000000000 +0200
@@ -656,11 +656,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	2008-12-31 16:48:01.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c	2008-12-31 17:04:36.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_key.c	2008-12-31 17:04:36.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	2008-12-31 17:03:09.000000000 +0200
+++ wireless-testing/net/mac80211/key.h	2008-12-31 17:04:36.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c	2008-12-31 17:06:31.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	2008-12-31 16:54:08.000000000 +0200
+++ wireless-testing/net/mac80211/tx.c	2008-12-31 17:04:36.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/mac80211/key.c	2008-12-31 17:04:36.000000000 +0200
@@ -18,6 +18,7 @@
 #include "ieee80211_i.h"
 #include "debugfs_key.h"
 #include "aes_ccm.h"
+#include "aes_cmac.h"
 
 
 /**
@@ -218,13 +219,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);
@@ -240,13 +266,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) {
@@ -265,7 +297,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)
@@ -294,6 +326,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);
@@ -311,6 +347,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;
 }
 
@@ -464,6 +513,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);
@@ -486,6 +537,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);
@@ -503,6 +555,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;
@@ -538,6 +595,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	2008-12-31 17:03:09.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2008-12-31 17:04:36.000000000 +0200
@@ -406,8 +406,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;
 
@@ -479,6 +481,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	2008-12-31 16:48:01.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h	2008-12-31 17:04:36.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_key.h	2008-12-31 17:04:36.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	2008-12-31 16:45:09.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2008-12-31 17:04:36.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	2008-12-31 16:48:01.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2008-12-31 17:04:36.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	2008-12-31 17:09:46.000000000 +0200
+++ wireless-testing/drivers/net/wireless/ath5k/pcu.c	2008-12-31 17:10:19.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] 15+ messages in thread

* [RFC 05/11] mac80211: 802.11w - WEXT parameter for setting mgmt cipher
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (3 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 04/11] mac80211: 802.11w - Use " Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 06/11] mac80211: 802.11w - WEXT configuration for IGTK Jouni Malinen
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:08:47.000000000 +0200
+++ wireless-testing/include/linux/wireless.h	2008-12-31 17:10:50.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	2008-12-31 17:08:47.000000000 +0200
+++ wireless-testing/net/mac80211/wext.c	2008-12-31 17:10:50.000000000 +0200
@@ -913,6 +913,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] 15+ messages in thread

* [RFC 06/11] mac80211: 802.11w - WEXT configuration for IGTK
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (4 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 05/11] mac80211: 802.11w - WEXT parameter for setting mgmt cipher Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 07/11] mac80211: 802.11w - Configuration of MFP disabled/optional/required Jouni Malinen
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:10:50.000000000 +0200
+++ wireless-testing/include/linux/wireless.h	2008-12-31 17:11:41.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	2008-12-31 17:10:50.000000000 +0200
+++ wireless-testing/net/mac80211/wext.c	2008-12-31 17:11:41.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:
@@ -1034,6 +1044,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;
 	}
@@ -1042,20 +1055,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] 15+ messages in thread

* [RFC 07/11] mac80211: 802.11w - Configuration of MFP disabled/optional/required
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (5 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 06/11] mac80211: 802.11w - WEXT configuration for IGTK Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 08/11] mac80211: 802.11w - SA Query processing Jouni Malinen
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:11:41.000000000 +0200
+++ wireless-testing/include/linux/wireless.h	2008-12-31 17:12:37.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	2008-12-31 17:04:36.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2008-12-31 17:12:37.000000000 +0200
@@ -317,6 +317,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	2008-12-31 17:11:41.000000000 +0200
+++ wireless-testing/net/mac80211/wext.c	2008-12-31 17:12:37.000000000 +0200
@@ -961,6 +961,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	2008-12-31 16:48:01.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2008-12-31 17:12:37.000000000 +0200
@@ -2332,6 +2332,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] 15+ messages in thread

* [RFC 08/11] mac80211: 802.11w - SA Query processing
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (6 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 07/11] mac80211: 802.11w - Configuration of MFP disabled/optional/required Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 09/11] mac80211: 802.11w - Do not force Action frames to disable encryption Jouni Malinen
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:04:36.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h	2008-12-31 17:15:01.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	2008-12-31 17:06:31.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c	2008-12-31 17:17:04.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)
 {
@@ -1691,6 +1742,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] 15+ messages in thread

* [RFC 09/11] mac80211: 802.11w - Do not force Action frames to disable encryption
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (7 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 08/11] mac80211: 802.11w - SA Query processing Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 10/11] mac80211: 802.11w - Drop unprotected robust management frames if MFP is used Jouni Malinen
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 16:45:08.000000000 +0200
+++ wireless-testing/net/mac80211/ht.c	2008-12-31 17:20:12.000000000 +0200
@@ -201,7 +201,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,
@@ -247,7 +247,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,
@@ -290,7 +290,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	2008-12-31 16:45:08.000000000 +0200
+++ wireless-testing/net/mac80211/mesh_hwmp.c	2008-12-31 17:20:12.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	2008-12-31 16:45:08.000000000 +0200
+++ wireless-testing/net/mac80211/mesh_plink.c	2008-12-31 17:20:12.000000000 +0200
@@ -217,7 +217,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	2008-12-31 16:45:08.000000000 +0200
+++ wireless-testing/net/mac80211/spectmgmt.c	2008-12-31 17:20:12.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] 15+ messages in thread

* [RFC 10/11] mac80211: 802.11w - Drop unprotected robust management frames if MFP is used
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (8 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 09/11] mac80211: 802.11w - Do not force Action frames to disable encryption Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2008-12-31 15:38 ` [RFC 11/11] mac80211: 802.11w - Implement Association Comeback processing Jouni Malinen
  2009-01-02 10:12 ` [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Johannes Berg
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:17:04.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c	2008-12-31 17:20:37.000000000 +0200
@@ -1703,6 +1703,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;
@@ -1773,10 +1776,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] 15+ messages in thread

* [RFC 11/11] mac80211: 802.11w - Implement Association Comeback processing
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (9 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 10/11] mac80211: 802.11w - Drop unprotected robust management frames if MFP is used Jouni Malinen
@ 2008-12-31 15:38 ` Jouni Malinen
  2009-01-02 10:12 ` [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Johannes Berg
  11 siblings, 0 replies; 15+ messages in thread
From: Jouni Malinen @ 2008-12-31 15:38 UTC (permalink / raw)
  To: 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	2008-12-31 17:15:01.000000000 +0200
+++ wireless-testing/include/linux/ieee80211.h	2008-12-31 17:25:32.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	2008-12-31 17:12:37.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2008-12-31 17:25:32.000000000 +0200
@@ -816,6 +816,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;
@@ -843,6 +844,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	2008-12-31 17:12:37.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2008-12-31 17:25:32.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	2008-12-31 16:45:07.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2008-12-31 17:25:32.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] 15+ messages in thread

* Re: [RFC 02/11] mac80211: 802.11w - CCMP for management frames
  2008-12-31 15:38 ` [RFC 02/11] mac80211: 802.11w - CCMP for management frames Jouni Malinen
@ 2009-01-02 10:04   ` Johannes Berg
  2009-01-02 10:06     ` Johannes Berg
  0 siblings, 1 reply; 15+ messages in thread
From: Johannes Berg @ 2009-01-02 10:04 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 806 bytes --]

On Wed, 2008-12-31 at 17:38 +0200, Jouni Malinen wrote:

>  /**
> + * 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)) {
> +		/*
> +		 * Action frames, excluding Public Action frames, are Robust
> +		 * Management Frames.
> +		 */
> +		u8 *category = ((u8 *) hdr) + 24;
> +		return *category != WLAN_CATEGORY_PUBLIC;
> +	}
> +
> +	return false;
> +}

Should that be in include/linux/ieee80211.h?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 02/11] mac80211: 802.11w - CCMP for management frames
  2009-01-02 10:04   ` Johannes Berg
@ 2009-01-02 10:06     ` Johannes Berg
  0 siblings, 0 replies; 15+ messages in thread
From: Johannes Berg @ 2009-01-02 10:06 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 182 bytes --]

On Fri, 2009-01-02 at 11:05 +0100, Johannes Berg wrote:

> Should that be in include/linux/ieee80211.h?

Ok, it is, d'oh. I guess even though it's Jan 2 already ...

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP)
  2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
                   ` (10 preceding siblings ...)
  2008-12-31 15:38 ` [RFC 11/11] mac80211: 802.11w - Implement Association Comeback processing Jouni Malinen
@ 2009-01-02 10:12 ` Johannes Berg
  11 siblings, 0 replies; 15+ messages in thread
From: Johannes Berg @ 2009-01-02 10:12 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 352 bytes --]

On Wed, 2008-12-31 at 17:38 +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.

Looks good to me, I wouldn't mind putting this in.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2009-01-02 10:11 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-31 15:38 [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Jouni Malinen
2008-12-31 15:38 ` [RFC 01/11] mac80211: 802.11w - STA flag for MFP Jouni Malinen
2008-12-31 15:38 ` [RFC 02/11] mac80211: 802.11w - CCMP for management frames Jouni Malinen
2009-01-02 10:04   ` Johannes Berg
2009-01-02 10:06     ` Johannes Berg
2008-12-31 15:38 ` [RFC 03/11] mac80211: 802.11w - Add BIP (AES-128-CMAC) Jouni Malinen
2008-12-31 15:38 ` [RFC 04/11] mac80211: 802.11w - Use " Jouni Malinen
2008-12-31 15:38 ` [RFC 05/11] mac80211: 802.11w - WEXT parameter for setting mgmt cipher Jouni Malinen
2008-12-31 15:38 ` [RFC 06/11] mac80211: 802.11w - WEXT configuration for IGTK Jouni Malinen
2008-12-31 15:38 ` [RFC 07/11] mac80211: 802.11w - Configuration of MFP disabled/optional/required Jouni Malinen
2008-12-31 15:38 ` [RFC 08/11] mac80211: 802.11w - SA Query processing Jouni Malinen
2008-12-31 15:38 ` [RFC 09/11] mac80211: 802.11w - Do not force Action frames to disable encryption Jouni Malinen
2008-12-31 15:38 ` [RFC 10/11] mac80211: 802.11w - Drop unprotected robust management frames if MFP is used Jouni Malinen
2008-12-31 15:38 ` [RFC 11/11] mac80211: 802.11w - Implement Association Comeback processing Jouni Malinen
2009-01-02 10:12 ` [RFC 00/11] mac80211: Add support for IEEE 802.11w (MFP) Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).