[go: nahoru, domu]

1ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman/*
2ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
3ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman *
4ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
5ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman *
6ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman * This program is free software; you can redistribute it and/or modify
7ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman * it under the terms of the GNU General Public License version 2 as
8ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman * published by the Free Software Foundation. See README and COPYING for
9ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman * more details.
10ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman */
11ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
12ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/module.h>
13ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/init.h>
14ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/slab.h>
15ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/random.h>
16ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/skbuff.h>
17ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/netdevice.h>
18ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/if_ether.h>
19ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/if_arp.h>
20a44325f98563c39bc63311db7471b848153e49feLarry Finger#include <linux/string.h>
21ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/wireless.h>
2294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger#include "rtllib.h"
23ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
24ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/crypto.h>
25ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
26cb76215448947ddcc133c4b1c2ff2d4a77e851e0Mike McCormack#include <linux/scatterlist.h>
27ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
28ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#define AES_BLOCK_LEN 16
29ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#define CCMP_HDR_LEN 8
30ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#define CCMP_MIC_LEN 8
31ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#define CCMP_TK_LEN 16
32ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#define CCMP_PN_LEN 6
33ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
3494a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerstruct rtllib_ccmp_data {
35ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 key[CCMP_TK_LEN];
36ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int key_set;
37ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
38ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 tx_pn[CCMP_PN_LEN];
39ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 rx_pn[CCMP_PN_LEN];
40ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
41ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u32 dot11RSNAStatsCCMPFormatErrors;
42ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u32 dot11RSNAStatsCCMPReplays;
43ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u32 dot11RSNAStatsCCMPDecryptErrors;
44ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
45ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int key_idx;
46ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
47ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	struct crypto_tfm *tfm;
48ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
49ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* scratch buffers for virt_to_page() (crypto API) */
50ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
51ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
52ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
53ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman};
54ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
55ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic void rtllib_ccmp_aes_encrypt(struct crypto_tfm *tfm,
56ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			     const u8 pt[16], u8 ct[16])
57ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
58a44325f98563c39bc63311db7471b848153e49feLarry Finger	crypto_cipher_encrypt_one((void *)tfm, ct, pt);
59ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
60ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
61a44325f98563c39bc63311db7471b848153e49feLarry Fingerstatic void *rtllib_ccmp_init(int key_idx)
62ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
6394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_ccmp_data *priv;
64ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
65929fa2a42e75e0c6ded89c450bd0f668e32190d7Thomas Meyer	priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
66ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (priv == NULL)
67ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		goto fail;
68ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	priv->key_idx = key_idx;
69ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
70a44325f98563c39bc63311db7471b848153e49feLarry Finger	priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
71ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (IS_ERR(priv->tfm)) {
725635b82a553620c511dc6bc8cb0990c0a791e21eMahati Chamarthy		pr_debug("rtllib_crypt_ccmp: could not allocate "
73ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		       "crypto API aes\n");
74ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		priv->tfm = NULL;
75ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		goto fail;
76ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
77ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return priv;
78ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
79ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanfail:
80ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (priv) {
81ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (priv->tfm)
82a44325f98563c39bc63311db7471b848153e49feLarry Finger			crypto_free_cipher((void *)priv->tfm);
83ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		kfree(priv);
84ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
85ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
86ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return NULL;
87ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
88ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
89ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
9094a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerstatic void rtllib_ccmp_deinit(void *priv)
91ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
9294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_ccmp_data *_priv = priv;
933a6b70c3f3558a2e47d2ca82752f0aed0f3c33c6Matthew Casey
94ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (_priv && _priv->tfm)
95a44325f98563c39bc63311db7471b848153e49feLarry Finger		crypto_free_cipher((void *)_priv->tfm);
96ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	kfree(priv);
97ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
98ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
99ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
100ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanstatic inline void xor_block(u8 *b, u8 *a, size_t len)
101ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
102ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int i;
1033a6b70c3f3558a2e47d2ca82752f0aed0f3c33c6Matthew Casey
104ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	for (i = 0; i < len; i++)
105ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		b[i] ^= a[i];
106ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
107ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
108ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
109ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
110ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanstatic void ccmp_init_blocks(struct crypto_tfm *tfm,
11194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			     struct rtllib_hdr_4addr *hdr,
112ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			     u8 *pn, size_t dlen, u8 *b0, u8 *auth,
113ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			     u8 *s0)
114ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
115ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 *pos, qc = 0;
116ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	size_t aad_len;
117ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u16 fc;
118ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int a4_included, qc_included;
119ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 aad[2 * AES_BLOCK_LEN];
120ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
121ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	fc = le16_to_cpu(hdr->frame_ctl);
12294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	a4_included = ((fc & (RTLLIB_FCTL_TODS | RTLLIB_FCTL_FROMDS)) ==
12394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		       (RTLLIB_FCTL_TODS | RTLLIB_FCTL_FROMDS));
124ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/*
12594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	qc_included = ((WLAN_FC_GET_TYPE(fc) == RTLLIB_FTYPE_DATA) &&
126ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		       (WLAN_FC_GET_STYPE(fc) & 0x08));
127a44325f98563c39bc63311db7471b848153e49feLarry Finger	*/
12894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	qc_included = ((WLAN_FC_GET_TYPE(fc) == RTLLIB_FTYPE_DATA) &&
129ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		       (WLAN_FC_GET_STYPE(fc) & 0x80));
130ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	aad_len = 22;
131ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (a4_included)
132ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		aad_len += 6;
133ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (qc_included) {
134ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		pos = (u8 *) &hdr->addr4;
135ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (a4_included)
136ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			pos += 6;
137ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		qc = *pos & 0x0f;
138ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		aad_len += 2;
139ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
140ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* CCM Initial Block:
141ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * Flag (Include authentication header, M=3 (8-octet MIC),
142ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 *       L=1 (2-octet Dlen))
143ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * Nonce: 0x00 | A2 | PN
144ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * Dlen */
145ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	b0[0] = 0x59;
146ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	b0[1] = qc;
147ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
148ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memcpy(b0 + 8, pn, CCMP_PN_LEN);
149ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	b0[14] = (dlen >> 8) & 0xff;
150ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	b0[15] = dlen & 0xff;
151ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
152ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* AAD:
153ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
154ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * A1 | A2 | A3
155ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * SC with bits 4..15 (seq#) masked to zero
156ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * A4 (if present)
157ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * QC (if present)
158ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 */
159ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pos = (u8 *) hdr;
160ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	aad[0] = 0; /* aad_len >> 8 */
161ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	aad[1] = aad_len & 0xff;
162ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	aad[2] = pos[0] & 0x8f;
163ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	aad[3] = pos[1] & 0xc7;
164ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
165ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pos = (u8 *) &hdr->seq_ctl;
166ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	aad[22] = pos[0] & 0x0f;
167ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	aad[23] = 0; /* all bits masked */
168ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memset(aad + 24, 0, 8);
169ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (a4_included)
170ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		memcpy(aad + 24, hdr->addr4, ETH_ALEN);
171ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (qc_included) {
172ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		aad[a4_included ? 30 : 24] = qc;
173ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		/* rest of QC masked */
174ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
175ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
176ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* Start with the first block and AAD */
17794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	rtllib_ccmp_aes_encrypt(tfm, b0, auth);
178ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	xor_block(auth, aad, AES_BLOCK_LEN);
17994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	rtllib_ccmp_aes_encrypt(tfm, auth, auth);
180ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
18194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	rtllib_ccmp_aes_encrypt(tfm, auth, auth);
182ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	b0[0] &= 0x07;
183ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	b0[14] = b0[15] = 0;
18494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	rtllib_ccmp_aes_encrypt(tfm, b0, s0);
185ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
186ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
187ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
188ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
18994a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerstatic int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
190ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
19194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_ccmp_data *key = priv;
192ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int data_len, i;
193ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 *pos;
19494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_hdr_4addr *hdr;
195a44325f98563c39bc63311db7471b848153e49feLarry Finger	struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
196a44325f98563c39bc63311db7471b848153e49feLarry Finger				    MAX_DEV_ADDR_SIZE);
197ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (skb_headroom(skb) < CCMP_HDR_LEN ||
198ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	    skb_tailroom(skb) < CCMP_MIC_LEN ||
199ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	    skb->len < hdr_len)
200ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -1;
201ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
202ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	data_len = skb->len - hdr_len;
203ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pos = skb_push(skb, CCMP_HDR_LEN);
204ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
205ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pos += hdr_len;
206ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
207ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	i = CCMP_PN_LEN - 1;
208ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	while (i >= 0) {
209ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		key->tx_pn[i]++;
210ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (key->tx_pn[i] != 0)
211ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			break;
212ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		i--;
213ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
214ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
215ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = key->tx_pn[5];
216ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = key->tx_pn[4];
217ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = 0;
218ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */;
219ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = key->tx_pn[3];
220ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = key->tx_pn[2];
221ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = key->tx_pn[1];
222ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*pos++ = key->tx_pn[0];
223ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
224ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
22594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	hdr = (struct rtllib_hdr_4addr *) skb->data;
22694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (!tcb_desc->bHwSec) {
227ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		int blocks, last, len;
228ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *mic;
229ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *b0 = key->tx_b0;
230ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *b = key->tx_b;
231ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *e = key->tx_e;
232ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *s0 = key->tx_s0;
233ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
234ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		mic = skb_put(skb, CCMP_MIC_LEN);
235ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
236a44325f98563c39bc63311db7471b848153e49feLarry Finger		ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len,
237a44325f98563c39bc63311db7471b848153e49feLarry Finger				 b0, b, s0);
238ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
239ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
240ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		last = data_len % AES_BLOCK_LEN;
241ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
242ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		for (i = 1; i <= blocks; i++) {
243ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			len = (i == blocks && last) ? last : AES_BLOCK_LEN;
244ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* Authentication */
245ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			xor_block(b, pos, len);
24694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_ccmp_aes_encrypt(key->tfm, b, b);
247ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* Encryption, with counter */
248ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			b0[14] = (i >> 8) & 0xff;
249ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			b0[15] = i & 0xff;
25094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_ccmp_aes_encrypt(key->tfm, b0, e);
251ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			xor_block(pos, e, len);
252ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			pos += len;
253ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
254ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
255ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		for (i = 0; i < CCMP_MIC_LEN; i++)
256ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			mic[i] = b[i] ^ s0[i];
257ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
258ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return 0;
259ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
260ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
261ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
26294a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerstatic int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
263ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
26494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_ccmp_data *key = priv;
265ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 keyidx, *pos;
26694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_hdr_4addr *hdr;
267a44325f98563c39bc63311db7471b848153e49feLarry Finger	struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
268a44325f98563c39bc63311db7471b848153e49feLarry Finger				    MAX_DEV_ADDR_SIZE);
269ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 pn[6];
270ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
271ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
272ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		key->dot11RSNAStatsCCMPFormatErrors++;
273ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -1;
274ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
275ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
27694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	hdr = (struct rtllib_hdr_4addr *) skb->data;
277ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pos = skb->data + hdr_len;
278ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	keyidx = pos[3];
279ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (!(keyidx & (1 << 5))) {
280ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (net_ratelimit()) {
2815635b82a553620c511dc6bc8cb0990c0a791e21eMahati Chamarthy			pr_debug("CCMP: received packet without ExtIV"
282ac50ddaaeeca4f649c53ce31175aa68d26420138Larry Finger			       " flag from %pM\n", hdr->addr2);
283ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
284ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		key->dot11RSNAStatsCCMPFormatErrors++;
285ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -2;
286ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
287ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	keyidx >>= 6;
288ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (key->key_idx != keyidx) {
2895635b82a553620c511dc6bc8cb0990c0a791e21eMahati Chamarthy		pr_debug("CCMP: RX tkey->key_idx=%d frame "
290ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		       "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
291ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -6;
292ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
293ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (!key->key_set) {
294ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (net_ratelimit()) {
2955635b82a553620c511dc6bc8cb0990c0a791e21eMahati Chamarthy			pr_debug("CCMP: received packet from %pM"
296ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			       " with keyid=%d that does not have a configured"
297ac50ddaaeeca4f649c53ce31175aa68d26420138Larry Finger			       " key\n", hdr->addr2, keyidx);
298ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
299ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -3;
300ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
301ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
302ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pn[0] = pos[7];
303ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pn[1] = pos[6];
304ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pn[2] = pos[5];
305ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pn[3] = pos[4];
306ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pn[4] = pos[1];
307ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pn[5] = pos[0];
308ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	pos += 8;
309ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
310ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		key->dot11RSNAStatsCCMPReplays++;
311ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -4;
312ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
31394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (!tcb_desc->bHwSec) {
314a44325f98563c39bc63311db7471b848153e49feLarry Finger		size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN -
315a44325f98563c39bc63311db7471b848153e49feLarry Finger				  CCMP_MIC_LEN;
316ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
317ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *b0 = key->rx_b0;
318ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *b = key->rx_b;
319ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		u8 *a = key->rx_a;
320ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		int i, blocks, last, len;
321ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
322ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
323ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
324ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		xor_block(mic, b, CCMP_MIC_LEN);
325ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
326ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
327ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		last = data_len % AES_BLOCK_LEN;
328ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
329ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		for (i = 1; i <= blocks; i++) {
330ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			len = (i == blocks && last) ? last : AES_BLOCK_LEN;
331ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* Decrypt, with counter */
332ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			b0[14] = (i >> 8) & 0xff;
333ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			b0[15] = i & 0xff;
33494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_ccmp_aes_encrypt(key->tfm, b0, b);
335ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			xor_block(pos, b, len);
336ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* Authentication */
337ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			xor_block(a, pos, len);
33894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_ccmp_aes_encrypt(key->tfm, a, a);
339ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			pos += len;
340ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
341ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
342ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
343ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			if (net_ratelimit()) {
3445635b82a553620c511dc6bc8cb0990c0a791e21eMahati Chamarthy				pr_debug("CCMP: decrypt failed: STA="
345ac50ddaaeeca4f649c53ce31175aa68d26420138Larry Finger				" %pM\n", hdr->addr2);
346ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
347ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			key->dot11RSNAStatsCCMPDecryptErrors++;
348ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			return -5;
349ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
350ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
351ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		memcpy(key->rx_pn, pn, CCMP_PN_LEN);
352ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
353ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* Remove hdr and MIC */
354ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
355ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	skb_pull(skb, CCMP_HDR_LEN);
356ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	skb_trim(skb, skb->len - CCMP_MIC_LEN);
357ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
358ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return keyidx;
359ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
360ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
361ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
36294a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerstatic int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
363ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
36494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_ccmp_data *data = priv;
365ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int keyidx;
366ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	struct crypto_tfm *tfm = data->tfm;
367ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
368ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	keyidx = data->key_idx;
369ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memset(data, 0, sizeof(*data));
370ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	data->key_idx = keyidx;
371ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	data->tfm = tfm;
372ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (len == CCMP_TK_LEN) {
373ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		memcpy(data->key, key, CCMP_TK_LEN);
374ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		data->key_set = 1;
375ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (seq) {
376ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			data->rx_pn[0] = seq[5];
377ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			data->rx_pn[1] = seq[4];
378ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			data->rx_pn[2] = seq[3];
379ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			data->rx_pn[3] = seq[2];
380ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			data->rx_pn[4] = seq[1];
381ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			data->rx_pn[5] = seq[0];
382ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
383a44325f98563c39bc63311db7471b848153e49feLarry Finger		crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN);
384ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	} else if (len == 0)
385ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		data->key_set = 0;
386ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	else
387ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -1;
388ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
389ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return 0;
390ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
391ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
392ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
39394a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerstatic int rtllib_ccmp_get_key(void *key, int len, u8 *seq, void *priv)
394ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
39594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_ccmp_data *data = priv;
396ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
397ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (len < CCMP_TK_LEN)
398ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -1;
399ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
400ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (!data->key_set)
401ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return 0;
402ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	memcpy(key, data->key, CCMP_TK_LEN);
403ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
404ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (seq) {
405ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		seq[0] = data->tx_pn[5];
406ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		seq[1] = data->tx_pn[4];
407ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		seq[2] = data->tx_pn[3];
408ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		seq[3] = data->tx_pn[2];
409ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		seq[4] = data->tx_pn[1];
410ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		seq[5] = data->tx_pn[0];
411ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
412ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
413ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return CCMP_TK_LEN;
414ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
415ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
416ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
4176bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic void rtllib_ccmp_print_stats(struct seq_file *m, void *priv)
418ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
41994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_ccmp_data *ccmp = priv;
4203a6b70c3f3558a2e47d2ca82752f0aed0f3c33c6Matthew Casey
4216bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells	seq_printf(m,
4226bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   "key[%d] alg=CCMP key_set=%d "
4236bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   "tx_pn=%pM rx_pn=%pM "
4246bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   "format_errors=%d replays=%d decrypt_errors=%d\n",
4256bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   ccmp->key_idx, ccmp->key_set,
4266bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   ccmp->tx_pn, ccmp->rx_pn,
4276bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   ccmp->dot11RSNAStatsCCMPFormatErrors,
4286bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   ccmp->dot11RSNAStatsCCMPReplays,
4296bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells		   ccmp->dot11RSNAStatsCCMPDecryptErrors);
430ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
431ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
43232c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennanstatic struct lib80211_crypto_ops rtllib_crypt_ccmp = {
4333b148be0df8e45a0259d7e84001cf02e897af614Sean MacLennan	.name			= "R-CCMP",
43494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	.init			= rtllib_ccmp_init,
43594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	.deinit			= rtllib_ccmp_deinit,
43694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	.encrypt_mpdu		= rtllib_ccmp_encrypt,
43794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	.decrypt_mpdu		= rtllib_ccmp_decrypt,
438ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	.encrypt_msdu		= NULL,
439ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	.decrypt_msdu		= NULL,
44094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	.set_key		= rtllib_ccmp_set_key,
44194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	.get_key		= rtllib_ccmp_get_key,
44294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	.print_stats		= rtllib_ccmp_print_stats,
44332c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan	.extra_mpdu_prefix_len = CCMP_HDR_LEN,
44432c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan	.extra_mpdu_postfix_len = CCMP_MIC_LEN,
445ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	.owner			= THIS_MODULE,
446ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman};
447ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
448ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
449327ca222aeed7cda0ba1e378088e1aa4f239ca0fRashika Kheriastatic int __init rtllib_crypto_ccmp_init(void)
450ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
4513b148be0df8e45a0259d7e84001cf02e897af614Sean MacLennan	return lib80211_register_crypto_ops(&rtllib_crypt_ccmp);
452ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
453ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
454ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
455327ca222aeed7cda0ba1e378088e1aa4f239ca0fRashika Kheriastatic void __exit rtllib_crypto_ccmp_exit(void)
456ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
4573b148be0df8e45a0259d7e84001cf02e897af614Sean MacLennan	lib80211_unregister_crypto_ops(&rtllib_crypt_ccmp);
458ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
459d37e0208df563af9c6fada84e620aabed581b3a8Sean MacLennan
460d37e0208df563af9c6fada84e620aabed581b3a8Sean MacLennanmodule_init(rtllib_crypto_ccmp_init);
461d37e0208df563af9c6fada84e620aabed581b3a8Sean MacLennanmodule_exit(rtllib_crypto_ccmp_exit);
462d37e0208df563af9c6fada84e620aabed581b3a8Sean MacLennan
463d37e0208df563af9c6fada84e620aabed581b3a8Sean MacLennanMODULE_LICENSE("GPL");
464