1f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc/*
2f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * Copyright 2002-2004, Instant802 Networks, Inc.
3765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen * Copyright 2008, Jouni Malinen <j@w1.fi>
4f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc *
5f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * This program is free software; you can redistribute it and/or modify
6f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * it under the terms of the GNU General Public License version 2 as
7f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * published by the Free Software Foundation.
8f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc */
9f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
10f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/netdevice.h>
11f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/types.h>
12f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/skbuff.h>
13f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/compiler.h>
14f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison#include <linux/ieee80211.h>
155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
16f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison#include <asm/unaligned.h>
17f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <net/mac80211.h>
18aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg#include <crypto/aes.h>
19eb063c1702a84d58eb4c05a032bbff6f1c29049dJohannes Berg
20f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "ieee80211_i.h"
21f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "michael.h"
22f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "tkip.h"
23f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "aes_ccm.h"
24765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen#include "aes_cmac.h"
25f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "wpa.h"
26f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
279ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_tx_result
285cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
29f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
30747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen	u8 *data, *key, *mic;
31f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	size_t data_len;
328e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	unsigned int hdrlen;
338e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	struct ieee80211_hdr *hdr;
34f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct sk_buff *skb = tx->skb;
35813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3623c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg	int tail;
37f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
38c34498b9e633baa3266af98106502633b6bc371bHarvey Harrison	hdr = (struct ieee80211_hdr *)skb->data;
3997359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg	if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
4097359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg	    skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
419ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg		return TX_CONTINUE;
42f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
438e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	hdrlen = ieee80211_hdrlen(hdr->frame_control);
448e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	if (skb->len < hdrlen)
459ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg		return TX_DROP;
46f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
478e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	data = skb->data + hdrlen;
488e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	data_len = skb->len - hdrlen;
498e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison
50681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen	if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) {
51681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen		/* Need to use software crypto for the test */
52681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen		info->control.hw_key = NULL;
53681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen	}
54681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen
55813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key &&
56a26eb27ab430147a82e4a9f2f1ebfadf03d99550Johannes Berg	    (info->flags & IEEE80211_TX_CTL_DONTFRAG ||
57a26eb27ab430147a82e4a9f2f1ebfadf03d99550Johannes Berg	     tx->local->ops->set_frag_threshold) &&
58813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
59813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg		/* hwaccel - with no need for SW-generated MMIC */
609ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg		return TX_CONTINUE;
61f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
62f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
6323c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg	tail = MICHAEL_MIC_LEN;
64813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (!info->control.hw_key)
654325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg		tail += IEEE80211_TKIP_ICV_LEN;
6623c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg
67b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg	if (WARN(skb_tailroom(skb) < tail ||
68b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg		 skb_headroom(skb) < IEEE80211_TKIP_IV_LEN,
69b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg		 "mmic: not enough head/tail (%d/%d,%d/%d)\n",
70b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg		 skb_headroom(skb), IEEE80211_TKIP_IV_LEN,
71b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg		 skb_tailroom(skb), tail))
7223c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg		return TX_DROP;
73f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
74747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen	key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY];
75f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	mic = skb_put(skb, MICHAEL_MIC_LEN);
768e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	michael_mic(key, hdr, data, data_len, mic);
77681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen	if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE))
78681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen		mic[0]++;
79f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
809ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg	return TX_CONTINUE;
81f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
82f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
83f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
849ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_rx_result
855cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
86f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
87747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen	u8 *data, *key = NULL;
88f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	size_t data_len;
898e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	unsigned int hdrlen;
90f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	u8 mic[MICHAEL_MIC_LEN];
91f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct sk_buff *skb = rx->skb;
92eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
93eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
94f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
95816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	/*
96816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * it makes no sense to check for MIC errors on anything other
97816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * than data frames.
98816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 */
99816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	if (!ieee80211_is_data_present(hdr->frame_control))
1009ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg		return RX_CONTINUE;
101f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
102816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	/*
103816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * No way to verify the MIC if the hardware stripped it or
104816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * the IV with the key index. In this case we have solely rely
105816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * on the driver to set RX_FLAG_MMIC_ERROR in the event of a
106816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * MIC failure report.
107816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 */
108816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
109816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		if (status->flag & RX_FLAG_MMIC_ERROR)
110b98ea05861d76f458029096e8b2939fcb58e9530Saravana			goto mic_fail_no_key;
111816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter
1124045f72bcf3c293c7c5932ef001742d8bb5ded76Stanislaw Gruszka		if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key &&
1134045f72bcf3c293c7c5932ef001742d8bb5ded76Stanislaw Gruszka		    rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
114816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter			goto update_iv;
115816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter
116816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		return RX_CONTINUE;
117816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	}
118816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter
119816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	/*
120816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * Some hardware seems to generate Michael MIC failure reports; even
121816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * though, the frame was not encrypted with TKIP and therefore has no
122816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 * MIC. Ignore the flag them to avoid triggering countermeasures.
123816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	 */
12497359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg	if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
125816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	    !(status->flag & RX_FLAG_DECRYPTED))
1269ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg		return RX_CONTINUE;
127f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
128816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) {
129816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		/*
130816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		 * APs with pairwise keys should never receive Michael MIC
131816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		 * errors for non-zero keyidx because these are reserved for
132816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		 * group keys and only the AP is sending real multicast
13387ee475ef62504609368a767f6ad2e903a442078Emmanuel Grumbach		 * frames in the BSS.
134816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		 */
135816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		return RX_DROP_UNUSABLE;
136816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	}
137816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter
138816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	if (status->flag & RX_FLAG_MMIC_ERROR)
139816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		goto mic_fail;
140816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter
1418e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	hdrlen = ieee80211_hdrlen(hdr->frame_control);
1428e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	if (skb->len < hdrlen + MICHAEL_MIC_LEN)
143e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg		return RX_DROP_UNUSABLE;
144f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
145a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	if (skb_linearize(rx->skb))
146a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg		return RX_DROP_UNUSABLE;
147a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	hdr = (void *)skb->data;
148a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg
1498e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	data = skb->data + hdrlen;
1508e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
151747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen	key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
1528e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison	michael_mic(key, hdr, data, data_len, mic);
153816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0)
154816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter		goto mic_fail;
155f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
156f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* remove Michael MIC from payload */
157f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
158f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
159816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparterupdate_iv:
16050741ae05a4742cae99361f57d84b5f8d33822a4Johannes Berg	/* update IV in key information to be able to detect replays */
1619e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg	rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32;
1629e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg	rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16;
16350741ae05a4742cae99361f57d84b5f8d33822a4Johannes Berg
1649ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg	return RX_CONTINUE;
165816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter
166816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lampartermic_fail:
167b98ea05861d76f458029096e8b2939fcb58e9530Saravana	rx->key->u.tkip.mic_failures++;
168b98ea05861d76f458029096e8b2939fcb58e9530Saravana
169b98ea05861d76f458029096e8b2939fcb58e9530Saravanamic_fail_no_key:
170a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov	/*
171a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov	 * In some cases the key can be unset - e.g. a multicast packet, in
172a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov	 * a driver that supports HW encryption. Send up the key idx only if
173a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov	 * the key is set.
174a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov	 */
175a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov	mac80211_ev_michael_mic_failure(rx->sdata,
176a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov					rx->key ? rx->key->conf.keyidx : -1,
177816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter					(void *) skb->data, NULL, GFP_ATOMIC);
178816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter	return RX_DROP_UNUSABLE;
179f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
180f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
181f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
182e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Bergstatic int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
183f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
184f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
185f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_key *key = tx->key;
186e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
187d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison	unsigned int hdrlen;
188d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison	int len, tail;
189f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	u8 *pos;
190f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
191813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key &&
192ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
193ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
194813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg		/* hwaccel - with no need for software-generated IV */
19523c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg		return 0;
196e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	}
197e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg
198d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison	hdrlen = ieee80211_hdrlen(hdr->frame_control);
199f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	len = skb->len - hdrlen;
200f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
201813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key)
20223c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg		tail = 0;
20311a843b7e16062389c53ba393c7913956e034eb2Johannes Berg	else
2044325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg		tail = IEEE80211_TKIP_ICV_LEN;
20523c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg
20623c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg	if (WARN_ON(skb_tailroom(skb) < tail ||
2074325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg		    skb_headroom(skb) < IEEE80211_TKIP_IV_LEN))
20823c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg		return -1;
209f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
2104325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	pos = skb_push(skb, IEEE80211_TKIP_IV_LEN);
2114325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen);
2124325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	skb_set_network_header(skb, skb_network_offset(skb) +
2134325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg				    IEEE80211_TKIP_IV_LEN);
214f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pos += hdrlen;
215f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
216ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com	/* the HW only needs room for the IV, but not the actual IV */
217ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com	if (info->control.hw_key &&
218ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com	    (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
219ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com		return 0;
220ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com
221f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* Increase IV for the frame */
22203395003bf8ac813b1a0ac9299b3496484caf228Johannes Berg	spin_lock(&key->u.tkip.txlock);
223b0f76b335f8b1c324b4b2be06369d391b26a7cc9Harvey Harrison	key->u.tkip.tx.iv16++;
224b0f76b335f8b1c324b4b2be06369d391b26a7cc9Harvey Harrison	if (key->u.tkip.tx.iv16 == 0)
225b0f76b335f8b1c324b4b2be06369d391b26a7cc9Harvey Harrison		key->u.tkip.tx.iv32++;
226523b02ea23b175dd3e46e3daf1bc9354376640a3Johannes Berg	pos = ieee80211_tkip_add_iv(pos, key);
22703395003bf8ac813b1a0ac9299b3496484caf228Johannes Berg	spin_unlock(&key->u.tkip.txlock);
228f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
229813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	/* hwaccel - with software IV */
230813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key)
231f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		return 0;
232f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
233f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* Add room for ICV */
2344325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	skb_put(skb, IEEE80211_TKIP_ICV_LEN);
235f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
2363473187d2459a078e00e5fac8aafc30af69c57faJohn W. Linville	return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
237523b02ea23b175dd3e46e3daf1bc9354376640a3Johannes Berg					   key, skb, pos, len);
238f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
239f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
240f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
2419ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_tx_result
2425cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
243f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
244252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	struct sk_buff *skb;
245f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
2465cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg	ieee80211_tx_set_protected(tx);
247f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
248252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	skb_queue_walk(&tx->skbs, skb) {
2492de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg		if (tkip_encrypt_skb(tx, skb) < 0)
2502de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg			return TX_DROP;
251252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	}
252f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
2539ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg	return TX_CONTINUE;
254f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
255f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
256f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
2579ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_rx_result
2585cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
259f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
260f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
261747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen	int hdrlen, res, hwaccel = 0;
262f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_key *key = rx->key;
263f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct sk_buff *skb = rx->skb;
264eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
265f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
266d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison	hdrlen = ieee80211_hdrlen(hdr->frame_control);
267f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
268c34498b9e633baa3266af98106502633b6bc371bHarvey Harrison	if (!ieee80211_is_data(hdr->frame_control))
2699ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg		return RX_CONTINUE;
270f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
271f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	if (!rx->sta || skb->len - hdrlen < 12)
272e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg		return RX_DROP_UNUSABLE;
273f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
274a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	/* it may be possible to optimize this a bit more */
275a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	if (skb_linearize(rx->skb))
276a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg		return RX_DROP_UNUSABLE;
277a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	hdr = (void *)skb->data;
278a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg
279dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg	/*
280dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg	 * Let TKIP code verify IV, but skip decryption.
281dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg	 * In the case where hardware checks the IV as well,
282dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg	 * we don't even get here, see ieee80211_rx_h_decrypt()
283dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg	 */
284dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg	if (status->flag & RX_FLAG_DECRYPTED)
285f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		hwaccel = 1;
286f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
287f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
288f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc					  key, skb->data + hdrlen,
28917741cdc264e4d768167766a252210e201c1519aJohannes Berg					  skb->len - hdrlen, rx->sta->sta.addr,
2909e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg					  hdr->addr1, hwaccel, rx->security_idx,
2915cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg					  &rx->tkip_iv32,
2925cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg					  &rx->tkip_iv16);
293747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen	if (res != TKIP_DECRYPT_OK)
294e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg		return RX_DROP_UNUSABLE;
295f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
296f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* Trim ICV */
2974325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
298f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
299f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* Remove IV */
3004325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen);
3014325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	skb_pull(skb, IEEE80211_TKIP_IV_LEN);
302f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
3039ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg	return RX_CONTINUE;
304f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
305f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
306f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
30730ef7ef9672d92ab2cac37f60a31955c118321e7Ard Biesheuvelstatic void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
308f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
309f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	__le16 mask_fc;
310fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	int a4_included, mgmt;
311f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	u8 qos_tid;
3127ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	u16 len_a;
313f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	unsigned int hdrlen;
314f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
315f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
316f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	/*
317fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	 * Mask FC: zero subtype b4 b5 b6 (if not mgmt)
318f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	 * Retry, PwrMgt, MoreData; set Protected
319f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	 */
320fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	mgmt = ieee80211_is_mgmt(hdr->frame_control);
321f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	mask_fc = hdr->frame_control;
322fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY |
323f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison				IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
324fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	if (!mgmt)
325fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen		mask_fc &= ~cpu_to_le16(0x0070);
326f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
327f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison
328f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	hdrlen = ieee80211_hdrlen(hdr->frame_control);
329f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	len_a = hdrlen - 2;
330f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	a4_included = ieee80211_has_a4(hdr->frame_control);
331f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
332f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	if (ieee80211_is_data_qos(hdr->frame_control))
333f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison		qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
334f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	else
335f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison		qos_tid = 0;
336f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison
3377ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	/* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
3387ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	 * mode authentication are not allowed to collide, yet both are derived
3397ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	 * from this vector b_0. We only set L := 1 here to indicate that the
3407ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	 * data size can be represented in (L+1) bytes. The CCM layer will take
3417ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	 * care of storing the data length in the top (L+1) bytes and setting
3427ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	 * and clearing the other bits as is required to derive the two IVs.
3437ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	 */
3447ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	b_0[0] = 0x1;
345f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison
346fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	/* Nonce: Nonce Flags | A2 | PN
347fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	 * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
348fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	 */
349fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	b_0[1] = qos_tid | (mgmt << 4);
35073e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison	memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
3514325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
352f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
353f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* AAD (extra authenticate-only data) / masked 802.11 header
354f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
355f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	put_unaligned_be16(len_a, &aad[0]);
356f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	put_unaligned(mask_fc, (__le16 *)&aad[2]);
35773e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison	memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
358f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
359f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* Mask Seq#, leave Frag# */
360f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
361f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	aad[23] = 0;
362f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison
363f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	if (a4_included) {
36473e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison		memcpy(&aad[24], hdr->addr4, ETH_ALEN);
365f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison		aad[30] = qos_tid;
366f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		aad[31] = 0;
367f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison	} else {
36873e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison		memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
369f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison		aad[24] = qos_tid;
370f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
371f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
372f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
373f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
374f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Bencstatic inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id)
375f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
376f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[0] = pn[5];
377f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[1] = pn[4];
378f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[2] = 0;
379f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[3] = 0x20 | (key_id << 6);
380f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[4] = pn[3];
381f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[5] = pn[2];
382f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[6] = pn[1];
383f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr[7] = pn[0];
384f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
385f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
386f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
387c6a1fa12d206882757264869f8e32d606b930e2aJohannes Bergstatic inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
388f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
389f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pn[0] = hdr[7];
390f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pn[1] = hdr[6];
391f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pn[2] = hdr[5];
392f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pn[3] = hdr[4];
393f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pn[4] = hdr[1];
394f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pn[5] = hdr[0];
395f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
396f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
397f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
398e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Bergstatic int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
399f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
400f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
401f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_key *key = tx->key;
402e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
40323c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg	int hdrlen, len, tail;
404aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	u8 *pos;
405aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	u8 pn[6];
406aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	u64 pn64;
4077ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	u8 aad[2 * AES_BLOCK_SIZE];
4087ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	u8 b_0[AES_BLOCK_SIZE];
409f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
410813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key &&
411077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
41217d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
41317d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski	    !((info->control.hw_key->flags &
41417d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski	       IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) &&
41517d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski	      ieee80211_is_mgmt(hdr->frame_control))) {
416813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg		/*
417813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg		 * hwaccel has no need for preallocated room for CCMP
418813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg		 * header or MIC fields
419813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg		 */
42023c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg		return 0;
421e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	}
422e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg
423d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison	hdrlen = ieee80211_hdrlen(hdr->frame_control);
424f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	len = skb->len - hdrlen;
425f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
426813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key)
42723c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg		tail = 0;
42811a843b7e16062389c53ba393c7913956e034eb2Johannes Berg	else
4294325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg		tail = IEEE80211_CCMP_MIC_LEN;
43023c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg
43123c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg	if (WARN_ON(skb_tailroom(skb) < tail ||
4324325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg		    skb_headroom(skb) < IEEE80211_CCMP_HDR_LEN))
43323c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg		return -1;
434f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
4354325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN);
4364325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen);
4374325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	skb_set_network_header(skb, skb_network_offset(skb) +
4384325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg				    IEEE80211_CCMP_HDR_LEN);
439077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov
440077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov	/* the HW only needs room for the IV, but not the actual IV */
441e0830f71e7b8c2c58031c9692384819943162e9bArik Nemtsov	if (info->control.hw_key &&
442e0830f71e7b8c2c58031c9692384819943162e9bArik Nemtsov	    (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
443077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov		return 0;
444077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov
445f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	hdr = (struct ieee80211_hdr *) pos;
446f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	pos += hdrlen;
447f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
448aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	pn64 = atomic64_inc_return(&key->u.ccmp.tx_pn);
449f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
450aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	pn[5] = pn64;
451aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	pn[4] = pn64 >> 8;
452aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	pn[3] = pn64 >> 16;
453aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	pn[2] = pn64 >> 24;
454aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	pn[1] = pn64 >> 32;
455aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg	pn[0] = pn64 >> 40;
456f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
4578f20fc24986a083228823d9b68adca20714b254eJohannes Berg	ccmp_pn2hdr(pos, pn, key->conf.keyidx);
458f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
459813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	/* hwaccel - with software CCMP header */
460813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key)
461f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		return 0;
462f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
4634325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	pos += IEEE80211_CCMP_HDR_LEN;
46430ef7ef9672d92ab2cac37f60a31955c118321e7Ard Biesheuvel	ccmp_special_blocks(skb, pn, b_0, aad);
4657ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel	ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
4667ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel				  skb_put(skb, IEEE80211_CCMP_MIC_LEN));
467f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
468f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	return 0;
469f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
470f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
471f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
4729ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_tx_result
4735cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
474f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
475252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	struct sk_buff *skb;
476f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
4775cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg	ieee80211_tx_set_protected(tx);
478f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
479252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	skb_queue_walk(&tx->skbs, skb) {
4802de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg		if (ccmp_encrypt_skb(tx, skb) < 0)
4812de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg			return TX_DROP;
482252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	}
483f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
4849ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg	return TX_CONTINUE;
485f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
486f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
487f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
4889ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_rx_result
4895cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
490f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{
491c34498b9e633baa3266af98106502633b6bc371bHarvey Harrison	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
492f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	int hdrlen;
493f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct ieee80211_key *key = rx->key;
494f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	struct sk_buff *skb = rx->skb;
495eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4964325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	u8 pn[IEEE80211_CCMP_PN_LEN];
497f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	int data_len;
4989190252c952a33efa1ceff4ef35188f8a27b81cbJouni Malinen	int queue;
499f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
500d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison	hdrlen = ieee80211_hdrlen(hdr->frame_control);
501f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
502fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen	if (!ieee80211_is_data(hdr->frame_control) &&
503d8ca16db6bb23d03fcb794df44bae64ae976f27cJohannes Berg	    !ieee80211_is_robust_mgmt_frame(skb))
5049ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg		return RX_CONTINUE;
505f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
5064325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN -
5074325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg		   IEEE80211_CCMP_MIC_LEN;
508f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	if (!rx->sta || data_len < 0)
509e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg		return RX_DROP_UNUSABLE;
510f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
511a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	if (status->flag & RX_FLAG_DECRYPTED) {
5124325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg		if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_CCMP_HDR_LEN))
513a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg			return RX_DROP_UNUSABLE;
514a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	} else {
515a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg		if (skb_linearize(rx->skb))
516a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg			return RX_DROP_UNUSABLE;
517a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	}
518a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg
519c6a1fa12d206882757264869f8e32d606b930e2aJohannes Berg	ccmp_hdr2pn(pn, skb->data + hdrlen);
520f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
5219e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg	queue = rx->security_idx;
5229190252c952a33efa1ceff4ef35188f8a27b81cbJouni Malinen
5234325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	if (memcmp(pn, key->u.ccmp.rx_pn[queue], IEEE80211_CCMP_PN_LEN) <= 0) {
524f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		key->u.ccmp.replays++;
525e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg		return RX_DROP_UNUSABLE;
526f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
527f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
528eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg	if (!(status->flag & RX_FLAG_DECRYPTED)) {
5297ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel		u8 aad[2 * AES_BLOCK_SIZE];
5307ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel		u8 b_0[AES_BLOCK_SIZE];
5317848ba7d7a010ccb265617fc2bc053e2bdf06f48Johannes Berg		/* hardware didn't decrypt/verify MIC */
53230ef7ef9672d92ab2cac37f60a31955c118321e7Ard Biesheuvel		ccmp_special_blocks(skb, pn, b_0, aad);
533f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
534f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc		if (ieee80211_aes_ccm_decrypt(
5357ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel			    key->u.ccmp.tfm, b_0, aad,
5364325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg			    skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
5374325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg			    data_len,
5387ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel			    skb->data + skb->len - IEEE80211_CCMP_MIC_LEN))
539e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg			return RX_DROP_UNUSABLE;
540f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	}
541f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
5424325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN);
543f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
544f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc	/* Remove CCMP header and MIC */
5454325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	if (pskb_trim(skb, skb->len - IEEE80211_CCMP_MIC_LEN))
546a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg		return RX_DROP_UNUSABLE;
5474325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	memmove(skb->data + IEEE80211_CCMP_HDR_LEN, skb->data, hdrlen);
5484325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg	skb_pull(skb, IEEE80211_CCMP_HDR_LEN);
549f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc
5509ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg	return RX_CONTINUE;
551f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc}
552765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
5532475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovstatic ieee80211_tx_result
5542475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
5552475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov			    struct sk_buff *skb)
5562475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{
5572475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
5582475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	struct ieee80211_key *key = tx->key;
5592475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
5602475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme;
5612475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	int hdrlen;
5622475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	u8 *pos;
5632475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5642475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (info->control.hw_key &&
5652475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
5662475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		/* hwaccel has no need for preallocated head room */
5672475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return TX_CONTINUE;
5682475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	}
5692475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5702475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (unlikely(skb_headroom(skb) < cs->hdr_len &&
5712475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		     pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC)))
5722475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return TX_DROP;
5732475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5742475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	hdrlen = ieee80211_hdrlen(hdr->frame_control);
5752475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5762475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	pos = skb_push(skb, cs->hdr_len);
5772475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	memmove(pos, pos + cs->hdr_len, hdrlen);
5782475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len);
5792475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5802475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	return TX_CONTINUE;
5812475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov}
5822475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5832475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovstatic inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len)
5842475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{
5852475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	int i;
5862475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5872475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	/* pn is little endian */
5882475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	for (i = len - 1; i >= 0; i--) {
5892475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		if (pn1[i] < pn2[i])
5902475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov			return -1;
5912475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		else if (pn1[i] > pn2[i])
5922475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov			return 1;
5932475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	}
5942475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5952475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	return 0;
5962475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov}
5972475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
5982475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovstatic ieee80211_rx_result
5992475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
6002475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{
6012475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	struct ieee80211_key *key = rx->key;
6022475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
6032475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	const struct ieee80211_cipher_scheme *cs = NULL;
6042475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	int hdrlen = ieee80211_hdrlen(hdr->frame_control);
6052475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
6062475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	int data_len;
6072475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	u8 *rx_pn;
6082475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	u8 *skb_pn;
6092475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	u8 qos_tid;
6102475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6112475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (!rx->sta || !rx->sta->cipher_scheme ||
6122475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	    !(status->flag & RX_FLAG_DECRYPTED))
6132475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return RX_DROP_UNUSABLE;
6142475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6152475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (!ieee80211_is_data(hdr->frame_control))
6162475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return RX_CONTINUE;
6172475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6182475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	cs = rx->sta->cipher_scheme;
6192475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6202475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	data_len = rx->skb->len - hdrlen - cs->hdr_len;
6212475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6222475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (data_len < 0)
6232475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return RX_DROP_UNUSABLE;
6242475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6252475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (ieee80211_is_data_qos(hdr->frame_control))
6262475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		qos_tid = *ieee80211_get_qos_ctl(hdr) &
6272475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov				IEEE80211_QOS_CTL_TID_MASK;
6282475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	else
6292475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		qos_tid = 0;
6302475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6312475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (skb_linearize(rx->skb))
6322475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return RX_DROP_UNUSABLE;
6332475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6342475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	hdr = (struct ieee80211_hdr *)rx->skb->data;
6352475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6362475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	rx_pn = key->u.gen.rx_pn[qos_tid];
6372475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	skb_pn = rx->skb->data + hdrlen + cs->pn_off;
6382475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6392475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0)
6402475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return RX_DROP_UNUSABLE;
6412475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6422475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	memcpy(rx_pn, skb_pn, cs->pn_len);
6432475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6442475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	/* remove security header and MIC */
6452475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len))
6462475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return RX_DROP_UNUSABLE;
6472475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6482475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen);
6492475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	skb_pull(rx->skb, cs->hdr_len);
6502475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
6512475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	return RX_CONTINUE;
6522475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov}
653765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
654765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenstatic void bip_aad(struct sk_buff *skb, u8 *aad)
655765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{
65633766368f6532313571534f9112b1796d6651bbeJouni Malinen	__le16 mask_fc;
65733766368f6532313571534f9112b1796d6651bbeJouni Malinen	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
65833766368f6532313571534f9112b1796d6651bbeJouni Malinen
659765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	/* BIP AAD: FC(masked) || A1 || A2 || A3 */
660765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
661765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	/* FC type/subtype */
662765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	/* Mask FC Retry, PwrMgt, MoreData flags to zero */
66333766368f6532313571534f9112b1796d6651bbeJouni Malinen	mask_fc = hdr->frame_control;
66433766368f6532313571534f9112b1796d6651bbeJouni Malinen	mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM |
66533766368f6532313571534f9112b1796d6651bbeJouni Malinen				IEEE80211_FCTL_MOREDATA);
66633766368f6532313571534f9112b1796d6651bbeJouni Malinen	put_unaligned(mask_fc, (__le16 *) &aad[0]);
667765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	/* A1 || A2 || A3 */
66833766368f6532313571534f9112b1796d6651bbeJouni Malinen	memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);
669765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen}
670765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
671765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
67275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Bergstatic inline void bip_ipn_set64(u8 *d, u64 pn)
67375396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg{
67475396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	*d++ = pn;
67575396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	*d++ = pn >> 8;
67675396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	*d++ = pn >> 16;
67775396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	*d++ = pn >> 24;
67875396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	*d++ = pn >> 32;
67975396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	*d = pn >> 40;
68075396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg}
68175396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg
682765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenstatic inline void bip_ipn_swap(u8 *d, const u8 *s)
683765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{
684765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	*d++ = s[5];
685765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	*d++ = s[4];
686765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	*d++ = s[3];
687765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	*d++ = s[2];
688765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	*d++ = s[1];
689765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	*d = s[0];
690765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen}
691765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
692765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
693765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_tx_result
694765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
695765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{
696252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	struct sk_buff *skb;
697252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	struct ieee80211_tx_info *info;
698765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	struct ieee80211_key *key = tx->key;
699765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	struct ieee80211_mmie *mmie;
70075396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	u8 aad[20];
70175396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	u64 pn64;
702765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
703252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
704252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg		return TX_DROP;
705252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg
706252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	skb = skb_peek(&tx->skbs);
707252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg
708252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg	info = IEEE80211_SKB_CB(skb);
709252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg
710813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg	if (info->control.hw_key)
711252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg		return TX_CONTINUE;
712765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
713765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
714765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		return TX_DROP;
715765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
716765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	mmie = (struct ieee80211_mmie *) skb_put(skb, sizeof(*mmie));
717765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	mmie->element_id = WLAN_EID_MMIE;
718765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	mmie->length = sizeof(*mmie) - 2;
719765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	mmie->key_id = cpu_to_le16(key->conf.keyidx);
720765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
721765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	/* PN = PN + 1 */
72275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn);
723765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
72475396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	bip_ipn_set64(mmie->sequence_number, pn64);
725765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
726765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	bip_aad(skb, aad);
727765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
728765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	/*
729765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	 * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
730765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	 */
73175396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg	ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
73275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg			   skb->data + 24, skb->len - 24, mmie->mic);
733765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
734765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	return TX_CONTINUE;
735765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen}
736765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
737765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
738765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_rx_result
739765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
740765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{
741765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	struct sk_buff *skb = rx->skb;
742eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
743765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	struct ieee80211_key *key = rx->key;
744765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	struct ieee80211_mmie *mmie;
745765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	u8 aad[20], mic[8], ipn[6];
746765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
747765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
748765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	if (!ieee80211_is_mgmt(hdr->frame_control))
749765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		return RX_CONTINUE;
750765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
751a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg	/* management frames are already linear */
752a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg
753765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	if (skb->len < 24 + sizeof(*mmie))
754765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		return RX_DROP_UNUSABLE;
755765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
756765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	mmie = (struct ieee80211_mmie *)
757765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		(skb->data + skb->len - sizeof(*mmie));
758765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	if (mmie->element_id != WLAN_EID_MMIE ||
759765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	    mmie->length != sizeof(*mmie) - 2)
760765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		return RX_DROP_UNUSABLE; /* Invalid MMIE */
761765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
762765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	bip_ipn_swap(ipn, mmie->sequence_number);
763765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
764765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
765765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		key->u.aes_cmac.replays++;
766765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		return RX_DROP_UNUSABLE;
767765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	}
768765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
769eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg	if (!(status->flag & RX_FLAG_DECRYPTED)) {
770765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		/* hardware didn't decrypt/verify MIC */
771765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		bip_aad(skb, aad);
77275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg		ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
773765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen				   skb->data + 24, skb->len - 24, mic);
774765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
775765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen			key->u.aes_cmac.icverrors++;
776765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen			return RX_DROP_UNUSABLE;
777765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen		}
778765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	}
779765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
780765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
781765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
782765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	/* Remove MMIE */
783765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	skb_trim(skb, skb->len - sizeof(*mmie));
784765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen
785765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen	return RX_CONTINUE;
786765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen}
787d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky
788d32a102819eef99d4d87019266bea208447be0a0Yoni Divinskyieee80211_tx_result
789d32a102819eef99d4d87019266bea208447be0a0Yoni Divinskyieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
790d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky{
791d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky	struct sk_buff *skb;
792d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky	struct ieee80211_tx_info *info = NULL;
7932475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	ieee80211_tx_result res;
794d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky
795d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky	skb_queue_walk(&tx->skbs, skb) {
796d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky		info  = IEEE80211_SKB_CB(skb);
797d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky
798d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky		/* handle hw-only algorithm */
799d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky		if (!info->control.hw_key)
800d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky			return TX_DROP;
8012475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
8022475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		if (tx->key->sta->cipher_scheme) {
8032475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov			res = ieee80211_crypto_cs_encrypt(tx, skb);
8042475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov			if (res != TX_CONTINUE)
8052475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov				return res;
8062475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		}
807d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky	}
808d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky
809d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky	ieee80211_tx_set_protected(tx);
810d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky
811d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky	return TX_CONTINUE;
812d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky}
8132475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
8142475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_rx_result
8152475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx)
8162475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{
817aeb136c5b433377324f030b1a50b96eb7a99193bMax Stepanov	if (rx->sta && rx->sta->cipher_scheme)
8182475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov		return ieee80211_crypto_cs_decrypt(rx);
8192475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov
8202475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov	return RX_DROP_UNUSABLE;
8212475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov}
822