2011-03-21 18:00:50 -07:00
/*
* Marvell Wireless LAN device driver : station RX data handling
*
* Copyright ( C ) 2011 , Marvell International Ltd .
*
* This software file ( the " File " ) is distributed by Marvell International
* Ltd . under the terms of the GNU General Public License Version 2 , June 1991
* ( the " License " ) . You may use , redistribute and / or modify this File in
* accordance with the terms and conditions of the License , a copy of which
* is available by writing to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA or on the
* worldwide web at http : //www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS - IS , WITHOUT WARRANTY OF ANY KIND , AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED . The License provides additional details about
* this warranty disclaimer .
*/
2013-08-23 16:48:23 -07:00
# include <uapi/linux/ipv6.h>
# include <net/ndisc.h>
2011-03-21 18:00:50 -07:00
# include "decl.h"
# include "ioctl.h"
# include "util.h"
# include "fw.h"
# include "main.h"
# include "11n_aggr.h"
# include "11n_rxreorder.h"
2013-08-23 16:48:23 -07:00
/* This function checks if a frame is IPv4 ARP or IPv6 Neighbour advertisement
* frame . If frame has both source and destination mac address as same , this
* function drops such gratuitous frames .
*/
static bool
mwifiex_discard_gratuitous_arp ( struct mwifiex_private * priv ,
struct sk_buff * skb )
{
const struct mwifiex_arp_eth_header * arp ;
2013-12-02 23:17:52 -08:00
struct ethhdr * eth ;
2013-08-23 16:48:23 -07:00
struct ipv6hdr * ipv6 ;
struct icmp6hdr * icmpv6 ;
2013-12-02 23:17:52 -08:00
eth = ( struct ethhdr * ) skb - > data ;
switch ( ntohs ( eth - > h_proto ) ) {
2013-08-23 16:48:23 -07:00
case ETH_P_ARP :
arp = ( void * ) ( skb - > data + sizeof ( struct ethhdr ) ) ;
if ( arp - > hdr . ar_op = = htons ( ARPOP_REPLY ) | |
arp - > hdr . ar_op = = htons ( ARPOP_REQUEST ) ) {
if ( ! memcmp ( arp - > ar_sip , arp - > ar_tip , 4 ) )
return true ;
}
break ;
case ETH_P_IPV6 :
ipv6 = ( void * ) ( skb - > data + sizeof ( struct ethhdr ) ) ;
icmpv6 = ( void * ) ( skb - > data + sizeof ( struct ethhdr ) +
sizeof ( struct ipv6hdr ) ) ;
if ( NDISC_NEIGHBOUR_ADVERTISEMENT = = icmpv6 - > icmp6_type ) {
if ( ! memcmp ( & ipv6 - > saddr , & ipv6 - > daddr ,
sizeof ( struct in6_addr ) ) )
return true ;
}
break ;
default :
break ;
}
return false ;
}
2011-03-21 18:00:50 -07:00
/*
* This function processes the received packet and forwards it
* to kernel / upper layer .
*
* This function parses through the received packet and determines
* if it is a debug packet or normal packet .
*
* For non - debug packets , the function chops off unnecessary leading
* header bytes , reconstructs the packet as an ethernet frame or
* 802.2 / llc / snap frame as required , and sends it to kernel / upper layer .
*
* The completion callback is called after processing in complete .
*/
2012-10-19 19:19:21 -07:00
int mwifiex_process_rx_packet ( struct mwifiex_private * priv ,
2011-03-21 18:00:50 -07:00
struct sk_buff * skb )
{
2011-05-03 20:11:46 -07:00
int ret ;
2011-03-21 18:00:50 -07:00
struct rx_packet_hdr * rx_pkt_hdr ;
struct rxpd * local_rx_pd ;
int hdr_chop ;
2013-12-02 23:17:52 -08:00
struct ethhdr * eth ;
2011-03-21 18:00:50 -07:00
local_rx_pd = ( struct rxpd * ) ( skb - > data ) ;
2012-08-03 18:06:02 -07:00
rx_pkt_hdr = ( void * ) local_rx_pd +
le16_to_cpu ( local_rx_pd - > rx_pkt_offset ) ;
2011-03-21 18:00:50 -07:00
2013-12-02 23:17:51 -08:00
if ( ( ! memcmp ( & rx_pkt_hdr - > rfc1042_hdr , bridge_tunnel_header ,
sizeof ( bridge_tunnel_header ) ) ) | |
( ! memcmp ( & rx_pkt_hdr - > rfc1042_hdr , rfc1042_header ,
sizeof ( rfc1042_header ) ) & &
ntohs ( rx_pkt_hdr - > rfc1042_hdr . snap_type ) ! = ETH_P_AARP & &
ntohs ( rx_pkt_hdr - > rfc1042_hdr . snap_type ) ! = ETH_P_IPX ) ) {
2011-03-21 18:00:50 -07:00
/*
* Replace the 803 header and rfc1042 header ( llc / snap ) with an
* EthernetII header , keep the src / dst and snap_type
* ( ethertype ) .
* The firmware only passes up SNAP frames converting
* all RX Data from 802.11 to 802.2 / LLC / SNAP frames .
* To create the Ethernet II , just move the src , dst address
* right before the snap_type .
*/
2013-12-02 23:17:52 -08:00
eth = ( struct ethhdr * )
2011-03-21 18:00:50 -07:00
( ( u8 * ) & rx_pkt_hdr - > eth803_hdr
+ sizeof ( rx_pkt_hdr - > eth803_hdr ) +
sizeof ( rx_pkt_hdr - > rfc1042_hdr )
- sizeof ( rx_pkt_hdr - > eth803_hdr . h_dest )
- sizeof ( rx_pkt_hdr - > eth803_hdr . h_source )
- sizeof ( rx_pkt_hdr - > rfc1042_hdr . snap_type ) ) ;
2013-12-02 23:17:52 -08:00
memcpy ( eth - > h_source , rx_pkt_hdr - > eth803_hdr . h_source ,
sizeof ( eth - > h_source ) ) ;
memcpy ( eth - > h_dest , rx_pkt_hdr - > eth803_hdr . h_dest ,
sizeof ( eth - > h_dest ) ) ;
2011-03-21 18:00:50 -07:00
/* Chop off the rxpd + the excess memory from the 802.2/llc/snap
header that was removed . */
2013-12-02 23:17:52 -08:00
hdr_chop = ( u8 * ) eth - ( u8 * ) local_rx_pd ;
2011-03-21 18:00:50 -07:00
} else {
/* Chop off the rxpd */
hdr_chop = ( u8 * ) & rx_pkt_hdr - > eth803_hdr -
( u8 * ) local_rx_pd ;
}
/* Chop off the leading header bytes so the it points to the start of
either the reconstructed EthII frame or the 802.2 / llc / snap frame */
skb_pull ( skb , hdr_chop ) ;
2013-08-23 16:48:23 -07:00
if ( priv - > hs2_enabled & &
mwifiex_discard_gratuitous_arp ( priv , skb ) ) {
dev_dbg ( priv - > adapter - > dev , " Bypassed Gratuitous ARP \n " ) ;
dev_kfree_skb_any ( skb ) ;
return 0 ;
}
2011-03-21 18:00:50 -07:00
priv - > rxpd_rate = local_rx_pd - > rx_rate ;
priv - > rxpd_htinfo = local_rx_pd - > ht_info ;
2012-10-19 19:19:21 -07:00
ret = mwifiex_recv_packet ( priv , skb ) ;
2011-03-21 18:00:50 -07:00
if ( ret = = - 1 )
2012-10-19 19:19:21 -07:00
dev_err ( priv - > adapter - > dev , " recv packet failed \n " ) ;
2011-03-21 18:00:50 -07:00
return ret ;
}
/*
* This function processes the received buffer .
*
* The function looks into the RxPD and performs sanity tests on the
* received buffer to ensure its a valid packet , before processing it
* further . If the packet is determined to be aggregated , it is
* de - aggregated accordingly . Non - unicast packets are sent directly to
* the kernel / upper layers . Unicast packets are handed over to the
* Rx reordering routine if 11 n is enabled .
*
* The completion callback is called after processing in complete .
*/
2012-10-19 19:19:21 -07:00
int mwifiex_process_sta_rx_packet ( struct mwifiex_private * priv ,
2011-03-21 18:00:50 -07:00
struct sk_buff * skb )
{
2012-10-19 19:19:21 -07:00
struct mwifiex_adapter * adapter = priv - > adapter ;
2011-03-21 18:00:50 -07:00
int ret = 0 ;
struct rxpd * local_rx_pd ;
struct rx_packet_hdr * rx_pkt_hdr ;
u8 ta [ ETH_ALEN ] ;
2012-08-03 18:06:02 -07:00
u16 rx_pkt_type , rx_pkt_offset , rx_pkt_length , seq_num ;
2011-11-07 21:41:10 -08:00
2011-03-21 18:00:50 -07:00
local_rx_pd = ( struct rxpd * ) ( skb - > data ) ;
2012-08-03 18:06:02 -07:00
rx_pkt_type = le16_to_cpu ( local_rx_pd - > rx_pkt_type ) ;
rx_pkt_offset = le16_to_cpu ( local_rx_pd - > rx_pkt_offset ) ;
rx_pkt_length = le16_to_cpu ( local_rx_pd - > rx_pkt_length ) ;
seq_num = le16_to_cpu ( local_rx_pd - > seq_num ) ;
2011-03-21 18:00:50 -07:00
2012-08-03 18:06:02 -07:00
rx_pkt_hdr = ( void * ) local_rx_pd + rx_pkt_offset ;
2011-03-21 18:00:50 -07:00
2012-08-03 18:06:02 -07:00
if ( ( rx_pkt_offset + rx_pkt_length ) > ( u16 ) skb - > len ) {
dev_err ( adapter - > dev ,
" wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d \n " ,
skb - > len , rx_pkt_offset , rx_pkt_length ) ;
2011-03-21 18:00:50 -07:00
priv - > stats . rx_dropped + + ;
2013-12-02 23:17:53 -08:00
dev_kfree_skb_any ( skb ) ;
2011-03-21 18:00:50 -07:00
return ret ;
}
2011-05-13 11:22:32 -07:00
2012-08-03 18:06:02 -07:00
if ( rx_pkt_type = = PKT_TYPE_AMSDU ) {
2011-05-13 11:22:32 -07:00
struct sk_buff_head list ;
struct sk_buff * rx_skb ;
__skb_queue_head_init ( & list ) ;
2012-08-03 18:06:02 -07:00
skb_pull ( skb , rx_pkt_offset ) ;
skb_trim ( skb , rx_pkt_length ) ;
2011-05-13 11:22:32 -07:00
ieee80211_amsdu_to_8023s ( skb , & list , priv - > curr_addr ,
2012-03-13 19:22:42 -07:00
priv - > wdev - > iftype , 0 , false ) ;
2011-05-13 11:22:32 -07:00
while ( ! skb_queue_empty ( & list ) ) {
rx_skb = __skb_dequeue ( & list ) ;
2012-10-19 19:19:21 -07:00
ret = mwifiex_recv_packet ( priv , rx_skb ) ;
2011-05-13 11:22:32 -07:00
if ( ret = = - 1 )
dev_err ( adapter - > dev , " Rx of A-MSDU failed " ) ;
}
return 0 ;
2012-09-25 20:23:35 -07:00
} else if ( rx_pkt_type = = PKT_TYPE_MGMT ) {
2012-10-19 19:19:21 -07:00
ret = mwifiex_process_mgmt_packet ( priv , skb ) ;
2012-09-25 20:23:35 -07:00
if ( ret )
dev_err ( adapter - > dev , " Rx of mgmt packet failed " ) ;
dev_kfree_skb_any ( skb ) ;
return ret ;
2011-03-21 18:00:50 -07:00
}
2011-05-13 11:22:32 -07:00
2011-03-21 18:00:50 -07:00
/*
* If the packet is not an unicast packet then send the packet
* directly to os . Don ' t pass thru rx reordering
*/
if ( ! IS_11N_ENABLED ( priv ) | |
2013-12-26 19:41:27 +08:00
! ether_addr_equal_unaligned ( priv - > curr_addr , rx_pkt_hdr - > eth803_hdr . h_dest ) ) {
2012-10-19 19:19:21 -07:00
mwifiex_process_rx_packet ( priv , skb ) ;
2011-03-21 18:00:50 -07:00
return ret ;
}
if ( mwifiex_queuing_ra_based ( priv ) ) {
memcpy ( ta , rx_pkt_hdr - > eth803_hdr . h_source , ETH_ALEN ) ;
} else {
if ( rx_pkt_type ! = PKT_TYPE_BAR )
2012-08-03 18:06:02 -07:00
priv - > rx_seq [ local_rx_pd - > priority ] = seq_num ;
2011-03-21 18:00:50 -07:00
memcpy ( ta , priv - > curr_bss_params . bss_descriptor . mac_address ,
ETH_ALEN ) ;
}
/* Reorder and send to OS */
2012-08-03 18:06:02 -07:00
ret = mwifiex_11n_rx_reorder_pkt ( priv , seq_num , local_rx_pd - > priority ,
ta , ( u8 ) rx_pkt_type , skb ) ;
2011-03-21 18:00:50 -07:00
2013-12-02 23:17:53 -08:00
if ( ret | | ( rx_pkt_type = = PKT_TYPE_BAR ) )
dev_kfree_skb_any ( skb ) ;
2011-11-07 21:41:10 -08:00
if ( ret )
priv - > stats . rx_dropped + + ;
2011-03-21 18:00:50 -07:00
return ret ;
}