diff options
| author | Jouni Malinen <j@w1.fi> | 2009-01-08 13:32:00 +0200 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:00:01 -0500 | 
| commit | fb7333367632c67d8b6b06fb8d906cdabb11b02a (patch) | |
| tree | 337d89f2c8c033b00dfcefbbcbded3f914d51661 | |
| parent | 5394af4d86ae51b369ff243c3f75b6f9a74e164b (diff) | |
| download | olio-linux-3.10-fb7333367632c67d8b6b06fb8d906cdabb11b02a.tar.xz olio-linux-3.10-fb7333367632c67d8b6b06fb8d906cdabb11b02a.zip  | |
mac80211: 802.11w - CCMP for management frames
Extend CCMP to support encryption and decryption of unicast management
frames.
Signed-off-by: Jouni Malinen <j@w1.fi>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | include/linux/ieee80211.h | 30 | ||||
| -rw-r--r-- | net/mac80211/tx.c | 23 | ||||
| -rw-r--r-- | net/mac80211/wpa.c | 18 | 
3 files changed, 64 insertions, 7 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index cade2556af0..d5165895f31 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -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(struct ieee80211_hdr *hdr)  }  /** + * 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   * diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cd6bc87eec7..50c6c4fabea 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -330,6 +330,22 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)  	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)  { @@ -428,10 +444,15 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)  			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;  		}  	} diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 7aa63caf8d5..aff46adde3f 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -266,7 +266,7 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,  				int encrypted)  {  	__le16 mask_fc; -	int a4_included; +	int a4_included, mgmt;  	u8 qos_tid;  	u8 *b_0, *aad;  	u16 data_len, len_a; @@ -277,12 +277,15 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,  	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); @@ -300,8 +303,10 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,  	/* 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) */ @@ -446,7 +451,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)  	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;  |