2007-05-05 11:45:53 -07:00
/*
* Copyright 2002 - 2004 , Instant802 Networks , Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/netdevice.h>
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/skbuff.h>
# include <linux/compiler.h>
2008-07-02 11:05:35 -07:00
# include <linux/ieee80211.h>
# include <asm/unaligned.h>
2007-05-05 11:45:53 -07:00
# include <net/mac80211.h>
2007-08-28 17:01:53 -04:00
2007-05-05 11:45:53 -07:00
# include "ieee80211_i.h"
# include "michael.h"
# include "tkip.h"
# include "aes_ccm.h"
# include "wpa.h"
2008-01-31 19:48:20 +01:00
ieee80211_tx_result
2008-02-25 16:27:43 +01:00
ieee80211_tx_h_michael_mic_add ( struct ieee80211_tx_data * tx )
2007-05-05 11:45:53 -07:00
{
2008-07-02 11:05:35 -07:00
u8 * data , * key , * mic , key_offset ;
2007-05-05 11:45:53 -07:00
size_t data_len ;
2008-07-02 11:05:35 -07:00
unsigned int hdrlen ;
struct ieee80211_hdr * hdr ;
2007-05-05 11:45:53 -07:00
struct sk_buff * skb = tx - > skb ;
int authenticator ;
int wpa_test = 0 ;
2008-05-29 10:38:53 +02:00
int tail ;
2007-05-05 11:45:53 -07:00
2008-07-02 16:30:52 -07:00
hdr = ( struct ieee80211_hdr * ) skb - > data ;
2007-08-28 17:01:54 -04:00
if ( ! tx - > key | | tx - > key - > conf . alg ! = ALG_TKIP | | skb - > len < 24 | |
2008-07-02 16:30:52 -07:00
! ieee80211_is_data_present ( hdr - > frame_control ) )
2008-01-31 19:48:20 +01:00
return TX_CONTINUE ;
2007-05-05 11:45:53 -07:00
2008-07-02 11:05:35 -07:00
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
if ( skb - > len < hdrlen )
2008-01-31 19:48:20 +01:00
return TX_DROP ;
2007-05-05 11:45:53 -07:00
2008-07-02 11:05:35 -07:00
data = skb - > data + hdrlen ;
data_len = skb - > len - hdrlen ;
2007-08-28 17:01:55 -04:00
if ( ( tx - > key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE ) & &
2008-02-25 16:27:43 +01:00
! ( tx - > flags & IEEE80211_TX_FRAGMENTED ) & &
2007-09-14 11:10:25 -04:00
! ( tx - > key - > conf . flags & IEEE80211_KEY_FLAG_GENERATE_MMIC ) & &
2007-05-05 11:45:53 -07:00
! wpa_test ) {
2008-10-07 12:04:32 +02:00
/* hwaccel - with no need for preallocated room for MMIC */
2008-01-31 19:48:20 +01:00
return TX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}
2008-05-29 10:38:53 +02:00
tail = MICHAEL_MIC_LEN ;
if ( ! ( tx - > key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE ) )
tail + = TKIP_ICV_LEN ;
if ( WARN_ON ( skb_tailroom ( skb ) < tail | |
skb_headroom ( skb ) < TKIP_IV_LEN ) )
return TX_DROP ;
2007-05-05 11:45:53 -07:00
#if 0
authenticator = fc & IEEE80211_FCTL_FROMDS ; /* FIX */
# else
authenticator = 1 ;
# endif
2008-06-21 10:02:46 -04:00
key_offset = authenticator ?
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY ;
key = & tx - > key - > conf . key [ key_offset ] ;
2007-05-05 11:45:53 -07:00
mic = skb_put ( skb , MICHAEL_MIC_LEN ) ;
2008-07-02 11:05:35 -07:00
michael_mic ( key , hdr , data , data_len , mic ) ;
2007-05-05 11:45:53 -07:00
2008-01-31 19:48:20 +01:00
return TX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}
2008-01-31 19:48:20 +01:00
ieee80211_rx_result
2008-02-25 16:27:43 +01:00
ieee80211_rx_h_michael_mic_verify ( struct ieee80211_rx_data * rx )
2007-05-05 11:45:53 -07:00
{
2008-07-02 11:05:35 -07:00
u8 * data , * key = NULL , key_offset ;
2007-05-05 11:45:53 -07:00
size_t data_len ;
2008-07-02 11:05:35 -07:00
unsigned int hdrlen ;
struct ieee80211_hdr * hdr ;
2007-05-05 11:45:53 -07:00
u8 mic [ MICHAEL_MIC_LEN ] ;
struct sk_buff * skb = rx - > skb ;
int authenticator = 1 , wpa_test = 0 ;
2008-10-07 12:04:32 +02:00
/* No way to verify the MIC if the hardware stripped it */
2008-02-25 16:27:43 +01:00
if ( rx - > status - > flag & RX_FLAG_MMIC_STRIPPED )
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
2008-07-02 16:30:52 -07:00
hdr = ( struct ieee80211_hdr * ) skb - > data ;
2007-08-28 17:01:54 -04:00
if ( ! rx - > key | | rx - > key - > conf . alg ! = ALG_TKIP | |
2008-07-02 16:30:52 -07:00
! ieee80211_has_protected ( hdr - > frame_control ) | |
! ieee80211_is_data_present ( hdr - > frame_control ) )
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
2008-07-02 11:05:35 -07:00
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
if ( skb - > len < hdrlen + MICHAEL_MIC_LEN )
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
2008-07-02 11:05:35 -07:00
data = skb - > data + hdrlen ;
data_len = skb - > len - hdrlen - MICHAEL_MIC_LEN ;
2007-05-05 11:45:53 -07:00
#if 0
authenticator = fc & IEEE80211_FCTL_TODS ; /* FIX */
# else
authenticator = 1 ;
# endif
2008-06-21 10:02:46 -04:00
key_offset = authenticator ?
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY ;
key = & rx - > key - > conf . key [ key_offset ] ;
2008-07-02 11:05:35 -07:00
michael_mic ( key , hdr , data , data_len , mic ) ;
2007-05-05 11:45:53 -07:00
if ( memcmp ( mic , data + data_len , MICHAEL_MIC_LEN ) ! = 0 | | wpa_test ) {
2008-02-25 16:27:43 +01:00
if ( ! ( rx - > flags & IEEE80211_RX_RA_MATCH ) )
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
2008-08-03 12:04:37 +12:00
mac80211_ev_michael_mic_failure ( rx - > sdata , rx - > key - > conf . keyidx ,
2007-08-28 17:01:53 -04:00
( void * ) skb - > data ) ;
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
}
/* remove Michael MIC from payload */
skb_trim ( skb , skb - > len - MICHAEL_MIC_LEN ) ;
2007-09-26 15:19:45 +02:00
/* update IV in key information to be able to detect replays */
2008-05-14 16:26:19 -07:00
rx - > key - > u . tkip . rx [ rx - > queue ] . iv32 = rx - > tkip_iv32 ;
rx - > key - > u . tkip . rx [ rx - > queue ] . iv16 = rx - > tkip_iv16 ;
2007-09-26 15:19:45 +02:00
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}
2008-05-15 12:55:29 +02:00
static int tkip_encrypt_skb ( struct ieee80211_tx_data * tx , struct sk_buff * skb )
2007-05-05 11:45:53 -07:00
{
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
struct ieee80211_key * key = tx - > key ;
2008-05-15 12:55:29 +02:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2008-06-11 14:21:58 -07:00
unsigned int hdrlen ;
int len , tail ;
2007-05-05 11:45:53 -07:00
u8 * pos ;
2008-05-15 12:55:29 +02:00
if ( ( tx - > key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE ) & &
! ( tx - > key - > conf . flags & IEEE80211_KEY_FLAG_GENERATE_IV ) ) {
/* hwaccel - with no need for preallocated room for IV/ICV */
info - > control . hw_key = & tx - > key - > conf ;
2008-05-29 10:38:53 +02:00
return 0 ;
2008-05-15 12:55:29 +02:00
}
2008-06-11 14:21:58 -07:00
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
2007-05-05 11:45:53 -07:00
len = skb - > len - hdrlen ;
2007-08-28 17:01:55 -04:00
if ( tx - > key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE )
2008-05-29 10:38:53 +02:00
tail = 0 ;
2007-08-28 17:01:55 -04:00
else
2008-05-29 10:38:53 +02:00
tail = TKIP_ICV_LEN ;
if ( WARN_ON ( skb_tailroom ( skb ) < tail | |
skb_headroom ( skb ) < TKIP_IV_LEN ) )
return - 1 ;
2007-05-05 11:45:53 -07:00
pos = skb_push ( skb , TKIP_IV_LEN ) ;
memmove ( pos , pos + TKIP_IV_LEN , hdrlen ) ;
pos + = hdrlen ;
/* Increase IV for the frame */
2008-05-14 16:26:19 -07:00
key - > u . tkip . tx . iv16 + + ;
if ( key - > u . tkip . tx . iv16 = = 0 )
key - > u . tkip . tx . iv32 + + ;
2007-05-05 11:45:53 -07:00
2007-08-28 17:01:55 -04:00
if ( tx - > key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE ) {
2007-05-05 11:45:53 -07:00
/* hwaccel - with preallocated room for IV */
2008-06-11 14:22:00 -07:00
ieee80211_tkip_add_iv ( pos , key , key - > u . tkip . tx . iv16 ) ;
2007-05-05 11:45:53 -07:00
2008-05-15 12:55:29 +02:00
info - > control . hw_key = & tx - > key - > conf ;
2007-05-05 11:45:53 -07:00
return 0 ;
}
/* Add room for ICV */
skb_put ( skb , TKIP_ICV_LEN ) ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
ieee80211_tkip_encrypt_data ( tx - > local - > wep_tx_tfm ,
key , pos , len , hdr - > addr2 ) ;
return 0 ;
}
2008-01-31 19:48:20 +01:00
ieee80211_tx_result
2008-02-25 16:27:43 +01:00
ieee80211_crypto_tkip_encrypt ( struct ieee80211_tx_data * tx )
2007-05-05 11:45:53 -07:00
{
struct sk_buff * skb = tx - > skb ;
2008-10-07 12:04:32 +02:00
int i ;
2007-05-05 11:45:53 -07:00
2008-02-25 16:27:43 +01:00
ieee80211_tx_set_protected ( tx ) ;
2007-05-05 11:45:53 -07:00
2008-05-15 12:55:29 +02:00
if ( tkip_encrypt_skb ( tx , skb ) < 0 )
2008-01-31 19:48:20 +01:00
return TX_DROP ;
2007-05-05 11:45:53 -07:00
2008-02-25 16:27:43 +01:00
if ( tx - > extra_frag ) {
for ( i = 0 ; i < tx - > num_extra_frag ; i + + ) {
2008-10-07 12:04:32 +02:00
if ( tkip_encrypt_skb ( tx , tx - > extra_frag [ i ] ) )
2008-01-31 19:48:20 +01:00
return TX_DROP ;
2007-05-05 11:45:53 -07:00
}
}
2008-01-31 19:48:20 +01:00
return TX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}
2008-01-31 19:48:20 +01:00
ieee80211_rx_result
2008-02-25 16:27:43 +01:00
ieee80211_crypto_tkip_decrypt ( struct ieee80211_rx_data * rx )
2007-05-05 11:45:53 -07:00
{
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) rx - > skb - > data ;
int hdrlen , res , hwaccel = 0 , wpa_test = 0 ;
struct ieee80211_key * key = rx - > key ;
struct sk_buff * skb = rx - > skb ;
2008-06-11 14:21:58 -07:00
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
2007-05-05 11:45:53 -07:00
2008-07-02 16:30:52 -07:00
if ( ! ieee80211_is_data ( hdr - > frame_control ) )
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
if ( ! rx - > sta | | skb - > len - hdrlen < 12 )
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
2008-02-25 16:27:43 +01:00
if ( rx - > status - > flag & RX_FLAG_DECRYPTED ) {
if ( rx - > status - > flag & RX_FLAG_IV_STRIPPED ) {
2007-09-14 11:10:25 -04:00
/*
* Hardware took care of all processing , including
* replay protection , and stripped the ICV / IV so
* we cannot do any checks here .
*/
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}
/* let TKIP code verify IV, but skip decryption */
hwaccel = 1 ;
}
res = ieee80211_tkip_decrypt_data ( rx - > local - > wep_rx_tfm ,
key , skb - > data + hdrlen ,
2008-09-11 00:02:02 +02:00
skb - > len - hdrlen , rx - > sta - > sta . addr ,
2008-03-20 15:06:42 +02:00
hdr - > addr1 , hwaccel , rx - > queue ,
2008-02-25 16:27:43 +01:00
& rx - > tkip_iv32 ,
& rx - > tkip_iv16 ) ;
2008-06-30 15:10:46 +02:00
if ( res ! = TKIP_DECRYPT_OK | | wpa_test )
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
/* Trim ICV */
skb_trim ( skb , skb - > len - TKIP_ICV_LEN ) ;
/* Remove IV */
memmove ( skb - > data + TKIP_IV_LEN , skb - > data , hdrlen ) ;
skb_pull ( skb , TKIP_IV_LEN ) ;
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}
2008-07-02 16:30:52 -07:00
static void ccmp_special_blocks ( struct sk_buff * skb , u8 * pn , u8 * scratch ,
2007-05-05 11:45:53 -07:00
int encrypted )
{
2008-07-02 11:05:35 -07:00
__le16 mask_fc ;
int a4_included ;
u8 qos_tid ;
2008-07-02 16:30:52 -07:00
u8 * b_0 , * aad ;
2008-07-02 11:05:35 -07:00
u16 data_len , len_a ;
unsigned int hdrlen ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2007-05-05 11:45:53 -07:00
2008-07-02 16:30:52 -07:00
b_0 = scratch + 3 * AES_BLOCK_LEN ;
aad = scratch + 4 * AES_BLOCK_LEN ;
2008-07-02 11:05:35 -07:00
/*
* Mask FC : zero subtype b4 b5 b6
* Retry , PwrMgt , MoreData ; set Protected
*/
mask_fc = hdr - > frame_control ;
mask_fc & = ~ cpu_to_le16 ( 0x0070 | IEEE80211_FCTL_RETRY |
IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA ) ;
mask_fc | = cpu_to_le16 ( IEEE80211_FCTL_PROTECTED ) ;
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
len_a = hdrlen - 2 ;
a4_included = ieee80211_has_a4 ( hdr - > frame_control ) ;
2007-05-05 11:45:53 -07:00
2008-07-02 11:05:35 -07:00
if ( ieee80211_is_data_qos ( hdr - > frame_control ) )
qos_tid = * ieee80211_get_qos_ctl ( hdr ) & IEEE80211_QOS_CTL_TID_MASK ;
else
qos_tid = 0 ;
data_len = skb - > len - hdrlen - CCMP_HDR_LEN ;
if ( encrypted )
data_len - = CCMP_MIC_LEN ;
/* First block, b_0 */
2007-05-05 11:45:53 -07:00
b_0 [ 0 ] = 0x59 ; /* flags: Adata: 1, M: 011, L: 001 */
/* Nonce: QoS Priority | A2 | PN */
b_0 [ 1 ] = qos_tid ;
2008-07-02 11:05:34 -07:00
memcpy ( & b_0 [ 2 ] , hdr - > addr2 , ETH_ALEN ) ;
2007-05-05 11:45:53 -07:00
memcpy ( & b_0 [ 8 ] , pn , CCMP_PN_LEN ) ;
/* l(m) */
2008-07-02 11:05:35 -07:00
put_unaligned_be16 ( data_len , & b_0 [ 14 ] ) ;
2007-05-05 11:45:53 -07:00
/* AAD (extra authenticate-only data) / masked 802.11 header
* FC | A1 | A2 | A3 | SC | [ A4 ] | [ QC ] */
2008-07-02 11:05:35 -07:00
put_unaligned_be16 ( len_a , & aad [ 0 ] ) ;
put_unaligned ( mask_fc , ( __le16 * ) & aad [ 2 ] ) ;
2008-07-02 11:05:34 -07:00
memcpy ( & aad [ 4 ] , & hdr - > addr1 , 3 * ETH_ALEN ) ;
2007-05-05 11:45:53 -07:00
/* Mask Seq#, leave Frag# */
aad [ 22 ] = * ( ( u8 * ) & hdr - > seq_ctrl ) & 0x0f ;
aad [ 23 ] = 0 ;
2008-07-02 11:05:35 -07:00
2007-05-05 11:45:53 -07:00
if ( a4_included ) {
2008-07-02 11:05:34 -07:00
memcpy ( & aad [ 24 ] , hdr - > addr4 , ETH_ALEN ) ;
2008-07-02 11:05:35 -07:00
aad [ 30 ] = qos_tid ;
2007-05-05 11:45:53 -07:00
aad [ 31 ] = 0 ;
2008-07-02 11:05:35 -07:00
} else {
2008-07-02 11:05:34 -07:00
memset ( & aad [ 24 ] , 0 , ETH_ALEN + IEEE80211_QOS_CTL_LEN ) ;
2008-07-02 11:05:35 -07:00
aad [ 24 ] = qos_tid ;
2007-05-05 11:45:53 -07:00
}
}
static inline void ccmp_pn2hdr ( u8 * hdr , u8 * pn , int key_id )
{
hdr [ 0 ] = pn [ 5 ] ;
hdr [ 1 ] = pn [ 4 ] ;
hdr [ 2 ] = 0 ;
hdr [ 3 ] = 0x20 | ( key_id < < 6 ) ;
hdr [ 4 ] = pn [ 3 ] ;
hdr [ 5 ] = pn [ 2 ] ;
hdr [ 6 ] = pn [ 1 ] ;
hdr [ 7 ] = pn [ 0 ] ;
}
2008-10-07 12:04:32 +02:00
static inline void ccmp_hdr2pn ( u8 * pn , u8 * hdr )
2007-05-05 11:45:53 -07:00
{
pn [ 0 ] = hdr [ 7 ] ;
pn [ 1 ] = hdr [ 6 ] ;
pn [ 2 ] = hdr [ 5 ] ;
pn [ 3 ] = hdr [ 4 ] ;
pn [ 4 ] = hdr [ 1 ] ;
pn [ 5 ] = hdr [ 0 ] ;
}
2008-05-15 12:55:29 +02:00
static int ccmp_encrypt_skb ( struct ieee80211_tx_data * tx , struct sk_buff * skb )
2007-05-05 11:45:53 -07:00
{
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
struct ieee80211_key * key = tx - > key ;
2008-05-15 12:55:29 +02:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
2008-05-29 10:38:53 +02:00
int hdrlen , len , tail ;
2008-07-02 16:30:52 -07:00
u8 * pos , * pn ;
2007-05-05 11:45:53 -07:00
int i ;
2008-05-15 12:55:29 +02:00
if ( ( tx - > key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE ) & &
! ( tx - > key - > conf . flags & IEEE80211_KEY_FLAG_GENERATE_IV ) ) {
2008-10-07 12:04:32 +02:00
/* hwaccel - with no need for preallocated room for CCMP
2008-05-15 12:55:29 +02:00
* header or MIC fields */
info - > control . hw_key = & tx - > key - > conf ;
2008-05-29 10:38:53 +02:00
return 0 ;
2008-05-15 12:55:29 +02:00
}
2008-06-11 14:21:58 -07:00
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
2007-05-05 11:45:53 -07:00
len = skb - > len - hdrlen ;
2007-08-28 17:01:55 -04:00
if ( key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE )
2008-05-29 10:38:53 +02:00
tail = 0 ;
2007-08-28 17:01:55 -04:00
else
2008-05-29 10:38:53 +02:00
tail = CCMP_MIC_LEN ;
if ( WARN_ON ( skb_tailroom ( skb ) < tail | |
skb_headroom ( skb ) < CCMP_HDR_LEN ) )
return - 1 ;
2007-05-05 11:45:53 -07:00
pos = skb_push ( skb , CCMP_HDR_LEN ) ;
memmove ( pos , pos + CCMP_HDR_LEN , hdrlen ) ;
hdr = ( struct ieee80211_hdr * ) pos ;
pos + = hdrlen ;
/* PN = PN + 1 */
pn = key - > u . ccmp . tx_pn ;
for ( i = CCMP_PN_LEN - 1 ; i > = 0 ; i - - ) {
pn [ i ] + + ;
if ( pn [ i ] )
break ;
}
2007-08-28 17:01:54 -04:00
ccmp_pn2hdr ( pos , pn , key - > conf . keyidx ) ;
2007-05-05 11:45:53 -07:00
2007-08-28 17:01:55 -04:00
if ( key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE ) {
2007-05-05 11:45:53 -07:00
/* hwaccel - with preallocated room for CCMP header */
2008-05-15 12:55:29 +02:00
info - > control . hw_key = & tx - > key - > conf ;
2007-05-05 11:45:53 -07:00
return 0 ;
}
pos + = CCMP_HDR_LEN ;
2008-07-02 16:30:52 -07:00
ccmp_special_blocks ( skb , pn , key - > u . ccmp . tx_crypto_buf , 0 ) ;
ieee80211_aes_ccm_encrypt ( key - > u . ccmp . tfm , key - > u . ccmp . tx_crypto_buf , pos , len ,
2007-05-05 11:45:53 -07:00
pos , skb_put ( skb , CCMP_MIC_LEN ) ) ;
return 0 ;
}
2008-01-31 19:48:20 +01:00
ieee80211_tx_result
2008-02-25 16:27:43 +01:00
ieee80211_crypto_ccmp_encrypt ( struct ieee80211_tx_data * tx )
2007-05-05 11:45:53 -07:00
{
struct sk_buff * skb = tx - > skb ;
2008-10-07 12:04:32 +02:00
int i ;
2007-05-05 11:45:53 -07:00
2008-02-25 16:27:43 +01:00
ieee80211_tx_set_protected ( tx ) ;
2007-05-05 11:45:53 -07:00
2008-05-15 12:55:29 +02:00
if ( ccmp_encrypt_skb ( tx , skb ) < 0 )
2008-01-31 19:48:20 +01:00
return TX_DROP ;
2007-05-05 11:45:53 -07:00
2008-02-25 16:27:43 +01:00
if ( tx - > extra_frag ) {
for ( i = 0 ; i < tx - > num_extra_frag ; i + + ) {
2008-10-07 12:04:32 +02:00
if ( ccmp_encrypt_skb ( tx , tx - > extra_frag [ i ] ) )
2008-01-31 19:48:20 +01:00
return TX_DROP ;
2007-05-05 11:45:53 -07:00
}
}
2008-01-31 19:48:20 +01:00
return TX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}
2008-01-31 19:48:20 +01:00
ieee80211_rx_result
2008-02-25 16:27:43 +01:00
ieee80211_crypto_ccmp_decrypt ( struct ieee80211_rx_data * rx )
2007-05-05 11:45:53 -07:00
{
2008-07-02 16:30:52 -07:00
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) rx - > skb - > data ;
2007-05-05 11:45:53 -07:00
int hdrlen ;
struct ieee80211_key * key = rx - > key ;
struct sk_buff * skb = rx - > skb ;
u8 pn [ CCMP_PN_LEN ] ;
int data_len ;
2008-06-11 14:21:58 -07:00
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
2007-05-05 11:45:53 -07:00
2008-07-02 16:30:52 -07:00
if ( ! ieee80211_is_data ( hdr - > frame_control ) )
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
data_len = skb - > len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN ;
if ( ! rx - > sta | | data_len < 0 )
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
2008-02-25 16:27:43 +01:00
if ( ( rx - > status - > flag & RX_FLAG_DECRYPTED ) & &
( rx - > status - > flag & RX_FLAG_IV_STRIPPED ) )
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
2008-10-07 12:04:32 +02:00
ccmp_hdr2pn ( pn , skb - > data + hdrlen ) ;
2007-05-05 11:45:53 -07:00
2008-02-25 16:27:43 +01:00
if ( memcmp ( pn , key - > u . ccmp . rx_pn [ rx - > queue ] , CCMP_PN_LEN ) < = 0 ) {
2007-05-05 11:45:53 -07:00
key - > u . ccmp . replays + + ;
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
}
2008-02-25 16:27:43 +01:00
if ( ! ( rx - > status - > flag & RX_FLAG_DECRYPTED ) ) {
2007-09-14 11:10:25 -04:00
/* hardware didn't decrypt/verify MIC */
2008-07-02 16:30:52 -07:00
ccmp_special_blocks ( skb , pn , key - > u . ccmp . rx_crypto_buf , 1 ) ;
2007-05-05 11:45:53 -07:00
if ( ieee80211_aes_ccm_decrypt (
2008-07-02 16:30:52 -07:00
key - > u . ccmp . tfm , key - > u . ccmp . rx_crypto_buf ,
2007-05-05 11:45:53 -07:00
skb - > data + hdrlen + CCMP_HDR_LEN , data_len ,
skb - > data + skb - > len - CCMP_MIC_LEN ,
2008-10-07 12:04:32 +02:00
skb - > data + hdrlen + CCMP_HDR_LEN ) )
2008-01-31 19:48:21 +01:00
return RX_DROP_UNUSABLE ;
2007-05-05 11:45:53 -07:00
}
2008-02-25 16:27:43 +01:00
memcpy ( key - > u . ccmp . rx_pn [ rx - > queue ] , pn , CCMP_PN_LEN ) ;
2007-05-05 11:45:53 -07:00
/* Remove CCMP header and MIC */
skb_trim ( skb , skb - > len - CCMP_MIC_LEN ) ;
memmove ( skb - > data + CCMP_HDR_LEN , skb - > data , hdrlen ) ;
skb_pull ( skb , CCMP_HDR_LEN ) ;
2008-01-31 19:48:20 +01:00
return RX_CONTINUE ;
2007-05-05 11:45:53 -07:00
}