2005-05-13 06:48:20 +04:00
/*
2008-10-29 18:35:05 +03:00
* lib80211 crypt : host - based CCMP encryption implementation for lib80211
2005-05-13 06:48:20 +04:00
*
2007-03-25 04:15:30 +04:00
* Copyright ( c ) 2003 - 2004 , Jouni Malinen < j @ w1 . fi >
2008-10-29 18:35:05 +03:00
* Copyright ( c ) 2008 , John W . Linville < linville @ tuxdriver . com >
2005-05-13 06:48:20 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation . See README and COPYING for
* more details .
*/
2007-08-29 02:50:33 +04:00
# include <linux/kernel.h>
2006-08-22 14:36:13 +04:00
# include <linux/err.h>
2005-05-13 06:48:20 +04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/random.h>
# include <linux/skbuff.h>
# include <linux/netdevice.h>
# include <linux/if_ether.h>
# include <linux/if_arp.h>
# include <asm/string.h>
# include <linux/wireless.h>
2008-10-29 18:35:05 +03:00
# include <linux/ieee80211.h>
2005-05-13 06:48:20 +04:00
# include <linux/crypto.h>
2008-10-29 18:35:05 +03:00
# include <net/lib80211.h>
2005-05-13 06:48:20 +04:00
MODULE_AUTHOR ( " Jouni Malinen " ) ;
MODULE_DESCRIPTION ( " Host AP crypt: CCMP " ) ;
MODULE_LICENSE ( " GPL " ) ;
# define AES_BLOCK_LEN 16
# define CCMP_HDR_LEN 8
# define CCMP_MIC_LEN 8
# define CCMP_TK_LEN 16
# define CCMP_PN_LEN 6
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data {
2005-05-13 06:48:20 +04:00
u8 key [ CCMP_TK_LEN ] ;
int key_set ;
u8 tx_pn [ CCMP_PN_LEN ] ;
u8 rx_pn [ CCMP_PN_LEN ] ;
u32 dot11RSNAStatsCCMPFormatErrors ;
u32 dot11RSNAStatsCCMPReplays ;
u32 dot11RSNAStatsCCMPDecryptErrors ;
int key_idx ;
2006-08-22 14:36:13 +04:00
struct crypto_cipher * tfm ;
2005-05-13 06:48:20 +04:00
/* scratch buffers for virt_to_page() (crypto API) */
u8 tx_b0 [ AES_BLOCK_LEN ] , tx_b [ AES_BLOCK_LEN ] ,
2005-09-07 08:48:31 +04:00
tx_e [ AES_BLOCK_LEN ] , tx_s0 [ AES_BLOCK_LEN ] ;
2005-05-13 06:48:20 +04:00
u8 rx_b0 [ AES_BLOCK_LEN ] , rx_b [ AES_BLOCK_LEN ] , rx_a [ AES_BLOCK_LEN ] ;
} ;
2008-10-29 18:35:05 +03:00
static inline void lib80211_ccmp_aes_encrypt ( struct crypto_cipher * tfm ,
2006-08-22 14:36:13 +04:00
const u8 pt [ 16 ] , u8 ct [ 16 ] )
2005-05-13 06:48:20 +04:00
{
2006-08-22 14:36:13 +04:00
crypto_cipher_encrypt_one ( tfm , ct , pt ) ;
2005-05-13 06:48:20 +04:00
}
2008-10-29 18:35:05 +03:00
static void * lib80211_ccmp_init ( int key_idx )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * priv ;
2005-05-13 06:48:20 +04:00
2006-07-22 01:51:30 +04:00
priv = kzalloc ( sizeof ( * priv ) , GFP_ATOMIC ) ;
2005-05-13 06:48:20 +04:00
if ( priv = = NULL )
goto fail ;
priv - > key_idx = key_idx ;
2006-08-22 14:36:13 +04:00
priv - > tfm = crypto_alloc_cipher ( " aes " , 0 , CRYPTO_ALG_ASYNC ) ;
if ( IS_ERR ( priv - > tfm ) ) {
priv - > tfm = NULL ;
2005-05-13 06:48:20 +04:00
goto fail ;
}
return priv ;
2005-09-07 08:48:31 +04:00
fail :
2005-05-13 06:48:20 +04:00
if ( priv ) {
if ( priv - > tfm )
2006-08-22 14:36:13 +04:00
crypto_free_cipher ( priv - > tfm ) ;
2005-05-13 06:48:20 +04:00
kfree ( priv ) ;
}
return NULL ;
}
2008-10-29 18:35:05 +03:00
static void lib80211_ccmp_deinit ( void * priv )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * _priv = priv ;
2005-05-13 06:48:20 +04:00
if ( _priv & & _priv - > tfm )
2006-08-22 14:36:13 +04:00
crypto_free_cipher ( _priv - > tfm ) ;
2005-05-13 06:48:20 +04:00
kfree ( priv ) ;
}
2005-09-07 08:48:31 +04:00
static inline void xor_block ( u8 * b , u8 * a , size_t len )
2005-05-13 06:48:20 +04:00
{
int i ;
for ( i = 0 ; i < len ; i + + )
b [ i ] ^ = a [ i ] ;
}
2006-08-22 14:36:13 +04:00
static void ccmp_init_blocks ( struct crypto_cipher * tfm ,
2008-10-29 18:35:05 +03:00
struct ieee80211_hdr * hdr ,
2005-09-07 08:48:31 +04:00
u8 * pn , size_t dlen , u8 * b0 , u8 * auth , u8 * s0 )
2005-05-13 06:48:20 +04:00
{
u8 * pos , qc = 0 ;
size_t aad_len ;
int a4_included , qc_included ;
u8 aad [ 2 * AES_BLOCK_LEN ] ;
2008-10-29 18:35:05 +03:00
a4_included = ieee80211_has_a4 ( hdr - > frame_control ) ;
qc_included = ieee80211_is_data_qos ( hdr - > frame_control ) ;
2005-05-13 06:48:20 +04:00
aad_len = 22 ;
if ( a4_included )
aad_len + = 6 ;
if ( qc_included ) {
2005-09-07 08:48:31 +04:00
pos = ( u8 * ) & hdr - > addr4 ;
2005-05-13 06:48:20 +04:00
if ( a4_included )
pos + = 6 ;
qc = * pos & 0x0f ;
aad_len + = 2 ;
}
/* CCM Initial Block:
* Flag ( Include authentication header , M = 3 ( 8 - octet MIC ) ,
* L = 1 ( 2 - octet Dlen ) )
* Nonce : 0x00 | A2 | PN
* Dlen */
b0 [ 0 ] = 0x59 ;
b0 [ 1 ] = qc ;
memcpy ( b0 + 2 , hdr - > addr2 , ETH_ALEN ) ;
memcpy ( b0 + 8 , pn , CCMP_PN_LEN ) ;
b0 [ 14 ] = ( dlen > > 8 ) & 0xff ;
b0 [ 15 ] = dlen & 0xff ;
/* AAD:
* FC with bits 4. .6 and 11. .13 masked to zero ; 14 is always one
* A1 | A2 | A3
* SC with bits 4. .15 ( seq # ) masked to zero
* A4 ( if present )
* QC ( if present )
*/
pos = ( u8 * ) hdr ;
2005-09-07 08:48:31 +04:00
aad [ 0 ] = 0 ; /* aad_len >> 8 */
2005-05-13 06:48:20 +04:00
aad [ 1 ] = aad_len & 0xff ;
aad [ 2 ] = pos [ 0 ] & 0x8f ;
aad [ 3 ] = pos [ 1 ] & 0xc7 ;
memcpy ( aad + 4 , hdr - > addr1 , 3 * ETH_ALEN ) ;
2008-10-29 18:35:05 +03:00
pos = ( u8 * ) & hdr - > seq_ctrl ;
2005-05-13 06:48:20 +04:00
aad [ 22 ] = pos [ 0 ] & 0x0f ;
2005-09-07 08:48:31 +04:00
aad [ 23 ] = 0 ; /* all bits masked */
2005-05-13 06:48:20 +04:00
memset ( aad + 24 , 0 , 8 ) ;
if ( a4_included )
memcpy ( aad + 24 , hdr - > addr4 , ETH_ALEN ) ;
if ( qc_included ) {
aad [ a4_included ? 30 : 24 ] = qc ;
/* rest of QC masked */
}
/* Start with the first block and AAD */
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( tfm , b0 , auth ) ;
2005-05-13 06:48:20 +04:00
xor_block ( auth , aad , AES_BLOCK_LEN ) ;
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( tfm , auth , auth ) ;
2005-05-13 06:48:20 +04:00
xor_block ( auth , & aad [ AES_BLOCK_LEN ] , AES_BLOCK_LEN ) ;
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( tfm , auth , auth ) ;
2005-05-13 06:48:20 +04:00
b0 [ 0 ] & = 0x07 ;
b0 [ 14 ] = b0 [ 15 ] = 0 ;
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( tfm , b0 , s0 ) ;
2005-05-13 06:48:20 +04:00
}
2008-10-29 18:35:05 +03:00
static int lib80211_ccmp_hdr ( struct sk_buff * skb , int hdr_len ,
2006-01-19 11:22:32 +03:00
u8 * aeskey , int keylen , void * priv )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * key = priv ;
2005-09-21 20:58:49 +04:00
int i ;
u8 * pos ;
2005-05-13 06:48:20 +04:00
2005-09-21 20:58:49 +04:00
if ( skb_headroom ( skb ) < CCMP_HDR_LEN | | skb - > len < hdr_len )
2005-05-13 06:48:20 +04:00
return - 1 ;
2006-01-19 11:22:32 +03:00
if ( aeskey ! = NULL & & keylen > = CCMP_TK_LEN )
memcpy ( aeskey , key - > key , CCMP_TK_LEN ) ;
2005-05-13 06:48:20 +04:00
pos = skb_push ( skb , CCMP_HDR_LEN ) ;
memmove ( pos , pos + CCMP_HDR_LEN , hdr_len ) ;
pos + = hdr_len ;
i = CCMP_PN_LEN - 1 ;
while ( i > = 0 ) {
key - > tx_pn [ i ] + + ;
if ( key - > tx_pn [ i ] ! = 0 )
break ;
i - - ;
}
* pos + + = key - > tx_pn [ 5 ] ;
* pos + + = key - > tx_pn [ 4 ] ;
* pos + + = 0 ;
2005-09-07 08:48:31 +04:00
* pos + + = ( key - > key_idx < < 6 ) | ( 1 < < 5 ) /* Ext IV included */ ;
2005-05-13 06:48:20 +04:00
* pos + + = key - > tx_pn [ 3 ] ;
* pos + + = key - > tx_pn [ 2 ] ;
* pos + + = key - > tx_pn [ 1 ] ;
* pos + + = key - > tx_pn [ 0 ] ;
2005-09-21 20:58:49 +04:00
return CCMP_HDR_LEN ;
}
2008-10-29 18:35:05 +03:00
static int lib80211_ccmp_encrypt ( struct sk_buff * skb , int hdr_len , void * priv )
2005-09-21 20:58:49 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * key = priv ;
2005-09-21 20:58:49 +04:00
int data_len , i , blocks , last , len ;
u8 * pos , * mic ;
2008-10-29 18:35:05 +03:00
struct ieee80211_hdr * hdr ;
2005-09-21 20:58:49 +04:00
u8 * b0 = key - > tx_b0 ;
u8 * b = key - > tx_b ;
u8 * e = key - > tx_e ;
u8 * s0 = key - > tx_s0 ;
if ( skb_tailroom ( skb ) < CCMP_MIC_LEN | | skb - > len < hdr_len )
return - 1 ;
data_len = skb - > len - hdr_len ;
2008-10-29 18:35:05 +03:00
len = lib80211_ccmp_hdr ( skb , hdr_len , NULL , 0 , priv ) ;
2005-09-21 20:58:49 +04:00
if ( len < 0 )
return - 1 ;
pos = skb - > data + hdr_len + CCMP_HDR_LEN ;
2008-10-29 18:35:05 +03:00
hdr = ( struct ieee80211_hdr * ) skb - > data ;
2005-05-13 06:48:20 +04:00
ccmp_init_blocks ( key - > tfm , hdr , key - > tx_pn , data_len , b0 , b , s0 ) ;
2007-08-29 02:50:33 +04:00
blocks = DIV_ROUND_UP ( data_len , AES_BLOCK_LEN ) ;
2005-05-13 06:48:20 +04:00
last = data_len % AES_BLOCK_LEN ;
for ( i = 1 ; i < = blocks ; i + + ) {
len = ( i = = blocks & & last ) ? last : AES_BLOCK_LEN ;
/* Authentication */
xor_block ( b , pos , len ) ;
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( key - > tfm , b , b ) ;
2005-05-13 06:48:20 +04:00
/* Encryption, with counter */
b0 [ 14 ] = ( i > > 8 ) & 0xff ;
b0 [ 15 ] = i & 0xff ;
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( key - > tfm , b0 , e ) ;
2005-05-13 06:48:20 +04:00
xor_block ( pos , e , len ) ;
pos + = len ;
}
2010-02-02 16:58:53 +03:00
mic = skb_put ( skb , CCMP_MIC_LEN ) ;
2005-05-13 06:48:20 +04:00
for ( i = 0 ; i < CCMP_MIC_LEN ; i + + )
mic [ i ] = b [ i ] ^ s0 [ i ] ;
return 0 ;
}
2006-08-21 07:33:09 +04:00
/*
* deal with seq counter wrapping correctly .
* refer to timer_after ( ) for jiffies wrapping handling
*/
static inline int ccmp_replay_check ( u8 * pn_n , u8 * pn_o )
{
u32 iv32_n , iv16_n ;
u32 iv32_o , iv16_o ;
iv32_n = ( pn_n [ 0 ] < < 24 ) | ( pn_n [ 1 ] < < 16 ) | ( pn_n [ 2 ] < < 8 ) | pn_n [ 3 ] ;
iv16_n = ( pn_n [ 4 ] < < 8 ) | pn_n [ 5 ] ;
iv32_o = ( pn_o [ 0 ] < < 24 ) | ( pn_o [ 1 ] < < 16 ) | ( pn_o [ 2 ] < < 8 ) | pn_o [ 3 ] ;
iv16_o = ( pn_o [ 4 ] < < 8 ) | pn_o [ 5 ] ;
if ( ( s32 ) iv32_n - ( s32 ) iv32_o < 0 | |
( iv32_n = = iv32_o & & iv16_n < = iv16_o ) )
return 1 ;
return 0 ;
}
2008-10-29 18:35:05 +03:00
static int lib80211_ccmp_decrypt ( struct sk_buff * skb , int hdr_len , void * priv )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * key = priv ;
2005-05-13 06:48:20 +04:00
u8 keyidx , * pos ;
2008-10-29 18:35:05 +03:00
struct ieee80211_hdr * hdr ;
2005-05-13 06:48:20 +04:00
u8 * b0 = key - > rx_b0 ;
u8 * b = key - > rx_b ;
u8 * a = key - > rx_a ;
u8 pn [ 6 ] ;
int i , blocks , last , len ;
size_t data_len = skb - > len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN ;
u8 * mic = skb - > data + skb - > len - CCMP_MIC_LEN ;
if ( skb - > len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN ) {
key - > dot11RSNAStatsCCMPFormatErrors + + ;
return - 1 ;
}
2008-10-29 18:35:05 +03:00
hdr = ( struct ieee80211_hdr * ) skb - > data ;
2005-05-13 06:48:20 +04:00
pos = skb - > data + hdr_len ;
keyidx = pos [ 3 ] ;
if ( ! ( keyidx & ( 1 < < 5 ) ) ) {
2012-05-14 01:56:26 +04:00
net_dbg_ratelimited ( " CCMP: received packet without ExtIV flag from %pM \n " ,
hdr - > addr2 ) ;
2005-05-13 06:48:20 +04:00
key - > dot11RSNAStatsCCMPFormatErrors + + ;
return - 2 ;
}
keyidx > > = 6 ;
if ( key - > key_idx ! = keyidx ) {
printk ( KERN_DEBUG " CCMP: RX tkey->key_idx=%d frame "
" keyidx=%d priv=%p \n " , key - > key_idx , keyidx , priv ) ;
return - 6 ;
}
if ( ! key - > key_set ) {
2012-05-14 01:56:26 +04:00
net_dbg_ratelimited ( " CCMP: received packet from %pM with keyid=%d that does not have a configured key \n " ,
hdr - > addr2 , keyidx ) ;
2005-05-13 06:48:20 +04:00
return - 3 ;
}
pn [ 0 ] = pos [ 7 ] ;
pn [ 1 ] = pos [ 6 ] ;
pn [ 2 ] = pos [ 5 ] ;
pn [ 3 ] = pos [ 4 ] ;
pn [ 4 ] = pos [ 1 ] ;
pn [ 5 ] = pos [ 0 ] ;
pos + = 8 ;
2006-08-21 07:33:09 +04:00
if ( ccmp_replay_check ( pn , key - > rx_pn ) ) {
2009-03-11 18:05:25 +03:00
# ifdef CONFIG_LIB80211_DEBUG
2012-05-14 01:56:26 +04:00
net_dbg_ratelimited ( " CCMP: replay detected: STA=%pM previous PN %02x%02x%02x%02x%02x%02x received PN %02x%02x%02x%02x%02x%02x \n " ,
hdr - > addr2 ,
key - > rx_pn [ 0 ] , key - > rx_pn [ 1 ] , key - > rx_pn [ 2 ] ,
key - > rx_pn [ 3 ] , key - > rx_pn [ 4 ] , key - > rx_pn [ 5 ] ,
pn [ 0 ] , pn [ 1 ] , pn [ 2 ] , pn [ 3 ] , pn [ 4 ] , pn [ 5 ] ) ;
2009-03-11 18:05:25 +03:00
# endif
2005-05-13 06:48:20 +04:00
key - > dot11RSNAStatsCCMPReplays + + ;
return - 4 ;
}
ccmp_init_blocks ( key - > tfm , hdr , pn , data_len , b0 , a , b ) ;
xor_block ( mic , b , CCMP_MIC_LEN ) ;
2007-08-29 02:50:33 +04:00
blocks = DIV_ROUND_UP ( data_len , AES_BLOCK_LEN ) ;
2005-05-13 06:48:20 +04:00
last = data_len % AES_BLOCK_LEN ;
for ( i = 1 ; i < = blocks ; i + + ) {
len = ( i = = blocks & & last ) ? last : AES_BLOCK_LEN ;
/* Decrypt, with counter */
b0 [ 14 ] = ( i > > 8 ) & 0xff ;
b0 [ 15 ] = i & 0xff ;
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( key - > tfm , b0 , b ) ;
2005-05-13 06:48:20 +04:00
xor_block ( pos , b , len ) ;
/* Authentication */
xor_block ( a , pos , len ) ;
2008-10-29 18:35:05 +03:00
lib80211_ccmp_aes_encrypt ( key - > tfm , a , a ) ;
2005-05-13 06:48:20 +04:00
pos + = len ;
}
if ( memcmp ( mic , a , CCMP_MIC_LEN ) ! = 0 ) {
2012-05-14 01:56:26 +04:00
net_dbg_ratelimited ( " CCMP: decrypt failed: STA=%pM \n " ,
hdr - > addr2 ) ;
2005-05-13 06:48:20 +04:00
key - > dot11RSNAStatsCCMPDecryptErrors + + ;
return - 5 ;
}
memcpy ( key - > rx_pn , pn , CCMP_PN_LEN ) ;
/* Remove hdr and MIC */
memmove ( skb - > data + CCMP_HDR_LEN , skb - > data , hdr_len ) ;
skb_pull ( skb , CCMP_HDR_LEN ) ;
skb_trim ( skb , skb - > len - CCMP_MIC_LEN ) ;
return keyidx ;
}
2008-10-29 18:35:05 +03:00
static int lib80211_ccmp_set_key ( void * key , int len , u8 * seq , void * priv )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * data = priv ;
2005-05-13 06:48:20 +04:00
int keyidx ;
2006-08-22 14:36:13 +04:00
struct crypto_cipher * tfm = data - > tfm ;
2005-05-13 06:48:20 +04:00
keyidx = data - > key_idx ;
memset ( data , 0 , sizeof ( * data ) ) ;
data - > key_idx = keyidx ;
data - > tfm = tfm ;
if ( len = = CCMP_TK_LEN ) {
memcpy ( data - > key , key , CCMP_TK_LEN ) ;
data - > key_set = 1 ;
if ( seq ) {
data - > rx_pn [ 0 ] = seq [ 5 ] ;
data - > rx_pn [ 1 ] = seq [ 4 ] ;
data - > rx_pn [ 2 ] = seq [ 3 ] ;
data - > rx_pn [ 3 ] = seq [ 2 ] ;
data - > rx_pn [ 4 ] = seq [ 1 ] ;
data - > rx_pn [ 5 ] = seq [ 0 ] ;
}
crypto_cipher_setkey ( data - > tfm , data - > key , CCMP_TK_LEN ) ;
} else if ( len = = 0 )
data - > key_set = 0 ;
else
return - 1 ;
return 0 ;
}
2008-10-29 18:35:05 +03:00
static int lib80211_ccmp_get_key ( void * key , int len , u8 * seq , void * priv )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * data = priv ;
2005-05-13 06:48:20 +04:00
if ( len < CCMP_TK_LEN )
return - 1 ;
if ( ! data - > key_set )
return 0 ;
memcpy ( key , data - > key , CCMP_TK_LEN ) ;
if ( seq ) {
seq [ 0 ] = data - > tx_pn [ 5 ] ;
seq [ 1 ] = data - > tx_pn [ 4 ] ;
seq [ 2 ] = data - > tx_pn [ 3 ] ;
seq [ 3 ] = data - > tx_pn [ 2 ] ;
seq [ 4 ] = data - > tx_pn [ 1 ] ;
seq [ 5 ] = data - > tx_pn [ 0 ] ;
}
return CCMP_TK_LEN ;
}
2013-04-11 00:13:23 +04:00
static void lib80211_ccmp_print_stats ( struct seq_file * m , void * priv )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
struct lib80211_ccmp_data * ccmp = priv ;
2007-10-04 04:59:30 +04:00
2013-04-11 00:13:23 +04:00
seq_printf ( m ,
" key[%d] alg=CCMP key_set=%d "
" tx_pn=%02x%02x%02x%02x%02x%02x "
" rx_pn=%02x%02x%02x%02x%02x%02x "
" format_errors=%d replays=%d decrypt_errors=%d \n " ,
ccmp - > key_idx , ccmp - > key_set ,
ccmp - > tx_pn [ 0 ] , ccmp - > tx_pn [ 1 ] , ccmp - > tx_pn [ 2 ] ,
ccmp - > tx_pn [ 3 ] , ccmp - > tx_pn [ 4 ] , ccmp - > tx_pn [ 5 ] ,
ccmp - > rx_pn [ 0 ] , ccmp - > rx_pn [ 1 ] , ccmp - > rx_pn [ 2 ] ,
ccmp - > rx_pn [ 3 ] , ccmp - > rx_pn [ 4 ] , ccmp - > rx_pn [ 5 ] ,
ccmp - > dot11RSNAStatsCCMPFormatErrors ,
ccmp - > dot11RSNAStatsCCMPReplays ,
ccmp - > dot11RSNAStatsCCMPDecryptErrors ) ;
2005-05-13 06:48:20 +04:00
}
2008-10-29 18:35:05 +03:00
static struct lib80211_crypto_ops lib80211_crypt_ccmp = {
2005-09-14 02:35:21 +04:00
. name = " CCMP " ,
2008-10-29 18:35:05 +03:00
. init = lib80211_ccmp_init ,
. deinit = lib80211_ccmp_deinit ,
. encrypt_mpdu = lib80211_ccmp_encrypt ,
. decrypt_mpdu = lib80211_ccmp_decrypt ,
2005-09-14 02:35:21 +04:00
. encrypt_msdu = NULL ,
. decrypt_msdu = NULL ,
2008-10-29 18:35:05 +03:00
. set_key = lib80211_ccmp_set_key ,
. get_key = lib80211_ccmp_get_key ,
. print_stats = lib80211_ccmp_print_stats ,
2005-09-21 20:54:53 +04:00
. extra_mpdu_prefix_len = CCMP_HDR_LEN ,
. extra_mpdu_postfix_len = CCMP_MIC_LEN ,
2005-09-14 02:35:21 +04:00
. owner = THIS_MODULE ,
2005-05-13 06:48:20 +04:00
} ;
2008-10-29 18:35:05 +03:00
static int __init lib80211_crypto_ccmp_init ( void )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
return lib80211_register_crypto_ops ( & lib80211_crypt_ccmp ) ;
2005-05-13 06:48:20 +04:00
}
2008-10-29 18:35:05 +03:00
static void __exit lib80211_crypto_ccmp_exit ( void )
2005-05-13 06:48:20 +04:00
{
2008-10-29 18:35:05 +03:00
lib80211_unregister_crypto_ops ( & lib80211_crypt_ccmp ) ;
2005-05-13 06:48:20 +04:00
}
2008-10-29 18:35:05 +03:00
module_init ( lib80211_crypto_ccmp_init ) ;
module_exit ( lib80211_crypto_ccmp_exit ) ;