2012-06-19 17:15:42 -06:00
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* FILE : unifi_pdu_processing . c
*
* PURPOSE :
* This file provides the PDU handling functionality before it gets sent to unfi and after
* receiving a PDU from unifi
*
* Copyright ( C ) 2010 by Cambridge Silicon Radio Ltd .
*
* Refer to LICENSE . txt included with this source code for details on
* the license terms .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
# include <linux/types.h>
# include <linux/etherdevice.h>
# include <linux/vmalloc.h>
# include "csr_wifi_hip_unifi.h"
# include "csr_wifi_hip_conversions.h"
# include "csr_time.h"
# include "unifi_priv.h"
# include <net/pkt_sched.h>
# ifdef CSR_SUPPORT_SME
static void _update_buffered_pkt_params_after_alignment ( unifi_priv_t * priv , bulk_data_param_t * bulkdata ,
tx_buffered_packets_t * buffered_pkt )
{
struct sk_buff * skb ;
2012-07-20 13:05:42 -06:00
u32 align_offset ;
2012-06-19 17:15:42 -06:00
if ( priv = = NULL | | bulkdata = = NULL | | buffered_pkt = = NULL ) {
return ;
}
2012-06-19 18:33:16 -06:00
2012-06-19 17:15:42 -06:00
skb = ( struct sk_buff * ) bulkdata - > d [ 0 ] . os_net_buf_ptr ;
2012-07-20 13:05:42 -06:00
align_offset = ( u32 ) ( long ) ( bulkdata - > d [ 0 ] . os_data_ptr ) & ( CSR_WIFI_ALIGN_BYTES - 1 ) ;
2012-06-19 17:15:42 -06:00
if ( align_offset ) {
skb_pull ( skb , align_offset ) ;
}
2012-06-19 18:33:16 -06:00
buffered_pkt - > bulkdata . os_data_ptr = bulkdata - > d [ 0 ] . os_data_ptr ;
buffered_pkt - > bulkdata . data_length = bulkdata - > d [ 0 ] . data_length ;
buffered_pkt - > bulkdata . os_net_buf_ptr = bulkdata - > d [ 0 ] . os_net_buf_ptr ;
buffered_pkt - > bulkdata . net_buf_length = bulkdata - > d [ 0 ] . net_buf_length ;
2012-06-19 17:15:42 -06:00
}
# endif
void
unifi_frame_ma_packet_req ( unifi_priv_t * priv , CSR_PRIORITY priority ,
CSR_RATE TransmitRate , CSR_CLIENT_TAG hostTag ,
2012-07-20 13:00:10 -06:00
u16 interfaceTag , CSR_TRANSMISSION_CONTROL transmissionControl ,
2012-07-20 12:51:01 -06:00
CSR_PROCESS_ID leSenderProcessId , u8 * peerMacAddress ,
2012-06-19 17:15:42 -06:00
CSR_SIGNAL * signal )
{
CSR_MA_PACKET_REQUEST * req = & signal - > u . MaPacketRequest ;
netInterface_priv_t * interfacePriv ;
2012-07-20 12:51:01 -06:00
u8 ba_session_idx = 0 ;
2012-06-19 17:15:42 -06:00
ba_session_tx_struct * ba_session = NULL ;
2012-07-20 12:51:01 -06:00
u8 * ba_addr = NULL ;
2012-06-19 17:15:42 -06:00
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
2012-07-06 09:28:14 -06:00
unifi_trace ( priv , UDBG5 ,
" In unifi_frame_ma_packet_req, Frame for Peer: %pMF \n " ,
peerMacAddress ) ;
2012-06-19 17:15:42 -06:00
signal - > SignalPrimitiveHeader . SignalId = CSR_MA_PACKET_REQUEST_ID ;
signal - > SignalPrimitiveHeader . ReceiverProcessId = 0 ;
signal - > SignalPrimitiveHeader . SenderProcessId = leSenderProcessId ;
/* Fill the MA-PACKET.req */
req - > Priority = priority ;
unifi_trace ( priv , UDBG3 , " Tx Frame with Priority: 0x%x \n " , req - > Priority ) ;
/* A value of 0 is used for auto selection of rates. But for P2P GO case
* for action frames the rate is governed by SME . Hence instead of 0 ,
* the rate is filled in with the value passed here
*/
req - > TransmitRate = TransmitRate ;
/* packets from netdev then no confirm required but packets from
* Nme / Sme eapol data frames requires the confirmation
*/
req - > TransmissionControl = transmissionControl ;
req - > VirtualInterfaceIdentifier =
uf_get_vif_identifier ( interfacePriv - > interfaceMode , interfaceTag ) ;
memcpy ( req - > Ra . x , peerMacAddress , ETH_ALEN ) ;
if ( hostTag = = 0xffffffff ) {
req - > HostTag = interfacePriv - > tag + + ;
req - > HostTag | = 0x40000000 ;
unifi_trace ( priv , UDBG3 , " new host tag assigned = 0x%x \n " , req - > HostTag ) ;
interfacePriv - > tag & = 0x0fffffff ;
} else {
req - > HostTag = hostTag ;
unifi_trace ( priv , UDBG3 , " host tag got from SME = 0x%x \n " , req - > HostTag ) ;
}
/* check if BA session exists for the peer MAC address on same tID */
if ( interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_AP | |
interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_P2PGO ) {
ba_addr = peerMacAddress ;
} else {
ba_addr = interfacePriv - > bssid . a ;
}
for ( ba_session_idx = 0 ; ba_session_idx < MAX_SUPPORTED_BA_SESSIONS_TX ; ba_session_idx + + ) {
ba_session = interfacePriv - > ba_session_tx [ ba_session_idx ] ;
if ( ba_session ) {
if ( ( ! memcmp ( ba_session - > macAddress . a , ba_addr , ETH_ALEN ) ) & & ( ba_session - > tID = = priority ) ) {
req - > TransmissionControl | = CSR_ALLOW_BA ;
break ;
}
}
}
unifi_trace ( priv , UDBG5 , " leaving unifi_frame_ma_packet_req \n " ) ;
}
# ifdef CSR_SUPPORT_SME
# define TRANSMISSION_CONTROL_TRIGGER_MASK 0x0001
2012-06-19 18:33:16 -06:00
# define TRANSMISSION_CONTROL_EOSP_MASK 0x0002
2012-06-19 17:15:42 -06:00
static
int frame_and_send_queued_pdu ( unifi_priv_t * priv , tx_buffered_packets_t * buffered_pkt ,
2012-07-20 13:25:15 -06:00
CsrWifiRouterCtrlStaInfo_t * staRecord , u8 moreData , u8 eosp )
2012-06-19 17:15:42 -06:00
{
CSR_SIGNAL signal ;
bulk_data_param_t bulkdata ;
int result ;
2012-07-20 12:51:01 -06:00
u8 toDs , fromDs , macHeaderLengthInBytes = MAC_HEADER_SIZE ;
u8 * qc ;
2012-07-20 13:00:10 -06:00
u16 * fc = ( u16 * ) ( buffered_pkt - > bulkdata . os_data_ptr ) ;
2012-06-19 17:15:42 -06:00
unsigned long lock_flags ;
unifi_trace ( priv , UDBG3 , " frame_and_send_queued_pdu with moreData: %d , EOSP: %d \n " , moreData , eosp ) ;
unifi_frame_ma_packet_req ( priv , buffered_pkt - > priority , buffered_pkt - > rate , buffered_pkt - > hostTag ,
buffered_pkt - > interfaceTag , buffered_pkt - > transmissionControl ,
buffered_pkt - > leSenderProcessId , buffered_pkt - > peerMacAddress . a , & signal ) ;
bulkdata . d [ 0 ] . os_data_ptr = buffered_pkt - > bulkdata . os_data_ptr ;
bulkdata . d [ 0 ] . data_length = buffered_pkt - > bulkdata . data_length ;
bulkdata . d [ 0 ] . os_net_buf_ptr = buffered_pkt - > bulkdata . os_net_buf_ptr ;
bulkdata . d [ 0 ] . net_buf_length = buffered_pkt - > bulkdata . net_buf_length ;
bulkdata . d [ 1 ] . os_data_ptr = NULL ;
bulkdata . d [ 1 ] . data_length = 0 ;
bulkdata . d [ 1 ] . os_net_buf_ptr = 0 ;
bulkdata . d [ 1 ] . net_buf_length = 0 ;
if ( moreData ) {
* fc | = cpu_to_le16 ( IEEE802_11_FC_MOREDATA_MASK ) ;
} else {
* fc & = cpu_to_le16 ( ~ IEEE802_11_FC_MOREDATA_MASK ) ;
}
if ( ( staRecord ! = NULL ) & & ( staRecord - > wmmOrQosEnabled = = TRUE ) )
{
unifi_trace ( priv , UDBG3 , " frame_and_send_queued_pdu WMM Enabled: %d \n " , staRecord - > wmmOrQosEnabled ) ;
toDs = ( * fc & cpu_to_le16 ( IEEE802_11_FC_TO_DS_MASK ) ) ? 1 : 0 ;
fromDs = ( * fc & cpu_to_le16 ( IEEE802_11_FC_FROM_DS_MASK ) ) ? 1 : 0 ;
switch ( le16_to_cpu ( * fc ) & IEEE80211_FC_SUBTYPE_MASK )
{
case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK :
case IEEE802_11_FC_TYPE_QOS_NULL & IEEE80211_FC_SUBTYPE_MASK :
/* If both are set then the Address4 exists (only for AP) */
2012-06-19 18:33:16 -06:00
if ( fromDs & & toDs ) {
2012-06-19 17:15:42 -06:00
/* 6 is the size of Address4 field */
macHeaderLengthInBytes + = ( QOS_CONTROL_HEADER_SIZE + 6 ) ;
2012-06-19 18:33:16 -06:00
} else {
2012-06-19 17:15:42 -06:00
macHeaderLengthInBytes + = QOS_CONTROL_HEADER_SIZE ;
}
/* If order bit set then HT control field is the part of MAC header */
if ( * fc & cpu_to_le16 ( IEEE80211_FC_ORDER_MASK ) ) {
macHeaderLengthInBytes + = HT_CONTROL_HEADER_SIZE ;
2012-07-20 12:51:01 -06:00
qc = ( u8 * ) ( buffered_pkt - > bulkdata . os_data_ptr + ( macHeaderLengthInBytes - 6 ) ) ;
2012-06-19 18:33:16 -06:00
} else {
2012-07-20 12:51:01 -06:00
qc = ( u8 * ) ( buffered_pkt - > bulkdata . os_data_ptr + ( macHeaderLengthInBytes - 2 ) ) ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
* qc = eosp ? * qc | ( 1 < < 4 ) : * qc & ( ~ ( 1 < < 4 ) ) ;
2012-06-19 17:15:42 -06:00
break ;
default :
if ( fromDs & & toDs )
macHeaderLengthInBytes + = 6 ;
}
}
result = ul_send_signal_unpacked ( priv , & signal , & bulkdata ) ;
if ( result ) {
_update_buffered_pkt_params_after_alignment ( priv , & bulkdata , buffered_pkt ) ;
}
/* Decrement the packet counts queued in driver */
if ( result ! = - ENOSPC ) {
/* protect entire counter updation by disabling preemption */
if ( ! priv - > noOfPktQueuedInDriver ) {
unifi_error ( priv , " packets queued in driver 0 still decrementing \n " ) ;
} else {
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
priv - > noOfPktQueuedInDriver - - ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
}
/* Sta Record is available for all unicast (except genericMgt Frames) & in other case its NULL */
if ( staRecord ) {
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
if ( ! staRecord - > noOfPktQueued ) {
unifi_error ( priv , " packets queued in driver per station is 0 still decrementing \n " ) ;
} else {
staRecord - > noOfPktQueued - - ;
}
/* if the STA alive probe frame has failed then reset the saved host tag */
if ( result ) {
if ( staRecord - > nullDataHostTag = = buffered_pkt - > hostTag ) {
staRecord - > nullDataHostTag = INVALID_HOST_TAG ;
}
}
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
}
}
return result ;
}
# ifdef CSR_SUPPORT_SME
static
void set_eosp_transmit_ctrl ( unifi_priv_t * priv , struct list_head * txList )
{
/* dequeue the tx data packets from the appropriate queue */
tx_buffered_packets_t * tx_q_item = NULL ;
struct list_head * listHead ;
struct list_head * placeHolder ;
unsigned long lock_flags ;
unifi_trace ( priv , UDBG5 , " entering set_eosp_transmit_ctrl \n " ) ;
/* check for list empty */
if ( list_empty ( txList ) ) {
unifi_warning ( priv , " In set_eosp_transmit_ctrl, the list is empty \n " ) ;
return ;
}
/* return the last node , and modify it. */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_for_each_prev_safe ( listHead , placeHolder , txList ) {
tx_q_item = list_entry ( listHead , tx_buffered_packets_t , q ) ;
2012-06-19 18:33:16 -06:00
tx_q_item - > transmissionControl | = TRANSMISSION_CONTROL_EOSP_MASK ;
2012-06-19 17:15:42 -06:00
tx_q_item - > transmissionControl = ( tx_q_item - > transmissionControl & ~ ( CSR_NO_CONFIRM_REQUIRED ) ) ;
unifi_trace ( priv , UDBG1 ,
" set_eosp_transmit_ctrl Transmission Control = 0x%x hostTag = 0x%x \n " , tx_q_item - > transmissionControl , tx_q_item - > hostTag ) ;
unifi_trace ( priv , UDBG3 , " in set_eosp_transmit_ctrl no.of buffered frames %d \n " , priv - > noOfPktQueuedInDriver ) ;
break ;
}
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
unifi_trace ( priv , UDBG1 , " List Empty %d \n " , list_empty ( txList ) ) ;
unifi_trace ( priv , UDBG5 , " leaving set_eosp_transmit_ctrl \n " ) ;
return ;
}
static
void send_vif_availibility_rsp ( unifi_priv_t * priv , CSR_VIF_IDENTIFIER vif , CSR_RESULT_CODE resultCode )
{
CSR_SIGNAL signal ;
CSR_MA_VIF_AVAILABILITY_RESPONSE * rsp ;
bulk_data_param_t * bulkdata = NULL ;
int r ;
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG3 , " send_vif_availibility_rsp : invoked with resultCode = %d \n " , resultCode ) ;
2012-06-19 17:15:42 -06:00
memset ( & signal , 0 , sizeof ( CSR_SIGNAL ) ) ;
rsp = & signal . u . MaVifAvailabilityResponse ;
rsp - > VirtualInterfaceIdentifier = vif ;
rsp - > ResultCode = resultCode ;
signal . SignalPrimitiveHeader . SignalId = CSR_MA_VIF_AVAILABILITY_RESPONSE_ID ;
signal . SignalPrimitiveHeader . ReceiverProcessId = 0 ;
signal . SignalPrimitiveHeader . SenderProcessId = priv - > netdev_client - > sender_id ;
/* Send the signal to UniFi */
r = ul_send_signal_unpacked ( priv , & signal , bulkdata ) ;
if ( r ) {
unifi_error ( priv , " Availibility response sending failed %x status %d \n " , vif , r ) ;
}
2012-06-19 18:33:16 -06:00
else {
unifi_trace ( priv , UDBG3 , " send_vif_availibility_rsp : status = %d \n " , r ) ;
}
2012-06-19 17:15:42 -06:00
}
# endif
static
void verify_and_accomodate_tx_packet ( unifi_priv_t * priv )
{
tx_buffered_packets_t * tx_q_item ;
unsigned long lock_flags ;
struct list_head * listHead , * list ;
struct list_head * placeHolder ;
2012-07-20 12:51:01 -06:00
u8 i , j , eospFramedeleted = 0 ;
2012-07-20 13:25:15 -06:00
u8 thresholdExcedeDueToBroadcast = TRUE ;
2012-06-19 17:15:42 -06:00
/* it will be made it interface Specific in the future when multi interfaces are supported ,
right now interface 0 is considered */
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ 0 ] ;
CsrWifiRouterCtrlStaInfo_t * staInfo = NULL ;
unifi_trace ( priv , UDBG3 , " entering verify_and_accomodate_tx_packet \n " ) ;
for ( i = 0 ; i < UNIFI_MAX_CONNECTIONS ; i + + ) {
staInfo = interfacePriv - > staInfo [ i ] ;
if ( staInfo & & ( staInfo - > noOfPktQueued > = CSR_WIFI_DRIVER_MAX_PKT_QUEUING_THRESHOLD_PER_PEER ) ) {
/* remove the first(oldest) packet from the all the access catogory, since data
* packets for station record crossed the threshold limit ( 64 for AP supporting
* 8 peers )
*/
unifi_trace ( priv , UDBG3 , " number of station pkts queued= %d for sta id = %d \n " , staInfo - > noOfPktQueued , staInfo - > aid ) ;
for ( j = 0 ; j < MAX_ACCESS_CATOGORY ; j + + ) {
list = & staInfo - > dataPdu [ j ] ;
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_for_each_safe ( listHead , placeHolder , list ) {
tx_q_item = list_entry ( listHead , tx_buffered_packets_t , q ) ;
list_del ( listHead ) ;
thresholdExcedeDueToBroadcast = FALSE ;
unifi_net_data_free ( priv , & tx_q_item - > bulkdata ) ;
kfree ( tx_q_item ) ;
tx_q_item = NULL ;
if ( ! priv - > noOfPktQueuedInDriver ) {
unifi_error ( priv , " packets queued in driver 0 still decrementing in %s \n " , __FUNCTION__ ) ;
} else {
/* protection provided by spinlock */
priv - > noOfPktQueuedInDriver - - ;
}
/* Sta Record is available for all unicast (except genericMgt Frames) & in other case its NULL */
if ( ! staInfo - > noOfPktQueued ) {
unifi_error ( priv , " packets queued in driver per station is 0 still decrementing in %s \n " , __FUNCTION__ ) ;
} else {
spin_lock ( & priv - > staRecord_lock ) ;
staInfo - > noOfPktQueued - - ;
spin_unlock ( & priv - > staRecord_lock ) ;
}
break ;
}
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
}
}
}
if ( thresholdExcedeDueToBroadcast & & interfacePriv - > noOfbroadcastPktQueued > CSR_WIFI_DRIVER_MINIMUM_BROADCAST_PKT_THRESHOLD ) {
/* Remove the packets from genericMulticastOrBroadCastFrames queue
* ( the max packets in driver is reached due to broadcast / multicast frames )
*/
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_for_each_safe ( listHead , placeHolder , & interfacePriv - > genericMulticastOrBroadCastFrames ) {
tx_q_item = list_entry ( listHead , tx_buffered_packets_t , q ) ;
if ( eospFramedeleted ) {
2012-06-19 18:33:16 -06:00
tx_q_item - > transmissionControl | = TRANSMISSION_CONTROL_EOSP_MASK ;
2012-06-19 17:15:42 -06:00
tx_q_item - > transmissionControl = ( tx_q_item - > transmissionControl & ~ ( CSR_NO_CONFIRM_REQUIRED ) ) ;
unifi_trace ( priv , UDBG1 , " updating eosp for next packet hostTag:= 0x%x " , tx_q_item - > hostTag ) ;
eospFramedeleted = 0 ;
break ;
}
2012-06-19 18:33:16 -06:00
if ( tx_q_item - > transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK ) {
2012-06-19 17:15:42 -06:00
eospFramedeleted = 1 ;
}
unifi_trace ( priv , UDBG1 , " freeing of multicast packets ToC = 0x%x hostTag = 0x%x \n " , tx_q_item - > transmissionControl , tx_q_item - > hostTag ) ;
list_del ( listHead ) ;
unifi_net_data_free ( priv , & tx_q_item - > bulkdata ) ;
kfree ( tx_q_item ) ;
priv - > noOfPktQueuedInDriver - - ;
spin_lock ( & priv - > staRecord_lock ) ;
interfacePriv - > noOfbroadcastPktQueued - - ;
spin_unlock ( & priv - > staRecord_lock ) ;
if ( ! eospFramedeleted ) {
break ;
}
}
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
}
unifi_trace ( priv , UDBG3 , " leaving verify_and_accomodate_tx_packet \n " ) ;
}
static
CsrResult enque_tx_data_pdu ( unifi_priv_t * priv , bulk_data_param_t * bulkdata ,
struct list_head * list , CSR_SIGNAL * signal ,
2012-07-20 13:25:15 -06:00
u8 requeueOnSamePos )
2012-06-19 17:15:42 -06:00
{
/* queue the tx data packets on to appropriate queue */
CSR_MA_PACKET_REQUEST * req = & signal - > u . MaPacketRequest ;
tx_buffered_packets_t * tx_q_item ;
unsigned long lock_flags ;
unifi_trace ( priv , UDBG5 , " entering enque_tx_data_pdu \n " ) ;
if ( ! list ) {
unifi_error ( priv , " List is not specified \n " ) ;
return CSR_RESULT_FAILURE ;
}
/* Removes aged packets & adds the incoming packet */
if ( priv - > noOfPktQueuedInDriver > = CSR_WIFI_DRIVER_SUPPORT_FOR_MAX_PKT_QUEUEING ) {
unifi_trace ( priv , UDBG3 , " number of pkts queued= %d \n " , priv - > noOfPktQueuedInDriver ) ;
verify_and_accomodate_tx_packet ( priv ) ;
}
tx_q_item = ( tx_buffered_packets_t * ) kmalloc ( sizeof ( tx_buffered_packets_t ) , GFP_ATOMIC ) ;
if ( tx_q_item = = NULL ) {
unifi_error ( priv ,
" Failed to allocate %d bytes for tx packet record \n " ,
sizeof ( tx_buffered_packets_t ) ) ;
return CSR_RESULT_FAILURE ;
}
/* disable the preemption */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
INIT_LIST_HEAD ( & tx_q_item - > q ) ;
/* fill the tx_q structure members */
tx_q_item - > bulkdata . os_data_ptr = bulkdata - > d [ 0 ] . os_data_ptr ;
tx_q_item - > bulkdata . data_length = bulkdata - > d [ 0 ] . data_length ;
tx_q_item - > bulkdata . os_net_buf_ptr = bulkdata - > d [ 0 ] . os_net_buf_ptr ;
tx_q_item - > bulkdata . net_buf_length = bulkdata - > d [ 0 ] . net_buf_length ;
tx_q_item - > interfaceTag = req - > VirtualInterfaceIdentifier & 0xff ;
tx_q_item - > hostTag = req - > HostTag ;
tx_q_item - > leSenderProcessId = signal - > SignalPrimitiveHeader . SenderProcessId ;
tx_q_item - > transmissionControl = req - > TransmissionControl ;
tx_q_item - > priority = req - > Priority ;
tx_q_item - > rate = req - > TransmitRate ;
memcpy ( tx_q_item - > peerMacAddress . a , req - > Ra . x , ETH_ALEN ) ;
if ( requeueOnSamePos ) {
list_add ( & tx_q_item - > q , list ) ;
} else {
list_add_tail ( & tx_q_item - > q , list ) ;
}
/* Count of packet queued in driver */
priv - > noOfPktQueuedInDriver + + ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
unifi_trace ( priv , UDBG5 , " leaving enque_tx_data_pdu \n " ) ;
return CSR_RESULT_SUCCESS ;
}
2012-06-19 18:33:16 -06:00
# ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL
2012-07-20 13:05:42 -06:00
CsrResult unifi_reque_ma_packet_request ( void * ospriv , u32 host_tag ,
2012-07-20 13:00:10 -06:00
u16 txStatus , bulk_data_desc_t * bulkDataDesc )
2012-06-19 17:15:42 -06:00
{
2012-06-19 18:33:16 -06:00
CsrResult status = CSR_RESULT_SUCCESS ;
unifi_priv_t * priv = ( unifi_priv_t * ) ospriv ;
netInterface_priv_t * interfacePriv ;
struct list_head * list = NULL ;
CsrWifiRouterCtrlStaInfo_t * staRecord = NULL ;
bulk_data_param_t bulkData ;
CSR_SIGNAL signal ;
CSR_PRIORITY priority = 0 ;
2012-07-20 13:00:10 -06:00
u16 interfaceTag = 0 ;
2012-06-19 18:33:16 -06:00
unifi_TrafficQueue priority_q ;
2012-07-20 13:00:10 -06:00
u16 frameControl = 0 , frameType = 0 ;
2012-06-19 18:33:16 -06:00
unsigned long lock_flags ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
/* If the current mode is not AP or P2PGO then just return failure
* to clear the hip slot
*/
if ( ! ( ( interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_AP ) | |
( interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_P2PGO ) ) ) {
return CSR_RESULT_FAILURE ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG6 , " unifi_reque_ma_packet_request: host_tag = 0x%x \n " , host_tag ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
staRecord = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( priv ,
2012-07-20 12:51:01 -06:00
( ( ( u8 * ) bulkDataDesc - > os_data_ptr ) + 4 ) ,
2012-06-19 18:33:16 -06:00
interfaceTag ) ;
if ( NULL = = staRecord ) {
unifi_trace ( priv , UDBG5 , " unifi_reque_ma_packet_request: Invalid STA record \n " ) ;
return CSR_RESULT_FAILURE ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
/* Update TIM if MA-PACKET.cfm fails with status as Tx-retry-limit or No-BSS and then just return failure
* to clear the hip slot associated with the Packet
*/
if ( CSR_TX_RETRY_LIMIT = = txStatus | | CSR_TX_NO_BSS = = txStatus ) {
if ( staRecord - > timSet = = CSR_WIFI_TIM_RESET | | staRecord - > timSet = = CSR_WIFI_TIM_RESETTING )
{
unifi_trace ( priv , UDBG2 , " unifi_reque_ma_packet_request: CFM failed with Retry Limit or No BSS-->update TIM \n " ) ;
if ( ! staRecord - > timRequestPendingFlag ) {
update_tim ( priv , staRecord - > aid , 1 , interfaceTag , staRecord - > assignedHandle ) ;
}
else {
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 1 ;
unifi_trace ( priv , UDBG6 , " unifi_reque_ma_packet_request: One more UpdateTim Request(:%d)Queued for AID %x \n " ,
staRecord - > updateTimReqQueued , staRecord - > aid ) ;
}
}
return CSR_RESULT_FAILURE ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
else if ( ( CSR_TX_LIFETIME = = txStatus ) | | ( CSR_TX_BLOCK_ACK_TIMEOUT = = txStatus ) | |
( CSR_TX_FAIL_TRANSMISSION_VIF_INTERRUPTED = = txStatus ) | |
( CSR_TX_REJECTED_PEER_STATION_SLEEPING = = txStatus ) | |
( CSR_TX_REJECTED_DTIM_STARTED = = txStatus ) ) {
/* Extract the Frame control and the frame type */
frameControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN ( bulkDataDesc - > os_data_ptr ) ;
frameType = ( ( frameControl & IEEE80211_FC_TYPE_MASK ) > > FRAME_CONTROL_TYPE_FIELD_OFFSET ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* Mgmt frames will not be re-queued for Tx
* so just return failure to clear the hip slot
*/
if ( IEEE802_11_FRAMETYPE_MANAGEMENT = = frameType ) {
return CSR_RESULT_FAILURE ;
}
else if ( IEEE802_11_FRAMETYPE_DATA = = frameType ) {
/* QOS NULL and DATA NULL frames will not be re-queued for Tx
* so just return failure to clear the hip slot
*/
if ( ( ( ( frameControl & IEEE80211_FC_SUBTYPE_MASK ) > > FRAME_CONTROL_SUBTYPE_FIELD_OFFSET ) = = QOS_DATA_NULL ) | |
( ( ( frameControl & IEEE80211_FC_SUBTYPE_MASK ) > > FRAME_CONTROL_SUBTYPE_FIELD_OFFSET ) = = DATA_NULL ) ) {
return CSR_RESULT_FAILURE ;
}
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* Extract the Packet priority */
if ( TRUE = = staRecord - > wmmOrQosEnabled ) {
2012-07-20 13:00:10 -06:00
u16 qosControl = 0 ;
2012-07-20 12:51:01 -06:00
u8 dataFrameType = 0 ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
dataFrameType = ( ( frameControl & IEEE80211_FC_SUBTYPE_MASK ) > > 4 ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( dataFrameType = = QOS_DATA ) {
/* QoS control field is offset from frame control by 2 (frame control)
* + 2 ( duration / ID ) + 2 ( sequence control ) + 3 * ETH_ALEN or 4 * ETH_ALEN
*/
if ( ( frameControl & IEEE802_11_FC_TO_DS_MASK ) & & ( frameControl & IEEE802_11_FC_FROM_DS_MASK ) ) {
qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN ( bulkDataDesc - > os_data_ptr + 30 ) ;
}
else {
qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN ( bulkDataDesc - > os_data_ptr + 24 ) ;
}
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
priority = ( CSR_PRIORITY ) ( qosControl & IEEE802_11_QC_TID_MASK ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( priority < CSR_QOS_UP0 | | priority > CSR_QOS_UP7 ) {
unifi_trace ( priv , UDBG5 , " unifi_reque_ma_packet_request: Invalid priority:%x \n " , priority ) ;
return CSR_RESULT_FAILURE ;
}
}
else {
priority = CSR_CONTENTION ;
}
/* Frame Bulk data to requeue it back to HAL Queues */
bulkData . d [ 0 ] . os_data_ptr = bulkDataDesc - > os_data_ptr ;
bulkData . d [ 0 ] . data_length = bulkDataDesc - > data_length ;
bulkData . d [ 0 ] . os_net_buf_ptr = bulkDataDesc - > os_net_buf_ptr ;
bulkData . d [ 0 ] . net_buf_length = bulkDataDesc - > net_buf_length ;
bulkData . d [ 1 ] . os_data_ptr = NULL ;
bulkData . d [ 1 ] . os_net_buf_ptr = NULL ;
bulkData . d [ 1 ] . data_length = bulkData . d [ 1 ] . net_buf_length = 0 ;
/* Initialize signal to zero */
memset ( & signal , 0 , sizeof ( CSR_SIGNAL ) ) ;
/* Frame MA Packet Req */
unifi_frame_ma_packet_req ( priv , priority , 0 , host_tag ,
interfaceTag , CSR_NO_CONFIRM_REQUIRED ,
priv - > netdev_client - > sender_id ,
staRecord - > peerMacAddress . a , & signal ) ;
/* Find the Q-Priority */
priority_q = unifi_frame_priority_to_queue ( priority ) ;
list = & staRecord - > dataPdu [ priority_q ] ;
/* Place the Packet on to HAL Queue */
status = enque_tx_data_pdu ( priv , & bulkData , list , & signal , TRUE ) ;
/* Update the Per-station queued packet counter */
if ( ! status ) {
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
staRecord - > noOfPktQueued + + ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
}
}
else {
/* Packet will not be re-queued for any of the other MA Packet Tx failure
* reasons so just return failure to clear the hip slot
*/
return CSR_RESULT_FAILURE ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
return status ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
# endif
2012-06-19 17:15:42 -06:00
2012-07-20 12:51:01 -06:00
static void is_all_ac_deliver_enabled_and_moredata ( CsrWifiRouterCtrlStaInfo_t * staRecord , u8 * allDeliveryEnabled , u8 * dataAvailable )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:51:01 -06:00
u8 i ;
2012-06-19 17:15:42 -06:00
* allDeliveryEnabled = TRUE ;
for ( i = 0 ; i < MAX_ACCESS_CATOGORY ; i + + ) {
if ( ! IS_DELIVERY_ENABLED ( staRecord - > powersaveMode [ i ] ) ) {
/* One is is not Delivery Enabled */
* allDeliveryEnabled = FALSE ;
break ;
}
}
if ( * allDeliveryEnabled ) {
* dataAvailable = ( ! list_empty ( & staRecord - > dataPdu [ 0 ] ) | | ! list_empty ( & staRecord - > dataPdu [ 1 ] )
| | ! list_empty ( & staRecord - > dataPdu [ 2 ] ) | | ! list_empty ( & staRecord - > dataPdu [ 3 ] )
| | ! list_empty ( & staRecord - > mgtFrames ) ) ;
}
}
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* uf_handle_tim_cfm
*
*
* This function updates tim status in host depending confirm status from firmware
*
* Arguments :
* priv Pointer to device private context struct
* cfm CSR_MLME_SET_TIM_CONFIRM
* receiverProcessId SenderProcessID to fetch handle & timSet status
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2012-07-20 13:00:10 -06:00
void uf_handle_tim_cfm ( unifi_priv_t * priv , CSR_MLME_SET_TIM_CONFIRM * cfm , u16 receiverProcessId )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:51:01 -06:00
u8 handle = CSR_WIFI_GET_STATION_HANDLE_FROM_RECEIVER_ID ( receiverProcessId ) ;
u8 timSetStatus = CSR_WIFI_GET_TIMSET_STATE_FROM_RECEIVER_ID ( receiverProcessId ) ;
2012-07-20 13:00:10 -06:00
u16 interfaceTag = ( cfm - > VirtualInterfaceIdentifier & 0xff ) ;
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
CsrWifiRouterCtrlStaInfo_t * staRecord = NULL ;
/* This variable holds what TIM value we wanted to set in firmware */
2012-07-20 13:00:10 -06:00
u16 timSetValue = 0 ;
2012-06-19 17:15:42 -06:00
/* Irrespective of interface the count maintained */
2012-07-20 12:51:01 -06:00
static u8 retryCount = 0 ;
2012-06-19 17:15:42 -06:00
unsigned long lock_flags ;
unifi_trace ( priv , UDBG3 , " entering %s, handle = %x, timSetStatus = %x \n " , __FUNCTION__ , handle , timSetStatus ) ;
if ( interfaceTag > = CSR_WIFI_NUM_INTERFACES ) {
unifi_warning ( priv , " bad interfaceTag = %x \n " , interfaceTag ) ;
return ;
}
if ( ( handle ! = CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE ) & & ( handle > = UNIFI_MAX_CONNECTIONS ) ) {
unifi_warning ( priv , " bad station Handle = %x \n " , handle ) ;
return ;
}
if ( handle ! = CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE ) {
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
if ( ( staRecord = ( ( CsrWifiRouterCtrlStaInfo_t * ) ( interfacePriv - > staInfo [ handle ] ) ) ) = = NULL ) {
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
unifi_warning ( priv , " uf_handle_tim_cfm: station record is NULL handle = %x \n " , handle ) ;
return ;
}
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
}
switch ( timSetStatus )
{
case CSR_WIFI_TIM_SETTING :
timSetValue = CSR_WIFI_TIM_SET ;
break ;
case CSR_WIFI_TIM_RESETTING :
timSetValue = CSR_WIFI_TIM_RESET ;
break ;
default :
unifi_warning ( priv , " timSet state is %x: Debug \n " , timSetStatus ) ;
return ;
}
/* check TIM confirm for success/failures */
switch ( cfm - > ResultCode )
{
case CSR_RC_SUCCESS :
if ( handle ! = CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE ) {
/* Unicast frame & station record available */
if ( timSetStatus = = staRecord - > timSet ) {
staRecord - > timSet = timSetValue ;
/* fh_cmd_q can also be full at some point of time!,
* resetting count as queue is cleaned by firmware at this point
*/
retryCount = 0 ;
unifi_trace ( priv , UDBG2 , " tim (%s) successfully in firmware \n " , ( timSetValue ) ? " SET " : " RESET " ) ;
} else {
unifi_trace ( priv , UDBG3 , " receiver processID = %x, success: request & confirm states are not matching in TIM cfm: Debug status = %x, staRecord->timSet = %x, handle = %x \n " ,
receiverProcessId , timSetStatus , staRecord - > timSet , handle ) ;
}
2012-06-19 18:33:16 -06:00
/* Reset TIM pending flag to send next TIM request */
staRecord - > timRequestPendingFlag = FALSE ;
/* Make sure that one more UpdateTim request is queued, if Queued its value
* should be CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET
*/
if ( 0xFF ! = staRecord - > updateTimReqQueued )
{
/* Process the UpdateTim Request which is queued while previous UpdateTim was in progress */
if ( staRecord - > timSet ! = staRecord - > updateTimReqQueued )
{
unifi_trace ( priv , UDBG2 , " uf_handle_tim_cfm : Processing Queued UpdateTimReq \n " ) ;
update_tim ( priv , staRecord - > aid , staRecord - > updateTimReqQueued , interfaceTag , handle ) ;
staRecord - > updateTimReqQueued = 0xFF ;
}
}
2012-06-19 17:15:42 -06:00
} else {
2012-06-19 18:33:16 -06:00
interfacePriv - > bcTimSet = timSetValue ;
2012-06-19 17:15:42 -06:00
/* fh_cmd_q can also be full at some point of time!,
* resetting count as queue is cleaned by firmware at this point
*/
retryCount = 0 ;
unifi_trace ( priv , UDBG3 , " tim (%s) successfully for broadcast frame in firmware \n " , ( timSetValue ) ? " SET " : " RESET " ) ;
2012-06-19 18:33:16 -06:00
/* Reset DTIM pending flag to send next DTIM request */
interfacePriv - > bcTimSetReqPendingFlag = FALSE ;
/* Make sure that one more UpdateDTim request is queued, if Queued its value
* should be CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET
*/
if ( 0xFF ! = interfacePriv - > bcTimSetReqQueued )
{
/* Process the UpdateTim Request which is queued while previous UpdateTim was in progress */
if ( interfacePriv - > bcTimSet ! = interfacePriv - > bcTimSetReqQueued )
{
unifi_trace ( priv , UDBG2 , " uf_handle_tim_cfm : Processing Queued UpdateDTimReq \n " ) ;
update_tim ( priv , 0 , interfacePriv - > bcTimSetReqQueued , interfaceTag , 0xFFFFFFFF ) ;
interfacePriv - > bcTimSetReqQueued = 0xFF ;
}
}
2012-06-19 17:15:42 -06:00
}
break ;
case CSR_RC_INVALID_PARAMETERS :
case CSR_RC_INSUFFICIENT_RESOURCE :
/* check for max retry limit & send again
* MAX_RETRY_LIMIT is not maintained for each set of transactions . . Its generic
* If failure crosses this Limit , we have to take a call to FIX
*/
if ( retryCount > UNIFI_MAX_RETRY_LIMIT ) {
2012-07-20 13:25:15 -06:00
u8 moreData = FALSE ;
2012-06-19 17:15:42 -06:00
retryCount = 0 ;
/* Because of continuos traffic in fh_cmd_q the tim set request is failing (exceeding retry limit)
* but if we didn ' t synchronize our timSet varible state with firmware then it can cause below issues
* cond 1. We want to SET tim in firmware if its fails & max retry limit reached
* - > If host set ' s the timSet to 1 , we wont try to send ( as max retry reached ) update tim but
* firmware is not updated with queue ( TIM ) status so it wont set TIM in beacon finally host start piling
* up data & wont try to set tim in firmware ( This can cause worser performance )
* cond 2. We want to reset tim in firmware it fails & reaches max retry limit
* - > If host sets the timSet to Zero , it wont try to set a TIM request unless we wont have any packets
* to be queued , so beacon unnecessarily advertizes the TIM
*/
if ( staRecord ) {
if ( ! staRecord - > wmmOrQosEnabled ) {
moreData = ( ! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) | |
! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_VO ] ) | |
! list_empty ( & staRecord - > mgtFrames ) ) ;
} else {
/* Peer is QSTA */
2012-07-20 12:51:01 -06:00
u8 allDeliveryEnabled = 0 , dataAvailable = 0 ;
2012-06-19 17:15:42 -06:00
/* Check if all AC's are Delivery Enabled */
is_all_ac_deliver_enabled_and_moredata ( staRecord , & allDeliveryEnabled , & dataAvailable ) ;
/*check for more data in non-delivery enabled queues*/
moreData = ( uf_is_more_data_for_non_delivery_ac ( staRecord ) | | ( allDeliveryEnabled & & dataAvailable ) ) ;
}
/* To avoid cond 1 & 2, check internal Queues status, if we have more Data then set RESET the timSet(0),
* so we are trying to be in sync with firmware & next packets before queuing atleast try to
* set TIM in firmware otherwise it SET timSet ( 1 )
*/
if ( moreData ) {
staRecord - > timSet = CSR_WIFI_TIM_RESET ;
} else {
staRecord - > timSet = CSR_WIFI_TIM_SET ;
}
} else {
/* Its a broadcast frames */
moreData = ( ! list_empty ( & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) | |
! list_empty ( & interfacePriv - > genericMulticastOrBroadCastFrames ) ) ;
if ( moreData ) {
update_tim ( priv , 0 , CSR_WIFI_TIM_SET , interfaceTag , 0xFFFFFFFF ) ;
} else {
update_tim ( priv , 0 , CSR_WIFI_TIM_RESET , interfaceTag , 0xFFFFFFFF ) ;
}
}
unifi_error ( priv , " no of error's for TIM setting crossed the Limit: verify \n " ) ;
return ;
}
retryCount + + ;
if ( handle ! = CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE ) {
if ( timSetStatus = = staRecord - > timSet ) {
unifi_warning ( priv , " tim request failed, retry for AID = %x \n " , staRecord - > aid ) ;
update_tim ( priv , staRecord - > aid , timSetValue , interfaceTag , handle ) ;
} else {
unifi_trace ( priv , UDBG1 , " failure: request & confirm states are not matching in TIM cfm: Debug status = %x, staRecord->timSet = %x \n " ,
timSetStatus , staRecord - > timSet ) ;
}
} else {
unifi_warning ( priv , " tim request failed, retry for broadcast frames \n " ) ;
update_tim ( priv , 0 , timSetValue , interfaceTag , 0xFFFFFFFF ) ;
}
break ;
default :
unifi_warning ( priv , " tim update request failed resultcode = %x \n " , cfm - > ResultCode ) ;
}
2012-06-19 18:33:16 -06:00
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG2 , " leaving %s \n " , __FUNCTION__ ) ;
}
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* update_tim
*
*
* This function updates tim status in firmware for AID [ 1 to UNIFI_MAX_CONNECTIONS ] or
* AID [ 0 ] for broadcast / multicast packets .
*
* NOTE : The LSB ( least significant BYTE ) of senderId while sending this MLME premitive
* has been modified ( utilized ) as below
*
* SenderID in signal ' s SignalPrimitiveHeader is 2 byte the lowe byte bitmap is below
*
* station handle ( 6 bits ) timSet Status ( 2 bits )
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 0 0 0 0 0 0 | 0 0
*
* timSet Status can be one of below :
*
* CSR_WIFI_TIM_RESET
* CSR_WIFI_TIM_RESETTING
* CSR_WIFI_TIM_SET
* CSR_WIFI_TIM_SETTING
*
* Arguments :
* priv Pointer to device private context struct
* aid can be 1 t0 UNIFI_MAX_CONNECTIONS & 0 means multicast / broadcast
* setTim value SET ( 1 ) / RESET ( 0 )
* interfaceTag the interfaceID on which activity going on
* handle from ( 0 < = handle < UNIFI_MAX_CONNECTIONS )
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2012-07-20 13:05:42 -06:00
void update_tim ( unifi_priv_t * priv , u16 aid , u8 setTim , u16 interfaceTag , u32 handle )
2012-06-19 17:15:42 -06:00
{
CSR_SIGNAL signal ;
2012-07-20 13:07:25 -06:00
s32 r ;
2012-06-19 17:15:42 -06:00
CSR_MLME_SET_TIM_REQUEST * req = & signal . u . MlmeSetTimRequest ;
bulk_data_param_t * bulkdata = NULL ;
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
2012-07-20 12:51:01 -06:00
u8 senderIdLsb = 0 ;
2012-06-19 17:15:42 -06:00
CsrWifiRouterCtrlStaInfo_t * staRecord = NULL ;
2012-07-20 13:05:42 -06:00
u32 oldTimSetStatus = 0 , timSetStatus = 0 ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG5 , " entering the update_tim routine \n " ) ;
2012-06-19 18:33:16 -06:00
2012-06-19 17:15:42 -06:00
if ( handle = = 0xFFFFFFFF ) {
handle & = CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE ;
2012-06-19 18:33:16 -06:00
if ( setTim = = interfacePriv - > bcTimSet )
{
unifi_trace ( priv , UDBG3 , " update_tim, Drop:Hdl=%x, timval=%d, globalTim=%d \n " , handle , setTim , interfacePriv - > bcTimSet ) ;
return ;
}
2012-06-19 17:15:42 -06:00
} else if ( ( handle ! = 0xFFFFFFFF ) & & ( handle > = UNIFI_MAX_CONNECTIONS ) ) {
unifi_warning ( priv , " bad station Handle = %x \n " , handle ) ;
return ;
}
if ( setTim ) {
timSetStatus = CSR_WIFI_TIM_SETTING ;
} else {
timSetStatus = CSR_WIFI_TIM_RESETTING ;
}
if ( handle ! = CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE ) {
if ( ( staRecord = ( ( CsrWifiRouterCtrlStaInfo_t * ) ( interfacePriv - > staInfo [ handle ] ) ) ) = = NULL ) {
unifi_warning ( priv , " station record is NULL in update_tim: handle = %x :debug \n " , handle ) ;
return ;
}
/* In case of signal sending failed, revert back to old state */
oldTimSetStatus = staRecord - > timSet ;
staRecord - > timSet = timSetStatus ;
}
/* pack senderID LSB */
senderIdLsb = CSR_WIFI_PACK_SENDER_ID_LSB_FOR_TIM_REQ ( handle , timSetStatus ) ;
/* initialize signal to zero */
memset ( & signal , 0 , sizeof ( CSR_SIGNAL ) ) ;
/* Frame the MLME-SET-TIM request */
signal . SignalPrimitiveHeader . SignalId = CSR_MLME_SET_TIM_REQUEST_ID ;
signal . SignalPrimitiveHeader . ReceiverProcessId = 0 ;
CSR_COPY_UINT16_TO_LITTLE_ENDIAN ( ( ( priv - > netdev_client - > sender_id & 0xff00 ) | senderIdLsb ) ,
( u8 * ) & signal . SignalPrimitiveHeader . SenderProcessId ) ;
/* set The virtual interfaceIdentifier, aid, tim value */
req - > VirtualInterfaceIdentifier = uf_get_vif_identifier ( interfacePriv - > interfaceMode , interfaceTag ) ;
req - > AssociationId = aid ;
req - > TimValue = setTim ;
unifi_trace ( priv , UDBG2 , " update_tim:AID %x,senderIdLsb = 0x%x, handle = 0x%x, timSetStatus = %x, sender proceesID = %x \n " ,
aid , senderIdLsb , handle , timSetStatus , signal . SignalPrimitiveHeader . SenderProcessId ) ;
/* Send the signal to UniFi */
r = ul_send_signal_unpacked ( priv , & signal , bulkdata ) ;
if ( r ) {
/* No need to free bulk data, as TIM request doesn't carries any data */
unifi_error ( priv , " Error queueing CSR_MLME_SET_TIM_REQUEST signal \n " ) ;
if ( staRecord ) {
staRecord - > timSet = oldTimSetStatus ;
}
2012-06-19 18:33:16 -06:00
else
{
/* MLME_SET_TIM.req sending failed here for AID0, so revert back our bcTimSet status */
interfacePriv - > bcTimSet = ! setTim ;
}
}
else {
/* Update tim request pending flag and ensure no more TIM set requests are send
for the same station until TIM confirm is received */
if ( staRecord ) {
staRecord - > timRequestPendingFlag = TRUE ;
}
else
{
/* Update tim request (for AID 0) pending flag and ensure no more DTIM set requests are send
* for the same station until TIM confirm is received
*/
interfacePriv - > bcTimSetReqPendingFlag = TRUE ;
}
2012-06-19 17:15:42 -06:00
}
unifi_trace ( priv , UDBG5 , " leaving the update_tim routine \n " ) ;
}
static
void process_peer_active_transition ( unifi_priv_t * priv ,
CsrWifiRouterCtrlStaInfo_t * staRecord ,
2012-07-20 13:00:10 -06:00
u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
int r , i ;
2012-07-20 13:25:15 -06:00
u8 spaceAvail [ 4 ] = { TRUE , TRUE , TRUE , TRUE } ;
2012-06-19 17:15:42 -06:00
tx_buffered_packets_t * buffered_pkt = NULL ;
unsigned long lock_flags ;
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
unifi_trace ( priv , UDBG5 , " entering process_peer_active_transition \n " ) ;
if ( IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) {
/* giving more priority to multicast packets so delaying unicast packets*/
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " Multicast transmission is going on so resume unicast transmission after DTIM over \n " ) ;
/* As station is active now, even though AP is not able to send frames to it
* because of DTIM , it needs to reset the TIM here
*/
if ( ! staRecord - > timRequestPendingFlag ) {
if ( ( staRecord - > timSet = = CSR_WIFI_TIM_SET ) | | ( staRecord - > timSet = = CSR_WIFI_TIM_SETTING ) ) {
update_tim ( priv , staRecord - > aid , 0 , interfaceTag , staRecord - > assignedHandle ) ;
}
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 0 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , staRecord - > updateTimReqQueued ,
staRecord - > aid ) ;
}
2012-06-19 17:15:42 -06:00
return ;
}
while ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staRecord - > mgtFrames ) ) ) {
buffered_pkt - > transmissionControl & =
2012-06-19 18:33:16 -06:00
~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staRecord , 0 , FALSE ) ) = = - ENOSPC ) {
unifi_trace ( priv , UDBG2 , " p_p_a_t:(ENOSPC) Mgt Frame queueing \n " ) ;
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staRecord - > mgtFrames ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 3 ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
spaceAvail [ 3 ] = FALSE ;
break ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
}
2012-06-19 18:33:16 -06:00
if ( ! staRecord - > timRequestPendingFlag ) {
if ( staRecord - > txSuspend ) {
if ( staRecord - > timSet = = CSR_WIFI_TIM_SET ) {
update_tim ( priv , staRecord - > aid , 0 , interfaceTag , staRecord - > assignedHandle ) ;
}
return ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 0 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , staRecord - > updateTimReqQueued ,
staRecord - > aid ) ;
2012-06-19 17:15:42 -06:00
}
for ( i = 3 ; i > = 0 ; i - - ) {
if ( ! spaceAvail [ i ] )
continue ;
unifi_trace ( priv , UDBG6 , " p_p_a_t:data pkt sending for AC %d \n " , i ) ;
while ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staRecord - > dataPdu [ i ] ) ) ) {
buffered_pkt - > transmissionControl & =
2012-06-19 18:33:16 -06:00
~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staRecord , 0 , FALSE ) ) = = - ENOSPC ) {
/* Clear the trigger bit transmission control*/
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staRecord - > dataPdu [ i ] ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ i ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
break ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
}
}
2012-06-19 18:33:16 -06:00
if ( ! staRecord - > timRequestPendingFlag ) {
if ( ( staRecord - > timSet = = CSR_WIFI_TIM_SET ) | | ( staRecord - > timSet = = CSR_WIFI_TIM_SETTING ) ) {
unifi_trace ( priv , UDBG3 , " p_p_a_t:resetting tim ..... \n " ) ;
update_tim ( priv , staRecord - > aid , 0 , interfaceTag , staRecord - > assignedHandle ) ;
}
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 0 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , staRecord - > updateTimReqQueued ,
staRecord - > aid ) ;
2012-06-19 17:15:42 -06:00
}
unifi_trace ( priv , UDBG5 , " leaving process_peer_active_transition \n " ) ;
}
2012-07-20 13:00:10 -06:00
void uf_process_ma_pkt_cfm_for_ap ( unifi_priv_t * priv , u16 interfaceTag , const CSR_MA_PACKET_CONFIRM * pkt_cfm )
2012-06-19 17:15:42 -06:00
{
netInterface_priv_t * interfacePriv ;
2012-07-20 12:51:01 -06:00
u8 i ;
2012-06-19 17:15:42 -06:00
CsrWifiRouterCtrlStaInfo_t * staRecord = NULL ;
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
if ( pkt_cfm - > HostTag = = interfacePriv - > multicastPduHostTag ) {
unifi_trace ( priv , UDBG2 , " CFM for marked Multicast Tag = %x \n " , interfacePriv - > multicastPduHostTag ) ;
interfacePriv - > multicastPduHostTag = 0xffffffff ;
resume_suspended_uapsd ( priv , interfaceTag ) ;
resume_unicast_buffered_frames ( priv , interfaceTag ) ;
if ( list_empty ( & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) & &
list_empty ( & interfacePriv - > genericMulticastOrBroadCastFrames ) ) {
unifi_trace ( priv , UDBG1 , " Resetting multicastTIM " ) ;
2012-06-19 18:33:16 -06:00
if ( ! interfacePriv - > bcTimSetReqPendingFlag )
{
update_tim ( priv , 0 , CSR_WIFI_TIM_RESET , interfaceTag , 0xFFFFFFFF ) ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
else
2012-06-19 17:15:42 -06:00
{
2012-06-19 18:33:16 -06:00
/* Cache the DTimSet value so that it will processed immidiatly after
* completing the current setDTim Request
*/
interfacePriv - > bcTimSetReqQueued = CSR_WIFI_TIM_RESET ;
unifi_trace ( priv , UDBG2 , " uf_process_ma_pkt_cfm_for_ap : One more UpdateDTim Request(%d) Queued \n " ,
interfacePriv - > bcTimSetReqQueued ) ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
return ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* Check if it is a Confirm for null data frame used
* for probing station activity
*/
for ( i = 0 ; i < UNIFI_MAX_CONNECTIONS ; i + + ) {
staRecord = ( CsrWifiRouterCtrlStaInfo_t * ) ( interfacePriv - > staInfo [ i ] ) ;
if ( staRecord & & ( staRecord - > nullDataHostTag = = pkt_cfm - > HostTag ) ) {
unifi_trace ( priv , UDBG1 , " CFM for Inactive probe Null frame (tag = %x, status = %d) \n " ,
pkt_cfm - > HostTag ,
pkt_cfm - > TransmissionStatus
) ;
staRecord - > nullDataHostTag = INVALID_HOST_TAG ;
if ( pkt_cfm - > TransmissionStatus = = CSR_TX_RETRY_LIMIT ) {
2012-10-24 00:33:57 -06:00
u32 now ;
u32 inactive_time ;
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG1 , " Nulldata to probe STA ALIVE Failed with retry limit \n " ) ;
/* Recheck if there is some activity after null data is sent.
*
* If still there is no activity then send a disconnected indication
* to SME to delete the station record .
*/
if ( staRecord - > activity_flag ) {
return ;
}
now = CsrTimeGet ( NULL ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( staRecord - > lastActivity > now )
{
/* simple timer wrap (for 1 wrap) */
2012-10-24 00:33:57 -06:00
inactive_time = CsrTimeAdd ( ( u32 ) CsrTimeSub ( CSR_SCHED_TIME_MAX , staRecord - > lastActivity ) ,
2012-06-19 18:33:16 -06:00
now ) ;
}
else
{
2012-10-24 00:33:57 -06:00
inactive_time = ( u32 ) CsrTimeSub ( now , staRecord - > lastActivity ) ;
2012-06-19 18:33:16 -06:00
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( inactive_time > = STA_INACTIVE_TIMEOUT_VAL )
{
struct list_head send_cfm_list ;
2012-07-20 12:51:01 -06:00
u8 j ;
2012-06-19 18:33:16 -06:00
/* The SME/NME may be waiting for confirmation for requested frames to this station.
* Though this is - - VERY UNLIKELY - - in case of station in active mode . But still as a
* a defensive check , it loops through buffered frames for this station and if confirmation
* is requested , send auto confirmation with failure status . Also flush the frames so
* that these are not processed again in PEER_DEL_REQ handler .
*/
INIT_LIST_HEAD ( & send_cfm_list ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
uf_prepare_send_cfm_list_for_queued_pkts ( priv ,
& send_cfm_list ,
& ( staRecord - > mgtFrames ) ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
uf_flush_list ( priv , & ( staRecord - > mgtFrames ) ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
for ( j = 0 ; j < MAX_ACCESS_CATOGORY ; j + + ) {
2012-06-19 17:15:42 -06:00
uf_prepare_send_cfm_list_for_queued_pkts ( priv ,
& send_cfm_list ,
2012-06-19 18:33:16 -06:00
& ( staRecord - > dataPdu [ j ] ) ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
uf_flush_list ( priv , & ( staRecord - > dataPdu [ j ] ) ) ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
send_auto_ma_packet_confirm ( priv , staRecord - > interfacePriv , & send_cfm_list ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
unifi_warning ( priv , " uf_process_ma_pkt_cfm_for_ap: Router Disconnected IND Peer (%x-%x-%x-%x-%x-%x) \n " ,
staRecord - > peerMacAddress . a [ 0 ] ,
staRecord - > peerMacAddress . a [ 1 ] ,
staRecord - > peerMacAddress . a [ 2 ] ,
staRecord - > peerMacAddress . a [ 3 ] ,
staRecord - > peerMacAddress . a [ 4 ] ,
staRecord - > peerMacAddress . a [ 5 ] ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
CsrWifiRouterCtrlConnectedIndSend ( priv - > CSR_WIFI_SME_IFACEQUEUE ,
0 ,
staRecord - > interfacePriv - > InterfaceTag ,
staRecord - > peerMacAddress ,
CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED ) ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
}
else if ( pkt_cfm - > TransmissionStatus = = CSR_TX_SUCCESSFUL )
{
staRecord - > activity_flag = TRUE ;
2012-06-19 17:15:42 -06:00
}
}
}
}
# endif
2012-07-20 13:00:10 -06:00
u16 uf_get_vif_identifier ( CsrWifiRouterCtrlMode mode , u16 tag )
2012-06-19 17:15:42 -06:00
{
switch ( mode )
{
case CSR_WIFI_ROUTER_CTRL_MODE_STA :
case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI :
return ( 0x02 < < 8 | tag ) ;
case CSR_WIFI_ROUTER_CTRL_MODE_AP :
case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO :
return ( 0x03 < < 8 | tag ) ;
case CSR_WIFI_ROUTER_CTRL_MODE_IBSS :
return ( 0x01 < < 8 | tag ) ;
case CSR_WIFI_ROUTER_CTRL_MODE_MONITOR :
return ( 0x04 < < 8 | tag ) ;
case CSR_WIFI_ROUTER_CTRL_MODE_AMP :
return ( 0x05 < < 8 | tag ) ;
default :
return tag ;
}
}
# ifdef CSR_SUPPORT_SME
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* update_macheader
*
*
* These functions updates mac header for intra BSS packet
* routing .
* NOTE : This function always has to be called in rx context which
* is in bh thread context since GFP_KERNEL is used . In soft IRQ / Interrupt
* context shouldn ' t be used
*
* Arguments :
* priv Pointer to device private context struct
* skb Socket buffer containing data packet to transmit
* newSkb Socket buffer containing data packet + Mac header if no sufficient headroom in skb
* priority to append QOS control header in Mac header
* bulkdata if newSkb allocated then bulkdata updated to send to unifi
* interfaceTag the interfaceID on which activity going on
* macHeaderLengthInBytes no . of bytes of mac header in received frame
* qosDestination used to append Qos control field
*
* Returns :
* Zero on success or - 1 on error .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static int update_macheader ( unifi_priv_t * priv , struct sk_buff * skb ,
struct sk_buff * newSkb , CSR_PRIORITY * priority ,
2012-07-20 13:00:10 -06:00
bulk_data_param_t * bulkdata , u16 interfaceTag ,
2012-07-20 12:51:01 -06:00
u8 macHeaderLengthInBytes ,
u8 qosDestination )
2012-06-19 17:15:42 -06:00
{
2012-07-20 13:00:10 -06:00
u16 * fc = NULL ;
2012-07-20 12:51:01 -06:00
u8 direction = 0 , toDs , fromDs ;
u8 * bufPtr = NULL ;
u8 sa [ ETH_ALEN ] , da [ ETH_ALEN ] ;
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
int headroom ;
2012-07-20 12:51:01 -06:00
u8 macHeaderBuf [ IEEE802_11_DATA_FRAME_MAC_HEADER_SIZE ] = { 0 } ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG5 , " entering the update_macheader function \n " ) ;
/* temporary buffer for the Mac header storage */
memcpy ( macHeaderBuf , skb - > data , macHeaderLengthInBytes ) ;
/* remove the Macheader from the skb */
skb_pull ( skb , macHeaderLengthInBytes ) ;
/* get the skb headroom for skb_push check */
headroom = skb_headroom ( skb ) ;
/* pointer to frame control field */
2012-07-20 13:00:10 -06:00
fc = ( u16 * ) macHeaderBuf ;
2012-06-19 17:15:42 -06:00
toDs = ( * fc & cpu_to_le16 ( IEEE802_11_FC_TO_DS_MASK ) ) ? 1 : 0 ;
fromDs = ( * fc & cpu_to_le16 ( IEEE802_11_FC_FROM_DS_MASK ) ) ? 1 : 0 ;
unifi_trace ( priv , UDBG5 , " In update_macheader function, fromDs = %x, toDs = %x \n " , fromDs , toDs ) ;
direction = ( ( fromDs | ( toDs < < 1 ) ) & 0x3 ) ;
/* Address1 or 3 from the macheader */
memcpy ( da , macHeaderBuf + 4 + toDs * 12 , ETH_ALEN ) ;
/* Address2, 3 or 4 from the mac header */
memcpy ( sa , macHeaderBuf + 10 + fromDs * ( 6 + toDs * 8 ) , ETH_ALEN ) ;
unifi_trace ( priv , UDBG3 , " update_macheader:direction = %x \n " , direction ) ;
/* update the toDs, fromDs & address fields in Mac header */
switch ( direction )
{
case 2 :
/* toDs = 1 & fromDs = 0 , toAp when frames received from peer
* while sending this packet to Destination the Mac header changed
* as fromDs = 1 & toDs = 0 , fromAp
*/
* fc & = cpu_to_le16 ( ~ IEEE802_11_FC_TO_DS_MASK ) ;
* fc | = cpu_to_le16 ( IEEE802_11_FC_FROM_DS_MASK ) ;
/* Address1: MAC address of the actual destination (4 = 2+2) */
memcpy ( macHeaderBuf + 4 , da , ETH_ALEN ) ;
/* Address2: The MAC address of the AP (10 = 2+2+6) */
memcpy ( macHeaderBuf + 10 , & interfacePriv - > bssid , ETH_ALEN ) ;
/* Address3: MAC address of the actual source from mac header (16 = 2+2+6+6) */
memcpy ( macHeaderBuf + 16 , sa , ETH_ALEN ) ;
break ;
case 3 :
unifi_trace ( priv , UDBG3 , " when both the toDs & fromDS set, NOT SUPPORTED \n " ) ;
break ;
default :
unifi_trace ( priv , UDBG3 , " problem in decoding packet in update_macheader \n " ) ;
return - 1 ;
}
/* frameType is Data always, Validation is done before calling this function */
/* check for the souce station type */
switch ( le16_to_cpu ( * fc ) & IEEE80211_FC_SUBTYPE_MASK )
{
case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK :
/* No need to modify the qos control field */
if ( ! qosDestination ) {
/* If source Sta is QOS enabled & if this bit set, then HTC is supported by
* peer station & htc field present in macHeader
*/
if ( * fc & cpu_to_le16 ( IEEE80211_FC_ORDER_MASK ) ) {
/* HT control field present in Mac header
* 6 = sizeof ( qosControl ) + sizeof ( htc )
*/
macHeaderLengthInBytes - = 6 ;
} else {
macHeaderLengthInBytes - = 2 ;
}
/* Destination STA is non qos so change subtype to DATA */
* fc & = cpu_to_le16 ( ~ IEEE80211_FC_SUBTYPE_MASK ) ;
* fc | = cpu_to_le16 ( IEEE802_11_FC_TYPE_DATA ) ;
/* remove the qos control field & HTC(if present). new macHeaderLengthInBytes is less than old
* macHeaderLengthInBytes so no need to verify skb headroom
*/
if ( headroom < macHeaderLengthInBytes ) {
unifi_trace ( priv , UDBG1 , " sufficient headroom not there to push updated mac header \n " ) ;
return - 1 ;
}
2012-07-20 12:51:01 -06:00
bufPtr = ( u8 * ) skb_push ( skb , macHeaderLengthInBytes ) ;
2012-06-19 17:15:42 -06:00
/* update bulk data os_data_ptr */
bulkdata - > d [ 0 ] . os_data_ptr = skb - > data ;
bulkdata - > d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) skb ;
bulkdata - > d [ 0 ] . data_length = skb - > len ;
} else {
/* pointing to QOS control field */
2012-07-20 12:51:01 -06:00
u8 qc ;
2012-06-19 17:15:42 -06:00
if ( * fc & cpu_to_le16 ( IEEE80211_FC_ORDER_MASK ) ) {
2012-07-20 12:51:01 -06:00
qc = * ( ( u8 * ) ( macHeaderBuf + ( macHeaderLengthInBytes - 4 - 2 ) ) ) ;
2012-06-19 17:15:42 -06:00
} else {
2012-07-20 12:51:01 -06:00
qc = * ( ( u8 * ) ( macHeaderBuf + ( macHeaderLengthInBytes - 2 ) ) ) ;
2012-06-19 17:15:42 -06:00
}
if ( ( qc & IEEE802_11_QC_TID_MASK ) > 7 ) {
* priority = 7 ;
} else {
* priority = qc & IEEE802_11_QC_TID_MASK ;
}
unifi_trace ( priv , UDBG1 , " Incoming packet priority from QSTA is %x \n " , * priority ) ;
if ( headroom < macHeaderLengthInBytes ) {
unifi_trace ( priv , UDBG3 , " sufficient headroom not there to push updated mac header \n " ) ;
return - 1 ;
}
2012-07-20 12:51:01 -06:00
bufPtr = ( u8 * ) skb_push ( skb , macHeaderLengthInBytes ) ;
2012-06-19 17:15:42 -06:00
}
break ;
default :
{
bulk_data_param_t data_ptrs ;
CsrResult csrResult ;
unifi_trace ( priv , UDBG5 , " normal Data packet, NO QOS \n " ) ;
if ( qosDestination ) {
2012-07-20 12:51:01 -06:00
u8 qc = 0 ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG3 , " destination is QOS station \n " ) ;
2012-06-19 18:33:16 -06:00
/* Set Ma-Packet.req UP to UP0 */
* priority = CSR_QOS_UP0 ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* prepare the qos control field */
qc | = CSR_QOS_UP0 ;
2012-06-19 17:15:42 -06:00
/* no Amsdu is in ap buffer so eosp is left 0 */
if ( da [ 0 ] & 0x1 ) {
/* multicast/broadcast frames, no acknowledgement needed */
qc | = 1 < < 5 ;
}
/* update new Mac header Length with 2 = sizeof(qos control) */
macHeaderLengthInBytes + = 2 ;
/* received DATA frame but destiantion is QOS station so update subtype to QOS*/
* fc & = cpu_to_le16 ( ~ IEEE80211_FC_SUBTYPE_MASK ) ;
* fc | = cpu_to_le16 ( IEEE802_11_FC_TYPE_QOS_DATA ) ;
/* appendQosControlOffset = macHeaderLengthInBytes - 2, since source sta is not QOS */
macHeaderBuf [ macHeaderLengthInBytes - 2 ] = qc ;
/* txopLimit is 0 */
macHeaderBuf [ macHeaderLengthInBytes - 1 ] = 0 ;
if ( headroom < macHeaderLengthInBytes ) {
csrResult = unifi_net_data_malloc ( priv , & data_ptrs . d [ 0 ] , skb - > len + macHeaderLengthInBytes ) ;
if ( csrResult ! = CSR_RESULT_SUCCESS ) {
unifi_error ( priv , " failed to allocate request_data. in update_macheader func \n " ) ;
return - 1 ;
}
newSkb = ( struct sk_buff * ) ( data_ptrs . d [ 0 ] . os_net_buf_ptr ) ;
newSkb - > len = skb - > len + macHeaderLengthInBytes ;
memcpy ( ( void * ) data_ptrs . d [ 0 ] . os_data_ptr + macHeaderLengthInBytes ,
skb - > data , skb - > len ) ;
bulkdata - > d [ 0 ] . os_data_ptr = newSkb - > data ;
bulkdata - > d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) newSkb ;
bulkdata - > d [ 0 ] . data_length = newSkb - > len ;
2012-07-20 12:51:01 -06:00
bufPtr = ( u8 * ) data_ptrs . d [ 0 ] . os_data_ptr ;
2012-06-19 17:15:42 -06:00
/* The old skb will not be used again */
kfree_skb ( skb ) ;
} else {
/* skb headroom is sufficient to append Macheader */
2012-07-20 12:51:01 -06:00
bufPtr = ( u8 * ) skb_push ( skb , macHeaderLengthInBytes ) ;
2012-06-19 17:15:42 -06:00
bulkdata - > d [ 0 ] . os_data_ptr = skb - > data ;
bulkdata - > d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) skb ;
bulkdata - > d [ 0 ] . data_length = skb - > len ;
}
} else {
unifi_trace ( priv , UDBG3 , " destination is not a QSTA \n " ) ;
if ( headroom < macHeaderLengthInBytes ) {
csrResult = unifi_net_data_malloc ( priv , & data_ptrs . d [ 0 ] , skb - > len + macHeaderLengthInBytes ) ;
if ( csrResult ! = CSR_RESULT_SUCCESS ) {
unifi_error ( priv , " failed to allocate request_data. in update_macheader func \n " ) ;
return - 1 ;
}
newSkb = ( struct sk_buff * ) ( data_ptrs . d [ 0 ] . os_net_buf_ptr ) ;
newSkb - > len = skb - > len + macHeaderLengthInBytes ;
memcpy ( ( void * ) data_ptrs . d [ 0 ] . os_data_ptr + macHeaderLengthInBytes ,
skb - > data , skb - > len ) ;
bulkdata - > d [ 0 ] . os_data_ptr = newSkb - > data ;
bulkdata - > d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) newSkb ;
bulkdata - > d [ 0 ] . data_length = newSkb - > len ;
2012-07-20 12:51:01 -06:00
bufPtr = ( u8 * ) data_ptrs . d [ 0 ] . os_data_ptr ;
2012-06-19 17:15:42 -06:00
/* The old skb will not be used again */
kfree_skb ( skb ) ;
} else {
/* skb headroom is sufficient to append Macheader */
2012-07-20 12:51:01 -06:00
bufPtr = ( u8 * ) skb_push ( skb , macHeaderLengthInBytes ) ;
2012-06-19 17:15:42 -06:00
bulkdata - > d [ 0 ] . os_data_ptr = skb - > data ;
bulkdata - > d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) skb ;
bulkdata - > d [ 0 ] . data_length = skb - > len ;
}
}
}
}
/* prepare the complete skb, by pushing the MAC header to the begining of the skb->data */
unifi_trace ( priv , UDBG5 , " updated Mac Header: %d \n " , macHeaderLengthInBytes ) ;
memcpy ( bufPtr , macHeaderBuf , macHeaderLengthInBytes ) ;
unifi_trace ( priv , UDBG5 , " leaving the update_macheader function \n " ) ;
return 0 ;
}
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* uf_ap_process_data_pdu
*
*
* Takes care of intra BSS admission control & routing packets within BSS
*
* Arguments :
* priv Pointer to device private context struct
* skb Socket buffer containing data packet to transmit
* ehdr ethernet header to fetch priority of packet
* srcStaInfo source stations record for connection verification
* packed_signal
* signal_len
* signal MA - PACKET . indication signal
* bulkdata if newSkb allocated then bulkdata updated to send to unifi
* macHeaderLengthInBytes no . of bytes of mac header in received frame
*
* Returns :
* Zero on success ( ap processing complete ) or - 1 if packet also have to be sent to NETDEV .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
int
uf_ap_process_data_pdu ( unifi_priv_t * priv , struct sk_buff * skb ,
struct ethhdr * ehdr , CsrWifiRouterCtrlStaInfo_t * srcStaInfo ,
const CSR_SIGNAL * signal ,
bulk_data_param_t * bulkdata ,
2012-07-20 12:51:01 -06:00
u8 macHeaderLengthInBytes )
2012-06-19 17:15:42 -06:00
{
const CSR_MA_PACKET_INDICATION * ind = & ( signal - > u . MaPacketIndication ) ;
2012-07-20 13:00:10 -06:00
u16 interfaceTag = ( ind - > VirtualInterfaceIdentifier & 0x00ff ) ;
2012-06-19 17:15:42 -06:00
struct sk_buff * newSkb = NULL ;
/* pointer to skb or private skb created using skb_copy() */
struct sk_buff * skbPtr = skb ;
2012-07-20 13:25:15 -06:00
u8 sendToNetdev = FALSE ;
u8 qosDestination = FALSE ;
2012-06-19 17:15:42 -06:00
CSR_PRIORITY priority = CSR_CONTENTION ;
CsrWifiRouterCtrlStaInfo_t * dstStaInfo = NULL ;
netInterface_priv_t * interfacePriv ;
unifi_trace ( priv , UDBG5 , " entering uf_ap_process_data_pdu %d \n " , macHeaderLengthInBytes ) ;
/* InterfaceTag validation from MA_PACKET.indication */
if ( interfaceTag > = CSR_WIFI_NUM_INTERFACES ) {
unifi_trace ( priv , UDBG1 , " Interface Tag is Invalid in uf_ap_process_data_pdu \n " ) ;
unifi_net_data_free ( priv , & bulkdata - > d [ 0 ] ) ;
return 0 ;
}
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
if ( ( interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_P2PGO ) & &
( interfacePriv - > intraBssEnabled = = FALSE ) ) {
unifi_trace ( priv , UDBG2 , " uf_ap_process_data_pdu:P2P GO intrabssEnabled?= %d \n " , interfacePriv - > intraBssEnabled ) ;
/*In P2P GO case, if intraBSS distribution Disabled then don't do IntraBSS routing */
/* If destination in our BSS then drop otherwise give packet to netdev */
dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( priv , ehdr - > h_dest , interfaceTag ) ;
if ( dstStaInfo ) {
unifi_net_data_free ( priv , & bulkdata - > d [ 0 ] ) ;
return 0 ;
}
/* May be associated P2PCLI trying to send the packets on backbone (Netdev) */
return - 1 ;
}
if ( ! memcmp ( ehdr - > h_dest , interfacePriv - > bssid . a , ETH_ALEN ) ) {
/* This packet will be given to the TCP/IP stack since this packet is for us(AP)
* No routing needed */
unifi_trace ( priv , UDBG4 , " destination address is csr_ap \n " ) ;
return - 1 ;
}
/* fetch the destination record from staion record database */
dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( priv , ehdr - > h_dest , interfaceTag ) ;
/* AP mode processing, & if packet is unicast */
if ( ! dstStaInfo ) {
if ( ! ( ehdr - > h_dest [ 0 ] & 0x1 ) ) {
/* destination not in station record & its a unicast packet, so pass the packet to network stack */
unifi_trace ( priv , UDBG3 , " unicast frame & destination record not exist, send to netdev proto = %x \n " , htons ( skb - > protocol ) ) ;
return - 1 ;
} else {
/* packet is multicast/broadcast */
/* copy the skb to skbPtr, send skb to netdev & skbPtr to multicast/broad cast list */
unifi_trace ( priv , UDBG5 , " skb_copy, in uf_ap_process_data_pdu, protocol = %x \n " , htons ( skb - > protocol ) ) ;
skbPtr = skb_copy ( skb , GFP_KERNEL ) ;
if ( skbPtr = = NULL ) {
/* We don't have memory to don't send the frame in BSS*/
unifi_notice ( priv , " broacast/multicast frame can't be sent in BSS No memeory: proto = %x \n " , htons ( skb - > protocol ) ) ;
return - 1 ;
}
sendToNetdev = TRUE ;
}
} else {
/* validate the Peer & Destination Station record */
if ( uf_process_station_records_for_sending_data ( priv , interfaceTag , srcStaInfo , dstStaInfo ) ) {
unifi_notice ( priv , " uf_ap_process_data_pdu: station record validation failed \n " ) ;
interfacePriv - > stats . rx_errors + + ;
unifi_net_data_free ( priv , & bulkdata - > d [ 0 ] ) ;
return 0 ;
}
}
/* BroadCast packet received and it's been sent as non QOS packets.
* Since WMM spec not mandates broadcast / multicast to be sent as QOS data only ,
* if all Peers are QSTA
*/
if ( sendToNetdev ) {
/* BroadCast packet and it's been sent as non QOS packets */
qosDestination = FALSE ;
} else if ( dstStaInfo & & ( dstStaInfo - > wmmOrQosEnabled = = TRUE ) ) {
qosDestination = TRUE ;
}
unifi_trace ( priv , UDBG3 , " uf_ap_process_data_pdu QoS destination = %s \n " , ( qosDestination ) ? " TRUE " : " FALSE " ) ;
/* packet is allowed to send to unifi, update the Mac header */
if ( update_macheader ( priv , skbPtr , newSkb , & priority , bulkdata , interfaceTag , macHeaderLengthInBytes , qosDestination ) ) {
interfacePriv - > stats . rx_errors + + ;
unifi_notice ( priv , " (Packet Drop) failed to update the Mac header in uf_ap_process_data_pdu \n " ) ;
if ( sendToNetdev ) {
/* Free's the skb_copy(skbPtr) data since packet processing failed */
bulkdata - > d [ 0 ] . os_data_ptr = skbPtr - > data ;
bulkdata - > d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) skbPtr ;
bulkdata - > d [ 0 ] . data_length = skbPtr - > len ;
unifi_net_data_free ( priv , & bulkdata - > d [ 0 ] ) ;
}
return - 1 ;
}
unifi_trace ( priv , UDBG3 , " Mac Header updated...calling uf_process_ma_packet_req \n " ) ;
/* Packet is ready to send to unifi ,transmissionControl = 0x0004, confirmation is not needed for data packets */
if ( uf_process_ma_packet_req ( priv , ehdr - > h_dest , 0xffffffff , interfaceTag , CSR_NO_CONFIRM_REQUIRED , ( CSR_RATE ) 0 , priority , priv - > netdev_client - > sender_id , bulkdata ) ) {
if ( sendToNetdev ) {
unifi_trace ( priv , UDBG1 , " In uf_ap_process_data_pdu, (Packet Drop) uf_process_ma_packet_req failed. freeing skb_copy data (original data sent to Netdev) \n " ) ;
/* Free's the skb_copy(skbPtr) data since packet processing failed */
bulkdata - > d [ 0 ] . os_data_ptr = skbPtr - > data ;
bulkdata - > d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) skbPtr ;
bulkdata - > d [ 0 ] . data_length = skbPtr - > len ;
unifi_net_data_free ( priv , & bulkdata - > d [ 0 ] ) ;
} else {
/* This free's the skb data */
unifi_trace ( priv , UDBG1 , " In uf_ap_process_data_pdu, (Packet Drop). Unicast data so freeing original skb \n " ) ;
unifi_net_data_free ( priv , & bulkdata - > d [ 0 ] ) ;
}
}
unifi_trace ( priv , UDBG5 , " leaving uf_ap_process_data_pdu \n " ) ;
if ( sendToNetdev ) {
/* The packet is multicast/broadcast, so after AP processing packet has to
* be sent to netdev , if peer port state is open
*/
unifi_trace ( priv , UDBG4 , " Packet will be routed to NetDev \n " ) ;
return - 1 ;
}
/* Ap handled the packet & its a unicast packet, no need to send to netdev */
return 0 ;
}
# endif
CsrResult uf_process_ma_packet_req ( unifi_priv_t * priv ,
2012-07-20 12:51:01 -06:00
u8 * peerMacAddress ,
2012-06-19 17:15:42 -06:00
CSR_CLIENT_TAG hostTag ,
2012-07-20 13:00:10 -06:00
u16 interfaceTag ,
2012-06-19 17:15:42 -06:00
CSR_TRANSMISSION_CONTROL transmissionControl ,
CSR_RATE TransmitRate ,
CSR_PRIORITY priority ,
CSR_PROCESS_ID leSenderProcessId ,
bulk_data_param_t * bulkdata )
{
CsrResult status = CSR_RESULT_SUCCESS ;
CSR_SIGNAL signal ;
int result ;
# ifdef CSR_SUPPORT_SME
CsrWifiRouterCtrlStaInfo_t * staRecord = NULL ;
2012-07-20 12:51:01 -06:00
const u8 * macHdrLocation = bulkdata - > d [ 0 ] . os_data_ptr ;
2012-06-19 17:15:42 -06:00
CsrWifiPacketType pktType ;
int frameType = 0 ;
2012-07-20 13:25:15 -06:00
u8 queuePacketDozing = FALSE ;
2012-07-20 13:05:42 -06:00
u32 priority_q ;
2012-07-20 13:00:10 -06:00
u16 frmCtrl ;
2012-06-19 17:15:42 -06:00
struct list_head * list = NULL ; /* List to which buffered PDUs are to be enqueued*/
2012-07-20 13:25:15 -06:00
u8 setBcTim = FALSE ;
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv ;
2012-07-20 13:25:15 -06:00
u8 requeueOnSamePos = FALSE ;
2012-07-20 13:05:42 -06:00
u32 handle = 0xFFFFFFFF ;
2012-06-19 17:15:42 -06:00
unsigned long lock_flags ;
2012-07-06 09:28:14 -06:00
unifi_trace ( priv , UDBG5 ,
" entering uf_process_ma_packet_req, peer: %pMF \n " ,
peerMacAddress ) ;
2012-06-19 17:15:42 -06:00
if ( interfaceTag > = CSR_WIFI_NUM_INTERFACES ) {
unifi_error ( priv , " interfaceTag >= CSR_WIFI_NUM_INTERFACES, interfacetag = %d \n " , interfaceTag ) ;
return CSR_RESULT_FAILURE ;
}
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
/* fetch the station record for corresponding peer mac address */
if ( ( staRecord = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( priv , peerMacAddress , interfaceTag ) ) ) {
handle = staRecord - > assignedHandle ;
}
/* Frame ma-packet.req, this is saved/transmitted depend on queue state */
unifi_frame_ma_packet_req ( priv , priority , TransmitRate , hostTag ,
interfaceTag , transmissionControl , leSenderProcessId ,
peerMacAddress , & signal ) ;
/* Since it's common path between STA & AP mode, in case of STA packet
* need not to be queued but in AP case we have to queue PDU ' s in
* different scenarios
*/
switch ( interfacePriv - > interfaceMode )
{
case CSR_WIFI_ROUTER_CTRL_MODE_AP :
case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO :
/* For this mode processing done below */
break ;
default :
/* In case of STA/IBSS/P2PCLI/AMP, no checks needed send the packet down & return */
unifi_trace ( priv , UDBG5 , " In %s, interface mode is %x \n " , __FUNCTION__ , interfacePriv - > interfaceMode ) ;
if ( interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_NONE ) {
unifi_warning ( priv , " In %s, interface mode NONE \n " , __FUNCTION__ ) ;
}
if ( ( result = ul_send_signal_unpacked ( priv , & signal , bulkdata ) ) ) {
status = CSR_RESULT_FAILURE ;
}
return status ;
}
/* -----Only AP/P2pGO mode handling falls below----- */
/* convert priority to queue */
priority_q = unifi_frame_priority_to_queue ( ( CSR_PRIORITY ) priority ) ;
/* check the powersave status of the peer */
if ( staRecord & & ( staRecord - > currentPeerState = =
CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE ) ) {
/* Peer is dozing & packet have to be delivered, so buffer the packet &
* update the TIM
*/
queuePacketDozing = TRUE ;
}
/* find the type of frame unicast or mulicast/broadcast */
if ( * peerMacAddress & 0x1 ) {
/* Multicast/broadCast data are always triggered by vif_availability.ind
* at the DTIM
*/
pktType = CSR_WIFI_MULTICAST_PDU ;
} else {
pktType = CSR_WIFI_UNICAST_PDU ;
}
/* Fetch the frame control field from mac header & check for frame type */
frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN ( macHdrLocation ) ;
/* Processing done according to Frame/Packet type */
frameType = ( ( frmCtrl & 0x000c ) > > FRAME_CONTROL_TYPE_FIELD_OFFSET ) ;
switch ( frameType )
{
case IEEE802_11_FRAMETYPE_MANAGEMENT :
switch ( pktType )
{
case CSR_WIFI_UNICAST_PDU :
unifi_trace ( priv , UDBG5 , " management unicast PDU in uf_process_ma_packet_req \n " ) ;
/* push the packet in to the queue with appropriate mgt list */
if ( ! staRecord ) {
/* push the packet to the unifi if list is empty (if packet lost how to re-enque) */
if ( list_empty ( & interfacePriv - > genericMgtFrames ) ) {
# ifdef CSR_SUPPORT_SME
if ( ! ( IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) ) {
# endif
unifi_trace ( priv , UDBG3 , " genericMgtFrames list is empty uf_process_ma_packet_req \n " ) ;
result = ul_send_signal_unpacked ( priv , & signal , bulkdata ) ;
/* reque only on ENOSPC */
if ( result = = - ENOSPC ) {
/* requeue the failed packet to genericMgtFrame with same position */
unifi_trace ( priv , UDBG1 , " (ENOSPC) Sending genericMgtFrames Failed so buffering \n " ) ;
list = & interfacePriv - > genericMgtFrames ;
requeueOnSamePos = TRUE ;
}
# ifdef CSR_SUPPORT_SME
} else {
list = & interfacePriv - > genericMgtFrames ;
unifi_trace ( priv , UDBG3 , " genericMgtFrames queue empty and dtim started \n hosttag is 0x%x, \n " , signal . u . MaPacketRequest . HostTag ) ;
update_eosp_to_head_of_broadcast_list_head ( priv , interfaceTag ) ;
}
# endif
} else {
/* Queue the packet to genericMgtFrame of unifi_priv_t data structure */
list = & interfacePriv - > genericMgtFrames ;
unifi_trace ( priv , UDBG2 , " genericMgtFrames queue not empty \n " ) ;
}
} else {
/* check peer power state */
if ( queuePacketDozing | | ! list_empty ( & staRecord - > mgtFrames ) | | IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) {
/* peer is in dozing mode, so queue packet in mgt frame list of station record */
/*if multicast traffic is going on, buffer the unicast packets*/
list = & staRecord - > mgtFrames ;
unifi_trace ( priv , UDBG1 , " staRecord->MgtFrames list empty? = %s, handle = %d, queuePacketDozing = %d \n " ,
( list_empty ( & staRecord - > mgtFrames ) ) ? " YES " : " NO " , staRecord - > assignedHandle , queuePacketDozing ) ;
if ( IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) {
update_eosp_to_head_of_broadcast_list_head ( priv , interfaceTag ) ;
}
} else {
unifi_trace ( priv , UDBG5 , " staRecord->mgtFrames list is empty uf_process_ma_packet_req \n " ) ;
result = ul_send_signal_unpacked ( priv , & signal , bulkdata ) ;
if ( result = = - ENOSPC ) {
/* requeue the failed packet to staRecord->mgtFrames with same position */
list = & staRecord - > mgtFrames ;
requeueOnSamePos = TRUE ;
unifi_trace ( priv , UDBG1 , " (ENOSPC) Sending MgtFrames Failed handle = %d so buffering \n " , staRecord - > assignedHandle ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 0 ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
} else if ( result ) {
status = CSR_RESULT_FAILURE ;
}
}
}
break ;
case CSR_WIFI_MULTICAST_PDU :
unifi_trace ( priv , UDBG5 , " management multicast/broadcast PDU in uf_process_ma_packet_req 'QUEUE it' \n " ) ;
/* Queue the packet to genericMulticastOrBroadCastMgtFrames of unifi_priv_t data structure
* will be sent when we receive VIF AVAILABILITY from firmware as part of DTIM
*/
list = & interfacePriv - > genericMulticastOrBroadCastMgtFrames ;
if ( ( interfacePriv - > interfaceMode ! = CSR_WIFI_ROUTER_CTRL_MODE_IBSS ) & &
( list_empty ( & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) ) ) {
setBcTim = TRUE ;
}
break ;
default :
unifi_error ( priv , " condition never meets: packet type unrecognized \n " ) ;
}
break ;
case IEEE802_11_FRAMETYPE_DATA :
switch ( pktType )
{
case CSR_WIFI_UNICAST_PDU :
unifi_trace ( priv , UDBG5 , " data unicast PDU in uf_process_ma_packet_req \n " ) ;
/* check peer power state, list status & peer port status */
if ( ! staRecord ) {
unifi_error ( priv , " In %s unicast but staRecord = NULL \n " , __FUNCTION__ ) ;
return CSR_RESULT_FAILURE ;
} else if ( queuePacketDozing | | isRouterBufferEnabled ( priv , priority_q ) | | ! list_empty ( & staRecord - > dataPdu [ priority_q ] ) | | IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) {
/* peer is in dozing mode, so queue packet in mgt frame list of station record */
/* if multicast traffic is going on, buffet the unicast packets */
unifi_trace ( priv , UDBG2 , " Enqueued to staRecord->dataPdu[%d] queuePacketDozing=%d, \
Buffering enabled = % d \ n " , priority_q,queuePacketDozing,isRouterBufferEnabled(priv,priority_q));
list = & staRecord - > dataPdu [ priority_q ] ;
} else {
unifi_trace ( priv , UDBG5 , " staRecord->dataPdu[%d] list is empty uf_process_ma_packet_req \n " , priority_q ) ;
/* Pdu allowed to send to unifi */
result = ul_send_signal_unpacked ( priv , & signal , bulkdata ) ;
if ( result = = - ENOSPC ) {
/* requeue the failed packet to staRecord->dataPdu[priority_q] with same position */
unifi_trace ( priv , UDBG1 , " (ENOSPC) Sending Unicast DataPDU to queue %d Failed so buffering \n " , priority_q ) ;
requeueOnSamePos = TRUE ;
list = & staRecord - > dataPdu [ priority_q ] ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ priority_q ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
if ( ! isRouterBufferEnabled ( priv , priority_q ) ) {
unifi_error ( priv , " Buffering Not enabled for queue %d \n " , priority_q ) ;
}
} else if ( result ) {
status = CSR_RESULT_FAILURE ;
}
}
break ;
case CSR_WIFI_MULTICAST_PDU :
unifi_trace ( priv , UDBG5 , " data multicast/broadcast PDU in uf_process_ma_packet_req \n " ) ;
/* Queue the packet to genericMulticastOrBroadCastFrames list of unifi_priv_t data structure
* will be sent when we receive VIF AVAILABILITY from firmware as part of DTIM
*/
list = & interfacePriv - > genericMulticastOrBroadCastFrames ;
if ( list_empty ( & interfacePriv - > genericMulticastOrBroadCastFrames ) ) {
setBcTim = TRUE ;
}
break ;
default :
unifi_error ( priv , " condition never meets: packet type un recognized \n " ) ;
}
break ;
default :
unifi_error ( priv , " unrecognized frame type \n " ) ;
}
if ( list ) {
status = enque_tx_data_pdu ( priv , bulkdata , list , & signal , requeueOnSamePos ) ;
/* Record no. of packet queued for each peer */
if ( staRecord & & ( pktType = = CSR_WIFI_UNICAST_PDU ) & & ( ! status ) ) {
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
staRecord - > noOfPktQueued + + ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
}
2012-06-19 18:33:16 -06:00
else if ( ( pktType = = CSR_WIFI_MULTICAST_PDU ) & & ( ! status ) )
{
/* If broadcast Tim is set && queuing is successfull, then only update TIM */
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
interfacePriv - > noOfbroadcastPktQueued + + ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
}
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
/* If broadcast Tim is set && queuing is successfull, then only update TIM */
if ( setBcTim & & ! status ) {
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG3 , " tim set due to broadcast pkt \n " ) ;
2012-06-19 18:33:16 -06:00
if ( ! interfacePriv - > bcTimSetReqPendingFlag )
{
update_tim ( priv , 0 , CSR_WIFI_TIM_SET , interfaceTag , handle ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
interfacePriv - > bcTimSetReqQueued = CSR_WIFI_TIM_SET ;
unifi_trace ( priv , UDBG2 , " uf_process_ma_packet_req : One more UpdateDTim Request(:%d) Queued \n " ,
interfacePriv - > bcTimSetReqQueued ) ;
}
2012-06-19 17:15:42 -06:00
} else if ( staRecord & & staRecord - > currentPeerState = =
CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE ) {
if ( staRecord - > timSet = = CSR_WIFI_TIM_RESET | | staRecord - > timSet = = CSR_WIFI_TIM_RESETTING ) {
if ( ! staRecord - > wmmOrQosEnabled ) {
if ( ! list_empty ( & staRecord - > mgtFrames ) | |
! list_empty ( & staRecord - > dataPdu [ 3 ] ) | |
! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) ) {
unifi_trace ( priv , UDBG3 , " tim set due to unicast pkt & peer in powersave \n " ) ;
2012-06-19 18:33:16 -06:00
if ( ! staRecord - > timRequestPendingFlag ) {
update_tim ( priv , staRecord - > aid , 1 , interfaceTag , handle ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 1 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , staRecord - > updateTimReqQueued ,
staRecord - > aid ) ;
}
}
} else {
/* Check for non delivery enable(i.e trigger enable), all delivery enable & legacy AC for TIM update in firmware */
2012-07-20 12:51:01 -06:00
u8 allDeliveryEnabled = 0 , dataAvailable = 0 ;
2012-06-19 17:15:42 -06:00
/* Check if all AC's are Delivery Enabled */
is_all_ac_deliver_enabled_and_moredata ( staRecord , & allDeliveryEnabled , & dataAvailable ) ;
2012-06-19 18:33:16 -06:00
if ( uf_is_more_data_for_non_delivery_ac ( staRecord ) | | ( allDeliveryEnabled & & dataAvailable )
| | ( ! list_empty ( & staRecord - > mgtFrames ) ) ) {
if ( ! staRecord - > timRequestPendingFlag ) {
update_tim ( priv , staRecord - > aid , 1 , interfaceTag , handle ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 1 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , staRecord - > updateTimReqQueued ,
staRecord - > aid ) ;
}
2012-06-19 17:15:42 -06:00
}
}
}
}
if ( ( list ) & & ( pktType = = CSR_WIFI_UNICAST_PDU & & ! queuePacketDozing ) & & ! ( isRouterBufferEnabled ( priv , priority_q ) ) & & ! ( IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) ) {
unifi_trace ( priv , UDBG2 , " buffering cleared for queue = %d So resending buffered frames \n " , priority_q ) ;
uf_send_buffered_frames ( priv , priority_q ) ;
}
unifi_trace ( priv , UDBG5 , " leaving uf_process_ma_packet_req \n " ) ;
return status ;
# else
# ifdef CSR_NATIVE_LINUX
if ( interfaceTag > = CSR_WIFI_NUM_INTERFACES ) {
unifi_error ( priv , " interfaceTag >= CSR_WIFI_NUM_INTERFACES, interfacetag = %d \n " , interfaceTag ) ;
return CSR_RESULT_FAILURE ;
}
/* Frame ma-packet.req, this is saved/transmitted depend on queue state */
unifi_frame_ma_packet_req ( priv , priority , TransmitRate , hostTag , interfaceTag ,
transmissionControl , leSenderProcessId ,
peerMacAddress , & signal ) ;
result = ul_send_signal_unpacked ( priv , & signal , bulkdata ) ;
if ( result ) {
return CSR_RESULT_FAILURE ;
}
# endif
return status ;
# endif
}
# ifdef CSR_SUPPORT_SME
2012-07-20 13:00:10 -06:00
s8 uf_get_protection_bit_from_interfacemode ( unifi_priv_t * priv , u16 interfaceTag , const u8 * daddr )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:56:26 -06:00
s8 protection = 0 ;
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
switch ( interfacePriv - > interfaceMode )
{
case CSR_WIFI_ROUTER_CTRL_MODE_STA :
case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI :
case CSR_WIFI_ROUTER_CTRL_MODE_AMP :
case CSR_WIFI_ROUTER_CTRL_MODE_IBSS :
protection = interfacePriv - > protect ;
break ;
case CSR_WIFI_ROUTER_CTRL_MODE_AP :
case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO :
{
CsrWifiRouterCtrlStaInfo_t * dstStaInfo = NULL ;
if ( daddr [ 0 ] & 0x1 ) {
unifi_trace ( priv , UDBG3 , " broadcast/multicast packet in send_ma_pkt_request \n " ) ;
/* In this mode, the protect member of priv structure has an information of how
* AP / P2PGO has started , & the member updated in set mode request for AP / P2PGO
*/
protection = interfacePriv - > protect ;
} else {
/* fetch the destination record from staion record database */
dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( priv , daddr , interfaceTag ) ;
if ( ! dstStaInfo ) {
unifi_trace ( priv , UDBG3 , " peer not found in station record in send_ma_pkt_request \n " ) ;
return - 1 ;
}
protection = dstStaInfo - > protection ;
}
}
break ;
default :
unifi_trace ( priv , UDBG2 , " mode unknown in send_ma_pkt_request \n " ) ;
}
return protection ;
}
# endif
# ifdef CSR_SUPPORT_SME
2012-07-20 13:00:10 -06:00
u8 send_multicast_frames ( unifi_priv_t * priv , u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
int r ;
tx_buffered_packets_t * buffered_pkt = NULL ;
2012-07-20 13:25:15 -06:00
u8 moreData = FALSE ;
2012-07-20 12:51:01 -06:00
u8 pduSent = 0 ;
2012-06-19 17:15:42 -06:00
unsigned long lock_flags ;
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
2012-07-20 13:05:42 -06:00
u32 hostTag = 0xffffffff ;
2012-06-19 17:15:42 -06:00
if ( ! isRouterBufferEnabled ( priv , UNIFI_TRAFFIC_Q_VO ) ) {
while ( ( interfacePriv - > dtimActive ) & & ( buffered_pkt = dequeue_tx_data_pdu ( priv , & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) ) ) {
buffered_pkt - > transmissionControl | = ( TRANSMISSION_CONTROL_TRIGGER_MASK ) ;
2012-06-19 18:33:16 -06:00
moreData = ( buffered_pkt - > transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK ) ? FALSE : TRUE ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG2 , " DTIM Occurred for interface:sending Mgt packet %d \n " , interfaceTag ) ;
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , NULL , moreData , FALSE ) ) = = - ENOSPC ) {
unifi_trace ( priv , UDBG1 , " frame_and_send_queued_pdu failed with ENOSPC for host tag = %x \n " , buffered_pkt - > hostTag ) ;
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
break ;
} else {
unifi_trace ( priv , UDBG1 , " send_multicast_frames: Send genericMulticastOrBroadCastMgtFrames (%x, %x) \n " ,
buffered_pkt - > hostTag ,
r ) ;
if ( r ) {
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
if ( ! moreData ) {
interfacePriv - > dtimActive = FALSE ;
if ( ! r ) {
hostTag = buffered_pkt - > hostTag ;
pduSent + + ;
} else {
send_vif_availibility_rsp ( priv , uf_get_vif_identifier ( interfacePriv - > interfaceMode , interfaceTag ) , CSR_RC_UNSPECIFIED_FAILURE ) ;
}
}
/* Buffered frame sent successfully */
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
interfacePriv - > noOfbroadcastPktQueued - - ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
kfree ( buffered_pkt ) ;
}
}
}
if ( ! isRouterBufferEnabled ( priv , UNIFI_TRAFFIC_Q_CONTENTION ) ) {
while ( ( interfacePriv - > dtimActive ) & & ( buffered_pkt = dequeue_tx_data_pdu ( priv , & interfacePriv - > genericMulticastOrBroadCastFrames ) ) ) {
buffered_pkt - > transmissionControl | = TRANSMISSION_CONTROL_TRIGGER_MASK ;
2012-06-19 18:33:16 -06:00
moreData = ( buffered_pkt - > transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK ) ? FALSE : TRUE ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , NULL , moreData , FALSE ) ) = = - ENOSPC ) {
/* Clear the trigger bit transmission control*/
buffered_pkt - > transmissionControl & = ~ ( TRANSMISSION_CONTROL_TRIGGER_MASK ) ;
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & interfacePriv - > genericMulticastOrBroadCastFrames ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
break ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " send_multicast_frames: Send genericMulticastOrBroadCastFrame failed (%x, %x) \n " ,
buffered_pkt - > hostTag ,
r ) ;
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
if ( ! moreData ) {
interfacePriv - > dtimActive = FALSE ;
if ( ! r ) {
pduSent + + ;
hostTag = buffered_pkt - > hostTag ;
} else {
send_vif_availibility_rsp ( priv , uf_get_vif_identifier ( interfacePriv - > interfaceMode , interfaceTag ) , CSR_RC_UNSPECIFIED_FAILURE ) ;
}
}
/* Buffered frame sent successfully */
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
interfacePriv - > noOfbroadcastPktQueued - - ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
kfree ( buffered_pkt ) ;
}
}
}
if ( ( interfacePriv - > dtimActive = = FALSE ) ) {
/* Record the host Tag*/
unifi_trace ( priv , UDBG2 , " send_multicast_frames: Recorded hostTag of EOSP packet: = 0x%x \n " , hostTag ) ;
interfacePriv - > multicastPduHostTag = hostTag ;
}
return pduSent ;
}
# endif
2012-07-20 12:51:01 -06:00
void uf_process_ma_vif_availibility_ind ( unifi_priv_t * priv , u8 * sigdata ,
2012-07-20 13:05:42 -06:00
u32 siglen )
2012-06-19 17:15:42 -06:00
{
# ifdef CSR_SUPPORT_SME
CSR_SIGNAL signal ;
CSR_MA_VIF_AVAILABILITY_INDICATION * ind ;
int r ;
2012-07-20 13:00:10 -06:00
u16 interfaceTag ;
2012-07-20 12:51:01 -06:00
u8 pduSent = 0 ;
2012-06-19 17:15:42 -06:00
CSR_RESULT_CODE resultCode = CSR_RC_SUCCESS ;
netInterface_priv_t * interfacePriv ;
unifi_trace ( priv , UDBG3 ,
" uf_process_ma_vif_availibility_ind: Process signal 0x%.4X \n " ,
2012-07-20 13:00:10 -06:00
* ( ( u16 * ) sigdata ) ) ;
2012-06-19 17:15:42 -06:00
r = read_unpack_signal ( sigdata , & signal ) ;
if ( r ) {
unifi_error ( priv ,
" uf_process_ma_vif_availibility_ind: Received unknown signal 0x%.4X. \n " ,
CSR_GET_UINT16_FROM_LITTLE_ENDIAN ( sigdata ) ) ;
return ;
}
ind = & signal . u . MaVifAvailabilityIndication ;
interfaceTag = ind - > VirtualInterfaceIdentifier & 0xff ;
if ( interfaceTag > = CSR_WIFI_NUM_INTERFACES ) {
unifi_error ( priv , " in vif_availability_ind interfaceTag is wrong \n " ) ;
return ;
}
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
if ( ind - > Multicast ) {
if ( list_empty ( & interfacePriv - > genericMulticastOrBroadCastFrames ) & &
list_empty ( & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) ) {
/* This condition can occur because of a potential race where the
TIM is not yet reset as host is waiting for confirm but it is sent
by firmware and DTIM occurs */
unifi_notice ( priv , " ma_vif_availibility_ind recevied for multicast but queues are empty%d \n " , interfaceTag ) ;
send_vif_availibility_rsp ( priv , ind - > VirtualInterfaceIdentifier , CSR_RC_NO_BUFFERED_BROADCAST_MULTICAST_FRAMES ) ;
interfacePriv - > dtimActive = FALSE ;
if ( interfacePriv - > multicastPduHostTag = = 0xffffffff ) {
unifi_notice ( priv , " ma_vif_availibility_ind recevied for multicast but queues are empty%d \n " , interfaceTag ) ;
/* This may be an extra request in very rare race conditions but it is fine as it would atleast remove the potential lock up */
2012-06-19 18:33:16 -06:00
if ( ! interfacePriv - > bcTimSetReqPendingFlag )
{
update_tim ( priv , 0 , CSR_WIFI_TIM_RESET , interfaceTag , 0xFFFFFFFF ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
interfacePriv - > bcTimSetReqQueued = CSR_WIFI_TIM_RESET ;
unifi_trace ( priv , UDBG2 , " uf_process_ma_vif_availibility_ind : One more UpdateDTim Request(%d) Queued \n " ,
interfacePriv - > bcTimSetReqQueued ) ;
}
2012-06-19 17:15:42 -06:00
}
return ;
}
if ( interfacePriv - > dtimActive ) {
unifi_trace ( priv , UDBG2 , " DTIM Occurred for already active DTIM interface %d \n " , interfaceTag ) ;
return ;
} else {
unifi_trace ( priv , UDBG2 , " DTIM Occurred for interface %d \n " , interfaceTag ) ;
if ( list_empty ( & interfacePriv - > genericMulticastOrBroadCastFrames ) ) {
set_eosp_transmit_ctrl ( priv , & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) ;
} else {
set_eosp_transmit_ctrl ( priv , & interfacePriv - > genericMulticastOrBroadCastFrames ) ;
}
}
interfacePriv - > dtimActive = TRUE ;
pduSent = send_multicast_frames ( priv , interfaceTag ) ;
}
else {
unifi_error ( priv , " Interface switching is not supported %d \n " , interfaceTag ) ;
resultCode = CSR_RC_NOT_SUPPORTED ;
send_vif_availibility_rsp ( priv , ind - > VirtualInterfaceIdentifier , CSR_RC_NOT_SUPPORTED ) ;
}
# endif
}
# ifdef CSR_SUPPORT_SME
# define GET_ACTIVE_INTERFACE_TAG(priv) 0
2012-07-20 13:25:15 -06:00
static u8 uf_is_more_data_for_delivery_ac ( unifi_priv_t * priv , CsrWifiRouterCtrlStaInfo_t * staRecord )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:56:26 -06:00
s8 i ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
for ( i = UNIFI_TRAFFIC_Q_VO ; i > = UNIFI_TRAFFIC_Q_BK ; i - - )
{
if ( ( ( staRecord - > powersaveMode [ i ] = = CSR_WIFI_AC_DELIVERY_ONLY_ENABLE )
| | ( staRecord - > powersaveMode [ i ] = = CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED ) )
& & ( ! list_empty ( & staRecord - > dataPdu [ i ] ) ) ) {
unifi_trace ( priv , UDBG2 , " uf_is_more_data_for_delivery_ac: Data Available AC = %d \n " , i ) ;
return TRUE ;
2012-06-19 17:15:42 -06:00
}
}
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " uf_is_more_data_for_delivery_ac: Data NOT Available \n " ) ;
return FALSE ;
}
2012-06-19 17:15:42 -06:00
2012-07-20 13:25:15 -06:00
static u8 uf_is_more_data_for_usp_delivery ( unifi_priv_t * priv , CsrWifiRouterCtrlStaInfo_t * staRecord , unifi_TrafficQueue queue )
2012-06-19 18:33:16 -06:00
{
2012-07-20 12:56:26 -06:00
s8 i ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
for ( i = queue ; i > = UNIFI_TRAFFIC_Q_BK ; i - - )
{
if ( ( ( staRecord - > powersaveMode [ i ] = = CSR_WIFI_AC_DELIVERY_ONLY_ENABLE )
| | ( staRecord - > powersaveMode [ i ] = = CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED ) )
& & ( ! list_empty ( & staRecord - > dataPdu [ i ] ) ) ) {
unifi_trace ( priv , UDBG2 , " uf_is_more_data_for_usp_delivery: Data Available AC = %d \n " , i ) ;
return TRUE ;
2012-06-19 17:15:42 -06:00
}
}
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " uf_is_more_data_for_usp_delivery: Data NOT Available \n " ) ;
return FALSE ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* uf_send_buffered_data_from_delivery_ac
*
* This function takes care of
* - > Parsing the delivery enabled queue & sending frame down to HIP
* - > Setting EOSP = 1 when USP to be terminated
* - > Depending on MAX SP length services the USP
*
* NOTE : This function always called from uf_handle_uspframes_delivery ( ) , Dont
* call this function from any other location in code
*
* Arguments :
* priv Pointer to device private context struct
* vif interface specific HIP vif instance
* staInfo peer for which UAPSD to be scheduled
* queue AC from which Data to be sent in USP
* txList access category for processing list
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2012-06-19 17:15:42 -06:00
void uf_send_buffered_data_from_delivery_ac ( unifi_priv_t * priv ,
CsrWifiRouterCtrlStaInfo_t * staInfo ,
2012-07-20 12:51:01 -06:00
u8 queue ,
2012-06-19 17:15:42 -06:00
struct list_head * txList )
{
2012-07-20 13:00:10 -06:00
u16 interfaceTag = GET_ACTIVE_INTERFACE_TAG ( priv ) ;
2012-06-19 17:15:42 -06:00
tx_buffered_packets_t * buffered_pkt = NULL ;
unsigned long lock_flags ;
2012-07-20 13:25:15 -06:00
u8 eosp = FALSE ;
2012-07-20 12:56:26 -06:00
s8 r = 0 ;
2012-07-20 13:25:15 -06:00
u8 moreData = FALSE ;
2012-06-19 18:33:16 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " ++uf_send_buffered_data_from_delivery_ac, active=%x \n " , staInfo - > uapsdActive ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( queue > UNIFI_TRAFFIC_Q_VO )
{
2012-06-19 17:15:42 -06:00
return ;
2012-06-19 18:33:16 -06:00
}
while ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , txList ) ) ) {
if ( ( IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) ) {
unifi_trace ( priv , UDBG2 , " uf_send_buffered_data_from_delivery_ac: DTIM Active, suspend UAPSD, staId: 0x%x \n " ,
staInfo - > aid ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* Once resume called, the U-APSD delivery operation will resume */
2012-06-19 17:15:42 -06:00
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
2012-06-19 18:33:16 -06:00
staInfo - > uspSuspend = TRUE ;
2012-06-19 17:15:42 -06:00
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
/* re-queueing the packet as DTIM started */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , txList ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
break ;
}
buffered_pkt - > transmissionControl & =
2012-06-19 18:33:16 -06:00
~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( ( staInfo - > wmmOrQosEnabled = = TRUE ) & & ( staInfo - > uapsdActive = = TRUE ) ) {
2012-06-19 17:15:42 -06:00
buffered_pkt - > transmissionControl = TRANSMISSION_CONTROL_TRIGGER_MASK ;
2012-06-19 18:33:16 -06:00
/* Check All delivery enables Ac for more data, because caller of this
* function not aware about last packet
* ( First check in moreData fetching helps in draining out Mgt frames Q )
*/
moreData = ( ! list_empty ( txList ) | | uf_is_more_data_for_usp_delivery ( priv , staInfo , queue ) ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( staInfo - > noOfSpFramesSent = = ( staInfo - > maxSpLength - 1 ) ) {
moreData = FALSE ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( moreData = = FALSE ) {
eosp = TRUE ;
buffered_pkt - > transmissionControl =
( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
}
} else {
/* Non QoS and non U-APSD */
unifi_warning ( priv , " uf_send_buffered_data_from_delivery_ac: non U-APSD !!! \n " ) ;
2012-06-19 17:15:42 -06:00
}
unifi_trace ( priv , UDBG2 , " uf_send_buffered_data_from_delivery_ac : MoreData:%d, EOSP:%d \n " , moreData , eosp ) ;
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staInfo , moreData , eosp ) ) = = - ENOSPC ) {
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " uf_send_buffered_data_from_delivery_ac: UASPD suspended, ENOSPC in hipQ=%x \n " , queue ) ;
/* Once resume called, the U-APSD delivery operation will resume */
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
staInfo - > uspSuspend = TRUE ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , txList ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ queue ] = ( u8 ) ( staInfo - > assignedHandle ) ;
2012-06-19 18:33:16 -06:00
break ;
2012-06-19 17:15:42 -06:00
} else {
if ( r ) {
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
2012-06-19 18:33:16 -06:00
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
staInfo - > noOfSpFramesSent + + ;
if ( ( ! moreData ) | | ( staInfo - > noOfSpFramesSent = = staInfo - > maxSpLength ) ) {
unifi_trace ( priv , UDBG2 , " uf_send_buffered_data_from_delivery_ac: Terminating USP \n " ) ;
staInfo - > uapsdActive = FALSE ;
staInfo - > uspSuspend = FALSE ;
staInfo - > noOfSpFramesSent = 0 ;
2012-06-19 17:15:42 -06:00
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
2012-06-19 18:33:16 -06:00
break ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
2012-06-19 17:15:42 -06:00
}
}
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " --uf_send_buffered_data_from_delivery_ac, active=%x \n " , staInfo - > uapsdActive ) ;
2012-06-19 17:15:42 -06:00
}
void uf_send_buffered_data_from_ac ( unifi_priv_t * priv ,
CsrWifiRouterCtrlStaInfo_t * staInfo ,
2012-07-20 12:51:01 -06:00
u8 queue ,
2012-06-19 17:15:42 -06:00
struct list_head * txList )
{
tx_buffered_packets_t * buffered_pkt = NULL ;
unsigned long lock_flags ;
2012-07-20 13:25:15 -06:00
u8 eosp = FALSE ;
u8 moreData = FALSE ;
2012-07-20 12:56:26 -06:00
s8 r = 0 ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG2 , " uf_send_buffered_data_from_ac : \n " ) ;
while ( ! isRouterBufferEnabled ( priv , queue ) & &
( ( buffered_pkt = dequeue_tx_data_pdu ( priv , txList ) ) ! = NULL ) ) {
buffered_pkt - > transmissionControl & =
2012-06-19 18:33:16 -06:00
~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG3 , " uf_send_buffered_data_from_ac : MoreData:%d, EOSP:%d \n " , moreData , eosp ) ;
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staInfo , moreData , eosp ) ) = = - ENOSPC ) {
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , txList ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
if ( staInfo ! = NULL ) {
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ queue ] = ( u8 ) ( staInfo - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
}
unifi_trace ( priv , UDBG3 , " uf_send_buffered_data_from_ac: PDU sending failed .. no space for queue %d \n " , queue ) ;
} else {
if ( r ) {
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
}
}
void uf_send_buffered_frames ( unifi_priv_t * priv , unifi_TrafficQueue q )
{
2012-07-20 13:00:10 -06:00
u16 interfaceTag = GET_ACTIVE_INTERFACE_TAG ( priv ) ;
2012-07-20 13:05:42 -06:00
u32 startIndex = 0 , endIndex = 0 ;
2012-06-19 17:15:42 -06:00
CsrWifiRouterCtrlStaInfo_t * staInfo = NULL ;
2012-07-20 12:51:01 -06:00
u8 queue ;
2012-07-20 13:25:15 -06:00
u8 moreData = FALSE ;
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
if ( ! ( ( interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_AP ) | |
( interfacePriv - > interfaceMode = = CSR_WIFI_ROUTER_CTRL_MODE_P2PGO ) ) )
return ;
queue = ( q < = 3 ) ? q : 0 ;
if ( interfacePriv - > dtimActive ) {
/* this function updates dtimActive*/
send_multicast_frames ( priv , interfaceTag ) ;
if ( ! interfacePriv - > dtimActive ) {
moreData = ( ! list_empty ( & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) | |
! list_empty ( & interfacePriv - > genericMulticastOrBroadCastFrames ) ) ;
if ( ! moreData ) {
2012-06-19 18:33:16 -06:00
if ( ! interfacePriv - > bcTimSetReqPendingFlag )
{
update_tim ( priv , 0 , CSR_WIFI_TIM_RESET , interfaceTag , 0 XFFFFFFFF ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
interfacePriv - > bcTimSetReqQueued = CSR_WIFI_TIM_RESET ;
unifi_trace ( priv , UDBG2 , " uf_send_buffered_frames : One more UpdateDTim Request(%d) Queued \n " ,
interfacePriv - > bcTimSetReqQueued ) ;
}
2012-06-19 17:15:42 -06:00
}
} else {
moreData = ( ! list_empty ( & interfacePriv - > genericMulticastOrBroadCastMgtFrames ) | |
! list_empty ( & interfacePriv - > genericMulticastOrBroadCastFrames ) ) ;
if ( ! moreData ) {
/* This should never happen but if it happens, we need a way out */
unifi_error ( priv , " ERROR: No More Data but DTIM is active sending Response \n " ) ;
send_vif_availibility_rsp ( priv , uf_get_vif_identifier ( interfacePriv - > interfaceMode , interfaceTag ) , CSR_RC_NO_BUFFERED_BROADCAST_MULTICAST_FRAMES ) ;
interfacePriv - > dtimActive = FALSE ;
}
}
return ;
}
if ( priv - > pausedStaHandle [ queue ] > 7 ) {
priv - > pausedStaHandle [ queue ] = 0 ;
}
if ( queue = = UNIFI_TRAFFIC_Q_VO ) {
unifi_trace ( priv , UDBG2 , " uf_send_buffered_frames : trying mgt from queue=%d \n " , queue ) ;
for ( startIndex = 0 ; startIndex < UNIFI_MAX_CONNECTIONS ; startIndex + + ) {
staInfo = CsrWifiRouterCtrlGetStationRecordFromHandle ( priv , startIndex , interfaceTag ) ;
if ( ! staInfo ) {
continue ;
} else if ( ( staInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE )
& & ( staInfo - > uapsdActive = = FALSE ) ) {
continue ;
}
if ( ( staInfo ! = NULL ) & & ( staInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE )
& & ( staInfo - > uapsdActive = = FALSE ) ) {
/*Non-UAPSD case push the management frames out*/
if ( ! list_empty ( & staInfo - > mgtFrames ) ) {
uf_send_buffered_data_from_ac ( priv , staInfo , UNIFI_TRAFFIC_Q_VO , & staInfo - > mgtFrames ) ;
}
}
if ( isRouterBufferEnabled ( priv , queue ) ) {
unifi_notice ( priv , " uf_send_buffered_frames : No space Left for queue = %d \n " , queue ) ;
break ;
}
}
/*push generic management frames out*/
2012-06-19 18:33:16 -06:00
if ( ! list_empty ( & interfacePriv - > genericMgtFrames ) ) {
unifi_trace ( priv , UDBG2 , " uf_send_buffered_frames : trying generic mgt from queue=%d \n " , queue ) ;
uf_send_buffered_data_from_ac ( priv , staInfo , UNIFI_TRAFFIC_Q_VO , & interfacePriv - > genericMgtFrames ) ;
2012-06-19 17:15:42 -06:00
}
}
unifi_trace ( priv , UDBG2 , " uf_send_buffered_frames : Resume called for Queue=%d \n " , queue ) ;
unifi_trace ( priv , UDBG2 , " uf_send_buffered_frames : start=%d end=%d \n " , startIndex , endIndex ) ;
startIndex = priv - > pausedStaHandle [ queue ] ;
endIndex = ( startIndex + UNIFI_MAX_CONNECTIONS - 1 ) % UNIFI_MAX_CONNECTIONS ;
while ( startIndex ! = endIndex ) {
staInfo = CsrWifiRouterCtrlGetStationRecordFromHandle ( priv , startIndex , interfaceTag ) ;
if ( ! staInfo ) {
startIndex + + ;
2012-06-19 18:33:16 -06:00
if ( startIndex > = UNIFI_MAX_CONNECTIONS ) {
2012-06-19 17:15:42 -06:00
startIndex = 0 ;
}
continue ;
} else if ( ( staInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE )
2012-06-19 18:33:16 -06:00
& & ( staInfo - > uapsdActive = = FALSE ) ) {
2012-06-19 17:15:42 -06:00
startIndex + + ;
2012-06-19 18:33:16 -06:00
if ( startIndex > = UNIFI_MAX_CONNECTIONS ) {
2012-06-19 17:15:42 -06:00
startIndex = 0 ;
}
continue ;
}
/* Peer is active or U-APSD is active so send PDUs to the peer */
unifi_trace ( priv , UDBG2 , " uf_send_buffered_frames : trying data from queue=%d \n " , queue ) ;
if ( ( staInfo ! = NULL ) & & ( staInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE )
2012-06-19 18:33:16 -06:00
& & ( staInfo - > uapsdActive = = FALSE ) ) {
if ( ! list_empty ( & staInfo - > dataPdu [ queue ] ) ) {
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/*Non-UAPSD case push the AC frames out*/
uf_send_buffered_data_from_ac ( priv , staInfo , queue , ( & staInfo - > dataPdu [ queue ] ) ) ;
2012-06-19 17:15:42 -06:00
}
}
startIndex + + ;
2012-06-19 18:33:16 -06:00
if ( startIndex > = UNIFI_MAX_CONNECTIONS ) {
2012-06-19 17:15:42 -06:00
startIndex = 0 ;
}
}
if ( isRouterBufferEnabled ( priv , queue ) ) {
priv - > pausedStaHandle [ queue ] = endIndex ;
} else {
priv - > pausedStaHandle [ queue ] = 0 ;
}
2012-06-19 18:33:16 -06:00
/* U-APSD might have stopped because of ENOSPC in lib_hip (pause activity).
* So restart it if U - APSD was active with any of the station
*/
unifi_trace ( priv , UDBG4 , " csrWifiHipSendBufferedFrames: UAPSD Resume Q=%x \n " , queue ) ;
resume_suspended_uapsd ( priv , interfaceTag ) ;
2012-06-19 17:15:42 -06:00
}
2012-07-20 13:25:15 -06:00
u8 uf_is_more_data_for_non_delivery_ac ( CsrWifiRouterCtrlStaInfo_t * staRecord )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:51:01 -06:00
u8 i ;
2012-06-19 17:15:42 -06:00
for ( i = 0 ; i < = 3 ; i + + )
{
if ( ( ( staRecord - > powersaveMode [ i ] = = CSR_WIFI_AC_TRIGGER_ONLY_ENABLED )
| | ( staRecord - > powersaveMode [ i ] = = CSR_WIFI_AC_LEGACY_POWER_SAVE ) )
& & ( ! list_empty ( & staRecord - > dataPdu [ i ] ) ) ) {
return TRUE ;
}
}
if ( ( ( staRecord - > powersaveMode [ UNIFI_TRAFFIC_Q_VO ] = = CSR_WIFI_AC_TRIGGER_ONLY_ENABLED )
| | ( staRecord - > powersaveMode [ UNIFI_TRAFFIC_Q_VO ] = = CSR_WIFI_AC_LEGACY_POWER_SAVE ) )
& & ( ! list_empty ( & staRecord - > mgtFrames ) ) ) {
return TRUE ;
}
return FALSE ;
}
2012-07-20 13:00:10 -06:00
int uf_process_station_records_for_sending_data ( unifi_priv_t * priv , u16 interfaceTag ,
2012-06-19 17:15:42 -06:00
CsrWifiRouterCtrlStaInfo_t * srcStaInfo ,
CsrWifiRouterCtrlStaInfo_t * dstStaInfo )
{
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
unifi_trace ( priv , UDBG5 , " entering uf_process_station_records_for_sending_data \n " ) ;
if ( srcStaInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED ) {
unifi_error ( priv , " Peer State not connected AID = %x, handle = %x, control port state = %x \n " ,
srcStaInfo - > aid , srcStaInfo - > assignedHandle , srcStaInfo - > peerControlledPort - > port_action ) ;
return - 1 ;
}
switch ( interfacePriv - > interfaceMode )
{
case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO :
case CSR_WIFI_ROUTER_CTRL_MODE_AP :
unifi_trace ( priv , UDBG5 , " mode is AP/P2PGO \n " ) ;
break ;
default :
unifi_warning ( priv , " mode is nor AP neither P2PGO, packet cant be xmit \n " ) ;
return - 1 ;
}
switch ( dstStaInfo - > peerControlledPort - > port_action )
{
case CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD :
case CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_BLOCK :
unifi_trace ( priv , UDBG5 , " destination port is closed/blocked, discarding the packet \n " ) ;
return - 1 ;
default :
unifi_trace ( priv , UDBG5 , " destination port state is open \n " ) ;
}
/* port state is open, destination station record is valid, Power save state is
* validated in uf_process_ma_packet_req function
*/
unifi_trace ( priv , UDBG5 , " leaving uf_process_station_records_for_sending_data \n " ) ;
return 0 ;
}
2012-06-19 18:33:16 -06:00
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* uf_handle_uspframes_delivery
*
* This function takes care of handling USP session for peer , when
* - > trigger frame from peer
* - > suspended USP to be processed ( resumed )
*
* NOTE : uf_send_buffered_data_from_delivery_ac ( ) always called from this function , Dont
* make a direct call to uf_send_buffered_data_from_delivery_ac ( ) from any other part of
* code
*
* Arguments :
* priv Pointer to device private context struct
* staInfo peer for which UAPSD to be scheduled
* interfaceTag virtual interface tag
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2012-07-20 13:00:10 -06:00
static void uf_handle_uspframes_delivery ( unifi_priv_t * priv , CsrWifiRouterCtrlStaInfo_t * staInfo , u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:56:26 -06:00
s8 i ;
2012-07-20 12:51:01 -06:00
u8 allDeliveryEnabled = 0 , dataAvailable = 0 ;
2012-06-19 18:33:16 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
2012-06-19 17:15:42 -06:00
unsigned long lock_flags ;
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " ++ uf_handle_uspframes_delivery, uapsd active=%x, suspended?=%x \n " ,
staInfo - > uapsdActive , staInfo - > uspSuspend ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* Check for Buffered frames according to priority order & deliver it
* 1. AC_VO delivery enable & Mgt frames available
* 2. Process remaining Ac ' s from order AC_VO to AC_BK
*/
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* USP initiated by WMMPS enabled peer & SET the status flag to TRUE */
if ( ! staInfo - > uspSuspend & & staInfo - > uapsdActive )
{
unifi_notice ( priv , " uf_handle_uspframes_delivery: U-APSD already active! STA=%x:%x:%x:%x:%x:%x \n " ,
staInfo - > peerMacAddress . a [ 0 ] , staInfo - > peerMacAddress . a [ 1 ] ,
staInfo - > peerMacAddress . a [ 2 ] , staInfo - > peerMacAddress . a [ 3 ] ,
staInfo - > peerMacAddress . a [ 4 ] , staInfo - > peerMacAddress . a [ 5 ] ) ;
return ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
staInfo - > uapsdActive = TRUE ;
staInfo - > uspSuspend = FALSE ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( ( ( staInfo - > powersaveMode [ UNIFI_TRAFFIC_Q_VO ] = = CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED ) | |
( staInfo - > powersaveMode [ UNIFI_TRAFFIC_Q_VO ] = = CSR_WIFI_AC_DELIVERY_ONLY_ENABLE ) )
& & ( ! list_empty ( & staInfo - > mgtFrames ) ) ) {
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* Management queue has data && UNIFI_TRAFFIC_Q_VO is delivery enable */
unifi_trace ( priv , UDBG4 , " uf_handle_uspframes_delivery: Sending buffered management frames \n " ) ;
uf_send_buffered_data_from_delivery_ac ( priv , staInfo , UNIFI_TRAFFIC_Q_VO , & staInfo - > mgtFrames ) ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( ! uf_is_more_data_for_delivery_ac ( priv , staInfo ) ) {
/* All delivery enable AC's are empty, so QNULL to be sent to terminate the USP
* NOTE : If we have sent Mgt frame also , we must send QNULL followed to terminate USP
*/
if ( ! staInfo - > uspSuspend ) {
2012-06-19 17:15:42 -06:00
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
2012-06-19 18:33:16 -06:00
staInfo - > uapsdActive = FALSE ;
2012-06-19 17:15:42 -06:00
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " uf_handle_uspframes_delivery: sending QNull for trigger \n " ) ;
uf_send_qos_null ( priv , interfaceTag , staInfo - > peerMacAddress . a , ( CSR_PRIORITY ) staInfo - > triggerFramePriority , staInfo ) ;
staInfo - > triggerFramePriority = CSR_QOS_UP0 ;
} else {
unifi_trace ( priv , UDBG2 , " uf_handle_uspframes_delivery: MgtQ xfer suspended \n " ) ;
}
} else {
for ( i = UNIFI_TRAFFIC_Q_VO ; i > = UNIFI_TRAFFIC_Q_BK ; i - - ) {
if ( ( ( staInfo - > powersaveMode [ i ] = = CSR_WIFI_AC_DELIVERY_ONLY_ENABLE )
| | ( staInfo - > powersaveMode [ i ] = = CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED ) )
& & ( ! list_empty ( & staInfo - > dataPdu [ i ] ) ) ) {
/* Deliver Data according to AC priority (from VO to BK) as part of USP */
unifi_trace ( priv , UDBG4 , " uf_handle_uspframes_delivery: Buffered data frames from Queue (%d) for USP \n " , i ) ;
uf_send_buffered_data_from_delivery_ac ( priv , staInfo , i , & staInfo - > dataPdu [ i ] ) ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( ( ! staInfo - > uapsdActive ) | |
( staInfo - > uspSuspend & & IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) ) {
/* If DTIM active found on one AC, No need to parse the remaining AC's
* as USP suspended . Break out of loop
*/
unifi_trace ( priv , UDBG2 , " uf_handle_uspframes_delivery: suspend=%x, DTIM=%x, USP terminated=%s \n " ,
staInfo - > uspSuspend , IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ,
staInfo - > uapsdActive ? " NO " : " YES " ) ;
break ;
}
}
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
/* Depending on the USP status, update the TIM accordingly for delivery enabled AC only
* ( since we are not manipulating any Non - delivery list ( AC ) )
*/
is_all_ac_deliver_enabled_and_moredata ( staInfo , & allDeliveryEnabled , & dataAvailable ) ;
if ( ( allDeliveryEnabled & & ! dataAvailable ) ) {
if ( ( staInfo - > timSet ! = CSR_WIFI_TIM_RESET ) | | ( staInfo - > timSet ! = CSR_WIFI_TIM_RESETTING ) ) {
2012-07-20 12:51:01 -06:00
staInfo - > updateTimReqQueued = ( u8 ) CSR_WIFI_TIM_RESET ;
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG4 , " --uf_handle_uspframes_delivery, UAPSD timset \n " ) ;
if ( ! staInfo - > timRequestPendingFlag ) {
update_tim ( priv , staInfo - > aid , 0 , interfaceTag , staInfo - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
}
}
unifi_trace ( priv , UDBG2 , " --uf_handle_uspframes_delivery, uapsd active=%x, suspend?=%x \n " ,
staInfo - > uapsdActive , staInfo - > uspSuspend ) ;
}
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
void uf_process_wmm_deliver_ac_uapsd ( unifi_priv_t * priv ,
CsrWifiRouterCtrlStaInfo_t * srcStaInfo ,
2012-07-20 13:00:10 -06:00
u16 qosControl ,
u16 interfaceTag )
2012-06-19 18:33:16 -06:00
{
CSR_PRIORITY priority ;
unifi_TrafficQueue priority_q ;
unsigned long lock_flags ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " ++uf_process_wmm_deliver_ac_uapsd: uapsdactive?=%x \n " , srcStaInfo - > uapsdActive ) ;
/* If recceived Frames trigger Frame and Devlivery enabled AC has data
* then transmit from High priorty delivery enabled AC
*/
priority = ( CSR_PRIORITY ) ( qosControl & IEEE802_11_QC_TID_MASK ) ;
priority_q = unifi_frame_priority_to_queue ( ( CSR_PRIORITY ) priority ) ;
2012-06-19 17:15:42 -06:00
2012-06-19 18:33:16 -06:00
if ( ( srcStaInfo - > powersaveMode [ priority_q ] = = CSR_WIFI_AC_TRIGGER_ONLY_ENABLED )
| | ( srcStaInfo - > powersaveMode [ priority_q ] = = CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED ) ) {
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
srcStaInfo - > triggerFramePriority = priority ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
unifi_trace ( priv , UDBG2 , " uf_process_wmm_deliver_ac_uapsd: trigger frame, Begin U-APSD, triggerQ=%x \n " , priority_q ) ;
uf_handle_uspframes_delivery ( priv , srcStaInfo , interfaceTag ) ;
}
unifi_trace ( priv , UDBG2 , " --uf_process_wmm_deliver_ac_uapsd: uapsdactive?=%x \n " , srcStaInfo - > uapsdActive ) ;
}
2012-06-19 17:15:42 -06:00
2012-07-20 13:00:10 -06:00
void uf_send_qos_null ( unifi_priv_t * priv , u16 interfaceTag , const u8 * da , CSR_PRIORITY priority , CsrWifiRouterCtrlStaInfo_t * srcStaInfo )
2012-06-19 17:15:42 -06:00
{
bulk_data_param_t bulkdata ;
CsrResult csrResult ;
struct sk_buff * skb , * newSkb = NULL ;
CsrWifiMacAddress peerAddress ;
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
2012-06-19 18:33:16 -06:00
CSR_TRANSMISSION_CONTROL transmissionControl = ( TRANSMISSION_CONTROL_EOSP_MASK | TRANSMISSION_CONTROL_TRIGGER_MASK ) ;
2012-06-19 17:15:42 -06:00
int r ;
CSR_SIGNAL signal ;
2012-07-20 13:05:42 -06:00
u32 priority_q ;
2012-06-19 17:15:42 -06:00
CSR_RATE transmitRate = 0 ;
/* Send a Null Frame to Peer,
* 32 = size of mac header */
csrResult = unifi_net_data_malloc ( priv , & bulkdata . d [ 0 ] , MAC_HEADER_SIZE + QOS_CONTROL_HEADER_SIZE ) ;
if ( csrResult ! = CSR_RESULT_SUCCESS ) {
unifi_error ( priv , " failed to allocate request_data. in uf_send_qos_null func \n " ) ;
return ;
}
skb = ( struct sk_buff * ) ( bulkdata . d [ 0 ] . os_net_buf_ptr ) ;
skb - > len = 0 ;
bulkdata . d [ 0 ] . os_data_ptr = skb - > data ;
bulkdata . d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) skb ;
bulkdata . d [ 0 ] . net_buf_length = bulkdata . d [ 0 ] . data_length = skb - > len ;
bulkdata . d [ 1 ] . os_data_ptr = NULL ;
bulkdata . d [ 1 ] . os_net_buf_ptr = NULL ;
bulkdata . d [ 1 ] . net_buf_length = bulkdata . d [ 1 ] . data_length = 0 ;
/* For null frames protection bit should not be set in MAC header, so passing value 0 below for protection field */
if ( prepare_and_add_macheader ( priv , skb , newSkb , priority , & bulkdata , interfaceTag , da , interfacePriv - > bssid . a , 0 ) ) {
unifi_error ( priv , " failed to create MAC header \n " ) ;
unifi_net_data_free ( priv , & bulkdata . d [ 0 ] ) ;
return ;
}
2012-07-20 12:51:01 -06:00
memcpy ( peerAddress . a , ( ( u8 * ) bulkdata . d [ 0 ] . os_data_ptr ) + 4 , ETH_ALEN ) ;
2012-06-19 17:15:42 -06:00
/* convert priority to queue */
priority_q = unifi_frame_priority_to_queue ( ( CSR_PRIORITY ) priority ) ;
/* Frame ma-packet.req, this is saved/transmitted depend on queue state
* send the null frame at data rate of 1 Mb / s for AP or 6 Mb / s for P2PGO
*/
switch ( interfacePriv - > interfaceMode )
{
case CSR_WIFI_ROUTER_CTRL_MODE_AP :
transmitRate = 2 ;
break ;
case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO :
transmitRate = 12 ;
break ;
default :
transmitRate = 0 ;
}
unifi_frame_ma_packet_req ( priv , priority , transmitRate , 0xffffffff , interfaceTag ,
transmissionControl , priv - > netdev_client - > sender_id ,
peerAddress . a , & signal ) ;
r = ul_send_signal_unpacked ( priv , & signal , & bulkdata ) ;
if ( r ) {
unifi_error ( priv , " failed to send QOS data null packet result: %d \n " , r ) ;
unifi_net_data_free ( priv , & bulkdata . d [ 0 ] ) ;
}
return ;
}
2012-07-20 13:00:10 -06:00
void uf_send_nulldata ( unifi_priv_t * priv , u16 interfaceTag , const u8 * da , CSR_PRIORITY priority , CsrWifiRouterCtrlStaInfo_t * srcStaInfo )
2012-06-19 17:15:42 -06:00
{
bulk_data_param_t bulkdata ;
CsrResult csrResult ;
struct sk_buff * skb , * newSkb = NULL ;
CsrWifiMacAddress peerAddress ;
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
CSR_TRANSMISSION_CONTROL transmissionControl = 0 ;
int r ;
CSR_SIGNAL signal ;
2012-07-20 13:05:42 -06:00
u32 priority_q ;
2012-06-19 17:15:42 -06:00
CSR_RATE transmitRate = 0 ;
CSR_MA_PACKET_REQUEST * req = & signal . u . MaPacketRequest ;
unsigned long lock_flags ;
/* Send a Null Frame to Peer, size = 24 for MAC header */
csrResult = unifi_net_data_malloc ( priv , & bulkdata . d [ 0 ] , MAC_HEADER_SIZE ) ;
if ( csrResult ! = CSR_RESULT_SUCCESS ) {
unifi_error ( priv , " uf_send_nulldata: Failed to allocate memory for NULL frame \n " ) ;
return ;
}
skb = ( struct sk_buff * ) ( bulkdata . d [ 0 ] . os_net_buf_ptr ) ;
skb - > len = 0 ;
bulkdata . d [ 0 ] . os_data_ptr = skb - > data ;
bulkdata . d [ 0 ] . os_net_buf_ptr = ( unsigned char * ) skb ;
bulkdata . d [ 0 ] . net_buf_length = bulkdata . d [ 0 ] . data_length = skb - > len ;
bulkdata . d [ 1 ] . os_data_ptr = NULL ;
bulkdata . d [ 1 ] . os_net_buf_ptr = NULL ;
bulkdata . d [ 1 ] . net_buf_length = bulkdata . d [ 1 ] . data_length = 0 ;
/* For null frames protection bit should not be set in MAC header, so passing value 0 below for protection field */
if ( prepare_and_add_macheader ( priv , skb , newSkb , priority , & bulkdata , interfaceTag , da , interfacePriv - > bssid . a , 0 ) ) {
unifi_error ( priv , " uf_send_nulldata: Failed to create MAC header \n " ) ;
unifi_net_data_free ( priv , & bulkdata . d [ 0 ] ) ;
return ;
}
2012-07-20 12:51:01 -06:00
memcpy ( peerAddress . a , ( ( u8 * ) bulkdata . d [ 0 ] . os_data_ptr ) + 4 , ETH_ALEN ) ;
2012-06-19 17:15:42 -06:00
/* convert priority to queue */
priority_q = unifi_frame_priority_to_queue ( ( CSR_PRIORITY ) priority ) ;
transmissionControl & = ~ ( CSR_NO_CONFIRM_REQUIRED ) ;
/* Frame ma-packet.req, this is saved/transmitted depend on queue state
* send the null frame at data rate of 1 Mb / s for AP or 6 Mb / s for P2PGO
*/
switch ( interfacePriv - > interfaceMode )
{
case CSR_WIFI_ROUTER_CTRL_MODE_AP :
transmitRate = 2 ;
break ;
case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO :
transmitRate = 12 ;
break ;
default :
transmitRate = 0 ;
}
unifi_frame_ma_packet_req ( priv , priority , transmitRate , INVALID_HOST_TAG , interfaceTag ,
transmissionControl , priv - > netdev_client - > sender_id ,
peerAddress . a , & signal ) ;
/* Save host tag to check the status on reception of MA packet confirm */
srcStaInfo - > nullDataHostTag = req - > HostTag ;
unifi_trace ( priv , UDBG1 , " uf_send_nulldata: STA AID = %d hostTag = %x \n " , srcStaInfo - > aid , req - > HostTag ) ;
r = ul_send_signal_unpacked ( priv , & signal , & bulkdata ) ;
if ( r = = - ENOSPC ) {
unifi_trace ( priv , UDBG1 , " uf_send_nulldata: ENOSPC Requeue the Null frame \n " ) ;
enque_tx_data_pdu ( priv , & bulkdata , & srcStaInfo - > dataPdu [ priority_q ] , & signal , 1 ) ;
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
srcStaInfo - > noOfPktQueued + + ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
}
if ( r & & r ! = - ENOSPC ) {
unifi_error ( priv , " uf_send_nulldata: Failed to send Null frame Error = %d \n " , r ) ;
unifi_net_data_free ( priv , & bulkdata . d [ 0 ] ) ;
srcStaInfo - > nullDataHostTag = INVALID_HOST_TAG ;
}
return ;
}
2012-07-20 13:25:15 -06:00
u8 uf_check_broadcast_bssid ( unifi_priv_t * priv , const bulk_data_param_t * bulkdata )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:51:01 -06:00
u8 * bssid = NULL ;
2012-06-19 17:15:42 -06:00
static const CsrWifiMacAddress broadcast_address = { { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } } ;
2012-07-20 12:51:01 -06:00
u8 toDs , fromDs ;
2012-06-19 17:15:42 -06:00
toDs = ( ( ( bulkdata - > d [ 0 ] . os_data_ptr ) [ 1 ] ) & 0x01 ) ? 1 : 0 ;
fromDs = ( ( ( bulkdata - > d [ 0 ] . os_data_ptr ) [ 1 ] ) & 0x02 ) ? 1 : 0 ;
if ( toDs & & fromDs )
{
unifi_trace ( priv , UDBG6 , " Address 4 present, Don't try to find BSSID \n " ) ;
bssid = NULL ;
}
else if ( ( toDs = = 0 ) & & ( fromDs = = 0 ) )
{
/* BSSID is Address 3 */
2012-07-20 12:51:01 -06:00
bssid = ( u8 * ) ( bulkdata - > d [ 0 ] . os_data_ptr + 4 + ( 2 * ETH_ALEN ) ) ;
2012-06-19 17:15:42 -06:00
}
else if ( toDs )
{
/* BSSID is Address 1 */
2012-07-20 12:51:01 -06:00
bssid = ( u8 * ) ( bulkdata - > d [ 0 ] . os_data_ptr + 4 ) ;
2012-06-19 17:15:42 -06:00
}
else if ( fromDs )
{
/* BSSID is Address 2 */
2012-07-20 12:51:01 -06:00
bssid = ( u8 * ) ( bulkdata - > d [ 0 ] . os_data_ptr + 4 + ETH_ALEN ) ;
2012-06-19 17:15:42 -06:00
}
if ( memcmp ( broadcast_address . a , bssid , ETH_ALEN ) = = 0 )
{
return TRUE ;
}
else
{
return FALSE ;
}
}
2012-07-20 13:25:15 -06:00
u8 uf_process_pm_bit_for_peer ( unifi_priv_t * priv , CsrWifiRouterCtrlStaInfo_t * srcStaInfo ,
2012-07-20 13:00:10 -06:00
u8 pmBit , u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
2012-07-20 13:25:15 -06:00
u8 moreData = FALSE ;
u8 powerSaveChanged = FALSE ;
2012-06-19 17:15:42 -06:00
unsigned long lock_flags ;
unifi_trace ( priv , UDBG3 , " entering uf_process_pm_bit_for_peer \n " ) ;
if ( pmBit ) {
priv - > allPeerDozing | = ( 0x01 < < ( srcStaInfo - > assignedHandle ) ) ;
} else {
priv - > allPeerDozing & = ~ ( 0x01 < < ( srcStaInfo - > assignedHandle ) ) ;
}
if ( pmBit ) {
if ( srcStaInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE ) {
/* disable the preemption */
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
srcStaInfo - > currentPeerState = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE ;
powerSaveChanged = TRUE ;
/* enable the preemption */
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
} else {
return powerSaveChanged ;
}
} else {
if ( srcStaInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE ) {
/* disable the preemption */
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
srcStaInfo - > currentPeerState = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE ;
powerSaveChanged = TRUE ;
/* enable the preemption */
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
} else {
return powerSaveChanged ;
}
}
if ( srcStaInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE ) {
unifi_trace ( priv , UDBG3 , " Peer with AID = %d is active now \n " , srcStaInfo - > aid ) ;
process_peer_active_transition ( priv , srcStaInfo , interfaceTag ) ;
} else {
unifi_trace ( priv , UDBG3 , " Peer with AID = %d is in PS Now \n " , srcStaInfo - > aid ) ;
/* Set TIM if needed */
if ( ! srcStaInfo - > wmmOrQosEnabled ) {
moreData = ( ! list_empty ( & srcStaInfo - > mgtFrames ) | |
! list_empty ( & srcStaInfo - > dataPdu [ UNIFI_TRAFFIC_Q_VO ] ) | |
! list_empty ( & srcStaInfo - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) ) ;
if ( moreData & & ( srcStaInfo - > timSet = = CSR_WIFI_TIM_RESET ) ) {
unifi_trace ( priv , UDBG3 , " This condition should not occur \n " ) ;
2012-06-19 18:33:16 -06:00
if ( ! srcStaInfo - > timRequestPendingFlag ) {
update_tim ( priv , srcStaInfo - > aid , 1 , interfaceTag , srcStaInfo - > assignedHandle ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
srcStaInfo - > updateTimReqQueued = 1 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , srcStaInfo - > updateTimReqQueued ,
srcStaInfo - > aid ) ;
}
2012-06-19 17:15:42 -06:00
}
} else {
2012-07-20 12:51:01 -06:00
u8 allDeliveryEnabled = 0 , dataAvailable = 0 ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG5 , " Qos in AP Mode \n " ) ;
/* Check if all AC's are Delivery Enabled */
is_all_ac_deliver_enabled_and_moredata ( srcStaInfo , & allDeliveryEnabled , & dataAvailable ) ;
/*check for more data in non-delivery enabled queues*/
moreData = ( uf_is_more_data_for_non_delivery_ac ( srcStaInfo ) | | ( allDeliveryEnabled & & dataAvailable ) ) ;
if ( moreData & & ( srcStaInfo - > timSet = = CSR_WIFI_TIM_RESET ) ) {
2012-06-19 18:33:16 -06:00
if ( ! srcStaInfo - > timRequestPendingFlag ) {
update_tim ( priv , srcStaInfo - > aid , 1 , interfaceTag , srcStaInfo - > assignedHandle ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
srcStaInfo - > updateTimReqQueued = 1 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , srcStaInfo - > updateTimReqQueued ,
srcStaInfo - > aid ) ;
}
2012-06-19 17:15:42 -06:00
}
}
}
unifi_trace ( priv , UDBG3 , " leaving uf_process_pm_bit_for_peer \n " ) ;
return powerSaveChanged ;
}
2012-07-20 13:00:10 -06:00
void uf_process_ps_poll ( unifi_priv_t * priv , u8 * sa , u8 * da , u8 pmBit , u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
CsrWifiRouterCtrlStaInfo_t * staRecord =
CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( priv , sa , interfaceTag ) ;
tx_buffered_packets_t * buffered_pkt = NULL ;
CsrWifiMacAddress peerMacAddress ;
unsigned long lock_flags ;
2012-07-20 12:56:26 -06:00
s8 r = 0 ;
2012-07-20 13:25:15 -06:00
u8 moreData = FALSE ;
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
unifi_trace ( priv , UDBG3 , " entering uf_process_ps_poll \n " ) ;
if ( ! staRecord ) {
memcpy ( peerMacAddress . a , sa , ETH_ALEN ) ;
unifi_trace ( priv , UDBG3 , " In uf_process_ps_poll, sta record not found:unexpected frame addr = %x:%x:%x:%x:%x:%x \n " ,
sa [ 0 ] , sa [ 1 ] , sa [ 2 ] , sa [ 3 ] , sa [ 4 ] , sa [ 5 ] ) ;
CsrWifiRouterCtrlUnexpectedFrameIndSend ( priv - > CSR_WIFI_SME_IFACEQUEUE , 0 , interfaceTag , peerMacAddress ) ;
return ;
}
uf_process_pm_bit_for_peer ( priv , staRecord , pmBit , interfaceTag ) ;
/* Update station last activity time */
staRecord - > activity_flag = TRUE ;
/* This should not change the PM bit as PS-POLL has PM bit always set */
if ( ! pmBit ) {
unifi_notice ( priv , " PM bit reset in PS-POLL \n " ) ;
return ;
}
if ( IS_DTIM_ACTIVE ( interfacePriv - > dtimActive , interfacePriv - > multicastPduHostTag ) ) {
/* giving more priority to multicast packets so dropping ps-poll*/
unifi_notice ( priv , " multicast transmission is going on so don't take action on PS-POLL \n " ) ;
return ;
}
if ( ! staRecord - > wmmOrQosEnabled ) {
if ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staRecord - > mgtFrames ) ) ) {
buffered_pkt - > transmissionControl | = TRANSMISSION_CONTROL_TRIGGER_MASK ;
moreData = ( ! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) | |
! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_VO ] ) | |
! list_empty ( & staRecord - > mgtFrames ) ) ;
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl | = ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staRecord , moreData , FALSE ) ) = = - ENOSPC ) {
/* Clear the trigger bit transmission control*/
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl & = ~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staRecord - > mgtFrames ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
unifi_trace ( priv , UDBG1 , " (ENOSPC) PS-POLL received : PDU sending failed \n " ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 3 ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
} else if ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_VO ] ) ) ) {
buffered_pkt - > transmissionControl | = TRANSMISSION_CONTROL_TRIGGER_MASK ;
moreData = ( ! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) | |
! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_VO ] ) ) ;
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl | = ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staRecord , moreData , FALSE ) ) = = - ENOSPC ) {
/* Clear the trigger bit transmission control*/
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl & = ~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_VO ] ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 3 ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG1 , " (ENOSPC) PS-POLL received : PDU sending failed \n " ) ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
} else if ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) ) ) {
buffered_pkt - > transmissionControl | = TRANSMISSION_CONTROL_TRIGGER_MASK ;
moreData = ! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) ;
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl | = ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staRecord , moreData , FALSE ) ) = = - ENOSPC ) {
/* Clear the trigger bit transmission control*/
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl & = ~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 0 ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG1 , " (ENOSPC) PS-POLL received : PDU sending failed \n " ) ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
} else {
/* Actually since we have sent an ACK, there
* there is no need to send a NULL frame */
}
moreData = ( ! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_VO ] ) | |
! list_empty ( & staRecord - > dataPdu [ UNIFI_TRAFFIC_Q_CONTENTION ] ) | |
! list_empty ( & staRecord - > mgtFrames ) ) ;
if ( ! moreData & & ( staRecord - > timSet = = CSR_WIFI_TIM_SET ) ) {
unifi_trace ( priv , UDBG3 , " more data = NULL, set tim to 0 in uf_process_ps_poll \n " ) ;
2012-06-19 18:33:16 -06:00
if ( ! staRecord - > timRequestPendingFlag ) {
update_tim ( priv , staRecord - > aid , 0 , interfaceTag , staRecord - > assignedHandle ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 0 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , staRecord - > updateTimReqQueued ,
staRecord - > aid ) ;
}
2012-06-19 17:15:42 -06:00
}
} else {
2012-07-20 12:51:01 -06:00
u8 allDeliveryEnabled = 0 , dataAvailable = 0 ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG3 , " Qos Support station.Processing PS-Poll \n " ) ;
/*Send Data From Management Frames*/
/* Priority orders for delivering the buffered packets are
2012-06-19 18:33:16 -06:00
* 1. Deliver the Management frames if there
* 2. Other access catagory frames which are non deliver enable including UNIFI_TRAFFIC_Q_VO
* priority is from VO - > BK
2012-06-19 17:15:42 -06:00
*/
/* Check if all AC's are Delivery Enabled */
is_all_ac_deliver_enabled_and_moredata ( staRecord , & allDeliveryEnabled , & dataAvailable ) ;
if ( allDeliveryEnabled ) {
unifi_trace ( priv , UDBG3 , " uf_process_ps_poll: All ACs are delivery enable so Sending QOS Null in response of Ps-poll \n " ) ;
uf_send_qos_null ( priv , interfaceTag , sa , CSR_QOS_UP0 , staRecord ) ;
return ;
}
2012-06-19 18:33:16 -06:00
if ( ! list_empty ( & staRecord - > mgtFrames ) ) {
if ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staRecord - > mgtFrames ) ) ) {
2012-06-19 17:15:42 -06:00
/* We dont have packets in non delivery enabled UNIFI_TRAFFIC_Q_VO, So we are looking in management
* queue of the station record
*/
moreData = uf_is_more_data_for_non_delivery_ac ( staRecord ) ;
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl | = ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
/* Last parameter is EOSP & its false always for PS-POLL processing */
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staRecord , moreData , FALSE ) ) = = - ENOSPC ) {
/* Clear the trigger bit transmission control*/
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl & = ~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staRecord - > mgtFrames ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 0 ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG1 , " (ENOSPC) PS-POLL received : PDU sending failed \n " ) ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
2012-06-19 18:33:16 -06:00
} else {
unifi_error ( priv , " uf_process_ps_poll: Mgt frame list empty!! \n " ) ;
2012-06-19 17:15:42 -06:00
}
2012-06-19 18:33:16 -06:00
2012-06-19 17:15:42 -06:00
} else {
2012-07-20 12:56:26 -06:00
s8 i ;
2012-06-19 18:33:16 -06:00
/* We dont have buffered packet in mangement frame queue (1 failed), So proceed with condition 2
* UNIFI_TRAFFIC_Q_VO - > VI - > BE - > BK
2012-06-19 17:15:42 -06:00
*/
2012-06-19 18:33:16 -06:00
for ( i = 3 ; i > = 0 ; i - - ) {
2012-06-19 17:15:42 -06:00
if ( ! IS_DELIVERY_ENABLED ( staRecord - > powersaveMode [ i ] ) ) {
/* Send One packet, if queue is NULL then continue */
if ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staRecord - > dataPdu [ i ] ) ) ) {
moreData = uf_is_more_data_for_non_delivery_ac ( staRecord ) ;
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl | = ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
/* Last parameter is EOSP & its false always for PS-POLL processing */
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staRecord , moreData , FALSE ) ) = = - ENOSPC ) {
/* Clear the trigger bit transmission control*/
2012-06-19 18:33:16 -06:00
buffered_pkt - > transmissionControl & = ~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staRecord - > dataPdu [ i ] ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 0 ] = ( u8 ) ( staRecord - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
unifi_trace ( priv , UDBG1 , " (ENOSPC) PS-POLL received : PDU sending failed \n " ) ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
break ;
}
}
}
}
/* Check if all AC's are Delivery Enabled */
is_all_ac_deliver_enabled_and_moredata ( staRecord , & allDeliveryEnabled , & dataAvailable ) ;
/*check for more data in non-delivery enabled queues*/
moreData = ( uf_is_more_data_for_non_delivery_ac ( staRecord ) | | ( allDeliveryEnabled & & dataAvailable ) ) ;
if ( ! moreData & & ( staRecord - > timSet = = CSR_WIFI_TIM_SET ) ) {
unifi_trace ( priv , UDBG3 , " more data = NULL, set tim to 0 in uf_process_ps_poll \n " ) ;
2012-06-19 18:33:16 -06:00
if ( ! staRecord - > timRequestPendingFlag ) {
update_tim ( priv , staRecord - > aid , 0 , interfaceTag , staRecord - > assignedHandle ) ;
}
else
{
/* Cache the TimSet value so that it will processed immidiatly after
* completing the current setTim Request
*/
staRecord - > updateTimReqQueued = 0 ;
unifi_trace ( priv , UDBG6 , " update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x \n " , staRecord - > updateTimReqQueued ,
staRecord - > aid ) ;
}
2012-06-19 17:15:42 -06:00
}
}
unifi_trace ( priv , UDBG3 , " leaving uf_process_ps_poll \n " ) ;
}
void add_to_send_cfm_list ( unifi_priv_t * priv ,
tx_buffered_packets_t * tx_q_item ,
struct list_head * frames_need_cfm_list )
{
tx_buffered_packets_t * send_cfm_list_item = NULL ;
send_cfm_list_item = ( tx_buffered_packets_t * ) kmalloc ( sizeof ( tx_buffered_packets_t ) , GFP_ATOMIC ) ;
if ( send_cfm_list_item = = NULL ) {
unifi_warning ( priv , " %s: Failed to allocate memory for new list item \n " ) ;
return ;
}
INIT_LIST_HEAD ( & send_cfm_list_item - > q ) ;
send_cfm_list_item - > hostTag = tx_q_item - > hostTag ;
send_cfm_list_item - > interfaceTag = tx_q_item - > interfaceTag ;
send_cfm_list_item - > transmissionControl = tx_q_item - > transmissionControl ;
send_cfm_list_item - > leSenderProcessId = tx_q_item - > leSenderProcessId ;
send_cfm_list_item - > rate = tx_q_item - > rate ;
memcpy ( send_cfm_list_item - > peerMacAddress . a , tx_q_item - > peerMacAddress . a , ETH_ALEN ) ;
send_cfm_list_item - > priority = tx_q_item - > priority ;
list_add_tail ( & send_cfm_list_item - > q , frames_need_cfm_list ) ;
}
void uf_prepare_send_cfm_list_for_queued_pkts ( unifi_priv_t * priv ,
struct list_head * frames_need_cfm_list ,
struct list_head * list )
{
tx_buffered_packets_t * tx_q_item = NULL ;
struct list_head * listHead ;
struct list_head * placeHolder ;
unsigned long lock_flags ;
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
/* Search through the list and if confirmation required for any frames,
add it to the send_cfm list */
list_for_each_safe ( listHead , placeHolder , list ) {
tx_q_item = list_entry ( listHead , tx_buffered_packets_t , q ) ;
if ( ! tx_q_item ) {
unifi_error ( priv , " Entry should exist, otherwise it is a (BUG) \n " ) ;
continue ;
}
/* check if confirmation is requested and if the sender ID
is not netdevice client then save the entry in the list for need cfms */
if ( ! ( tx_q_item - > transmissionControl & CSR_NO_CONFIRM_REQUIRED ) & &
( tx_q_item - > leSenderProcessId ! = priv - > netdev_client - > sender_id ) ) {
unifi_trace ( priv , UDBG1 , " %s: SenderProcessID=%x host tag=%x transmission control=%x \n " ,
__FUNCTION__ ,
tx_q_item - > leSenderProcessId ,
tx_q_item - > hostTag ,
tx_q_item - > transmissionControl ) ;
add_to_send_cfm_list ( priv , tx_q_item , frames_need_cfm_list ) ;
}
}
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
}
void uf_flush_list ( unifi_priv_t * priv , struct list_head * list )
{
tx_buffered_packets_t * tx_q_item ;
struct list_head * listHead ;
struct list_head * placeHolder ;
unsigned long lock_flags ;
unifi_trace ( priv , UDBG5 , " entering the uf_flush_list \n " ) ;
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
/* go through list, delete & free memory */
list_for_each_safe ( listHead , placeHolder , list ) {
tx_q_item = list_entry ( listHead , tx_buffered_packets_t , q ) ;
if ( ! tx_q_item ) {
unifi_error ( priv , " entry should exists, otherwise crashes (bug) \n " ) ;
}
unifi_trace ( priv , UDBG5 ,
" proccess_tx: in uf_flush_list peerMacAddress=%02X%02X%02X%02X%02X%02X senderProcessId=%x \n " ,
tx_q_item - > peerMacAddress . a [ 0 ] , tx_q_item - > peerMacAddress . a [ 1 ] ,
tx_q_item - > peerMacAddress . a [ 2 ] , tx_q_item - > peerMacAddress . a [ 3 ] ,
tx_q_item - > peerMacAddress . a [ 4 ] , tx_q_item - > peerMacAddress . a [ 5 ] ,
tx_q_item - > leSenderProcessId ) ;
list_del ( listHead ) ;
/* free the allocated memory */
unifi_net_data_free ( priv , & tx_q_item - > bulkdata ) ;
kfree ( tx_q_item ) ;
tx_q_item = NULL ;
if ( ! priv - > noOfPktQueuedInDriver ) {
unifi_error ( priv , " packets queued in driver 0 still decrementing in %s \n " , __FUNCTION__ ) ;
} else {
priv - > noOfPktQueuedInDriver - - ;
}
}
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
}
tx_buffered_packets_t * dequeue_tx_data_pdu ( unifi_priv_t * priv , struct list_head * txList )
{
/* dequeue the tx data packets from the appropriate queue */
tx_buffered_packets_t * tx_q_item = NULL ;
struct list_head * listHead ;
struct list_head * placeHolder ;
unsigned long lock_flags ;
unifi_trace ( priv , UDBG5 , " entering dequeue_tx_data_pdu \n " ) ;
/* check for list empty */
if ( list_empty ( txList ) ) {
unifi_trace ( priv , UDBG5 , " In dequeue_tx_data_pdu, the list is empty \n " ) ;
return NULL ;
}
/* Verification, if packet count is negetive */
if ( priv - > noOfPktQueuedInDriver = = 0xFFFF ) {
unifi_warning ( priv , " no packet available in queue: debug " ) ;
return NULL ;
}
/* return first node after header, & delete from the list && atleast one item exist */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_for_each_safe ( listHead , placeHolder , txList ) {
tx_q_item = list_entry ( listHead , tx_buffered_packets_t , q ) ;
list_del ( listHead ) ;
break ;
}
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
if ( tx_q_item ) {
unifi_trace ( priv , UDBG5 ,
" proccess_tx: In dequeue_tx_data_pdu peerMacAddress=%02X%02X%02X%02X%02X%02X senderProcessId=%x \n " ,
tx_q_item - > peerMacAddress . a [ 0 ] , tx_q_item - > peerMacAddress . a [ 1 ] ,
tx_q_item - > peerMacAddress . a [ 2 ] , tx_q_item - > peerMacAddress . a [ 3 ] ,
tx_q_item - > peerMacAddress . a [ 4 ] , tx_q_item - > peerMacAddress . a [ 5 ] ,
tx_q_item - > leSenderProcessId ) ;
}
unifi_trace ( priv , UDBG5 , " leaving dequeue_tx_data_pdu \n " ) ;
return tx_q_item ;
}
/* generic function to get the station record handler */
CsrWifiRouterCtrlStaInfo_t * CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( unifi_priv_t * priv ,
2012-07-20 12:51:01 -06:00
const u8 * peerMacAddress ,
2012-07-20 13:00:10 -06:00
u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:51:01 -06:00
u8 i ;
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv ;
unsigned long lock_flags ;
if ( interfaceTag > = CSR_WIFI_NUM_INTERFACES ) {
unifi_error ( priv , " interfaceTag is not proper, interfaceTag = %d \n " , interfaceTag ) ;
return NULL ;
}
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
/* disable the preemption untill station record is fetched */
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
for ( i = 0 ; i < UNIFI_MAX_CONNECTIONS ; i + + ) {
if ( interfacePriv - > staInfo [ i ] ! = NULL ) {
if ( ! memcmp ( ( ( CsrWifiRouterCtrlStaInfo_t * ) ( interfacePriv - > staInfo [ i ] ) ) - > peerMacAddress . a , peerMacAddress , ETH_ALEN ) ) {
/* enable the preemption as station record is fetched */
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
unifi_trace ( priv , UDBG5 , " peer entry found in station record \n " ) ;
return ( ( CsrWifiRouterCtrlStaInfo_t * ) ( interfacePriv - > staInfo [ i ] ) ) ;
}
}
}
/* enable the preemption as station record is fetched */
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
unifi_trace ( priv , UDBG5 , " peer entry not found in station record \n " ) ;
return NULL ;
}
/* generic function to get the station record handler from the handle */
CsrWifiRouterCtrlStaInfo_t * CsrWifiRouterCtrlGetStationRecordFromHandle ( unifi_priv_t * priv ,
2012-07-20 13:05:42 -06:00
u32 handle ,
2012-07-20 13:00:10 -06:00
u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
netInterface_priv_t * interfacePriv ;
if ( ( handle > = UNIFI_MAX_CONNECTIONS ) | | ( interfaceTag > = CSR_WIFI_NUM_INTERFACES ) ) {
unifi_error ( priv , " handle/interfaceTag is not proper, handle = %d, interfaceTag = %d \n " , handle , interfaceTag ) ;
return NULL ;
}
interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
return ( ( CsrWifiRouterCtrlStaInfo_t * ) ( interfacePriv - > staInfo [ handle ] ) ) ;
}
/* Function to do inactivity */
2012-10-24 00:33:57 -06:00
void uf_check_inactivity ( unifi_priv_t * priv , u16 interfaceTag , u32 currentTime )
2012-06-19 17:15:42 -06:00
{
2012-07-20 13:05:42 -06:00
u32 i ;
2012-06-19 17:15:42 -06:00
CsrWifiRouterCtrlStaInfo_t * staInfo ;
2012-10-24 00:33:57 -06:00
u32 elapsedTime ; /* Time in microseconds */
2012-06-19 17:15:42 -06:00
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
CsrWifiMacAddress peerMacAddress ;
unsigned long lock_flags ;
if ( interfacePriv = = NULL ) {
unifi_trace ( priv , UDBG3 , " uf_check_inactivity: Interface priv is NULL \n " ) ;
return ;
}
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
/* Go through the list of stations to check for inactivity */
for ( i = 0 ; i < UNIFI_MAX_CONNECTIONS ; i + + ) {
staInfo = CsrWifiRouterCtrlGetStationRecordFromHandle ( priv , i , interfaceTag ) ;
if ( ! staInfo ) {
continue ;
}
unifi_trace ( priv , UDBG3 , " Running Inactivity handler Time %xus station's last activity %xus \n " ,
currentTime , staInfo - > lastActivity ) ;
elapsedTime = ( currentTime > = staInfo - > lastActivity ) ?
( currentTime - staInfo - > lastActivity ) :
2012-07-20 13:05:42 -06:00
( ~ ( ( u32 ) 0 ) - staInfo - > lastActivity + currentTime ) ;
2012-06-19 17:15:42 -06:00
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
if ( elapsedTime > MAX_INACTIVITY_INTERVAL ) {
2012-07-20 12:51:01 -06:00
memcpy ( ( u8 * ) & peerMacAddress , ( u8 * ) & staInfo - > peerMacAddress , sizeof ( CsrWifiMacAddress ) ) ;
2012-06-19 17:15:42 -06:00
/* Indicate inactivity for the station */
unifi_trace ( priv , UDBG3 , " Station %x:%x:%x:%x:%x:%x inactive since %xus \n sending Inactive Ind \n " ,
peerMacAddress . a [ 0 ] , peerMacAddress . a [ 1 ] ,
peerMacAddress . a [ 2 ] , peerMacAddress . a [ 3 ] ,
peerMacAddress . a [ 4 ] , peerMacAddress . a [ 5 ] ,
elapsedTime ) ;
CsrWifiRouterCtrlStaInactiveIndSend ( priv - > CSR_WIFI_SME_IFACEQUEUE , 0 , interfaceTag , peerMacAddress ) ;
}
}
interfacePriv - > last_inactivity_check = currentTime ;
}
/* Function to update activity of a station */
2012-07-20 13:00:10 -06:00
void uf_update_sta_activity ( unifi_priv_t * priv , u16 interfaceTag , const u8 * peerMacAddress )
2012-06-19 17:15:42 -06:00
{
2012-10-24 00:33:57 -06:00
u32 elapsedTime , currentTime ; /* Time in microseconds */
u32 timeHi ; /* Not used - Time in microseconds */
2012-06-19 17:15:42 -06:00
CsrWifiRouterCtrlStaInfo_t * staInfo ;
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
unsigned long lock_flags ;
if ( interfacePriv = = NULL ) {
unifi_trace ( priv , UDBG3 , " uf_check_inactivity: Interface priv is NULL \n " ) ;
return ;
}
currentTime = CsrTimeGet ( & timeHi ) ;
staInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress ( priv , peerMacAddress , interfaceTag ) ;
if ( staInfo = = NULL ) {
unifi_trace ( priv , UDBG4 , " Sta does not exist yet " ) ;
return ;
}
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
/* Update activity */
staInfo - > lastActivity = currentTime ;
/* See if inactivity handler needs to be run
* Here it is theoretically possible that the counter may have wrapped around . But
* since we just want to know when to run the inactivity handler it does not really matter .
* Especially since this is data path it makes sense in keeping it simple and avoiding
* 64 bit handling */
elapsedTime = ( currentTime > = interfacePriv - > last_inactivity_check ) ?
( currentTime - interfacePriv - > last_inactivity_check ) :
2012-07-20 13:05:42 -06:00
( ~ ( ( u32 ) 0 ) - interfacePriv - > last_inactivity_check + currentTime ) ;
2012-06-19 17:15:42 -06:00
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
/* Check if it is time to run the inactivity handler */
if ( elapsedTime > INACTIVITY_CHECK_INTERVAL ) {
uf_check_inactivity ( priv , interfaceTag , currentTime ) ;
}
}
2012-07-20 13:00:10 -06:00
void resume_unicast_buffered_frames ( unifi_priv_t * priv , u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
2012-07-20 12:51:01 -06:00
u8 i ;
2012-06-19 17:15:42 -06:00
int j ;
tx_buffered_packets_t * buffered_pkt = NULL ;
2012-07-20 13:25:15 -06:00
u8 hipslotFree [ 4 ] = { TRUE , TRUE , TRUE , TRUE } ;
2012-06-19 17:15:42 -06:00
int r ;
unsigned long lock_flags ;
while ( ! isRouterBufferEnabled ( priv , 3 ) & &
( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & interfacePriv - > genericMgtFrames ) ) ! = NULL ) ) {
buffered_pkt - > transmissionControl & =
2012-06-19 18:33:16 -06:00
~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , NULL , 0 , FALSE ) ) = = - ENOSPC ) {
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & interfacePriv - > genericMgtFrames ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
hipslotFree [ 3 ] = FALSE ;
break ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
}
for ( i = 0 ; i < UNIFI_MAX_CONNECTIONS ; i + + ) {
CsrWifiRouterCtrlStaInfo_t * staInfo = interfacePriv - > staInfo [ i ] ;
if ( ! hipslotFree [ 0 ] & & ! hipslotFree [ 1 ] & & ! hipslotFree [ 2 ] & & ! hipslotFree [ 3 ] ) {
unifi_trace ( priv , UDBG3 , " (ENOSPC) in resume_unicast_buffered_frames:: hip slots are full \n " ) ;
break ;
}
if ( staInfo & & ( staInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE ) ) {
while ( ( ( TRUE = = hipslotFree [ 3 ] ) & & ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staInfo - > mgtFrames ) ) ) ) {
buffered_pkt - > transmissionControl & =
2012-06-19 18:33:16 -06:00
~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staInfo , 0 , FALSE ) ) = = - ENOSPC ) {
unifi_trace ( priv , UDBG3 , " (ENOSPC) in resume_unicast_buffered_frames:: hip slots are full for voice queue \n " ) ;
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staInfo - > mgtFrames ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ 3 ] = ( u8 ) ( staInfo - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
hipslotFree [ 3 ] = FALSE ;
break ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
}
for ( j = 3 ; j > = 0 ; j - - ) {
if ( ! hipslotFree [ j ] )
continue ;
while ( ( buffered_pkt = dequeue_tx_data_pdu ( priv , & staInfo - > dataPdu [ j ] ) ) ) {
buffered_pkt - > transmissionControl & =
2012-06-19 18:33:16 -06:00
~ ( TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK ) ;
2012-06-19 17:15:42 -06:00
if ( ( r = frame_and_send_queued_pdu ( priv , buffered_pkt , staInfo , 0 , FALSE ) ) = = - ENOSPC ) {
/* Enqueue at the head of the queue */
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_add ( & buffered_pkt - > q , & staInfo - > dataPdu [ j ] ) ;
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
2012-07-20 12:51:01 -06:00
priv - > pausedStaHandle [ j ] = ( u8 ) ( staInfo - > assignedHandle ) ;
2012-06-19 17:15:42 -06:00
hipslotFree [ j ] = FALSE ;
break ;
} else {
if ( r ) {
unifi_trace ( priv , UDBG1 , " HIP validation failure : PDU sending failed \n " ) ;
/* the PDU failed where we can't do any thing so free the storage */
unifi_net_data_free ( priv , & buffered_pkt - > bulkdata ) ;
}
kfree ( buffered_pkt ) ;
}
}
}
}
}
}
2012-07-20 13:00:10 -06:00
void update_eosp_to_head_of_broadcast_list_head ( unifi_priv_t * priv , u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
netInterface_priv_t * interfacePriv = priv - > interfacePriv [ interfaceTag ] ;
unsigned long lock_flags ;
struct list_head * listHead ;
struct list_head * placeHolder ;
tx_buffered_packets_t * tx_q_item ;
if ( interfacePriv - > noOfbroadcastPktQueued ) {
/* Update the EOSP to the HEAD of b/c list
* beacuse we have received any mgmt packet so it should not hold for long time
* peer may time out .
*/
spin_lock_irqsave ( & priv - > tx_q_lock , lock_flags ) ;
list_for_each_safe ( listHead , placeHolder , & interfacePriv - > genericMulticastOrBroadCastFrames ) {
tx_q_item = list_entry ( listHead , tx_buffered_packets_t , q ) ;
2012-06-19 18:33:16 -06:00
tx_q_item - > transmissionControl | = TRANSMISSION_CONTROL_EOSP_MASK ;
2012-06-19 17:15:42 -06:00
tx_q_item - > transmissionControl = ( tx_q_item - > transmissionControl & ~ ( CSR_NO_CONFIRM_REQUIRED ) ) ;
unifi_trace ( priv , UDBG1 , " updating eosp for list Head hostTag:= 0x%x " , tx_q_item - > hostTag ) ;
break ;
}
spin_unlock_irqrestore ( & priv - > tx_q_lock , lock_flags ) ;
}
}
2012-06-19 18:33:16 -06:00
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* resume_suspended_uapsd
*
* This function takes care processing packets of Unscheduled Service Period ,
* which been suspended earlier due to DTIM / HIP ENOSPC scenarios
*
* Arguments :
* priv Pointer to device private context struct
* interfaceTag For which resume should happen
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2012-07-20 13:00:10 -06:00
void resume_suspended_uapsd ( unifi_priv_t * priv , u16 interfaceTag )
2012-06-19 17:15:42 -06:00
{
2012-07-20 12:51:01 -06:00
u8 startIndex ;
2012-06-19 17:15:42 -06:00
CsrWifiRouterCtrlStaInfo_t * staInfo = NULL ;
2012-06-19 18:33:16 -06:00
unsigned long lock_flags ;
unifi_trace ( priv , UDBG2 , " ++resume_suspended_uapsd: \n " ) ;
2012-06-19 17:15:42 -06:00
for ( startIndex = 0 ; startIndex < UNIFI_MAX_CONNECTIONS ; startIndex + + ) {
staInfo = CsrWifiRouterCtrlGetStationRecordFromHandle ( priv , startIndex , interfaceTag ) ;
2012-06-19 18:33:16 -06:00
if ( ! staInfo | | ! staInfo - > wmmOrQosEnabled ) {
2012-06-19 17:15:42 -06:00
continue ;
} else if ( ( staInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE )
2012-06-19 18:33:16 -06:00
& & staInfo - > uapsdActive & & staInfo - > uspSuspend ) {
/* U-APSD Still active & previously suspended either ENOSPC of FH queues OR
* due to DTIM activity
*/
uf_handle_uspframes_delivery ( priv , staInfo , interfaceTag ) ;
} else {
unifi_trace ( priv , UDBG2 , " resume_suspended_uapsd: PS state=%x, uapsdActive?=%x, suspend?=%x \n " ,
staInfo - > currentPeerState , staInfo - > uapsdActive , staInfo - > uspSuspend ) ;
if ( staInfo - > currentPeerState = = CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE )
{
spin_lock_irqsave ( & priv - > staRecord_lock , lock_flags ) ;
staInfo - > uapsdActive = FALSE ;
staInfo - > uspSuspend = FALSE ;
spin_unlock_irqrestore ( & priv - > staRecord_lock , lock_flags ) ;
}
2012-06-19 17:15:42 -06:00
}
}
2012-06-19 18:33:16 -06:00
unifi_trace ( priv , UDBG2 , " --resume_suspended_uapsd: \n " ) ;
2012-06-19 17:15:42 -06:00
}
# endif