2006-01-14 03:09:34 +01:00
# include "hostap_80211.h"
# include "hostap_common.h"
# include "hostap_wlan.h"
# include "hostap.h"
# include "hostap_ap.h"
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
static unsigned char rfc1042_header [ ] =
{ 0xaa , 0xaa , 0x03 , 0x00 , 0x00 , 0x00 } ;
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
static unsigned char bridge_tunnel_header [ ] =
{ 0xaa , 0xaa , 0x03 , 0x00 , 0x00 , 0xf8 } ;
/* No encapsulation header if EtherType < 0x600 (=length) */
2005-05-12 22:54:16 -04:00
void hostap_dump_tx_80211 ( const char * name , struct sk_buff * skb )
{
2005-09-21 12:23:49 -05:00
struct ieee80211_hdr_4addr * hdr ;
2005-05-12 22:54:16 -04:00
u16 fc ;
2005-09-21 12:23:49 -05:00
hdr = ( struct ieee80211_hdr_4addr * ) skb - > data ;
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " %s: TX len=%d jiffies=%ld \n " ,
name , skb - > len , jiffies ) ;
if ( skb - > len < 2 )
return ;
2005-08-14 19:08:43 -07:00
fc = le16_to_cpu ( hdr - > frame_ctl ) ;
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s " ,
2005-08-14 19:08:44 -07:00
fc , WLAN_FC_GET_TYPE ( fc ) > > 2 , WLAN_FC_GET_STYPE ( fc ) > > 4 ,
2005-08-14 21:00:01 -07:00
fc & IEEE80211_FCTL_TODS ? " [ToDS] " : " " ,
fc & IEEE80211_FCTL_FROMDS ? " [FromDS] " : " " ) ;
2005-05-12 22:54:16 -04:00
if ( skb - > len < IEEE80211_DATA_HDR3_LEN ) {
printk ( " \n " ) ;
return ;
}
printk ( " dur=0x%04x seq=0x%04x \n " , le16_to_cpu ( hdr - > duration_id ) ,
2005-08-14 19:08:43 -07:00
le16_to_cpu ( hdr - > seq_ctl ) ) ;
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " A1= " MACSTR " A2= " MACSTR " A3= " MACSTR ,
MAC2STR ( hdr - > addr1 ) , MAC2STR ( hdr - > addr2 ) , MAC2STR ( hdr - > addr3 ) ) ;
if ( skb - > len > = 30 )
printk ( " A4= " MACSTR , MAC2STR ( hdr - > addr4 ) ) ;
printk ( " \n " ) ;
}
/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
* Convert Ethernet header into a suitable IEEE 802.11 header depending on
* device configuration . */
int hostap_data_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
int need_headroom , need_tailroom = 0 ;
2005-09-21 12:23:49 -05:00
struct ieee80211_hdr_4addr hdr ;
2005-05-12 22:54:16 -04:00
u16 fc , ethertype = 0 ;
enum {
WDS_NO = 0 , WDS_OWN_FRAME , WDS_COMPLIANT_FRAME
} use_wds = WDS_NO ;
u8 * encaps_data ;
int hdr_len , encaps_len , skip_header_bytes ;
int to_assoc_ap = 0 ;
struct hostap_skb_tx_data * meta ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( skb - > len < ETH_HLEN ) {
printk ( KERN_DEBUG " %s: hostap_data_start_xmit: short skb "
" (len=%d) \n " , dev - > name , skb - > len ) ;
kfree_skb ( skb ) ;
return 0 ;
}
if ( local - > ddev ! = dev ) {
use_wds = ( local - > iw_mode = = IW_MODE_MASTER & &
! ( local - > wds_type & HOSTAP_WDS_STANDARD_FRAME ) ) ?
WDS_OWN_FRAME : WDS_COMPLIANT_FRAME ;
if ( dev = = local - > stadev ) {
to_assoc_ap = 1 ;
use_wds = WDS_NO ;
} else if ( dev = = local - > apdev ) {
printk ( KERN_DEBUG " %s: prism2_tx: trying to use "
" AP device with Ethernet net dev \n " , dev - > name ) ;
kfree_skb ( skb ) ;
return 0 ;
}
} else {
if ( local - > iw_mode = = IW_MODE_REPEAT ) {
printk ( KERN_DEBUG " %s: prism2_tx: trying to use "
" non-WDS link in Repeater mode \n " , dev - > name ) ;
kfree_skb ( skb ) ;
return 0 ;
} else if ( local - > iw_mode = = IW_MODE_INFRA & &
( local - > wds_type & HOSTAP_WDS_AP_CLIENT ) & &
memcmp ( skb - > data + ETH_ALEN , dev - > dev_addr ,
ETH_ALEN ) ! = 0 ) {
/* AP client mode: send frames with foreign src addr
* using 4 - addr WDS frames */
use_wds = WDS_COMPLIANT_FRAME ;
}
}
/* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload
* = = >
* Prism2 TX frame with 802.11 header :
* txdesc ( address order depending on used mode ; includes dst_addr and
* src_addr ) , possible encapsulation ( RFC1042 / Bridge - Tunnel ;
* proto [ 2 ] , payload { , possible addr4 [ 6 ] } */
ethertype = ( skb - > data [ 12 ] < < 8 ) | skb - > data [ 13 ] ;
memset ( & hdr , 0 , sizeof ( hdr ) ) ;
/* Length of data after IEEE 802.11 header */
encaps_data = NULL ;
encaps_len = 0 ;
skip_header_bytes = ETH_HLEN ;
if ( ethertype = = ETH_P_AARP | | ethertype = = ETH_P_IPX ) {
encaps_data = bridge_tunnel_header ;
encaps_len = sizeof ( bridge_tunnel_header ) ;
skip_header_bytes - = 2 ;
} else if ( ethertype > = 0x600 ) {
encaps_data = rfc1042_header ;
encaps_len = sizeof ( rfc1042_header ) ;
skip_header_bytes - = 2 ;
}
2005-08-14 19:08:44 -07:00
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA ;
2005-05-12 22:54:16 -04:00
hdr_len = IEEE80211_DATA_HDR3_LEN ;
if ( use_wds ! = WDS_NO ) {
/* Note! Prism2 station firmware has problems with sending real
* 802.11 frames with four addresses ; until these problems can
* be fixed or worked around , 4 - addr frames needed for WDS are
* using incompatible format : FromDS flag is not set and the
* fourth address is added after the frame payload ; it is
* assumed , that the receiving station knows how to handle this
* frame format */
if ( use_wds = = WDS_COMPLIANT_FRAME ) {
2005-08-14 21:00:01 -07:00
fc | = IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS ;
2005-05-12 22:54:16 -04:00
/* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
* Addr4 = SA */
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data_offset ( skb , ETH_ALEN ,
& hdr . addr4 , ETH_ALEN ) ;
2005-05-12 22:54:16 -04:00
hdr_len + = ETH_ALEN ;
} else {
/* bogus 4-addr format to workaround Prism2 station
* f / w bug */
2005-08-14 21:00:01 -07:00
fc | = IEEE80211_FCTL_TODS ;
2005-05-12 22:54:16 -04:00
/* From DS: Addr1 = DA (used as RA),
* Addr2 = BSSID ( used as TA ) , Addr3 = SA ( used as DA ) ,
*/
/* SA from skb->data + ETH_ALEN will be added after
* frame payload ; use hdr . addr4 as a temporary buffer
*/
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data_offset ( skb , ETH_ALEN ,
& hdr . addr4 , ETH_ALEN ) ;
2005-05-12 22:54:16 -04:00
need_tailroom + = ETH_ALEN ;
}
/* send broadcast and multicast frames to broadcast RA, if
* configured ; otherwise , use unicast RA of the WDS link */
if ( ( local - > wds_type & HOSTAP_WDS_BROADCAST_RA ) & &
skb - > data [ 0 ] & 0x01 )
memset ( & hdr . addr1 , 0xff , ETH_ALEN ) ;
else if ( iface - > type = = HOSTAP_INTERFACE_WDS )
memcpy ( & hdr . addr1 , iface - > u . wds . remote_addr ,
ETH_ALEN ) ;
else
memcpy ( & hdr . addr1 , local - > bssid , ETH_ALEN ) ;
memcpy ( & hdr . addr2 , dev - > dev_addr , ETH_ALEN ) ;
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data ( skb , & hdr . addr3 , ETH_ALEN ) ;
2005-05-12 22:54:16 -04:00
} else if ( local - > iw_mode = = IW_MODE_MASTER & & ! to_assoc_ap ) {
2005-08-14 21:00:01 -07:00
fc | = IEEE80211_FCTL_FROMDS ;
2005-05-12 22:54:16 -04:00
/* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data ( skb , & hdr . addr1 , ETH_ALEN ) ;
2005-05-12 22:54:16 -04:00
memcpy ( & hdr . addr2 , dev - > dev_addr , ETH_ALEN ) ;
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data_offset ( skb , ETH_ALEN , & hdr . addr3 ,
ETH_ALEN ) ;
2005-05-12 22:54:16 -04:00
} else if ( local - > iw_mode = = IW_MODE_INFRA | | to_assoc_ap ) {
2005-08-14 21:00:01 -07:00
fc | = IEEE80211_FCTL_TODS ;
2005-05-12 22:54:16 -04:00
/* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
memcpy ( & hdr . addr1 , to_assoc_ap ?
local - > assoc_ap_addr : local - > bssid , ETH_ALEN ) ;
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data_offset ( skb , ETH_ALEN , & hdr . addr2 ,
ETH_ALEN ) ;
skb_copy_from_linear_data ( skb , & hdr . addr3 , ETH_ALEN ) ;
2005-05-12 22:54:16 -04:00
} else if ( local - > iw_mode = = IW_MODE_ADHOC ) {
/* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
2007-03-27 18:55:52 -03:00
skb_copy_from_linear_data ( skb , & hdr . addr1 , ETH_ALEN ) ;
skb_copy_from_linear_data_offset ( skb , ETH_ALEN , & hdr . addr2 ,
ETH_ALEN ) ;
2005-05-12 22:54:16 -04:00
memcpy ( & hdr . addr3 , local - > bssid , ETH_ALEN ) ;
}
2005-08-14 19:08:43 -07:00
hdr . frame_ctl = cpu_to_le16 ( fc ) ;
2005-05-12 22:54:16 -04:00
skb_pull ( skb , skip_header_bytes ) ;
need_headroom = local - > func - > need_tx_headroom + hdr_len + encaps_len ;
if ( skb_tailroom ( skb ) < need_tailroom ) {
skb = skb_unshare ( skb , GFP_ATOMIC ) ;
if ( skb = = NULL ) {
iface - > stats . tx_dropped + + ;
return 0 ;
}
if ( pskb_expand_head ( skb , need_headroom , need_tailroom ,
GFP_ATOMIC ) ) {
kfree_skb ( skb ) ;
iface - > stats . tx_dropped + + ;
return 0 ;
}
} else if ( skb_headroom ( skb ) < need_headroom ) {
struct sk_buff * tmp = skb ;
skb = skb_realloc_headroom ( skb , need_headroom ) ;
kfree_skb ( tmp ) ;
if ( skb = = NULL ) {
iface - > stats . tx_dropped + + ;
return 0 ;
}
} else {
skb = skb_unshare ( skb , GFP_ATOMIC ) ;
if ( skb = = NULL ) {
iface - > stats . tx_dropped + + ;
return 0 ;
}
}
if ( encaps_data )
memcpy ( skb_push ( skb , encaps_len ) , encaps_data , encaps_len ) ;
memcpy ( skb_push ( skb , hdr_len ) , & hdr , hdr_len ) ;
if ( use_wds = = WDS_OWN_FRAME ) {
memcpy ( skb_put ( skb , ETH_ALEN ) , & hdr . addr4 , ETH_ALEN ) ;
}
iface - > stats . tx_packets + + ;
iface - > stats . tx_bytes + = skb - > len ;
2007-03-19 15:30:44 -07:00
skb_reset_mac_header ( skb ) ;
2005-05-12 22:54:16 -04:00
meta = ( struct hostap_skb_tx_data * ) skb - > cb ;
memset ( meta , 0 , sizeof ( * meta ) ) ;
meta - > magic = HOSTAP_SKB_TX_DATA_MAGIC ;
2005-08-14 19:08:39 -07:00
if ( use_wds )
meta - > flags | = HOSTAP_TX_FLAGS_WDS ;
2005-05-12 22:54:16 -04:00
meta - > ethertype = ethertype ;
meta - > iface = iface ;
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb - > dev = local - > dev ;
dev_queue_xmit ( skb ) ;
return 0 ;
}
/* hard_start_xmit function for hostapd wlan#ap interfaces */
int hostap_mgmt_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
struct hostap_skb_tx_data * meta ;
2005-09-21 12:23:49 -05:00
struct ieee80211_hdr_4addr * hdr ;
2005-05-12 22:54:16 -04:00
u16 fc ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( skb - > len < 10 ) {
printk ( KERN_DEBUG " %s: hostap_mgmt_start_xmit: short skb "
" (len=%d) \n " , dev - > name , skb - > len ) ;
kfree_skb ( skb ) ;
return 0 ;
}
iface - > stats . tx_packets + + ;
iface - > stats . tx_bytes + = skb - > len ;
meta = ( struct hostap_skb_tx_data * ) skb - > cb ;
memset ( meta , 0 , sizeof ( * meta ) ) ;
meta - > magic = HOSTAP_SKB_TX_DATA_MAGIC ;
meta - > iface = iface ;
if ( skb - > len > = IEEE80211_DATA_HDR3_LEN + sizeof ( rfc1042_header ) + 2 ) {
2005-09-21 12:23:49 -05:00
hdr = ( struct ieee80211_hdr_4addr * ) skb - > data ;
2005-08-14 19:08:43 -07:00
fc = le16_to_cpu ( hdr - > frame_ctl ) ;
2005-08-14 19:08:44 -07:00
if ( WLAN_FC_GET_TYPE ( fc ) = = IEEE80211_FTYPE_DATA & &
WLAN_FC_GET_STYPE ( fc ) = = IEEE80211_STYPE_DATA ) {
2005-05-12 22:54:16 -04:00
u8 * pos = & skb - > data [ IEEE80211_DATA_HDR3_LEN +
sizeof ( rfc1042_header ) ] ;
meta - > ethertype = ( pos [ 0 ] < < 8 ) | pos [ 1 ] ;
}
}
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb - > dev = local - > dev ;
dev_queue_xmit ( skb ) ;
return 0 ;
}
/* Called only from software IRQ */
2006-03-24 21:24:54 -08:00
static struct sk_buff * hostap_tx_encrypt ( struct sk_buff * skb ,
struct ieee80211_crypt_data * crypt )
2005-05-12 22:54:16 -04:00
{
struct hostap_interface * iface ;
local_info_t * local ;
2005-09-21 12:23:49 -05:00
struct ieee80211_hdr_4addr * hdr ;
2005-05-12 22:54:16 -04:00
u16 fc ;
2007-05-28 09:38:46 -07:00
int prefix_len , postfix_len , hdr_len , res ;
2005-05-12 22:54:16 -04:00
iface = netdev_priv ( skb - > dev ) ;
local = iface - > local ;
if ( skb - > len < IEEE80211_DATA_HDR3_LEN ) {
kfree_skb ( skb ) ;
return NULL ;
}
if ( local - > tkip_countermeasures & &
2006-03-24 21:24:54 -08:00
strcmp ( crypt - > ops - > name , " TKIP " ) = = 0 ) {
2005-09-21 12:23:49 -05:00
hdr = ( struct ieee80211_hdr_4addr * ) skb - > data ;
2005-05-12 22:54:16 -04:00
if ( net_ratelimit ( ) ) {
printk ( KERN_DEBUG " %s: TKIP countermeasures: dropped "
" TX packet to " MACSTR " \n " ,
local - > dev - > name , MAC2STR ( hdr - > addr1 ) ) ;
}
kfree_skb ( skb ) ;
return NULL ;
}
skb = skb_unshare ( skb , GFP_ATOMIC ) ;
if ( skb = = NULL )
return NULL ;
2007-05-28 09:38:46 -07:00
prefix_len = crypt - > ops - > extra_mpdu_prefix_len +
crypt - > ops - > extra_msdu_prefix_len ;
postfix_len = crypt - > ops - > extra_mpdu_postfix_len +
crypt - > ops - > extra_msdu_postfix_len ;
if ( ( skb_headroom ( skb ) < prefix_len | |
skb_tailroom ( skb ) < postfix_len ) & &
pskb_expand_head ( skb , prefix_len , postfix_len , GFP_ATOMIC ) ) {
2005-05-12 22:54:16 -04:00
kfree_skb ( skb ) ;
return NULL ;
}
2005-09-21 12:23:49 -05:00
hdr = ( struct ieee80211_hdr_4addr * ) skb - > data ;
2005-08-14 19:08:43 -07:00
fc = le16_to_cpu ( hdr - > frame_ctl ) ;
2005-05-12 22:54:16 -04:00
hdr_len = hostap_80211_get_hdrlen ( fc ) ;
/* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
* call both MSDU and MPDU encryption functions from here . */
atomic_inc ( & crypt - > refcnt ) ;
res = 0 ;
if ( crypt - > ops - > encrypt_msdu )
res = crypt - > ops - > encrypt_msdu ( skb , hdr_len , crypt - > priv ) ;
if ( res = = 0 & & crypt - > ops - > encrypt_mpdu )
res = crypt - > ops - > encrypt_mpdu ( skb , hdr_len , crypt - > priv ) ;
atomic_dec ( & crypt - > refcnt ) ;
if ( res < 0 ) {
kfree_skb ( skb ) ;
return NULL ;
}
return skb ;
}
/* hard_start_xmit function for master radio interface wifi#.
* AP processing ( TX rate control , power save buffering , etc . ) .
* Use hardware TX function to send the frame . */
int hostap_master_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
int ret = 1 ;
u16 fc ;
struct hostap_tx_data tx ;
ap_tx_ret tx_ret ;
struct hostap_skb_tx_data * meta ;
int no_encrypt = 0 ;
2005-09-21 12:23:49 -05:00
struct ieee80211_hdr_4addr * hdr ;
2005-05-12 22:54:16 -04:00
iface = netdev_priv ( dev ) ;
local = iface - > local ;
tx . skb = skb ;
tx . sta_ptr = NULL ;
meta = ( struct hostap_skb_tx_data * ) skb - > cb ;
if ( meta - > magic ! = HOSTAP_SKB_TX_DATA_MAGIC ) {
printk ( KERN_DEBUG " %s: invalid skb->cb magic (0x%08x, "
" expected 0x%08x) \n " ,
dev - > name , meta - > magic , HOSTAP_SKB_TX_DATA_MAGIC ) ;
ret = 0 ;
iface - > stats . tx_dropped + + ;
goto fail ;
}
if ( local - > host_encrypt ) {
/* Set crypt to default algorithm and key; will be replaced in
* AP code if STA has own alg / key */
tx . crypt = local - > crypt [ local - > tx_keyidx ] ;
tx . host_encrypt = 1 ;
} else {
tx . crypt = NULL ;
tx . host_encrypt = 0 ;
}
if ( skb - > len < 24 ) {
printk ( KERN_DEBUG " %s: hostap_master_start_xmit: short skb "
" (len=%d) \n " , dev - > name , skb - > len ) ;
ret = 0 ;
iface - > stats . tx_dropped + + ;
goto fail ;
}
/* FIX (?):
* Wi - Fi 802.11 b test plan suggests that AP should ignore power save
* bit in authentication and ( re ) association frames and assume tha
* STA remains awake for the response . */
tx_ret = hostap_handle_sta_tx ( local , & tx ) ;
skb = tx . skb ;
meta = ( struct hostap_skb_tx_data * ) skb - > cb ;
2005-09-21 12:23:49 -05:00
hdr = ( struct ieee80211_hdr_4addr * ) skb - > data ;
2005-08-14 19:08:43 -07:00
fc = le16_to_cpu ( hdr - > frame_ctl ) ;
2005-05-12 22:54:16 -04:00
switch ( tx_ret ) {
case AP_TX_CONTINUE :
break ;
case AP_TX_CONTINUE_NOT_AUTHORIZED :
if ( local - > ieee_802_1x & &
2005-08-14 19:08:44 -07:00
WLAN_FC_GET_TYPE ( fc ) = = IEEE80211_FTYPE_DATA & &
2005-08-14 19:08:39 -07:00
meta - > ethertype ! = ETH_P_PAE & &
! ( meta - > flags & HOSTAP_TX_FLAGS_WDS ) ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " %s: dropped frame to unauthorized "
" port (IEEE 802.1X): ethertype=0x%04x \n " ,
dev - > name , meta - > ethertype ) ;
hostap_dump_tx_80211 ( dev - > name , skb ) ;
ret = 0 ; /* drop packet */
iface - > stats . tx_dropped + + ;
goto fail ;
}
break ;
case AP_TX_DROP :
ret = 0 ; /* drop packet */
iface - > stats . tx_dropped + + ;
goto fail ;
case AP_TX_RETRY :
goto fail ;
case AP_TX_BUFFERED :
/* do not free skb here, it will be freed when the
* buffered frame is sent / timed out */
ret = 0 ;
goto tx_exit ;
}
/* Request TX callback if protocol version is 2 in 802.11 header;
* this version 2 is a special case used between hostapd and kernel
* driver */
2005-08-14 21:00:01 -07:00
if ( ( ( fc & IEEE80211_FCTL_VERS ) = = BIT ( 1 ) ) & &
2005-05-12 22:54:16 -04:00
local - > ap & & local - > ap - > tx_callback_idx & & meta - > tx_cb_idx = = 0 ) {
meta - > tx_cb_idx = local - > ap - > tx_callback_idx ;
/* remove special version from the frame header */
2005-08-14 21:00:01 -07:00
fc & = ~ IEEE80211_FCTL_VERS ;
2005-08-14 19:08:43 -07:00
hdr - > frame_ctl = cpu_to_le16 ( fc ) ;
2005-05-12 22:54:16 -04:00
}
2005-08-14 19:08:44 -07:00
if ( WLAN_FC_GET_TYPE ( fc ) ! = IEEE80211_FTYPE_DATA ) {
2005-05-12 22:54:16 -04:00
no_encrypt = 1 ;
tx . crypt = NULL ;
}
if ( local - > ieee_802_1x & & meta - > ethertype = = ETH_P_PAE & & tx . crypt & &
2006-03-24 21:24:55 -08:00
! ( fc & IEEE80211_FCTL_PROTECTED ) ) {
2005-05-12 22:54:16 -04:00
no_encrypt = 1 ;
PDEBUG ( DEBUG_EXTRA2 , " %s: TX: IEEE 802.1X - passing "
" unencrypted EAPOL frame \n " , dev - > name ) ;
tx . crypt = NULL ; /* no encryption for IEEE 802.1X frames */
}
if ( tx . crypt & & ( ! tx . crypt - > ops | | ! tx . crypt - > ops - > encrypt_mpdu ) )
tx . crypt = NULL ;
else if ( ( tx . crypt | | local - > crypt [ local - > tx_keyidx ] ) & & ! no_encrypt ) {
/* Add ISWEP flag both for firmware and host based encryption
*/
2005-08-25 20:59:10 -04:00
fc | = IEEE80211_FCTL_PROTECTED ;
2005-08-14 19:08:43 -07:00
hdr - > frame_ctl = cpu_to_le16 ( fc ) ;
2005-05-12 22:54:16 -04:00
} else if ( local - > drop_unencrypted & &
2005-08-14 19:08:44 -07:00
WLAN_FC_GET_TYPE ( fc ) = = IEEE80211_FTYPE_DATA & &
2005-05-12 22:54:16 -04:00
meta - > ethertype ! = ETH_P_PAE ) {
if ( net_ratelimit ( ) ) {
printk ( KERN_DEBUG " %s: dropped unencrypted TX data "
" frame (drop_unencrypted=1) \n " , dev - > name ) ;
}
iface - > stats . tx_dropped + + ;
ret = 0 ;
goto fail ;
}
if ( tx . crypt ) {
skb = hostap_tx_encrypt ( skb , tx . crypt ) ;
if ( skb = = NULL ) {
printk ( KERN_DEBUG " %s: TX - encryption failed \n " ,
dev - > name ) ;
ret = 0 ;
goto fail ;
}
meta = ( struct hostap_skb_tx_data * ) skb - > cb ;
if ( meta - > magic ! = HOSTAP_SKB_TX_DATA_MAGIC ) {
printk ( KERN_DEBUG " %s: invalid skb->cb magic (0x%08x, "
" expected 0x%08x) after hostap_tx_encrypt \n " ,
dev - > name , meta - > magic ,
HOSTAP_SKB_TX_DATA_MAGIC ) ;
ret = 0 ;
iface - > stats . tx_dropped + + ;
goto fail ;
}
}
if ( local - > func - > tx = = NULL | | local - > func - > tx ( skb , dev ) ) {
ret = 0 ;
iface - > stats . tx_dropped + + ;
} else {
ret = 0 ;
iface - > stats . tx_packets + + ;
iface - > stats . tx_bytes + = skb - > len ;
}
fail :
if ( ! ret & & skb )
dev_kfree_skb ( skb ) ;
tx_exit :
if ( tx . sta_ptr )
hostap_handle_sta_release ( tx . sta_ptr ) ;
return ret ;
}
EXPORT_SYMBOL ( hostap_master_start_xmit ) ;