2020-01-13 02:09:32 +00:00
/** @file moal_main.c
*
* @ brief This file contains the major functions in WLAN
* driver .
*
* Copyright ( C ) 2008 - 2019 , Marvell International Ltd .
*
* This software file ( the " File " ) is distributed by Marvell International
* Ltd . under the terms of the GNU General Public License Version 2 , June 1991
* ( the " License " ) . You may use , redistribute and / or modify this File in
* accordance with the terms and conditions of the License , a copy of which
* is available by writing to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA or on the
* worldwide web at http : //www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS - IS , WITHOUT WARRANTY OF ANY KIND , AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED . The License provides additional details about
* this warranty disclaimer .
*
*/
/********************************************************
Change log :
10 / 21 / 2008 : initial version
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "moal_main.h"
# include "moal_pcie.h"
# ifdef UAP_SUPPORT
# include "moal_uap.h"
# endif
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# include "moal_cfg80211.h"
# include "moal_cfgvendor.h"
# endif
# ifdef STA_CFG80211
# ifdef STA_SUPPORT
# include "moal_sta_cfg80211.h"
# endif
# endif
# ifdef UAP_CFG80211
# ifdef UAP_SUPPORT
# include "moal_uap_cfg80211.h"
# endif
# endif
# include "moal_eth_ioctl.h"
# include <linux/if_ether.h>
# include <linux/in.h>
# include <linux/tcp.h>
# include <net/tcp.h>
# include <net/dsfield.h>
# ifdef CONFIG_OF
# include <linux/of.h>
# endif
/********************************************************
Local Variables
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define KERN_VERSION "4X"
/** Driver version */
char driver_version [ ] =
" PCIE8997-%s-C " KERN_VERSION " 16 " MLAN_RELEASE_VERSION
" -GPL " " -( " " FP " FPNUM " ) "
# ifdef DEBUG_LEVEL2
" -dbg "
# endif
" " ;
/** Firmware name */
char * fw_name ;
int req_fw_nowait ;
int fw_reload ;
/** MAC address */
char * mac_addr ;
# ifdef MFG_CMD_SUPPORT
/** Mfg mode */
int mfg_mode ;
# endif
# ifdef CONFIG_OF
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
/** Region alpha2 string */
extern char * reg_alpha2 ;
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
extern int country_ie_ignore ;
extern int beacon_hints ;
# endif
# endif
extern int cfg80211_drcs ;
# endif
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
extern int host_mlme ;
# endif
# endif
int drcs_chantime_mode = 0 ;
/** Auto deep sleep */
int auto_ds ;
/** IEEE PS mode */
int ps_mode ;
/** Max Tx buffer size */
int max_tx_buf ;
# ifdef STA_SUPPORT
/** Max STA interfaces */
int max_sta_bss = DEF_STA_BSS ;
/** STA interface name */
char * sta_name ;
# endif
# ifdef UAP_SUPPORT
/** Max uAP interfaces */
int max_uap_bss = DEF_UAP_BSS ;
/** uAP interface name */
char * uap_name ;
/** Max uAP station number */
int uap_max_sta = 0 ;
# endif
# if defined(WIFI_DIRECT_SUPPORT)
/** Max WIFIDIRECT interfaces */
int max_wfd_bss = DEF_WIFIDIRECT_BSS ;
/** WIFIDIRECT interface name */
char * wfd_name ;
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
/** max VIRTUAL bss */
int max_vir_bss = DEF_VIRTUAL_BSS ;
# endif
# endif
/** Max NAN interfaces */
int max_nan_bss = DEF_NAN_BSS ;
/** NAN interface name */
char * nan_name ;
# if defined(STA_SUPPORT)
/** 802.11d configuration */
int cfg_11d ;
# endif
/** fw serial download check */
int fw_serial = 1 ;
/** napi support*/
int napi ;
/** DPD data config file */
char * dpd_data_cfg ;
/** CAL data config file */
char * cal_data_cfg ;
/** Init config file (MAC address, register etc.) */
char * init_cfg ;
/** Set configuration data of Tx power limitation */
char * txpwrlimit_cfg ;
/** Set configuration data of Tx power limitatio */
char * country_txpwrlimit ;
/** Allow setting tx power table of country */
int cntry_txpwr = 0 ;
/** Init hostcmd file */
char * init_hostcmd_cfg ;
# if defined(STA_WEXT) || defined(UAP_WEXT)
/** CFG80211 and WEXT mode */
int cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK ;
# else
/** CFG80211 mode */
int cfg80211_wext = STA_CFG80211_MASK | UAP_CFG80211_MASK ;
# endif
int fw_region = 1 ;
/** Work queue priority */
int wq_sched_prio ;
/** Work queue scheduling policy */
int wq_sched_policy = SCHED_NORMAL ;
/** rx_work flag */
int rx_work ;
/* Enable/disable Message Signaled Interrupt (MSI) */
int pcie_int_mode = PCIE_INT_MODE_MSI ;
int hw_test ;
# ifdef CONFIG_OF
int dts_enable = 1 ;
# endif
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
int p2p_enh ;
# endif
# endif
# endif
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
int dfs_offload = 0 ;
# endif
int roamoffload_in_hs = 0 ;
# ifdef ANDROID_KERNEL
int wakelock_timeout = WAKE_LOCK_TIMEOUT ;
# endif
/** woal_callbacks */
static mlan_callbacks woal_callbacks = {
. moal_get_fw_data = moal_get_fw_data ,
. moal_get_hw_spec_complete = moal_get_hw_spec_complete ,
. moal_init_fw_complete = moal_init_fw_complete ,
. moal_shutdown_fw_complete = moal_shutdown_fw_complete ,
. moal_send_packet_complete = moal_send_packet_complete ,
. moal_recv_packet = moal_recv_packet ,
. moal_recv_event = moal_recv_event ,
. moal_ioctl_complete = moal_ioctl_complete ,
. moal_alloc_mlan_buffer = moal_alloc_mlan_buffer ,
. moal_free_mlan_buffer = moal_free_mlan_buffer ,
. moal_write_reg = moal_write_reg ,
. moal_read_reg = moal_read_reg ,
. moal_write_data_sync = moal_write_data_sync ,
. moal_read_data_sync = moal_read_data_sync ,
. moal_malloc = moal_malloc ,
. moal_mfree = moal_mfree ,
. moal_vmalloc = moal_vmalloc ,
. moal_vfree = moal_vfree ,
. moal_malloc_consistent = moal_malloc_consistent ,
. moal_mfree_consistent = moal_mfree_consistent ,
. moal_map_memory = moal_map_memory ,
. moal_unmap_memory = moal_unmap_memory ,
. moal_memset = moal_memset ,
. moal_memcpy = moal_memcpy ,
. moal_memmove = moal_memmove ,
. moal_memcmp = moal_memcmp ,
. moal_udelay = moal_udelay ,
. moal_get_system_time = moal_get_system_time ,
. moal_get_boot_ktime = moal_get_boot_ktime ,
. moal_usleep = moal_usleep ,
. moal_init_timer = moal_init_timer ,
. moal_free_timer = moal_free_timer ,
. moal_start_timer = moal_start_timer ,
. moal_stop_timer = moal_stop_timer ,
. moal_init_lock = moal_init_lock ,
. moal_free_lock = moal_free_lock ,
. moal_spin_lock = moal_spin_lock ,
. moal_spin_unlock = moal_spin_unlock ,
. moal_print = moal_print ,
. moal_print_netintf = moal_print_netintf ,
. moal_assert = moal_assert ,
. moal_hist_data_add = moal_hist_data_add ,
. moal_updata_peer_signal = moal_updata_peer_signal ,
. moal_get_host_time_ns = moal_get_host_time_ns ,
. moal_do_div = moal_do_div ,
# if defined(DRV_EMBEDDED_AUTHENTICATOR) || defined(DRV_EMBEDDED_SUPPLICANT)
. moal_wait_hostcmd_complete = moal_wait_hostcmd_complete ,
. moal_notify_hostcmd_complete = moal_notify_hostcmd_complete ,
# endif
} ;
# if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
# if defined(WIFI_DIRECT_SUPPORT)
int drv_mode = ( DRV_MODE_STA | DRV_MODE_UAP | DRV_MODE_WIFIDIRECT ) ;
# else
int drv_mode = ( DRV_MODE_STA | DRV_MODE_UAP ) ;
# endif
# else
# ifdef STA_SUPPORT
int drv_mode = DRV_MODE_STA ;
# else
int drv_mode = DRV_MODE_UAP ;
# endif /* STA_SUPPORT */
# endif /* STA_SUPPORT & UAP_SUPPORT */
int gtk_rekey_offload = GTK_REKEY_OFFLOAD_DISABLE ;
int pmic = 0 ;
t_u32 uap_oper_ctrl = 0 ;
int hs_wake_interval = 400 ;
int indication_gpio = 0xff ;
int hs_mimo_switch = 0 ;
int indrstcfg = 0xffffffff ;
/** all the feature are enabled */
# define DEFAULT_DEV_CAP_MASK 0xffffffff
t_u32 dev_cap_mask = DEFAULT_DEV_CAP_MASK ;
/********************************************************
Global Variables
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** Semaphore for add/remove card */
struct semaphore AddRemoveCardSem ;
/**
* The global variable of a pointer to moal_handle
* structure variable
* */
moal_handle * m_handle [ MAX_MLAN_ADAPTER ] ;
/** The global variable of scan beacon buffer **/
int fixed_beacon_buffer = 0 ;
/** the pointer of new fwdump fname for each dump**/
char * fwdump_fname = NULL ;
# ifdef WIFI_DIRECT_SUPPORT
int GoAgeoutTime = 0 ;
# endif
t_u16 multi_dtim = 0 ;
t_u16 inact_tmo = 0 ;
# ifdef DEBUG_LEVEL1
# ifdef DEBUG_LEVEL2
# define DEFAULT_DEBUG_MASK (0xffffffff)
# else
# define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
# endif /* DEBUG_LEVEL2 */
t_u32 drvdbg = DEFAULT_DEBUG_MASK ;
# endif /* DEBUG_LEVEL1 */
int woal_open ( struct net_device * dev ) ;
int woal_close ( struct net_device * dev ) ;
int woal_set_mac_address ( struct net_device * dev , void * addr ) ;
void woal_tx_timeout ( struct net_device * dev ) ;
struct net_device_stats * woal_get_stats ( struct net_device * dev ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
2020-01-13 02:21:55 +00:00
# if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
u16 woal_select_queue ( struct net_device * dev , struct sk_buff * skb ,
struct net_device * sb_dev ) ;
# else
2020-01-13 02:09:32 +00:00
u16 woal_select_queue ( struct net_device * dev , struct sk_buff * skb ,
struct net_device * sb_dev ,
select_queue_fallback_t fallback ) ;
2020-01-13 02:21:55 +00:00
# endif
2020-01-13 02:09:32 +00:00
# else
u16 woal_select_queue ( struct net_device * dev , struct sk_buff * skb ,
void * accel_priv , select_queue_fallback_t fallback ) ;
# endif
# else
u16 woal_select_queue ( struct net_device * dev , struct sk_buff * skb ,
void * accel_priv ) ;
# endif
# else
u16 woal_select_queue ( struct net_device * dev , struct sk_buff * skb ) ;
# endif
# endif
mlan_debug_info info ;
static moal_handle * reset_handle ;
/** Hang workqueue */
static struct workqueue_struct * hang_workqueue ;
/** Hang work */
static struct work_struct hang_work ;
/**
* @ brief This function process FW hang
*
* @ param handle Pointer to structure moal_handle
*
* @ return N / A
*/
static void
woal_hang_work_queue ( struct work_struct * work )
{
int i ;
ENTER ( ) ;
if ( ! reset_handle ) {
LEAVE ( ) ;
return ;
}
for ( i = 0 ; i < reset_handle - > priv_num ; i + + ) {
if ( reset_handle - > priv [ i ] & & reset_handle - > priv [ i ] - > netdev ) {
PRINTM ( MMSG , " Close netdev %s \n " ,
reset_handle - > priv [ i ] - > netdev - > name ) ;
rtnl_lock ( ) ;
dev_close ( reset_handle - > priv [ i ] - > netdev ) ;
rtnl_unlock ( ) ;
break ;
}
}
reset_handle = NULL ;
LEAVE ( ) ;
}
/**
* @ brief This function process FW hang
*
* @ param handle Pointer to structure moal_handle
*
* @ return N / A
*/
void
woal_process_hang ( moal_handle * handle )
{
ENTER ( ) ;
if ( reset_handle = = NULL ) {
PRINTM ( MMSG , " Start to process hanging \n " ) ;
reset_handle = handle ;
mlan_ioctl ( handle - > pmlan_adapter , NULL ) ;
queue_work ( hang_workqueue , & hang_work ) ;
# ifdef ANDROID_KERNEL
# define WAKE_LOCK_HANG 5000
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
__pm_wakeup_event ( & reset_handle - > ws , WAKE_LOCK_HANG ) ;
# else
wake_lock_timeout ( & reset_handle - > wake_lock ,
msecs_to_jiffies ( WAKE_LOCK_HANG ) ) ;
# endif
# endif
}
LEAVE ( ) ;
}
/**
* @ brief Check if any interface is active
*
* @ param handle A pointer to moal_handle
*
*
* @ return MTRUE / MFALSE ;
*/
t_u8
woal_is_any_interface_active ( moal_handle * handle )
{
int i ;
for ( i = 0 ; i < handle - > priv_num ; i + + ) {
# ifdef STA_SUPPORT
if ( GET_BSS_ROLE ( handle - > priv [ i ] ) = = MLAN_BSS_ROLE_STA ) {
if ( handle - > priv [ i ] - > media_connected = = MTRUE )
return MTRUE ;
}
# endif
# ifdef UAP_SUPPORT
if ( GET_BSS_ROLE ( handle - > priv [ i ] ) = = MLAN_BSS_ROLE_UAP ) {
if ( handle - > priv [ i ] - > bss_started = = MTRUE )
return MTRUE ;
}
# endif
}
return MFALSE ;
}
/** @brief This function set/clear pmk to FW
*
* @ param priv A Pointer to the moal_private structure
* @ param action set / clear action
*
* @ return 0 : success fail otherwise
*/
int
woal_set_clear_pmk ( moal_private * priv , t_u8 action )
{
mlan_ioctl_req * req ;
mlan_ds_sec_cfg * sec ;
mlan_status status ;
int ret = 0 ;
t_u8 zero [ MLAN_MAX_KEY_LENGTH ] = { 0 } ;
ENTER ( ) ;
req = woal_alloc_mlan_ioctl_req ( sizeof ( mlan_ds_sec_cfg ) ) ;
if ( req = = NULL ) {
ret = - ENOMEM ;
} else {
sec = ( mlan_ds_sec_cfg * ) req - > pbuf ;
sec - > sub_command = MLAN_OID_SEC_CFG_PASSPHRASE ;
req - > req_id = MLAN_IOCTL_SEC_CFG ;
req - > action = action ;
if ( action = = MLAN_ACT_SET ) {
sec - > param . passphrase . psk_type = MLAN_PSK_PMK ;
if ( memcmp ( priv - > pmk . pmk , zero , MLAN_MAX_KEY_LENGTH ) )
memcpy ( & sec - > param . passphrase . psk . pmk . pmk ,
priv - > pmk . pmk , MLAN_MAX_KEY_LENGTH ) ;
if ( memcmp ( priv - > pmk . pmk_r0 , zero , MLAN_MAX_KEY_LENGTH )
& & memcmp ( priv - > pmk . pmk_r0_name , zero ,
MLAN_MAX_PMKR0_NAME_LENGTH ) ) {
memcpy ( & sec - > param . passphrase . psk . pmk . pmk_r0 ,
priv - > pmk . pmk_r0 , MLAN_MAX_KEY_LENGTH ) ;
memcpy ( & sec - > param . passphrase . psk . pmk .
pmk_r0_name , priv - > pmk . pmk_r0_name ,
MLAN_MAX_PMKR0_NAME_LENGTH ) ;
}
}
status = woal_request_ioctl ( priv , req , MOAL_IOCTL_WAIT ) ;
if ( MLAN_STATUS_SUCCESS ! = status )
ret = - EFAULT ;
if ( status ! = MLAN_STATUS_PENDING )
kfree ( req ) ;
}
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function handle the net interface ipaddr change event
*
* @ param nb pointer to the notifier_block
* @ param event event type
* @ param ptr pointer to event struct
*
* @ return NOTIFY_DONE or NOTIFY_OK
*/
static int
woal_netdevice_event ( struct notifier_block * nb , unsigned long event , void * ptr )
{
struct in_ifaddr * ifa = ( struct in_ifaddr * ) ptr ;
struct net_device * ndev ;
moal_private * priv ;
int ret = NOTIFY_OK ;
# ifdef STA_CFG80211
char rssi_low [ 11 ] ;
# endif
ENTER ( ) ;
ndev = ifa - > ifa_dev - > dev ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
if ( ! ndev | | ndev - > netdev_ops - > ndo_open ! = woal_open )
# else
if ( ! ndev | | ndev - > open ! = woal_open )
# endif
{
PRINTM ( MIOCTL , " IP changes not for us, ignore. ndev[%p] \n " ,
ndev ) ;
if ( ndev )
PRINTM ( MIOCTL , " changes on %s \n " , ndev - > name ) ;
ret = NOTIFY_DONE ;
goto done ;
}
priv = ( moal_private * ) netdev_priv ( ndev ) ;
if ( priv - > bss_type ! = MLAN_BSS_TYPE_STA
# if defined(WIFI_DIRECT_SUPPORT)
& & priv - > bss_type ! = MLAN_BSS_TYPE_WIFIDIRECT
# endif
& & priv - > bss_type ! = MLAN_BSS_TYPE_NAN ) {
PRINTM ( MIOCTL , " Bss type [%d] is not STA/P2P, ignore \n " ,
( int ) priv - > bss_type ) ;
ret = NOTIFY_DONE ;
goto done ;
}
switch ( event ) {
case NETDEV_UP :
PRINTM ( MIOCTL , " [%s]: New ip addr: 0x%08x \n " , ndev - > name ,
ifa - > ifa_address ) ;
/* Save the IP addr now */
memcpy ( priv - > ip_addr , & ifa - > ifa_address ,
sizeof ( ifa - > ifa_address ) ) ;
priv - > ip_addr_type = IPADDR_TYPE_IPV4 ;
# ifdef STA_CFG80211
if ( ! hw_test & & priv - > roaming_enabled ) {
sprintf ( rssi_low , " %d " , priv - > rssi_low ) ;
woal_set_rssi_low_threshold ( priv , rssi_low ,
MOAL_IOCTL_WAIT ) ;
}
# endif
# ifdef STA_CFG80211
if ( priv - > phandle - > fw_roam_enable & &
( priv - > phandle - > fw_roam_enable ! = AUTO_RECONNECT )
& & ! roamoffload_in_hs ) {
sprintf ( rssi_low , " %d " , priv - > rssi_low ) ;
woal_set_rssi_low_threshold ( priv , rssi_low ,
MOAL_IOCTL_WAIT ) ;
if ( priv - > pmk_saved ) {
woal_set_clear_pmk ( priv , MLAN_ACT_SET ) ;
priv - > pmk_saved = false ;
}
}
# endif
break ;
case NETDEV_DOWN :
PRINTM ( MIOCTL , " [%s]: Ip addr removed. \n " , ndev - > name ) ;
priv - > ip_addr_type = IPADDR_TYPE_NONE ;
memset ( priv - > ip_addr , 0 , sizeof ( priv - > ip_addr ) ) ;
break ;
default :
PRINTM ( MIOCTL , " [%s]: Ignore event: %u \n " , ndev - > name ,
( unsigned int ) event ) ;
ret = NOTIFY_DONE ;
goto done ;
}
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function validates a SSID as being able to be printed
*
* @ param pssid SSID structure to validate
*
* @ return MTRUE or MFALSE
*/
BOOLEAN
woal_ssid_valid ( mlan_802_11_ssid * pssid )
{
# ifdef ASCII_SSID_CHECK
unsigned int ssid_idx ;
ENTER ( ) ;
for ( ssid_idx = 0 ; ssid_idx < pssid - > ssid_len ; ssid_idx + + ) {
if ( ( pssid - > ssid [ ssid_idx ] < 0x20 ) | |
( pssid - > ssid [ ssid_idx ] > 0x7e ) ) {
LEAVE ( ) ;
return MFALSE ;
}
}
LEAVE ( ) ;
# endif
return MTRUE ;
}
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
/**
* @ brief Remain on Channel timeout function
*
* @ param context A pointer to context
* @ return N / A
*/
void
woal_remain_timer_func ( void * context )
{
moal_handle * handle = ( moal_handle * ) context ;
moal_private * priv = handle - > priv [ handle - > remain_bss_index ] ;
ENTER ( ) ;
PRINTM ( MEVENT , " remain_timer fired. \n " ) ;
if ( handle - > cookie ) {
cfg80211_remain_on_channel_expired (
# if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
priv - > netdev ,
# else
priv - > wdev ,
# endif
handle - > cookie ,
& handle - > chan ,
# if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
handle - > channel_type ,
# endif
GFP_ATOMIC ) ;
handle - > cookie = 0 ;
}
handle - > is_remain_timer_set = MFALSE ;
LEAVE ( ) ;
return ;
}
# endif
# endif
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
/**
* @ brief GO timeout function
*
* @ param context A pointer to context
* @ return N / A
*/
void
woal_go_timer_func ( void * context )
{
moal_handle * handle = ( moal_handle * ) context ;
ENTER ( ) ;
PRINTM ( MEVENT , " go_timer fired. \n " ) ;
handle - > is_go_timer_set = MFALSE ;
LEAVE ( ) ;
return ;
}
# endif
# endif
/**
* @ brief check if we already connect to the AP .
* @ param priv A pointer to moal_private structure
* @ param ssid_bssid A pointer to mlan_ssid_bssid structure
*
* @ return MTRUE / MFALSE ;
*/
int
woal_is_connected ( moal_private * priv , mlan_ssid_bssid * ssid_bssid )
{
mlan_bss_info bss_info ;
int ret = MFALSE ;
t_u8 zero_mac [ ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
ENTER ( ) ;
memset ( & bss_info , 0 , sizeof ( bss_info ) ) ;
if ( MLAN_STATUS_SUCCESS ! =
woal_get_bss_info ( priv , MOAL_IOCTL_WAIT , & bss_info ) )
goto done ;
if ( bss_info . media_connected ) {
if ( memcmp ( ssid_bssid - > bssid , zero_mac , sizeof ( zero_mac ) ) ) {
if ( ssid_bssid - > ssid . ssid_len ) { /* compare ssid and bssid */
if ( ( ssid_bssid - > ssid . ssid_len = =
bss_info . ssid . ssid_len ) & &
! memcmp ( ssid_bssid - > ssid . ssid ,
bss_info . ssid . ssid ,
bss_info . ssid . ssid_len ) & &
! memcmp ( ssid_bssid - > bssid , bss_info . bssid ,
MLAN_MAC_ADDR_LENGTH ) )
ret = MTRUE ;
} else { /* compare bssid */
if ( ! memcmp
( ssid_bssid - > bssid , bss_info . bssid ,
MLAN_MAC_ADDR_LENGTH ) ) {
memcpy ( & ssid_bssid - > ssid ,
& bss_info . ssid ,
sizeof ( bss_info . ssid ) ) ;
ret = MTRUE ;
}
}
} else { /* compare ssid */
if ( ssid_bssid - > ssid . ssid_len & &
( ssid_bssid - > ssid . ssid_len = =
bss_info . ssid . ssid_len ) & &
! memcmp ( ssid_bssid - > ssid . ssid , bss_info . ssid . ssid ,
bss_info . ssid . ssid_len ) ) {
memcpy ( & ssid_bssid - > bssid , & bss_info . bssid ,
MLAN_MAC_ADDR_LENGTH ) ;
ret = MTRUE ;
}
}
}
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief Look up specific IE in a buf
*
* @ param ie Pointer to IEs
* @ param len Total length of ie
* @ param id Element id to lookup
*
* @ return Pointer of the specific IE - - success , NULL - - fail
*/
const t_u8 *
woal_parse_ie_tlv ( const t_u8 * ie , int len , t_u8 id )
{
int left_len = len ;
const t_u8 * pos = ie ;
int length ;
/* IE format:
* | u8 | id |
* | u8 | len |
* | var | data |
*/
while ( left_len > = 2 ) {
length = * ( pos + 1 ) ;
if ( ( * pos = = id ) & & ( length + 2 ) < = left_len )
return pos ;
pos + = ( length + 2 ) ;
left_len - = ( length + 2 ) ;
}
return NULL ;
}
/**
* @ brief Get mode
*
* @ param priv A pointer to moal_private structure
* @ param wait_option Wait option ( MOAL_IOCTL_WAIT or MOAL_NO_WAIT )
*
* @ return Wireless mode
*/
t_u32
woal_get_mode ( moal_private * priv , t_u8 wait_option )
{
int ret = 0 ;
mlan_ds_bss * bss = NULL ;
mlan_ioctl_req * req = NULL ;
mlan_status status = MLAN_STATUS_SUCCESS ;
t_u32 mode = 0 ;
ENTER ( ) ;
# if defined(STA_WEXT) || defined(UAP_WEXT)
mode = priv - > w_stats . status ;
# endif
/* Allocate an IOCTL request buffer */
req = woal_alloc_mlan_ioctl_req ( sizeof ( mlan_ds_bss ) ) ;
if ( req = = NULL ) {
ret = - ENOMEM ;
goto done ;
}
/* Fill request buffer */
bss = ( mlan_ds_bss * ) req - > pbuf ;
bss - > sub_command = MLAN_OID_BSS_MODE ;
req - > req_id = MLAN_IOCTL_BSS ;
req - > action = MLAN_ACT_GET ;
/* Send IOCTL request to MLAN */
status = woal_request_ioctl ( priv , req , wait_option ) ;
if ( status = = MLAN_STATUS_SUCCESS ) {
switch ( bss - > param . bss_mode ) {
case MLAN_BSS_MODE_INFRA :
mode = MW_MODE_INFRA ;
break ;
case MLAN_BSS_MODE_IBSS :
mode = MW_MODE_ADHOC ;
break ;
default :
mode = MW_MODE_AUTO ;
break ;
}
}
done :
if ( status ! = MLAN_STATUS_PENDING )
kfree ( req ) ;
LEAVE ( ) ;
return mode ;
}
/********************************************************
Local Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ brief This function update the default firmware name
*
* @ param handle A pointer to moal_handle structure
*
* @ return N / A
*/
static void
woal_update_firmware_name ( moal_handle * handle )
{
if ( fw_name ) {
handle - > drv_mode . fw_name = fw_name ;
} else {
if ( ! fw_serial | | handle - > fw_reload | | fw_reload )
handle - > drv_mode . fw_name = DEFAULT_WLAN_FW_NAME ;
else
# if defined(UAP_SUPPORT) && defined(STA_SUPPORT)
handle - > drv_mode . fw_name = DEFAULT_AP_STA_FW_NAME ;
# else
# ifdef UAP_SUPPORT
handle - > drv_mode . fw_name = DEFAULT_AP_FW_NAME ;
# else
handle - > drv_mode . fw_name = DEFAULT_FW_NAME ;
# endif /* UAP_SUPPORT */
# endif /* UAP_SUPPORT && STA_SUPPORT */
}
}
/**
* @ brief This function dynamically populates the driver mode table
*
* @ param handle A pointer to moal_handle structure
* @ param drv_mode_local Driver mode
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
woal_update_drv_tbl ( moal_handle * handle , int drv_mode_local )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
unsigned int intf_num = 0 ;
int i = 0 , j = 0 ;
mlan_bss_attr * bss_tbl = NULL ;
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
int last_wfd_index = 0 ;
# endif
# endif
ENTER ( ) ;
/* Calculate number of interfaces */
# ifdef STA_SUPPORT
if ( drv_mode_local & DRV_MODE_STA ) {
if ( ( max_sta_bss < 1 ) | | ( max_sta_bss > MAX_STA_BSS ) ) {
PRINTM ( MWARN ,
" Unsupported max_sta_bss (%d), setting to default \n " ,
max_sta_bss ) ;
max_sta_bss = DEF_STA_BSS ;
}
intf_num + = max_sta_bss ;
}
# endif /* STA_SUPPORT */
# ifdef UAP_SUPPORT
if ( drv_mode_local & DRV_MODE_UAP ) {
if ( ( max_uap_bss < 1 ) | | ( max_uap_bss > MAX_UAP_BSS ) ) {
PRINTM ( MWARN ,
" Unsupported max_uap_bss (%d), setting to default \n " ,
max_uap_bss ) ;
max_uap_bss = DEF_UAP_BSS ;
}
intf_num + = max_uap_bss ;
}
# endif /* UAP_SUPPORT */
# if defined(WIFI_DIRECT_SUPPORT)
if ( drv_mode_local & DRV_MODE_WIFIDIRECT ) {
if ( ( max_wfd_bss < 1 ) | | ( max_wfd_bss > MAX_WIFIDIRECT_BSS ) ) {
PRINTM ( MWARN ,
" Unsupported max_wfd_bss (%d), setting to default \n " ,
max_wfd_bss ) ;
max_wfd_bss = DEF_WIFIDIRECT_BSS ;
}
intf_num + = max_wfd_bss ;
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
intf_num + = max_vir_bss ;
# endif
}
# endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
if ( drv_mode_local & DRV_MODE_NAN ) {
if ( ( max_nan_bss < 1 ) | | ( max_nan_bss > MAX_NAN_BSS ) ) {
PRINTM ( MWARN ,
" Unsupported max_nan_bss (%d), setting to default \n " ,
max_nan_bss ) ;
max_nan_bss = DEF_NAN_BSS ;
}
intf_num + = max_nan_bss ;
}
/* Create BSS attribute table */
if ( ( intf_num = = 0 ) | | ( intf_num > MLAN_MAX_BSS_NUM ) ) {
PRINTM ( MERROR , " Unsupported number of BSS %d \n " , intf_num ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
} else {
/* Create new table */
bss_tbl = kmalloc ( sizeof ( mlan_bss_attr ) * intf_num , GFP_KERNEL ) ;
if ( ! bss_tbl ) {
PRINTM ( MERROR ,
" Could not create BSS attribute table \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
}
/* Populate BSS attribute table */
# ifdef STA_SUPPORT
if ( drv_mode_local & DRV_MODE_STA ) {
for ( j = 0 ; j < max_sta_bss ; j + + ) {
if ( i > = intf_num )
break ;
bss_tbl [ i ] . bss_type = MLAN_BSS_TYPE_STA ;
bss_tbl [ i ] . frame_type = MLAN_DATA_FRAME_TYPE_ETH_II ;
bss_tbl [ i ] . active = MTRUE ;
bss_tbl [ i ] . bss_priority = 0 ;
bss_tbl [ i ] . bss_num = j ;
bss_tbl [ i ] . bss_virtual = MFALSE ;
i + + ;
}
}
# endif /* STA_SUPPORT */
# ifdef UAP_SUPPORT
if ( drv_mode_local & DRV_MODE_UAP ) {
for ( j = 0 ; j < max_uap_bss ; j + + ) {
if ( i > = intf_num )
break ;
bss_tbl [ i ] . bss_type = MLAN_BSS_TYPE_UAP ;
bss_tbl [ i ] . frame_type = MLAN_DATA_FRAME_TYPE_ETH_II ;
bss_tbl [ i ] . active = MTRUE ;
bss_tbl [ i ] . bss_priority = 0 ;
bss_tbl [ i ] . bss_num = j ;
bss_tbl [ i ] . bss_virtual = MFALSE ;
i + + ;
}
}
# endif /* UAP_SUPPORT */
# if defined(WIFI_DIRECT_SUPPORT)
if ( drv_mode_local & DRV_MODE_WIFIDIRECT ) {
for ( j = 0 ; j < max_wfd_bss ; j + + ) {
if ( i > = intf_num )
break ;
bss_tbl [ i ] . bss_type = MLAN_BSS_TYPE_WIFIDIRECT ;
bss_tbl [ i ] . frame_type = MLAN_DATA_FRAME_TYPE_ETH_II ;
bss_tbl [ i ] . active = MTRUE ;
bss_tbl [ i ] . bss_priority = 0 ;
bss_tbl [ i ] . bss_num = j ;
bss_tbl [ i ] . bss_virtual = MFALSE ;
i + + ;
}
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
last_wfd_index = j ;
# endif
}
# endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
if ( drv_mode_local & DRV_MODE_NAN ) {
for ( j = 0 ; j < max_nan_bss ; j + + ) {
if ( i > = intf_num )
break ;
bss_tbl [ i ] . bss_type = MLAN_BSS_TYPE_NAN ;
bss_tbl [ i ] . frame_type = MLAN_DATA_FRAME_TYPE_ETH_II ;
bss_tbl [ i ] . active = MTRUE ;
bss_tbl [ i ] . bss_priority = 0 ;
bss_tbl [ i ] . bss_num = j ;
bss_tbl [ i ] . bss_virtual = MFALSE ;
i + + ;
}
}
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
/** append virtual interface at the end of table */
for ( j = 0 ; j < max_vir_bss ; j + + ) {
if ( i > = intf_num )
break ;
bss_tbl [ i ] . bss_type = MLAN_BSS_TYPE_WIFIDIRECT ;
bss_tbl [ i ] . frame_type = MLAN_DATA_FRAME_TYPE_ETH_II ;
bss_tbl [ i ] . active = MTRUE ;
bss_tbl [ i ] . bss_priority = 0 ;
bss_tbl [ i ] . bss_num = j + last_wfd_index ;
bss_tbl [ i ] . bss_virtual = MTRUE ;
i + + ;
}
# endif
# endif
/* Clear existing table, if any */
kfree ( handle - > drv_mode . bss_attr ) ;
handle - > drv_mode . bss_attr = NULL ;
/* Create moal_drv_mode entry */
handle - > drv_mode . drv_mode = drv_mode ;
handle - > drv_mode . intf_num = intf_num ;
handle - > drv_mode . bss_attr = bss_tbl ;
/* update default firmware name */
woal_update_firmware_name ( handle ) ;
done :
LEAVE ( ) ;
return ret ;
}
# ifdef CONFIG_OF
/**
* @ brief This function read the initial parameter from device tress
*
* @ return N / A
*/
static void
woal_init_from_dev_tree ( void )
{
struct device_node * dt_node = NULL ;
struct property * prop ;
t_u32 data ;
const char * string_data ;
ENTER ( ) ;
if ( ! dts_enable ) {
PRINTM ( MIOCTL , " DTS is disabled! " ) ;
return ;
}
dt_node = of_find_node_by_name ( NULL , " sd8xxx-wlan " ) ;
if ( ! dt_node ) {
LEAVE ( ) ;
return ;
}
for_each_property_of_node ( dt_node , prop ) {
if ( ! strncmp ( prop - > name , " drv_mode " , strlen ( " drv_mode " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " drv_mode=0x%x \n " , data ) ;
drv_mode = data ;
}
}
# ifdef DEBUG_LEVEL1
else if ( ! strncmp ( prop - > name , " drvdbg " , strlen ( " drvdbg " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " drvdbg=0x%x \n " , data ) ;
drvdbg = data ;
}
}
# endif
else if ( ! strncmp
( prop - > name , " dev_cap_mask " , strlen ( " dev_cap_mask " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " dev_cap_mask=0x%x \n " , data ) ;
dev_cap_mask = data ;
}
} else if ( ! strncmp ( prop - > name , " hw_test " , strlen ( " hw_test " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " hw_test=0x%x \n " , data ) ;
hw_test = data ;
}
}
# ifdef MFG_CMD_SUPPORT
else if ( ! strncmp ( prop - > name , " mfg_mode " , strlen ( " mfg_mode " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " mfg_mode=0x%x \n " , data ) ;
mfg_mode = data ;
}
}
# endif
else if ( ! strncmp ( prop - > name , " mac_addr " , strlen ( " mac_addr " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
mac_addr = ( char * ) string_data ;
PRINTM ( MIOCTL , " mac_addr=%s \n " , mac_addr ) ;
}
} else if ( ! strncmp ( prop - > name , " fw_name " , strlen ( " fw_name " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
fw_name = ( char * ) string_data ;
PRINTM ( MIOCTL , " fw_name=%s \n " , fw_name ) ;
}
}
# if defined(STA_WEXT) || defined(UAP_WEXT)
else if ( ! strncmp
( prop - > name , " cfg80211_wext " ,
strlen ( " cfg80211_wext " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " cfg80211_wext=0x%x \n " , data ) ;
cfg80211_wext = data ;
}
}
# endif
# ifdef STA_SUPPORT
else if ( ! strncmp ( prop - > name , " sta_name " , strlen ( " sta_name " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
sta_name = ( char * ) string_data ;
PRINTM ( MIOCTL , " sta_name=%s \n " , sta_name ) ;
}
}
# endif
# if defined(WIFI_DIRECT_SUPPORT)
else if ( ! strncmp ( prop - > name , " wfd_name " , strlen ( " wfd_name " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
wfd_name = ( char * ) string_data ;
PRINTM ( MIOCTL , " wfd_name=%s \n " , wfd_name ) ;
}
}
# endif
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
else if ( ! strncmp
( prop - > name , " reg_alpha2 " , strlen ( " reg_alpha2 " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
reg_alpha2 = ( char * ) string_data ;
PRINTM ( MIOCTL , " reg_alpha2=%s \n " , reg_alpha2 ) ;
}
}
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
else if ( ! strncmp
( prop - > name , " country_ie_ignore " ,
strlen ( " country_ie_ignore " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " country_ie_ignore=0x%x \n " ,
data ) ;
country_ie_ignore = data ;
}
} else if ( ! strncmp
( prop - > name , " beacon_hints " ,
strlen ( " beacon_hints " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " beacon_hints=0x%x \n " , data ) ;
beacon_hints = data ;
}
}
# endif
# endif
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
else if ( ! strncmp
( prop - > name , " max_vir_bss " , strlen ( " max_vir_bss " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " max_vir_bss=0x%x \n " , data ) ;
max_vir_bss = data ;
}
} else if ( ! strncmp ( prop - > name , " p2p_enh " , strlen ( " p2p_enh " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " p2p_enh=0x%x \n " , data ) ;
p2p_enh = data ;
}
} else if ( ! strncmp
( prop - > name , " cfg80211_drcs " ,
strlen ( " cfg80211_drcs " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " cfg80211_drcs=0x%x \n " , data ) ;
cfg80211_drcs = data ;
}
}
# endif
# endif
else if ( ! strncmp
( prop - > name , " dpd_data_cfg " , strlen ( " dpd_data_cfg " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
dpd_data_cfg = ( char * ) string_data ;
PRINTM ( MIOCTL , " dpd_data_cfg=%s \n " ,
dpd_data_cfg ) ;
}
} else if ( ! strncmp ( prop - > name , " init_cfg " , strlen ( " init_cfg " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
init_cfg = ( char * ) string_data ;
PRINTM ( MIOCTL , " init_cfg=%s \n " , init_cfg ) ;
}
} else if ( ! strncmp
( prop - > name , " cal_data_cfg " ,
strlen ( " cal_data_cfg " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
cal_data_cfg = ( char * ) string_data ;
PRINTM ( MIOCTL , " cal_data_cfg=%s \n " ,
cal_data_cfg ) ;
}
} else if ( ! strncmp
( prop - > name , " txpwrlimit_cfg " ,
strlen ( " txpwrlimit_cfg " ) ) ) {
if ( ! of_property_read_string
( dt_node , prop - > name , & string_data ) ) {
txpwrlimit_cfg = ( char * ) string_data ;
PRINTM ( MIOCTL , " txpwrlimit_cfg=%s \n " ,
txpwrlimit_cfg ) ;
}
} else if ( ! strncmp
( prop - > name , " cntry_txpwr " , strlen ( " cntry_txpwr " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
cntry_txpwr = data ;
PRINTM ( MIOCTL , " cntry_txpwr=%d \n " , cntry_txpwr ) ;
}
} else if ( ! strncmp ( prop - > name , " pmic " , strlen ( " pmic " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
pmic = data ;
PRINTM ( MIOCTL , " pmic=%d \n " , pmic ) ;
}
} else if ( ! strncmp
( prop - > name , " hs_wake_interval " ,
strlen ( " hs_wake_interval " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
hs_wake_interval = data ;
PRINTM ( MIOCTL , " hs_wake_interval=%d \n " ,
hs_wake_interval ) ;
}
} else if ( ! strncmp
( prop - > name , " indication_gpio " ,
strlen ( " indication_gpio " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
indication_gpio = ( t_u8 ) data ;
PRINTM ( MIOCTL , " indication_gpio=%d \n " ,
indication_gpio ) ;
}
} else if ( ! strncmp
( prop - > name , " hs_mimo_switch " ,
strlen ( " hs_mimo_switch " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
hs_mimo_switch = data ;
PRINTM ( MIOCTL , " hs_mimo_switch=%d \n " ,
hs_mimo_switch ) ;
}
}
# ifdef WIFI_DIRECT_SUPPORT
else if ( ! strncmp
( prop - > name , " GoAgeoutTime " , strlen ( " GoAgeoutTime " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
GoAgeoutTime = data ;
PRINTM ( MIOCTL , " GoAgeoutTime=%d \n " ,
GoAgeoutTime ) ;
}
}
# endif
else if ( ! strncmp ( prop - > name , " indrstcfg " , strlen ( " indrstcfg " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
indrstcfg = data ;
PRINTM ( MIOCTL , " indrstcfg=%d \n " , indrstcfg ) ;
}
} else if ( ! strncmp
( prop - > name , " drcs_chantime_mode " ,
strlen ( " drcs_chantime_mode " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
drcs_chantime_mode = data ;
PRINTM ( MIOCTL , " drcs_chantime_mode=%d \n " ,
drcs_chantime_mode ) ;
}
} else if ( ! strncmp
( prop - > name , " fixed_beacon_buffer " ,
strlen ( " fixed_beacon_buffer " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
fixed_beacon_buffer = data ;
PRINTM ( MIOCTL , " fixed_beacon_buffer=%d \n " ,
fixed_beacon_buffer ) ;
}
} else if ( ! strncmp
( prop - > name , " multi_dtim " , strlen ( " multi_dtim " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
multi_dtim = data ;
PRINTM ( MIOCTL , " multi_dtim=%d \n " , multi_dtim ) ;
}
} else if ( ! strncmp
( prop - > name , " inact_tmo " , strlen ( " inact_tmo " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
inact_tmo = data ;
PRINTM ( MIOCTL , " inact_tmo=%d \n " , inact_tmo ) ;
}
}
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
else if ( ! strncmp
( prop - > name , " dfs_offload " , strlen ( " dfs_offload " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
dfs_offload = data ;
PRINTM ( MIOCTL , " dfs_offload=%d \n " , dfs_offload ) ;
}
}
# endif
else if ( ! strncmp
( prop - > name , " roamoffload_in_hs " ,
strlen ( " roamoffload_in_hs " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
roamoffload_in_hs = data ;
PRINTM ( MIOCTL , " roamoffload_in_hs=%d \n " ,
roamoffload_in_hs ) ;
}
} else if ( ! strncmp
( prop - > name , " gtk_rekey_offload " ,
strlen ( " gtk_rekey_offload " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
gtk_rekey_offload = data ;
PRINTM ( MIOCTL , " gtk_rekey_offload=%d \n " ,
gtk_rekey_offload ) ;
}
}
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
else if ( ! strncmp ( prop - > name , " host_mlme " , strlen ( " host_mlme " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MIOCTL , " host_mlme=0x%x \n " , data ) ;
host_mlme = data ;
}
}
# endif
# endif
# ifdef UAP_SUPPORT
else if ( ! strncmp
( prop - > name , " uap_max_sta " , strlen ( " uap_max_sta " ) ) ) {
if ( ! of_property_read_u32 ( dt_node , prop - > name , & data ) ) {
PRINTM ( MERROR , " uap_max_sta=0x%x \n " , data ) ;
uap_max_sta = data ;
}
}
# endif
}
LEAVE ( ) ;
return ;
}
# endif
/**
* @ brief This function initializes software
*
* @ param handle A pointer to moal_handle structure
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
woal_init_sw ( moal_handle * handle )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
unsigned int i ;
mlan_device device ;
t_void * pmlan ;
ENTER ( ) ;
/* Initialize moal_handle structure */
handle - > hardware_status = HardwareStatusInitializing ;
handle - > main_state = MOAL_STATE_IDLE ;
# ifdef STA_SUPPORT
if ( ( drv_mode & DRV_MODE_STA )
# ifdef STA_WEXT
& & ! IS_STA_WEXT ( cfg80211_wext )
# endif
# ifdef STA_CFG80211
& & ! IS_STA_CFG80211 ( cfg80211_wext )
# endif
) {
PRINTM ( MERROR ,
" STA without WEXT or CFG80211 bit definition! \n " ) ;
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
# endif /* STA_SUPPORT */
# if defined(STA_CFG80211) && defined(STA_SUPPORT)
if ( IS_STA_CFG80211 ( cfg80211_wext ) )
cfg80211_wext | = STA_CFG80211_MASK | UAP_CFG80211_MASK ;
# endif
# if defined(UAP_CFG80211) && defined(UAP_SUPPORT)
if ( IS_UAP_CFG80211 ( cfg80211_wext ) )
cfg80211_wext | = STA_CFG80211_MASK | UAP_CFG80211_MASK ;
# endif
memcpy ( handle - > driver_version , driver_version , strlen ( driver_version ) ) ;
if ( woal_update_drv_tbl ( handle , drv_mode ) ! = MLAN_STATUS_SUCCESS ) {
PRINTM ( MERROR , " Could not update driver mode table \n " ) ;
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
/** user config file */
init_waitqueue_head ( & handle - > init_user_conf_wait_q ) ;
/* PnP and power profile */
handle - > surprise_removed = MFALSE ;
init_waitqueue_head ( & handle - > init_wait_q ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
spin_lock_init ( & handle - > queue_lock ) ;
# endif
spin_lock_init ( & handle - > driver_lock ) ;
spin_lock_init ( & handle - > ioctl_lock ) ;
spin_lock_init ( & handle - > scan_req_lock ) ;
handle - > is_suspended = MFALSE ;
handle - > hs_activated = MFALSE ;
handle - > hs_auto_arp = MTRUE ;
handle - > suspend_fail = MFALSE ;
handle - > hs_skip_count = 0 ;
handle - > hs_force_count = 0 ;
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
handle - > scan_chan_gap = DEF_SCAN_CHAN_GAP ;
# ifdef WIFI_DIRECT_SUPPORT
handle - > miracast_scan_time = DEF_MIRACAST_SCAN_TIME ;
# define DEF_NOA_DURATION 0
# define DEF_NOA_INTERVAL 100
handle - > noa_duration = DEF_NOA_DURATION ;
handle - > noa_interval = DEF_NOA_INTERVAL ;
# endif
# endif
init_waitqueue_head ( & handle - > hs_activate_wait_q ) ;
/* Initialize measurement wait queue */
handle - > meas_wait_q_woken = MFALSE ;
handle - > meas_start_jiffies = 0 ;
handle - > cac_period = MFALSE ;
handle - > delay_bss_start = MFALSE ;
init_waitqueue_head ( & handle - > meas_wait_q ) ;
# if defined(UAP_SUPPORT)
handle - > chsw_wait_q_woken = MFALSE ;
init_waitqueue_head ( & handle - > chsw_wait_q ) ;
# endif
# ifdef DFS_TESTING_SUPPORT
handle - > cac_period_jiffies = 0 ;
# endif
# ifdef UAP_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
memset ( & handle - > dfs_channel , 0 , sizeof ( struct cfg80211_chan_def ) ) ;
woal_initialize_timer ( & handle - > cac_timer , woal_cac_timer_func , handle ) ;
handle - > is_cac_timer_set = MFALSE ;
handle - > cac_bss_index = 0xff ;
# endif
# endif
handle - > mon_if = NULL ;
# ifdef REASSOCIATION
MOAL_INIT_SEMAPHORE ( & handle - > reassoc_sem ) ;
handle - > reassoc_on = 0 ;
/* Initialize the timer for the reassociation */
woal_initialize_timer ( & handle - > reassoc_timer ,
woal_reassoc_timer_func , handle ) ;
handle - > is_reassoc_timer_set = MFALSE ;
# endif /* REASSOCIATION */
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
/* Initialize the timer for GO timeout */
woal_initialize_timer ( & handle - > go_timer , woal_go_timer_func , handle ) ;
handle - > is_go_timer_set = MFALSE ;
# endif
# endif
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
handle - > remain_on_channel = MFALSE ;
/* Initialize the timer for remain on channel */
woal_initialize_timer ( & handle - > remain_timer ,
woal_remain_timer_func , handle ) ;
handle - > is_remain_timer_set = MFALSE ;
# endif
# endif
/* Register to MLAN */
memset ( & device , 0 , sizeof ( mlan_device ) ) ;
device . pmoal_handle = handle ;
# ifdef MFG_CMD_SUPPORT
if ( mfg_mode )
device . mfg_mode = ( t_u32 ) MLAN_INIT_PARA_ENABLED ;
# endif
# ifdef DEBUG_LEVEL1
device . drvdbg = drvdbg ;
# endif
device . fixed_beacon_buffer = ( t_u32 ) fixed_beacon_buffer ;
device . auto_ds = ( t_u32 ) auto_ds ;
device . ps_mode = ( t_u32 ) ps_mode ;
device . max_tx_buf = ( t_u32 ) max_tx_buf ;
# if defined(STA_SUPPORT)
device . cfg_11d = ( t_u32 ) cfg_11d ;
# endif
device . indrstcfg = ( t_u32 ) indrstcfg ;
device . drcs_chantime_mode = ( t_u32 ) drcs_chantime_mode ;
if ( rx_work = = MLAN_INIT_PARA_ENABLED )
device . rx_work = MTRUE ;
else if ( rx_work = = MLAN_INIT_PARA_DISABLED )
device . rx_work = MFALSE ;
else {
if ( num_possible_cpus ( ) > 1 )
device . rx_work = MTRUE ;
else
device . rx_work = MFALSE ;
}
PRINTM ( MMSG , " rx_work=%d cpu_num=%d \n " , device . rx_work ,
num_possible_cpus ( ) ) ;
if ( napi )
device . rx_work = MTRUE ;
device . dev_cap_mask = dev_cap_mask ;
device . multi_dtim = multi_dtim ;
device . inact_tmo = inact_tmo ;
device . hs_wake_interval = hs_wake_interval ;
device . indication_gpio = indication_gpio ;
device . hs_mimo_switch = hs_mimo_switch ;
for ( i = 0 ; i < handle - > drv_mode . intf_num ; i + + ) {
device . bss_attr [ i ] . bss_type =
handle - > drv_mode . bss_attr [ i ] . bss_type ;
device . bss_attr [ i ] . frame_type =
handle - > drv_mode . bss_attr [ i ] . frame_type ;
device . bss_attr [ i ] . active = handle - > drv_mode . bss_attr [ i ] . active ;
device . bss_attr [ i ] . bss_priority =
handle - > drv_mode . bss_attr [ i ] . bss_priority ;
device . bss_attr [ i ] . bss_num =
handle - > drv_mode . bss_attr [ i ] . bss_num ;
device . bss_attr [ i ] . bss_virtual =
handle - > drv_mode . bss_attr [ i ] . bss_virtual ;
}
memcpy ( & device . callbacks , & woal_callbacks , sizeof ( mlan_callbacks ) ) ;
if ( fw_region )
device . fw_region = MTRUE ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
if ( MLAN_STATUS_SUCCESS = = mlan_register ( & device , & pmlan ) )
handle - > pmlan_adapter = pmlan ;
else
ret = MLAN_STATUS_FAILURE ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function frees the structure of moal_handle
*
* @ param handle A pointer to moal_handle structure
*
* @ return N / A
*/
static void
woal_free_moal_handle ( moal_handle * handle )
{
ENTER ( ) ;
if ( ! handle ) {
PRINTM ( MERROR , " The handle is NULL \n " ) ;
LEAVE ( ) ;
return ;
}
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
/* Unregister wiphy device and free */
if ( handle - > wiphy ) {
wiphy_unregister ( handle - > wiphy ) ;
wiphy_free ( handle - > wiphy ) ;
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
kfree ( handle - > regd ) ;
# endif
handle - > wiphy = NULL ;
}
# endif
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
if ( ( handle - > nl_sk ) & & ( ( handle - > nl_sk ) - > sk_socket ) ) {
sock_release ( ( handle - > nl_sk ) - > sk_socket ) ;
handle - > nl_sk = NULL ;
}
# else
netlink_kernel_release ( handle - > nl_sk ) ;
# endif
if ( handle - > pmlan_adapter )
mlan_unregister ( handle - > pmlan_adapter ) ;
/* Free BSS attribute table */
kfree ( handle - > drv_mode . bss_attr ) ;
handle - > drv_mode . bss_attr = NULL ;
PRINTM ( MINFO , " Free Adapter \n " ) ;
if ( atomic_read ( & handle - > lock_count ) | |
atomic_read ( & handle - > malloc_count ) | |
atomic_read ( & handle - > mbufalloc_count ) ) {
PRINTM ( MERROR ,
" mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d \n " ,
atomic_read ( & handle - > lock_count ) ,
atomic_read ( & handle - > malloc_count ) ,
atomic_read ( & handle - > mbufalloc_count ) ) ;
}
if ( atomic_read ( & handle - > malloc_cons_count ) ) {
PRINTM ( MERROR , " mlan has memory leak: malloc_cons_count=%d \n " ,
atomic_read ( & handle - > malloc_cons_count ) ) ;
}
/* Free allocated memory for fwdump filename */
kfree ( handle - > fwdump_fname ) ;
if ( fwdump_fname ) {
kfree ( fwdump_fname ) ;
fwdump_fname = NULL ;
}
/* Free the moal handle itself */
kfree ( handle ) ;
LEAVE ( ) ;
}
/**
* @ brief WOAL get one line data from ASCII format data
*
* @ param data Source data
* @ param size Source data length
* @ param line_pos Destination data
* @ return routnine status
*/
static t_size
parse_cfg_get_line ( t_u8 * data , t_size size , t_u8 * line_pos )
{
t_u8 * src , * dest ;
static t_s32 pos ;
ENTER ( ) ;
if ( pos > = size ) { /* reach the end */
pos = 0 ; /* Reset position for rfkill */
LEAVE ( ) ;
return - 1 ;
}
memset ( line_pos , 0 , MAX_LINE_LEN ) ;
src = data + pos ;
dest = line_pos ;
while ( ( dest - line_pos < MAX_LINE_LEN - 1 ) & & pos < size & &
* src ! = ' \x0A ' & & * src ! = ' \0 ' ) {
if ( * src ! = ' ' & & * src ! = ' \t ' ) /* parse space */
* dest + + = * src + + ;
else
src + + ;
pos + + ;
}
/* parse new line */
pos + + ;
* dest = ' \0 ' ;
LEAVE ( ) ;
return strlen ( line_pos ) ;
}
/**
* @ brief Process register access request
* @ param type_string String format Register type
* @ param offset_string String format Register offset
* @ param value_string String format Pointer to value
* @ return MLAN_STATUS_SUCCESS - - success , otherwise - - fail
*/
static t_u32
woal_process_regrdwr ( moal_handle * handle , t_u8 * type_string ,
t_u8 * offset_string , t_u8 * value_string )
{
mlan_status ret = MLAN_STATUS_FAILURE ;
int type , offset , value ;
pmlan_ioctl_req ioctl_req = NULL ;
mlan_ds_reg_mem * reg = NULL ;
ENTER ( ) ;
/* Alloc ioctl_req */
ioctl_req = woal_alloc_mlan_ioctl_req ( sizeof ( mlan_ds_reg_mem ) ) ;
if ( ioctl_req = = NULL ) {
PRINTM ( MERROR , " Can't alloc memory \n " ) ;
goto done ;
}
if ( MLAN_STATUS_SUCCESS ! = woal_atoi ( & type , type_string ) )
goto done ;
if ( MLAN_STATUS_SUCCESS ! = woal_atoi ( & offset , offset_string ) )
goto done ;
if ( MLAN_STATUS_SUCCESS ! = woal_atoi ( & value , value_string ) )
goto done ;
ioctl_req - > req_id = MLAN_IOCTL_REG_MEM ;
ioctl_req - > action = MLAN_ACT_SET ;
reg = ( mlan_ds_reg_mem * ) ioctl_req - > pbuf ;
reg - > sub_command = MLAN_OID_REG_RW ;
if ( type < 5 ) {
reg - > param . reg_rw . type = type ;
} else {
PRINTM ( MERROR , " Unsupported Type \n " ) ;
goto done ;
}
reg - > param . reg_rw . offset = offset ;
reg - > param . reg_rw . value = value ;
/* request ioctl for STA */
ret = woal_request_ioctl ( handle - > priv [ 0 ] , ioctl_req , MOAL_IOCTL_WAIT ) ;
if ( ret ! = MLAN_STATUS_SUCCESS )
goto done ;
PRINTM ( MINFO , " Register type: %d, offset: 0x%x, value: 0x%x \n " , type ,
offset , value ) ;
ret = MLAN_STATUS_SUCCESS ;
done :
if ( ret ! = MLAN_STATUS_PENDING )
kfree ( ioctl_req ) ;
LEAVE ( ) ;
return ret ;
}
# ifdef UAP_SUPPORT
/**
* @ brief set uap operation contrl value
*
* @ param handle MOAL handle
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
woal_set_uap_operation_ctrl ( moal_handle * handle )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
moal_private * priv = NULL ;
mlan_ds_bss * bss = NULL ;
mlan_ioctl_req * req = NULL ;
ENTER ( ) ;
priv = woal_get_priv ( handle , MLAN_BSS_ROLE_UAP ) ;
if ( ! priv ) {
PRINTM ( MERROR ,
" woal_set_uap_operation_ctrl failed, no uap interface \n " ) ;
LEAVE ( ) ;
return ret ;
}
req = woal_alloc_mlan_ioctl_req ( sizeof ( mlan_ds_bss ) ) ;
if ( req = = NULL ) {
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
bss = ( mlan_ds_bss * ) req - > pbuf ;
bss - > sub_command = MLAN_OID_UAP_OPER_CTRL ;
req - > req_id = MLAN_IOCTL_BSS ;
req - > action = MLAN_ACT_SET ;
bss - > param . ap_oper_ctrl . ctrl_value =
( t_u16 ) ( ( uap_oper_ctrl & 0xffff0000 ) > > 16 ) ;
bss - > param . ap_oper_ctrl . chan_opt = ( t_u16 ) ( uap_oper_ctrl & 0xffff ) ;
PRINTM ( MMSG , " Uap oper_ctrl=0x%x chan_opt=0x%x \n " ,
bss - > param . ap_oper_ctrl . ctrl_value ,
bss - > param . ap_oper_ctrl . chan_opt ) ;
ret = woal_request_ioctl ( priv , req , MOAL_IOCTL_WAIT ) ;
done :
if ( ret ! = MLAN_STATUS_PENDING )
kfree ( req ) ;
LEAVE ( ) ;
return ret ;
}
# endif
/**
* @ brief WOAL parse ASCII format data to MAC address
*
* @ param handle MOAL handle
* @ param data Source data
* @ param size data length
* @ return MLAN_STATUS_SUCCESS - - success , otherwise - - fail
*/
static t_u32
woal_process_init_cfg ( moal_handle * handle , t_u8 * data , t_size size )
{
mlan_status ret = MLAN_STATUS_FAILURE ;
t_u8 * pos ;
t_u8 * intf_s , * intf_e ;
t_u8 s [ MAX_LINE_LEN ] ; /* 1 line data */
t_size line_len ;
t_u8 index = 0 ;
t_u32 i ;
t_u8 bss_mac_addr [ MAX_MAC_ADDR_LEN ] ;
t_u8 bss_mac_name [ MAX_PARAM_LEN ] ;
t_u8 type [ MAX_PARAM_LEN ] ;
t_u8 offset [ MAX_PARAM_LEN ] ;
t_u8 value [ MAX_PARAM_LEN ] ;
ENTER ( ) ;
while ( ( line_len = parse_cfg_get_line ( data , size , s ) ) ! = - 1 ) {
pos = s ;
while ( * pos = = ' ' | | * pos = = ' \t ' )
pos + + ;
if ( * pos = = ' # ' | | ( * pos = = ' \r ' & & * ( pos + 1 ) = = ' \n ' ) | |
* pos = = ' \n ' | | * pos = = ' \0 ' )
continue ; /* Needn't process this line */
/* Process MAC addr */
if ( strncmp ( pos , " mac_addr " , 8 ) = = 0 ) {
intf_s = strchr ( pos , ' = ' ) ;
if ( intf_s ! = NULL )
intf_e = strchr ( intf_s , ' : ' ) ;
else
intf_e = NULL ;
if ( intf_s ! = NULL & & intf_e ! = NULL ) {
strncpy ( bss_mac_addr , intf_e + 1 ,
MAX_MAC_ADDR_LEN - 1 ) ;
bss_mac_addr [ MAX_MAC_ADDR_LEN - 1 ] = ' \0 ' ;
if ( ( intf_e - intf_s ) > MAX_PARAM_LEN ) {
PRINTM ( MERROR ,
" Too long interface name %d \n " ,
__LINE__ ) ;
goto done ;
}
strncpy ( bss_mac_name , intf_s + 1 ,
intf_e - intf_s - 1 ) ;
bss_mac_name [ intf_e - intf_s - 1 ] = ' \0 ' ;
for ( i = 0 ; i < handle - > priv_num ; i + + ) {
if ( strcmp
( bss_mac_name ,
handle - > priv [ i ] - > netdev - > name ) = =
0 ) {
memset ( handle - > priv [ i ] - >
current_addr , 0 ,
ETH_ALEN ) ;
PRINTM ( MINFO ,
" Interface name: %s mac: %s \n " ,
bss_mac_name ,
bss_mac_addr ) ;
woal_mac2u8 ( handle - > priv [ i ] - >
current_addr ,
bss_mac_addr ) ;
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
if ( handle - > priv [ i ] - > bss_type = =
MLAN_BSS_TYPE_WIFIDIRECT ) {
handle - > priv [ i ] - >
current_addr [ 0 ]
| = 0x02 ;
PRINTM ( MCMND ,
" Set WFD device addr: "
MACSTR " \n " ,
MAC2STR ( handle - >
priv [ i ] - >
current_addr ) ) ;
}
# endif
# endif
# endif
/* Set WLAN MAC addresses */
if ( MLAN_STATUS_SUCCESS ! =
woal_request_set_mac_address
( handle - > priv [ i ] ) ) {
PRINTM ( MERROR ,
" Set MAC address failed \n " ) ;
goto done ;
}
memcpy ( handle - > priv [ i ] - > netdev - >
dev_addr ,
handle - > priv [ i ] - >
current_addr , ETH_ALEN ) ;
index + + ; /* Mark found one interface matching */
}
}
} else {
PRINTM ( MERROR , " Wrong config file format %d \n " ,
__LINE__ ) ;
goto done ;
}
}
/* Process REG value */
else if ( strncmp ( pos , " wlan_reg " , 8 ) = = 0 ) {
intf_s = strchr ( pos , ' = ' ) ;
if ( intf_s ! = NULL )
intf_e = strchr ( intf_s , ' , ' ) ;
else
intf_e = NULL ;
if ( intf_s ! = NULL & & intf_e ! = NULL ) {
/* Copy type */
strncpy ( type , intf_s + 1 , 1 ) ;
type [ 1 ] = ' \0 ' ;
} else {
PRINTM ( MERROR , " Wrong config file format %d \n " ,
__LINE__ ) ;
goto done ;
}
intf_s = intf_e + 1 ;
intf_e = strchr ( intf_s , ' , ' ) ;
if ( intf_e ! = NULL ) {
if ( ( intf_e - intf_s ) > = MAX_PARAM_LEN ) {
PRINTM ( MERROR ,
" Regsier offset is too long %d \n " ,
__LINE__ ) ;
goto done ;
}
/* Copy offset */
strncpy ( offset , intf_s , intf_e - intf_s ) ;
offset [ intf_e - intf_s ] = ' \0 ' ;
} else {
PRINTM ( MERROR , " Wrong config file format %d \n " ,
__LINE__ ) ;
goto done ;
}
intf_s = intf_e + 1 ;
if ( ( strlen ( intf_s ) > = MAX_PARAM_LEN ) ) {
PRINTM ( MERROR , " Regsier value is too long %d \n " ,
__LINE__ ) ;
goto done ;
}
/* Copy value */
strncpy ( value , intf_s ,
MIN ( ( MAX_PARAM_LEN - 1 ) , strlen ( intf_s ) ) ) ;
if ( MLAN_STATUS_SUCCESS ! =
woal_process_regrdwr ( handle , type , offset , value ) ) {
PRINTM ( MERROR , " Access Reg failed \n " ) ;
goto done ;
}
PRINTM ( MINFO , " Reg type: %s, offset: %s, value: %s \n " ,
type , offset , value ) ;
}
}
if ( index = = 0 )
PRINTM ( MINFO , " Can't find any matching MAC Address " ) ;
ret = MLAN_STATUS_SUCCESS ;
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief WOAL parse ASCII format raw data to hex format
*
* @ param handle MOAL handle
* @ param data Source data
* @ param size data length
* @ param wait_option wait option
* @ return MLAN_STATUS_SUCCESS - - success , otherwise - - fail
*/
static t_u32
woal_process_hostcmd_cfg ( moal_handle * handle , t_u8 * data , t_size size ,
t_u8 wait_option )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
t_u8 * pos = data ;
t_u8 * intf_s , * intf_e ;
t_u8 * buf = NULL ;
t_u8 * ptr = NULL ;
t_u32 cmd_len = 0 ;
t_u8 start_raw = MFALSE ;
gfp_t flag ;
# define CMD_STR "MRVL_CMDhostcmd"
# define CMD_BUF_LEN 2048
ENTER ( ) ;
flag = ( in_atomic ( ) | | irqs_disabled ( ) ) ? GFP_ATOMIC : GFP_KERNEL ;
buf = kzalloc ( CMD_BUF_LEN , flag ) ;
if ( ! buf ) {
PRINTM ( MERROR , " Could not allocate buffer space! \n " ) ;
goto done ;
}
ptr = buf ;
strcpy ( ptr , CMD_STR ) ;
ptr = buf + strlen ( CMD_STR ) + sizeof ( t_u32 ) ;
while ( ( pos - data ) < size ) {
while ( * pos = = ' ' | | * pos = = ' \t ' )
pos + + ;
if ( * pos = = ' # ' ) { /* Line comment */
while ( * pos ! = ' \n ' )
pos + + ;
pos + + ;
}
if ( ( * pos = = ' \r ' & & * ( pos + 1 ) = = ' \n ' ) | |
* pos = = ' \n ' | | * pos = = ' \0 ' ) {
pos + + ;
continue ; /* Needn't process this line */
}
if ( * pos = = ' } ' ) {
cmd_len =
* ( ( t_u16 * ) ( buf + strlen ( CMD_STR ) +
sizeof ( t_u32 ) + sizeof ( t_u16 ) ) ) ;
memcpy ( buf + strlen ( CMD_STR ) , & cmd_len , sizeof ( t_u32 ) ) ;
/* fire the hostcommand from here */
woal_priv_hostcmd ( handle - > priv [ 0 ] , buf , CMD_BUF_LEN ,
wait_option ) ;
memset ( buf + strlen ( CMD_STR ) , 0 ,
CMD_BUF_LEN - strlen ( CMD_STR ) ) ;
ptr = buf + strlen ( CMD_STR ) + sizeof ( t_u32 ) ;
start_raw = MFALSE ;
pos + + ;
continue ;
}
if ( start_raw = = MFALSE ) {
intf_s = strchr ( pos , ' = ' ) ;
if ( intf_s )
intf_e = strchr ( intf_s , ' { ' ) ;
else
intf_e = NULL ;
if ( intf_s & & intf_e ) {
start_raw = MTRUE ;
pos = intf_e + 1 ;
continue ;
}
}
if ( start_raw ) {
/* Raw data block exists */
while ( * pos ! = ' \n ' ) {
if ( ( * pos < = ' f ' & & * pos > = ' a ' ) | |
( * pos < = ' F ' & & * pos > = ' A ' ) | |
( * pos < = ' 9 ' & & * pos > = ' 0 ' ) ) {
* ptr + + = woal_atox ( pos ) ;
pos + = 2 ;
} else
pos + + ;
}
}
}
done :
kfree ( buf ) ;
LEAVE ( ) ;
return ret ;
}
# define INIT_CFG_DATA 0x00
# define INIT_HOSTCMD_CFG_DATA 0x02
# define COUNTRY_POWER_TABLE 0x04
/**
* @ brief Request init conf firmware callback
* This function is invoked by request_firmware_nowait system call
*
* @ param firmware A pointer to firmware image
* @ param context A pointer to moal_handle structure
*
* @ return N / A
*/
static void
woal_request_init_user_conf_callback ( const struct firmware * firmware ,
void * context )
{
moal_handle * handle ;
ENTER ( ) ;
handle = ( moal_handle * ) context ;
if ( ! handle ) {
LEAVE ( ) ;
return ;
}
if ( firmware )
handle - > user_data = firmware ;
else
PRINTM ( MERROR , " User init config request firmware failed \n " ) ;
handle - > init_user_conf_wait_flag = MTRUE ;
wake_up_interruptible ( & handle - > init_user_conf_wait_q ) ;
LEAVE ( ) ;
return ;
}
/**
* @ brief Request init conf firmware callback
* This function is invoked by request_firmware_nowait system call
*
* @ param firmware A pointer to firmware image
* @ param context A pointer to moal_handle structure
*
* @ return N / A
*/
static void
woal_request_init_dpd_conf_callback ( const struct firmware * firmware ,
void * context )
{
moal_handle * handle ;
ENTER ( ) ;
handle = ( moal_handle * ) context ;
if ( ! handle ) {
LEAVE ( ) ;
return ;
}
if ( firmware & & handle )
handle - > dpd_data = firmware ;
else
PRINTM ( MERROR , " User init cfg data request firmware failed \n " ) ;
handle - > init_user_conf_wait_flag = MTRUE ;
wake_up_interruptible ( & handle - > init_user_conf_wait_q ) ;
LEAVE ( ) ;
return ;
}
/**
* @ brief Request init conf firmware callback
* This function is invoked by request_firmware_nowait system call
*
* @ param firmware A pointer to firmware image
* @ param context A pointer to moal_handle structure
*
* @ return N / A
*/
static void
woal_request_init_txpwr_conf_callback ( const struct firmware * firmware ,
void * context )
{
moal_handle * handle ;
ENTER ( ) ;
handle = ( moal_handle * ) context ;
if ( ! handle ) {
LEAVE ( ) ;
return ;
}
if ( firmware & & handle )
handle - > txpwr_data = firmware ;
else
PRINTM ( MERROR , " User init cfg data request firmware failed \n " ) ;
handle - > init_user_conf_wait_flag = MTRUE ;
wake_up_interruptible ( & handle - > init_user_conf_wait_q ) ;
LEAVE ( ) ;
return ;
}
/**
* @ brief Request init conf firmware callback
* This function is invoked by request_firmware_nowait system call
*
* @ param firmware A pointer to firmware image
* @ param context A pointer to moal_handle structure
*
* @ return N / A
*/
static void
woal_request_init_cfg_data_callback ( const struct firmware * firmware ,
void * context )
{
moal_handle * handle ;
ENTER ( ) ;
handle = ( moal_handle * ) context ;
if ( ! handle ) {
LEAVE ( ) ;
return ;
}
if ( firmware & & handle )
handle - > init_cfg_data = firmware ;
else
PRINTM ( MERROR , " User init cfg data request firmware failed \n " ) ;
handle - > init_user_conf_wait_flag = MTRUE ;
wake_up_interruptible ( & handle - > init_user_conf_wait_q ) ;
LEAVE ( ) ;
return ;
}
/**
* @ brief WOAL set user defined init data and param
*
* @ param handle MOAL handle structure
* @ param type type argument
* @ param wait_option wait option
* @ return MLAN_STATUS_SUCCESS - - success , otherwise - - fail
*/
static t_u32
woal_set_user_init_data ( moal_handle * handle , int type , t_u8 wait_option )
{
mlan_status ret = MLAN_STATUS_FAILURE ;
t_u8 * cfg_data = NULL ;
t_size len ;
ENTER ( ) ;
if ( type = = INIT_CFG_DATA ) {
if ( req_fw_nowait ) {
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , init_cfg ,
handle - > hotplug_device , GFP_KERNEL , handle ,
woal_request_init_cfg_data_callback ) ) < 0 ) {
# else
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , init_cfg ,
handle - > hotplug_device , handle ,
woal_request_init_cfg_data_callback ) ) < 0 ) {
# else
if ( ( request_firmware_nowait
( THIS_MODULE , init_cfg , handle - > hotplug_device ,
handle ,
woal_request_init_cfg_data_callback ) ) < 0 ) {
# endif
# endif
PRINTM ( MERROR ,
" Init config file request_firmware_nowait() failed \n " ) ;
goto done ;
}
handle - > init_user_conf_wait_flag = MFALSE ;
wait_event_interruptible ( handle - > init_user_conf_wait_q ,
handle - >
init_user_conf_wait_flag ) ;
} else {
if ( ( request_firmware
( & handle - > init_cfg_data , init_cfg ,
handle - > hotplug_device ) ) < 0 ) {
PRINTM ( MERROR ,
" Init config file request_firmware() failed \n " ) ;
goto done ;
}
}
} else if ( type = = COUNTRY_POWER_TABLE ) {
if ( req_fw_nowait ) {
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG ,
country_txpwrlimit , handle - > hotplug_device ,
GFP_KERNEL , handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# else
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG ,
country_txpwrlimit , handle - > hotplug_device ,
handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# else
if ( ( request_firmware_nowait
( THIS_MODULE , country_txpwrlimit ,
handle - > hotplug_device , handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# endif
# endif
PRINTM ( MERROR ,
" country txpwrlimit config file request_firmware_nowait() failed \n " ) ;
goto done ;
}
handle - > init_user_conf_wait_flag = MFALSE ;
wait_event_interruptible ( handle - > init_user_conf_wait_q ,
handle - >
init_user_conf_wait_flag ) ;
} else {
int status =
request_firmware ( & handle - > user_data ,
country_txpwrlimit ,
handle - > hotplug_device ) ;
/* File does not exist, skip download */
if ( status = = - ENOENT ) {
PRINTM ( MIOCTL ,
" Country power table file does not exist \n " ) ;
LEAVE ( ) ;
return MLAN_STATUS_SUCCESS ;
} else if ( status ) {
PRINTM ( MERROR ,
" country txpwrlimit config file request_firmware() failed \n " ) ;
goto done ;
}
}
} else if ( type = = INIT_HOSTCMD_CFG_DATA ) {
if ( req_fw_nowait ) {
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , init_hostcmd_cfg ,
handle - > hotplug_device , GFP_KERNEL , handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# else
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , init_hostcmd_cfg ,
handle - > hotplug_device , handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# else
if ( ( request_firmware_nowait
( THIS_MODULE , init_hostcmd_cfg ,
handle - > hotplug_device , handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# endif
# endif
PRINTM ( MERROR ,
" Init hostcmd config file request_firmware_nowait() failed \n " ) ;
goto done ;
}
handle - > init_user_conf_wait_flag = MFALSE ;
wait_event_interruptible ( handle - > init_user_conf_wait_q ,
handle - >
init_user_conf_wait_flag ) ;
} else {
if ( ( request_firmware
( & handle - > user_data , init_hostcmd_cfg ,
handle - > hotplug_device ) ) < 0 ) {
PRINTM ( MERROR ,
" Init hostcmd config file request_firmware() failed \n " ) ;
goto done ;
}
}
}
if ( handle - > user_data ) {
cfg_data = ( t_u8 * ) ( handle - > user_data ) - > data ;
len = ( handle - > user_data ) - > size ;
if ( type = = INIT_HOSTCMD_CFG_DATA
| | type = = COUNTRY_POWER_TABLE ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_process_hostcmd_cfg ( handle , cfg_data , len ,
wait_option ) ) {
PRINTM ( MERROR ,
" Can't process hostcmd config file \n " ) ;
goto done ;
}
}
ret = MLAN_STATUS_SUCCESS ;
} else if ( type = = INIT_CFG_DATA & & handle - > init_cfg_data ) {
PRINTM ( MIOCTL , " Load init_cfg success \n " ) ;
ret = MLAN_STATUS_SUCCESS ;
}
done :
if ( handle - > user_data ) {
release_firmware ( handle - > user_data ) ;
handle - > user_data = NULL ;
}
LEAVE ( ) ;
return ret ;
}
static int woal_netdevice_event ( struct notifier_block * nb ,
unsigned long event , void * ptr ) ;
/**
* @ brief Add interfaces DPC
*
* @ param handle A pointer to moal_handle structure
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
woal_add_card_dpc ( moal_handle * handle )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
int i ;
char str_buf [ MLAN_MAX_VER_STR_LEN ] ;
ENTER ( ) ;
# ifdef CONFIG_PROC_FS
/* Initialize proc fs */
woal_proc_init ( handle ) ;
# endif /* CONFIG_PROC_FS */
/* Add interfaces */
for ( i = 0 ; i < handle - > drv_mode . intf_num ; i + + ) {
if ( handle - > drv_mode . bss_attr [ i ] . bss_virtual )
continue ;
if ( ! woal_add_interface
( handle , handle - > priv_num ,
handle - > drv_mode . bss_attr [ i ] . bss_type ) ) {
ret = MLAN_STATUS_FAILURE ;
goto err ;
}
}
woal_get_version ( handle , str_buf , sizeof ( str_buf ) - 1 ) ;
PRINTM ( MMSG , " wlan: version = %s \n " , str_buf ) ;
handle - > woal_notifier . notifier_call = woal_netdevice_event ;
if ( register_inetaddr_notifier ( & handle - > woal_notifier ) ) {
PRINTM ( MFATAL ,
" Error registering register_inetaddr_notifier \n " ) ;
goto err ;
}
# ifdef MFG_CMD_SUPPORT
if ( mfg_mode = = MLAN_INIT_PARA_ENABLED )
goto done ;
# endif
if ( init_cfg & & handle - > init_cfg_data ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_process_init_cfg ( handle ,
( t_u8 * ) ( handle - > init_cfg_data ) - > data ,
( handle - > init_cfg_data ) - > size ) ) {
PRINTM ( MERROR , " Can't process init config file \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto err ;
}
}
if ( pmic ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_pmic_configure ( handle , MOAL_IOCTL_WAIT ) ) {
PRINTM ( MFATAL , " Failed to configure PMIC \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto err ;
}
}
# ifdef UAP_SUPPORT
if ( uap_oper_ctrl )
woal_set_uap_operation_ctrl ( handle ) ;
# endif
# ifdef MFG_CMD_SUPPORT
done :
# endif
err :
if ( init_cfg & & handle - > init_cfg_data ) {
release_firmware ( handle - > init_cfg_data ) ;
handle - > init_cfg_data = NULL ;
}
if ( ret ! = MLAN_STATUS_SUCCESS ) {
PRINTM ( MERROR , " Failed to add interface \n " ) ;
unregister_inetaddr_notifier ( & handle - > woal_notifier ) ;
for ( i = 0 ; i < MIN ( MLAN_MAX_BSS_NUM , handle - > priv_num ) ; i + + )
woal_remove_interface ( handle , i ) ;
handle - > priv_num = 0 ;
# ifdef CONFIG_PROC_FS
woal_proc_exit ( handle ) ;
# endif
}
LEAVE ( ) ;
return ret ;
}
/**
* @ brief Download and Initialize firmware DPC
*
* @ param handle A pointer to moal_handle structure
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
woal_init_fw_dpc ( moal_handle * handle )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
mlan_fw_image fw ;
mlan_init_param param ;
int status ;
ENTER ( ) ;
if ( handle - > firmware ) {
memset ( & fw , 0 , sizeof ( mlan_fw_image ) ) ;
fw . pfw_buf = ( t_u8 * ) handle - > firmware - > data ;
fw . fw_len = handle - > firmware - > size ;
if ( handle - > fw_reload = = FW_RELOAD_NO_EMULATION )
fw . fw_reload = FW_RELOAD_NO_EMULATION ;
else
fw . fw_reload = 0 ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
ret = mlan_dnld_fw ( handle - > pmlan_adapter , & fw ) ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
if ( ret = = MLAN_STATUS_FAILURE ) {
PRINTM ( MERROR ,
" WLAN: Fail download FW with nowwait: %d \n " ,
req_fw_nowait ) ;
goto done ;
}
PRINTM ( MMSG , " WLAN FW is active \n " ) ;
}
/** data request */
memset ( & param , 0 , sizeof ( mlan_init_param ) ) ;
if ( dpd_data_cfg & & strncmp ( dpd_data_cfg , " none " , strlen ( " none " ) ) ) {
if ( req_fw_nowait ) {
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , dpd_data_cfg ,
handle - > hotplug_device , GFP_KERNEL , handle ,
woal_request_init_dpd_conf_callback ) ) < 0 ) {
# else
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , dpd_data_cfg ,
handle - > hotplug_device , handle ,
woal_request_init_dpd_conf_callback ) ) < 0 ) {
# else
if ( ( request_firmware_nowait
( THIS_MODULE , dpd_data_cfg , handle - > hotplug_device ,
handle ,
woal_request_init_dpd_conf_callback ) ) < 0 ) {
# endif
# endif
PRINTM ( MERROR ,
" DPD data request_firmware_nowait() failed \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
handle - > init_user_conf_wait_flag = MFALSE ;
wait_event_interruptible ( handle - > init_user_conf_wait_q ,
handle - >
init_user_conf_wait_flag ) ;
} else {
status = request_firmware ( & handle - > dpd_data ,
dpd_data_cfg ,
handle - > hotplug_device ) ;
if ( status < 0 & & status ! = - ENOENT ) {
PRINTM ( MERROR ,
" DPD data request_firmware() failed \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
}
if ( handle - > dpd_data ) {
param . pdpd_data_buf = ( t_u8 * ) handle - > dpd_data - > data ;
param . dpd_data_len = handle - > dpd_data - > size ;
} else {
param . dpd_data_len = UNKNOW_DPD_LENGTH ;
}
}
if ( txpwrlimit_cfg & & strncmp ( txpwrlimit_cfg , " none " , strlen ( " none " ) ) ) {
if ( req_fw_nowait ) {
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , txpwrlimit_cfg ,
handle - > hotplug_device , GFP_KERNEL , handle ,
woal_request_init_txpwr_conf_callback ) ) < 0 ) {
# else
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , txpwrlimit_cfg ,
handle - > hotplug_device , handle ,
woal_request_init_txpwr_conf_callback ) ) < 0 ) {
# else
if ( ( request_firmware_nowait
( THIS_MODULE , txpwrlimit_cfg ,
handle - > hotplug_device , handle ,
woal_request_init_txpwr_conf_callback ) ) < 0 ) {
# endif
# endif
PRINTM ( MERROR , " Region txpwrlimit cfg data "
" request_firmware_nowait() failed \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
handle - > init_user_conf_wait_flag = MFALSE ;
wait_event_interruptible ( handle - > init_user_conf_wait_q ,
handle - >
init_user_conf_wait_flag ) ;
} else {
if ( ( request_firmware
( & handle - > txpwr_data , txpwrlimit_cfg ,
handle - > hotplug_device ) ) < 0 ) {
PRINTM ( MERROR ,
" Region txpwrlimit cfg data "
" request_firmware() failed \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
}
if ( handle - > txpwr_data ) {
param . ptxpwr_data_buf =
( t_u8 * ) handle - > txpwr_data - > data ;
param . txpwr_data_len = handle - > txpwr_data - > size ;
}
}
if ( cal_data_cfg & & strncmp ( cal_data_cfg , " none " , strlen ( " none " ) ) ) {
if ( req_fw_nowait ) {
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , cal_data_cfg ,
handle - > hotplug_device , GFP_KERNEL , handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# else
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
if ( ( request_firmware_nowait
( THIS_MODULE , FW_ACTION_HOTPLUG , cal_data_cfg ,
handle - > hotplug_device , handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# else
if ( ( request_firmware_nowait
( THIS_MODULE , cal_data_cfg , handle - > hotplug_device ,
handle ,
woal_request_init_user_conf_callback ) ) < 0 ) {
# endif
# endif
PRINTM ( MERROR ,
" Cal data request_firmware_nowait() failed \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
handle - > init_user_conf_wait_flag = MFALSE ;
wait_event_interruptible ( handle - > init_user_conf_wait_q ,
handle - >
init_user_conf_wait_flag ) ;
} else {
if ( ( request_firmware
( & handle - > user_data , cal_data_cfg ,
handle - > hotplug_device ) ) < 0 ) {
PRINTM ( MERROR ,
" Cal data request_firmware() failed \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
}
} else if ( ! cal_data_cfg ) {
PRINTM ( MERROR ,
" Please add cal_data_cfg for 8887/8977/8997/8987/9098/8978 \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
if ( handle - > user_data ) {
param . pcal_data_buf = ( t_u8 * ) handle - > user_data - > data ;
param . cal_data_len = handle - > user_data - > size ;
}
handle - > hardware_status = HardwareStatusFwReady ;
if ( ret ! = MLAN_STATUS_SUCCESS )
goto done ;
if ( handle - > fw_reload )
goto done ;
handle - > init_wait_q_woken = MFALSE ;
ret = mlan_set_init_param ( handle - > pmlan_adapter , & param ) ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
ret = mlan_init_fw ( handle - > pmlan_adapter ) ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
if ( ret = = MLAN_STATUS_FAILURE )
goto done ;
else if ( ret = = MLAN_STATUS_SUCCESS ) {
handle - > hardware_status = HardwareStatusReady ;
goto done ;
}
/* Wait for mlan_init to complete */
/* Wait for mlan_init to complete */
wait_event_timeout ( handle - > init_wait_q ,
handle - > init_wait_q_woken , 5 * HZ ) ;
if ( handle - > hardware_status ! = HardwareStatusReady ) {
woal_moal_debug_info ( woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ,
handle , MTRUE ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
ret = MLAN_STATUS_SUCCESS ;
done :
if ( handle - > dpd_data ) {
release_firmware ( handle - > dpd_data ) ;
handle - > dpd_data = NULL ;
}
if ( handle - > txpwr_data ) {
release_firmware ( handle - > txpwr_data ) ;
handle - > txpwr_data = NULL ;
}
if ( handle - > user_data ) {
release_firmware ( handle - > user_data ) ;
handle - > user_data = NULL ;
}
LEAVE ( ) ;
return ret ;
}
/**
* @ brief Request firmware DPC
*
* @ param handle A pointer to moal_handle structure
* @ param firmware A pointer to firmware image
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
woal_request_fw_dpc ( moal_handle * handle , const struct firmware * firmware )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
struct timeval tstamp ;
ENTER ( ) ;
if ( ! firmware ) {
woal_get_monotonic_time ( & tstamp ) ;
if ( tstamp . tv_sec >
( handle - > req_fw_time . tv_sec + REQUEST_FW_TIMEOUT ) ) {
PRINTM ( MERROR ,
" No firmware image found. Skipping download \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
PRINTM ( MERROR ,
" request_firmware_nowait failed for %s. Retrying.. \n " ,
handle - > drv_mode . fw_name ) ;
woal_sched_timeout ( MOAL_TIMER_1S ) ;
woal_request_fw ( handle ) ;
LEAVE ( ) ;
return ret ;
}
handle - > firmware = firmware ;
ret = woal_init_fw_dpc ( handle ) ;
if ( ret )
goto done ;
ret = woal_add_card_dpc ( handle ) ;
if ( ret )
goto done ;
done :
/* We should hold the semaphore until callback finishes execution */
MOAL_REL_SEMAPHORE ( & AddRemoveCardSem ) ;
LEAVE ( ) ;
return ret ;
}
/**
* @ brief Request firmware callback
* This function is invoked by request_firmware_nowait system call
*
* @ param firmware A pointer to firmware image
* @ param context A pointer to moal_handle structure
*
* @ return N / A
*/
static void
woal_request_fw_callback ( const struct firmware * firmware , void * context )
{
ENTER ( ) ;
woal_request_fw_dpc ( ( moal_handle * ) context , firmware ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
if ( firmware )
release_firmware ( firmware ) ;
# endif
LEAVE ( ) ;
return ;
}
/**
* @ brief Download firmware using helper
*
* @ param handle A pointer to moal_handle structure
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
woal_request_fw ( moal_handle * handle )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
int err ;
ENTER ( ) ;
PRINTM ( MMSG , " Request firmware: %s \n " , handle - > drv_mode . fw_name ) ;
if ( req_fw_nowait ) {
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
err = request_firmware_nowait ( THIS_MODULE , FW_ACTION_HOTPLUG ,
handle - > drv_mode . fw_name ,
handle - > hotplug_device ,
GFP_KERNEL , handle ,
woal_request_fw_callback ) ;
# else
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)
err = request_firmware_nowait ( THIS_MODULE , FW_ACTION_HOTPLUG ,
handle - > drv_mode . fw_name ,
handle - > hotplug_device , handle ,
woal_request_fw_callback ) ;
# else
err = request_firmware_nowait ( THIS_MODULE ,
handle - > drv_mode . fw_name ,
handle - > hotplug_device , handle ,
woal_request_fw_callback ) ;
# endif
# endif
if ( err < 0 ) {
PRINTM ( MFATAL ,
" WLAN: request_firmware_nowait() failed, error code = %d \n " ,
err ) ;
ret = MLAN_STATUS_FAILURE ;
}
} else {
err = request_firmware ( & handle - > firmware ,
handle - > drv_mode . fw_name ,
handle - > hotplug_device ) ;
if ( err < 0 ) {
PRINTM ( MFATAL ,
" WLAN: request_firmware() failed, error code = %d \n " ,
err ) ;
ret = MLAN_STATUS_FAILURE ;
} else {
if ( handle - > fw_reload )
ret = woal_init_fw_dpc ( handle ) ;
else
ret = woal_request_fw_dpc ( handle ,
handle - > firmware ) ;
release_firmware ( handle - > firmware ) ;
}
}
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function initializes firmware
*
* @ param handle A pointer to moal_handle structure
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
woal_init_fw ( moal_handle * handle )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
ENTER ( ) ;
woal_get_monotonic_time ( & handle - > req_fw_time ) ;
ret = woal_request_fw ( handle ) ;
if ( ret = = MLAN_STATUS_FAILURE ) {
PRINTM ( MFATAL , " woal_request_fw failed \n " ) ;
goto done ;
}
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function will fill in the mlan_buffer
*
* @ param pmbuf A pointer to mlan_buffer
* @ param skb A pointer to struct sk_buff
*
* @ return N / A
*/
static void
woal_fill_mlan_buffer ( moal_private * priv ,
mlan_buffer * pmbuf , struct sk_buff * skb )
{
struct timeval tstamp ;
struct ethhdr * eth ;
t_u8 tid ;
dot11_txcontrol * txcontrol ;
t_u8 tx_ctrl_flag = MFALSE ;
int i = 0 ;
ENTER ( ) ;
/*
* skb - > priority values from 256 - > 263 are magic values to
* directly indicate a specific 802.1 d priority . This is used
* to allow 802.1 d priority to be passed directly in from VLAN
* tags , etc .
*/
if ( IS_SKB_MAGIC_VLAN ( skb ) ) {
tid = GET_VLAN_PRIO ( skb ) ;
} else {
eth = ( struct ethhdr * ) skb - > data ;
switch ( eth - > h_proto ) {
case __constant_htons ( ETH_P_IP ) :
tid = priv - > dscp_map [ SKB_TOS ( skb ) > > DSCP_OFFSET ] ;
if ( tid = = 0xFF )
tid = ( IPTOS_PREC ( SKB_TOS ( skb ) ) > >
IPTOS_OFFSET ) ;
PRINTM ( MDAT_D ,
" packet type ETH_P_IP: dscp[%x], map[%x], tid=%d \n " ,
SKB_TOS ( skb ) > > DSCP_OFFSET ,
priv - > dscp_map [ SKB_TOS ( skb ) > > DSCP_OFFSET ] ,
tid ) ;
break ;
case __constant_htons ( ETH_P_IPV6 ) :
tid = SKB_TIDV6 ( skb ) ;
PRINTM ( MDAT_D ,
" packet type ETH_P_IPV6: %04x, tid=%#x prio=%#x \n " ,
eth - > h_proto , tid , skb - > priority ) ;
break ;
case __constant_htons ( ETH_P_ARP ) :
tid = 0 ;
PRINTM ( MDATA , " ARP packet %04x \n " , eth - > h_proto ) ;
break ;
default :
tid = 0 ;
if ( priv - > tx_protocols . protocol_num ) {
for ( i = 0 ; i < priv - > tx_protocols . protocol_num ;
i + + ) {
if ( eth - > h_proto = =
__constant_htons ( priv - > tx_protocols .
protocols [ i ] ) )
tx_ctrl_flag = MTRUE ;
}
}
if ( tx_ctrl_flag ) {
txcontrol =
( dot11_txcontrol * ) ( skb - > data +
sizeof ( struct
ethhdr ) ) ;
pmbuf - > u . tx_info . data_rate =
txcontrol - > datarate ;
pmbuf - > u . tx_info . channel = txcontrol - > channel ;
pmbuf - > u . tx_info . bw = txcontrol - > bw ;
pmbuf - > u . tx_info . tx_power . val =
txcontrol - > power ;
pmbuf - > u . tx_info . retry_limit =
txcontrol - > retry_limit ;
tid = txcontrol - > priority ;
memmove ( skb - > data + sizeof ( dot11_txcontrol ) ,
skb - > data , sizeof ( struct ethhdr ) ) ;
skb_pull ( skb , sizeof ( dot11_txcontrol ) ) ;
pmbuf - > flags | = MLAN_BUF_FLAG_TX_CTRL ;
}
break ;
}
}
skb - > priority = tid ;
/* Record the current time the packet was queued; used to determine
* the amount of time the packet was queued in the driver before it
* was sent to the firmware . The delay is then sent along with the
* packet to the firmware for aggregate delay calculation for stats
* and MSDU lifetime expiry .
*/
woal_get_monotonic_time ( & tstamp ) ;
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
skb - > tstamp = timeval_to_ktime ( tstamp ) ;
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
skb_set_timestamp ( skb , & tstamp ) ;
# else
memcpy ( & skb - > stamp , & tstamp , sizeof ( skb - > stamp ) ) ;
# endif
pmbuf - > pdesc = skb ;
pmbuf - > pbuf = skb - > head + sizeof ( mlan_buffer ) ;
pmbuf - > buf_pa = 0 ;
pmbuf - > data_offset = skb - > data - ( skb - > head + sizeof ( mlan_buffer ) ) ;
pmbuf - > data_len = skb - > len ;
pmbuf - > priority = skb - > priority ;
pmbuf - > buf_type = 0 ;
pmbuf - > in_ts_sec = ( t_u32 ) tstamp . tv_sec ;
pmbuf - > in_ts_usec = ( t_u32 ) tstamp . tv_usec ;
LEAVE ( ) ;
return ;
}
/**
* @ brief This function opens the network device for monitor interface
*
* @ param dev A pointer to net_device structure
*
* @ return 0 - - success , otherwise fail
*/
int
woal_mon_open ( struct net_device * ndev )
{
ENTER ( ) ;
LEAVE ( ) ;
return 0 ;
}
/**
* @ brief This function closes the network device for monitor interface
*
* @ param dev A pointer to net_device structure
*
* @ return 0 - - success , otherwise fail
*/
int
woal_mon_close ( struct net_device * ndev )
{
ENTER ( ) ;
LEAVE ( ) ;
return 0 ;
}
/**
* @ brief This function sets the MAC address to firmware for monitor interface
*
* @ param dev A pointer to net_device structure
* @ param addr MAC address to set
*
* @ return 0 - - success , otherwise fail
*/
int
woal_mon_set_mac_address ( struct net_device * ndev , void * addr )
{
ENTER ( ) ;
LEAVE ( ) ;
return 0 ;
}
/**
* @ brief This function sets multicast address to firmware for monitor interface
*
* @ param dev A pointer to net_device structure
*
* @ return 0 - - success , otherwise fail
*/
void
woal_mon_set_multicast_list ( struct net_device * ndev )
{
ENTER ( ) ;
LEAVE ( ) ;
}
/**
* @ brief This function handles packet transmission for monitor interface
*
* @ param skb A pointer to sk_buff structure
* @ param dev A pointer to net_device structure
*
* @ return 0 - - success , otherwise fail
*/
int
woal_mon_hard_start_xmit ( struct sk_buff * skb , struct net_device * ndev )
{
int len_rthdr ;
int qos_len = 0 ;
int dot11_hdr_len = 24 ;
int snap_len = 6 ;
unsigned char * pdata ;
unsigned short fc ;
unsigned char src_mac_addr [ 6 ] ;
unsigned char dst_mac_addr [ 6 ] ;
struct ieee80211_hdr * dot11_hdr ;
struct ieee80211_radiotap_header * prthdr =
( struct ieee80211_radiotap_header * ) skb - > data ;
monitor_iface * mon_if = netdev_priv ( ndev ) ;
ENTER ( ) ;
if ( mon_if = = NULL | | mon_if - > base_ndev = = NULL ) {
goto fail ;
}
/* check for not even having the fixed radiotap header part */
if ( unlikely ( skb - > len < sizeof ( struct ieee80211_radiotap_header ) ) ) {
PRINTM ( MERROR , " Invalid radiotap hdr length, "
" skb->len: %d \n " , skb - > len ) ;
goto fail ; /* too short to be possibly valid */
}
/* is it a header version we can trust to find length from? */
if ( unlikely ( prthdr - > it_version ) )
goto fail ; /* only version 0 is supported */
/* then there must be a radiotap header with a length we can use */
len_rthdr = ieee80211_get_radiotap_len ( skb - > data ) ;
/* does the skb contain enough to deliver on the alleged length? */
if ( unlikely ( skb - > len < len_rthdr ) ) {
PRINTM ( MERROR , " Invalid data length, "
" skb->len: %d \n " , skb - > len ) ;
goto fail ; /* skb too short for claimed rt header extent */
}
/* Skip the ratiotap header */
skb_pull ( skb , len_rthdr ) ;
dot11_hdr = ( struct ieee80211_hdr * ) skb - > data ;
fc = le16_to_cpu ( dot11_hdr - > frame_control ) ;
if ( ( fc & IEEE80211_FCTL_FTYPE ) = = IEEE80211_FTYPE_DATA ) {
/* Check if this ia a Wireless Distribution System (WDS) frame
* which has 4 MAC addresses
*/
if ( dot11_hdr - > frame_control & 0x0080 )
qos_len = 2 ;
if ( ( dot11_hdr - > frame_control & 0x0300 ) = = 0x0300 )
dot11_hdr_len + = 6 ;
memcpy ( dst_mac_addr , dot11_hdr - > addr1 , sizeof ( dst_mac_addr ) ) ;
memcpy ( src_mac_addr , dot11_hdr - > addr2 , sizeof ( src_mac_addr ) ) ;
/* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
* for two MAC addresses
*/
skb_pull ( skb ,
dot11_hdr_len + qos_len + snap_len -
sizeof ( src_mac_addr ) * 2 ) ;
pdata = ( unsigned char * ) skb - > data ;
memcpy ( pdata , dst_mac_addr , sizeof ( dst_mac_addr ) ) ;
memcpy ( pdata + sizeof ( dst_mac_addr ) , src_mac_addr ,
sizeof ( src_mac_addr ) ) ;
LEAVE ( ) ;
return woal_hard_start_xmit ( skb , mon_if - > base_ndev ) ;
}
fail :
dev_kfree_skb ( skb ) ;
LEAVE ( ) ;
return NETDEV_TX_OK ;
}
/**
* @ brief This function returns the network statistics
*
* @ param dev A pointer to net_device structure
*
* @ return A pointer to net_device_stats structure
*/
struct net_device_stats *
woal_mon_get_stats ( struct net_device * dev )
{
monitor_iface * mon_if = ( monitor_iface * ) netdev_priv ( dev ) ;
return & mon_if - > stats ;
}
static const struct net_device_ops woal_cfg80211_mon_if_ops = {
. ndo_open = woal_mon_open ,
. ndo_start_xmit = woal_mon_hard_start_xmit ,
. ndo_stop = woal_mon_close ,
. ndo_get_stats = woal_mon_get_stats ,
. ndo_set_mac_address = woal_mon_set_mac_address ,
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
. ndo_set_rx_mode = woal_mon_set_multicast_list ,
# else
. ndo_set_multicast_list = woal_mon_set_multicast_list ,
# endif
} ;
/**
* @ brief This function setup monitor interface
*
* @ param dev A pointer to net_device structure
* @ param addr MAC address to set
*
* @ return 0 - - success , otherwise fail
*/
void
woal_mon_if_setup ( struct net_device * dev )
{
ENTER ( ) ;
ether_setup ( dev ) ;
dev - > netdev_ops = & woal_cfg80211_mon_if_ops ;
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 9)
dev - > needs_free_netdev = true ;
# else
dev - > destructor = free_netdev ;
# endif
LEAVE ( ) ;
}
/**
* @ brief Request the driver to add a monitor interface
*
* @ param priv A pointer to moal_private
* @ param name Virtual interface name
* @ param name_assign_type Interface name assignment type
*
* @ return A pointer to monitor_iface
*/
monitor_iface *
woal_prepare_mon_if ( moal_private * priv ,
const char * name , unsigned char name_assign_type )
{
int ret = 0 ;
struct net_device * ndev = NULL ;
monitor_iface * mon_if = NULL ;
ENTER ( ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
ndev = alloc_netdev_mq ( sizeof ( * mon_if ) , name , name_assign_type ,
woal_mon_if_setup , 1 ) ;
# else
ndev = alloc_netdev_mq ( sizeof ( * mon_if ) , name , NET_NAME_UNKNOWN ,
woal_mon_if_setup , 1 ) ;
# endif
# else
ndev = alloc_netdev_mq ( sizeof ( * mon_if ) , name , woal_mon_if_setup , 1 ) ;
# endif
# else
ndev = alloc_netdev_mq ( sizeof ( * mon_if ) , name , woal_mon_if_setup ) ;
# endif
if ( ! ndev ) {
PRINTM ( MFATAL , " Init virtual ethernet device failed \n " ) ;
ret = - EFAULT ;
goto fail ;
}
ret = dev_alloc_name ( ndev , ndev - > name ) ;
if ( ret < 0 ) {
PRINTM ( MFATAL , " Net device alloc name fail. \n " ) ;
ret = - EFAULT ;
goto fail ;
}
//?memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
mon_if = netdev_priv ( ndev ) ;
memcpy ( mon_if - > ifname , ndev - > name , IFNAMSIZ ) ;
ndev - > type = ARPHRD_IEEE80211_RADIOTAP ;
ndev - > netdev_ops = & woal_cfg80211_mon_if_ops ;
mon_if - > priv = priv ;
mon_if - > mon_ndev = ndev ;
mon_if - > base_ndev = priv - > netdev ;
mon_if - > radiotap_enabled = 1 ;
mon_if - > flag = 1 ;
fail :
if ( ret ) {
if ( ndev )
free_netdev ( ndev ) ;
LEAVE ( ) ;
return NULL ;
}
LEAVE ( ) ;
return mon_if ;
}
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
static struct device_type wlan_type = { . name = " wlan " , } ;
# endif
# ifdef STA_SUPPORT
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
/** Network device handlers */
const struct net_device_ops woal_netdev_ops = {
. ndo_open = woal_open ,
. ndo_start_xmit = woal_hard_start_xmit ,
. ndo_stop = woal_close ,
. ndo_do_ioctl = woal_do_ioctl ,
. ndo_set_mac_address = woal_set_mac_address ,
. ndo_tx_timeout = woal_tx_timeout ,
. ndo_get_stats = woal_get_stats ,
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
. ndo_set_rx_mode = woal_set_multicast_list ,
# else
. ndo_set_multicast_list = woal_set_multicast_list ,
# endif
. ndo_select_queue = woal_select_queue ,
. ndo_validate_addr = eth_validate_addr ,
} ;
# endif
/**
* @ brief This function initializes the private structure
* and dev structure for station mode
*
* @ param dev A pointer to net_device structure
* @ param priv A pointer to moal_private structure
*
* @ return MLAN_STATUS_SUCCESS
*/
mlan_status
woal_init_sta_dev ( struct net_device * dev , moal_private * priv )
{
ENTER ( ) ;
/* Setup the OS Interface to our functions */
# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
dev - > open = woal_open ;
dev - > hard_start_xmit = woal_hard_start_xmit ;
dev - > stop = woal_close ;
dev - > do_ioctl = woal_do_ioctl ;
dev - > set_mac_address = woal_set_mac_address ;
dev - > tx_timeout = woal_tx_timeout ;
dev - > get_stats = woal_get_stats ;
dev - > set_multicast_list = woal_set_multicast_list ;
# else
dev - > netdev_ops = & woal_netdev_ops ;
# endif
dev - > watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT ;
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
dev - > needed_headroom + = MLAN_MIN_DATA_HEADER_LEN + sizeof ( mlan_buffer )
+ priv - > extra_tx_head_len ;
# else
dev - > hard_header_len + = MLAN_MIN_DATA_HEADER_LEN + sizeof ( mlan_buffer )
+ priv - > extra_tx_head_len ;
# endif
# ifdef STA_WEXT
if ( IS_STA_WEXT ( cfg80211_wext ) ) {
# if WIRELESS_EXT < 21
dev - > get_wireless_stats = woal_get_wireless_stats ;
# endif
dev - > wireless_handlers =
( struct iw_handler_def * ) & woal_handler_def ;
}
# endif
dev - > flags | = IFF_BROADCAST | IFF_MULTICAST ;
# ifdef STA_CFG80211
if ( IS_STA_CFG80211 ( cfg80211_wext ) )
init_waitqueue_head ( & priv - > ft_wait_q ) ;
# endif
# ifdef STA_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
if ( IS_STA_CFG80211 ( cfg80211_wext ) ) {
if ( host_mlme )
init_waitqueue_head ( & priv - > host_mlme_wait_q ) ;
}
# endif
# endif
LEAVE ( ) ;
return MLAN_STATUS_SUCCESS ;
}
# endif /* STA_SUPPORT */
# ifdef UAP_SUPPORT
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
/** Network device handlers */
const struct net_device_ops woal_uap_netdev_ops = {
. ndo_open = woal_open ,
. ndo_start_xmit = woal_hard_start_xmit ,
. ndo_stop = woal_close ,
. ndo_do_ioctl = woal_uap_do_ioctl ,
. ndo_set_mac_address = woal_set_mac_address ,
. ndo_tx_timeout = woal_tx_timeout ,
. ndo_get_stats = woal_get_stats ,
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
. ndo_set_rx_mode = woal_uap_set_multicast_list ,
# else
. ndo_set_multicast_list = woal_uap_set_multicast_list ,
# endif
. ndo_select_queue = woal_select_queue ,
. ndo_validate_addr = eth_validate_addr ,
} ;
# endif
/**
* @ brief This function initializes the private structure
* and dev structure for uap mode
*
* @ param dev A pointer to net_device structure
* @ param priv A pointer to moal_private structure
*
* @ return MLAN_STATUS_SUCCESS
*/
mlan_status
woal_init_uap_dev ( struct net_device * dev , moal_private * priv )
{
mlan_status status = MLAN_STATUS_SUCCESS ;
ENTER ( ) ;
/* Setup the OS Interface to our functions */
# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
dev - > open = woal_open ;
dev - > hard_start_xmit = woal_hard_start_xmit ;
dev - > stop = woal_close ;
dev - > set_mac_address = woal_set_mac_address ;
dev - > tx_timeout = woal_tx_timeout ;
dev - > get_stats = woal_get_stats ;
dev - > do_ioctl = woal_uap_do_ioctl ;
dev - > set_multicast_list = woal_uap_set_multicast_list ;
# else
dev - > netdev_ops = & woal_uap_netdev_ops ;
# endif
dev - > watchdog_timeo = MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT ;
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
dev - > needed_headroom + = MLAN_MIN_DATA_HEADER_LEN + sizeof ( mlan_buffer )
+ priv - > extra_tx_head_len ;
# else
dev - > hard_header_len + = MLAN_MIN_DATA_HEADER_LEN + sizeof ( mlan_buffer )
+ priv - > extra_tx_head_len ;
# endif
# ifdef UAP_WEXT
if ( IS_UAP_WEXT ( cfg80211_wext ) ) {
# if WIRELESS_EXT < 21
dev - > get_wireless_stats = woal_get_uap_wireless_stats ;
# endif
dev - > wireless_handlers =
( struct iw_handler_def * ) & woal_uap_handler_def ;
}
# endif /* UAP_WEXT */
dev - > flags | = IFF_BROADCAST | IFF_MULTICAST ;
LEAVE ( ) ;
return status ;
}
# endif /* UAP_SUPPORT */
/**
* @ brief This function adds a new interface . It will
* allocate , initialize and register the device .
*
* @ param handle A pointer to moal_handle structure
* @ param bss_index BSS index number
* @ param bss_type BSS type
*
* @ return A pointer to the new priv structure
*/
moal_private *
woal_add_interface ( moal_handle * handle , t_u8 bss_index , t_u8 bss_type )
{
struct net_device * dev = NULL ;
moal_private * priv = NULL ;
char name [ 256 ] ;
int i = 0 ;
# ifdef UAP_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
char csa_str [ 256 ] ;
# endif
# endif
ENTER ( ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
# define MAX_WMM_QUEUE 4
/* Allocate an Ethernet device */
dev = alloc_etherdev_mq ( sizeof ( moal_private ) , MAX_WMM_QUEUE ) ;
# else
dev = alloc_etherdev ( sizeof ( moal_private ) ) ;
# endif
if ( ! dev ) {
PRINTM ( MFATAL , " Init virtual ethernet device failed \n " ) ;
goto error ;
}
/* Allocate device name */
# ifdef STA_SUPPORT
memset ( name , 0 , sizeof ( name ) ) ;
if ( sta_name )
snprintf ( name , sizeof ( name ) , " %s%%d " , sta_name ) ;
else
snprintf ( name , sizeof ( name ) , " %s " , default_mlan_name ) ;
if ( ( bss_type = = MLAN_BSS_TYPE_STA ) & & ( dev_alloc_name ( dev , name ) < 0 ) ) {
PRINTM ( MERROR , " Could not allocate mlan device name \n " ) ;
goto error ;
}
# endif
# ifdef UAP_SUPPORT
memset ( name , 0 , sizeof ( name ) ) ;
if ( uap_name )
snprintf ( name , sizeof ( name ) , " %s%%d " , uap_name ) ;
else
snprintf ( name , sizeof ( name ) , " %s " , default_uap_name ) ;
if ( ( bss_type = = MLAN_BSS_TYPE_UAP ) & & ( dev_alloc_name ( dev , name ) < 0 ) ) {
PRINTM ( MERROR , " Could not allocate uap device name \n " ) ;
goto error ;
}
# endif
# if defined(WIFI_DIRECT_SUPPORT)
memset ( name , 0 , sizeof ( name ) ) ;
if ( wfd_name )
snprintf ( name , sizeof ( name ) , " %s%%d " , wfd_name ) ;
else
snprintf ( name , sizeof ( name ) , " %s " , default_wfd_name ) ;
if ( ( bss_type = = MLAN_BSS_TYPE_WIFIDIRECT ) & &
( dev_alloc_name ( dev , name ) < 0 ) ) {
PRINTM ( MERROR , " Could not allocate wifidirect device name \n " ) ;
goto error ;
}
# endif
memset ( name , 0 , sizeof ( name ) ) ;
if ( nan_name )
snprintf ( name , sizeof ( name ) , " %s%%d " , nan_name ) ;
else
snprintf ( name , sizeof ( name ) , " %s " , default_nan_name ) ;
if ( ( bss_type = = MLAN_BSS_TYPE_NAN ) & & ( dev_alloc_name ( dev , name ) < 0 ) ) {
PRINTM ( MERROR , " Could not allocate nan device name \n " ) ;
goto error ;
}
priv = ( moal_private * ) netdev_priv ( dev ) ;
/* Save the priv to handle */
handle - > priv [ bss_index ] = priv ;
/* Use the same handle structure */
priv - > phandle = handle ;
priv - > netdev = dev ;
priv - > bss_index = bss_index ;
priv - > bss_type = bss_type ;
priv - > extra_tx_head_len = 0 ;
if ( bss_type = = MLAN_BSS_TYPE_STA )
priv - > bss_role = MLAN_BSS_ROLE_STA ;
else if ( bss_type = = MLAN_BSS_TYPE_UAP )
priv - > bss_role = MLAN_BSS_ROLE_UAP ;
# if defined(WIFI_DIRECT_SUPPORT)
else if ( bss_type = = MLAN_BSS_TYPE_WIFIDIRECT )
priv - > bss_role = MLAN_BSS_ROLE_STA ;
# endif
else if ( bss_type = = MLAN_BSS_TYPE_NAN )
priv - > bss_role = MLAN_BSS_ROLE_STA ;
INIT_LIST_HEAD ( & priv - > tcp_sess_queue ) ;
spin_lock_init ( & priv - > tcp_sess_lock ) ;
# ifdef STA_SUPPORT
INIT_LIST_HEAD ( & priv - > tdls_list ) ;
spin_lock_init ( & priv - > tdls_lock ) ;
# endif
INIT_LIST_HEAD ( & priv - > tx_stat_queue ) ;
spin_lock_init ( & priv - > tx_stat_lock ) ;
# ifdef STA_CFG80211
# ifdef STA_SUPPORT
spin_lock_init ( & priv - > connect_lock ) ;
# endif
# endif
# ifdef STA_SUPPORT
INIT_LIST_HEAD ( & priv - > pmksa_cache_list ) ;
if ( bss_type = = MLAN_BSS_TYPE_STA ) {
init_waitqueue_head ( & priv - > okc_wait_q ) ;
spin_lock_init ( & priv - > pmksa_list_lock ) ;
priv - > okc_roaming_ie = NULL ;
priv - > okc_ie_len = 0 ;
}
# endif
# if defined(DRV_EMBEDDED_AUTHENTICATOR)
init_waitqueue_head ( & priv - > hostcmd_wait_q ) ;
# endif
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
SET_MODULE_OWNER ( dev ) ;
# endif
# ifdef STA_SUPPORT
if ( bss_type = = MLAN_BSS_TYPE_STA
# if defined(WIFI_DIRECT_SUPPORT)
| | bss_type = = MLAN_BSS_TYPE_WIFIDIRECT
# endif
| | bss_type = = MLAN_BSS_TYPE_NAN )
woal_init_sta_dev ( dev , priv ) ;
# endif
# ifdef UAP_SUPPORT
if ( bss_type = = MLAN_BSS_TYPE_UAP ) {
if ( MLAN_STATUS_SUCCESS ! = woal_init_uap_dev ( dev , priv ) )
goto error ;
}
# endif
if ( ! handle - > priv_num
# ifdef MFG_CMD_SUPPORT
& & ( mfg_mode ! = MLAN_INIT_PARA_ENABLED )
# endif
) {
if ( init_cfg ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_set_user_init_data ( handle , INIT_CFG_DATA ,
MOAL_IOCTL_WAIT ) ) {
PRINTM ( MFATAL ,
" Set user init data and param failed \n " ) ;
goto error ;
}
}
if ( init_hostcmd_cfg ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_set_user_init_data ( handle ,
INIT_HOSTCMD_CFG_DATA ,
MOAL_IOCTL_WAIT ) ) {
PRINTM ( MFATAL ,
" Set user init hostcmd data and param failed \n " ) ;
goto error ;
}
}
}
handle - > priv_num + + ;
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
if ( ! priv - > phandle - > wiphy & & IS_STA_OR_UAP_CFG80211 ( cfg80211_wext ) ) {
if ( woal_register_cfg80211 ( priv ) ) {
PRINTM ( MERROR , " Cannot register with cfg80211 \n " ) ;
goto error ;
}
}
# endif
# ifdef STA_CFG80211
# ifdef STA_SUPPORT
if ( ( priv - > bss_role = = MLAN_BSS_ROLE_STA ) & &
IS_STA_CFG80211 ( cfg80211_wext ) ) {
if ( bss_type = = MLAN_BSS_TYPE_STA
# if defined(WIFI_DIRECT_SUPPORT)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
| | bss_type = = MLAN_BSS_TYPE_WIFIDIRECT
# endif
# endif
| | bss_type = = MLAN_BSS_TYPE_NAN )
/* Register cfg80211 for STA or Wifi direct */
if ( woal_register_sta_cfg80211 ( dev , bss_type ) ) {
PRINTM ( MERROR ,
" Cannot register STA with cfg80211 \n " ) ;
goto error ;
}
}
# endif /* STA_SUPPORT */
# endif /* STA_CFG80211 */
# ifdef UAP_CFG80211
# ifdef UAP_SUPPORT
if ( ( priv - > bss_role = = MLAN_BSS_ROLE_UAP ) & &
IS_UAP_CFG80211 ( cfg80211_wext ) ) {
/* Register cfg80211 for UAP */
if ( woal_register_uap_cfg80211 ( dev , bss_type ) ) {
PRINTM ( MERROR , " Cannot register UAP with cfg80211 \n " ) ;
goto error ;
}
}
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
strcpy ( csa_str , " CSA " ) ;
strcat ( csa_str , name ) ;
priv - > csa_workqueue =
alloc_workqueue ( csa_str ,
WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND , 1 ) ;
if ( ! priv - > csa_workqueue ) {
PRINTM ( MERROR , " cannot alloc csa workqueue \n " ) ;
goto error ;
}
INIT_DELAYED_WORK ( & priv - > csa_work , woal_csa_work_queue ) ;
# endif
# endif
# endif /*UAP_CFG80211 */
/* Initialize priv structure */
woal_init_priv ( priv , MOAL_IOCTL_WAIT ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
SET_NETDEV_DEV ( dev , handle - > hotplug_device ) ;
# endif
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
SET_NETDEV_DEVTYPE ( dev , & wlan_type ) ;
# endif
/* Register network device */
if ( register_netdev ( dev ) ) {
PRINTM ( MERROR , " Cannot register virtual network device \n " ) ;
goto error ;
}
netif_carrier_off ( dev ) ;
woal_stop_queue ( dev ) ;
PRINTM ( MINFO , " %s: Marvell 802.11 Adapter \n " , dev - > name ) ;
if ( bss_type = = MLAN_BSS_TYPE_STA | |
priv - > bss_type = = MLAN_BSS_TYPE_UAP ) {
mlan_fw_info fw_info ;
woal_request_get_fw_info ( priv , MOAL_IOCTL_WAIT , & fw_info ) ;
for ( i = 0 ; i < handle - > histogram_table_num ; i + + ) {
priv - > hist_data [ i ] = kmalloc ( sizeof ( hgm_data ) +
RX_RATE_MAX *
sizeof ( atomic_t )
, GFP_KERNEL ) ;
if ( ! ( priv - > hist_data [ i ] ) ) {
PRINTM ( MERROR ,
" kmalloc priv->hist_data[%d] failed \n " ,
i ) ;
goto error ;
}
}
if ( priv - > hist_data )
woal_hist_data_reset ( priv ) ;
}
# ifdef CONFIG_PROC_FS
woal_create_proc_entry ( priv ) ;
# ifdef PROC_DEBUG
woal_debug_entry ( priv ) ;
# endif /* PROC_DEBUG */
# endif /* CONFIG_PROC_FS */
LEAVE ( ) ;
return priv ;
error :
handle - > priv_num = bss_index ;
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
/* Unregister wiphy device and free */
if ( priv ) {
if ( priv - > wdev & & IS_STA_OR_UAP_CFG80211 ( cfg80211_wext ) )
priv - > wdev = NULL ;
# ifdef UAP_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
if ( priv - > csa_workqueue ) {
destroy_workqueue ( priv - > csa_workqueue ) ;
priv - > csa_workqueue = NULL ;
}
# endif
# endif
}
# endif
if ( dev & & dev - > reg_state = = NETREG_REGISTERED )
unregister_netdev ( dev ) ;
if ( dev )
free_netdev ( dev ) ;
LEAVE ( ) ;
return NULL ;
}
/**
* @ brief This function removes an interface .
*
* @ param handle A pointer to the moal_handle structure
* @ param bss_index BSS index number
*
* @ return N / A
*/
void
woal_remove_interface ( moal_handle * handle , t_u8 bss_index )
{
struct net_device * dev = NULL ;
moal_private * priv = handle - > priv [ bss_index ] ;
# if defined(STA_WEXT) || defined(UAP_WEXT)
union iwreq_data wrqu ;
# endif
int i = 0 ;
ENTER ( ) ;
if ( ! priv | | ! priv - > netdev )
goto error ;
dev = priv - > netdev ;
if ( priv - > media_connected = = MTRUE ) {
priv - > media_connected = MFALSE ;
# if defined(STA_WEXT) || defined(UAP_WEXT)
if ( IS_STA_OR_UAP_WEXT ( cfg80211_wext ) & &
GET_BSS_ROLE ( priv ) = = MLAN_BSS_ROLE_STA ) {
memset ( wrqu . ap_addr . sa_data , 0x00 , ETH_ALEN ) ;
wrqu . ap_addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( priv - > netdev , SIOCGIWAP , & wrqu ,
NULL ) ;
}
# endif
}
woal_flush_tcp_sess_queue ( priv ) ;
woal_flush_tx_stat_queue ( priv ) ;
if ( priv - > bss_type = = MLAN_BSS_TYPE_STA )
woal_flush_tdls_list ( priv ) ;
# ifdef STA_CFG80211
if ( priv - > bss_type = = MLAN_BSS_TYPE_STA & &
IS_STA_CFG80211 ( cfg80211_wext ) ) {
woal_flush_pmksa_list ( priv ) ;
if ( priv - > okc_roaming_ie ) {
kfree ( priv - > okc_roaming_ie ) ;
priv - > okc_roaming_ie = NULL ;
priv - > okc_ie_len = 0 ;
}
}
# endif
if ( priv - > bss_type = = MLAN_BSS_TYPE_STA | |
priv - > bss_type = = MLAN_BSS_TYPE_UAP ) {
for ( i = 0 ; i < handle - > histogram_table_num ; i + + ) {
kfree ( priv - > hist_data [ i ] ) ;
priv - > hist_data [ i ] = NULL ;
}
}
# ifdef CONFIG_PROC_FS
# ifdef PROC_DEBUG
/* Remove proc debug */
woal_debug_remove ( priv ) ;
# endif /* PROC_DEBUG */
woal_proc_remove ( priv ) ;
# endif /* CONFIG_PROC_FS */
/* Last reference is our one */
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
PRINTM ( MINFO , " refcnt = %d \n " , atomic_read ( & dev - > refcnt ) ) ;
# else
PRINTM ( MINFO , " refcnt = %d \n " , netdev_refcnt_read ( dev ) ) ;
# endif
PRINTM ( MINFO , " netdev_finish_unregister: %s \n " , dev - > name ) ;
if ( dev - > reg_state = = NETREG_REGISTERED )
unregister_netdev ( dev ) ;
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
/* Unregister wiphy device and free */
if ( priv - > wdev & & IS_STA_OR_UAP_CFG80211 ( cfg80211_wext ) )
priv - > wdev = NULL ;
# ifdef UAP_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
if ( priv - > csa_workqueue ) {
flush_workqueue ( priv - > csa_workqueue ) ;
destroy_workqueue ( priv - > csa_workqueue ) ;
priv - > csa_workqueue = NULL ;
}
# endif
# endif
# endif
/* Clear the priv in handle */
priv - > phandle - > priv [ priv - > bss_index ] = NULL ;
priv - > phandle = NULL ;
priv - > netdev = NULL ;
free_netdev ( dev ) ;
error :
LEAVE ( ) ;
return ;
}
/**
* @ brief Configure pmic in firmware
*
* @ param handle A pointer to moal_handle
* @ param wait_option Wait option
*
* @ return MLAN_STATUS_SUCCESS / MLAN_STATUS_PENDING - - success ,
* otherwise fail
*/
mlan_status
woal_pmic_configure ( moal_handle * handle , t_u8 wait_option )
{
moal_private * priv = NULL ;
mlan_ioctl_req * req = NULL ;
mlan_ds_misc_cfg * misc = NULL ;
mlan_status status ;
ENTER ( ) ;
priv = woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ;
if ( ! priv ) {
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
/* Allocate an IOCTL request buffer */
req = ( mlan_ioctl_req * )
woal_alloc_mlan_ioctl_req ( sizeof ( mlan_ds_misc_cfg ) ) ;
if ( req = = NULL ) {
status = MLAN_STATUS_FAILURE ;
goto done ;
}
/* Fill request buffer */
misc = ( mlan_ds_misc_cfg * ) req - > pbuf ;
misc - > sub_command = MLAN_OID_MISC_PMIC_CFG ;
req - > req_id = MLAN_IOCTL_MISC_CFG ;
req - > action = MLAN_ACT_SET ;
/* Send IOCTL request to MLAN */
status = woal_request_ioctl ( priv , req , wait_option ) ;
done :
kfree ( req ) ;
LEAVE ( ) ;
return status ;
}
/**
* @ brief Send FW shutdown command to MLAN
*
* @ param priv A pointer to moal_private structure
* @ param wait_option Wait option
*
* @ return MLAN_STATUS_SUCCESS / MLAN_STATUS_PENDING - - success ,
* otherwise fail
*/
static mlan_status
woal_shutdown_fw ( moal_private * priv , t_u8 wait_option )
{
mlan_ioctl_req * req = NULL ;
mlan_ds_misc_cfg * misc = NULL ;
mlan_status status ;
ENTER ( ) ;
/* Allocate an IOCTL request buffer */
req = ( mlan_ioctl_req * )
woal_alloc_mlan_ioctl_req ( sizeof ( mlan_ds_misc_cfg ) ) ;
if ( req = = NULL ) {
status = MLAN_STATUS_FAILURE ;
goto done ;
}
/* Fill request buffer */
misc = ( mlan_ds_misc_cfg * ) req - > pbuf ;
misc - > sub_command = MLAN_OID_MISC_INIT_SHUTDOWN ;
misc - > param . func_init_shutdown = MLAN_FUNC_SHUTDOWN ;
req - > req_id = MLAN_IOCTL_MISC_CFG ;
req - > action = MLAN_ACT_SET ;
/* Send IOCTL request to MLAN */
status = woal_request_ioctl ( priv , req , wait_option ) ;
/* add 100 ms delay to avoid back to back init/shutdown */
mdelay ( 100 ) ;
done :
if ( status ! = MLAN_STATUS_PENDING )
kfree ( req ) ;
LEAVE ( ) ;
return status ;
}
/**
* @ brief Return hex value of a give character
*
* @ param chr Character to be converted
*
* @ return The converted character if chr is a valid hex , else 0
*/
int
woal_hexval ( char chr )
{
if ( chr > = ' 0 ' & & chr < = ' 9 ' )
return chr - ' 0 ' ;
if ( chr > = ' A ' & & chr < = ' F ' )
return chr - ' A ' + 10 ;
if ( chr > = ' a ' & & chr < = ' f ' )
return chr - ' a ' + 10 ;
return 0 ;
}
# ifdef STA_SUPPORT
# endif
/**
* @ brief This function cancel all works in the queue
* and destroy the main workqueue .
*
* @ param handle A pointer to moal_handle
*
* @ return N / A
*/
static void
woal_terminate_workqueue ( moal_handle * handle )
{
ENTER ( ) ;
/* Terminate main workqueue */
if ( handle - > workqueue ) {
flush_workqueue ( handle - > workqueue ) ;
destroy_workqueue ( handle - > workqueue ) ;
handle - > workqueue = NULL ;
}
if ( handle - > rx_workqueue ) {
flush_workqueue ( handle - > rx_workqueue ) ;
destroy_workqueue ( handle - > rx_workqueue ) ;
handle - > rx_workqueue = NULL ;
}
LEAVE ( ) ;
}
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
/**
* @ brief Function to process pre / post PCIe function level reset
*
* @ param handle A pointer to moal_handle structure
* @ param prepare True : - its a pre FLR call from the kernel
* False : - its a post FLR call from the kernel
*
* Note : This function is mix of woal_switch_drv_mode ( ) and
* remove_card ( ) . Idea is to cleanup the software only without
* touching the PCIe specific code . Likewise , during init init
* everything , including hw , but do not reinitiate PCIe stack
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
woal_do_flr ( moal_handle * handle , bool prepare )
{
unsigned int i ;
int index = 0 ;
mlan_status status = MLAN_STATUS_SUCCESS ;
moal_private * priv = NULL ;
void * card ;
int fw_serial_bkp ;
ENTER ( ) ;
if ( ! handle ) {
PRINTM ( MINFO , " \n Handle null during prepare=%d \n " , prepare ) ;
}
if ( MOAL_ACQ_SEMAPHORE_BLOCK ( & AddRemoveCardSem ) )
goto exit_sem_err ;
if ( ! prepare )
goto perform_init ;
/* Reset all interfaces */
priv = woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ;
woal_reset_intf ( priv , MOAL_IOCTL_WAIT , MTRUE ) ;
/* Shutdown firmware */
handle - > init_wait_q_woken = MFALSE ;
status = mlan_shutdown_fw ( handle - > pmlan_adapter ) ;
if ( status = = MLAN_STATUS_PENDING )
wait_event_interruptible ( handle - > init_wait_q ,
handle - > init_wait_q_woken ) ;
if ( atomic_read ( & handle - > rx_pending ) | |
atomic_read ( & handle - > tx_pending ) | |
atomic_read ( & handle - > ioctl_pending ) ) {
PRINTM ( MERROR ,
" ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d \n " ,
atomic_read ( & handle - > rx_pending ) ,
atomic_read ( & handle - > tx_pending ) ,
atomic_read ( & handle - > ioctl_pending ) ) ;
}
unregister_inetaddr_notifier ( & handle - > woal_notifier ) ;
/* Remove interface */
for ( i = 0 ; i < handle - > priv_num ; i + + )
woal_remove_interface ( handle , i ) ;
/* Unregister mlan */
if ( handle - > pmlan_adapter ) {
mlan_unregister ( handle - > pmlan_adapter ) ;
if ( atomic_read ( & handle - > lock_count ) | |
atomic_read ( & handle - > malloc_count ) | |
atomic_read ( & handle - > mbufalloc_count ) ) {
PRINTM ( MERROR , " mlan has memory leak: lock_count=%d, "
" malloc_count=%d, mbufalloc_count=%d \n " ,
atomic_read ( & handle - > lock_count ) ,
atomic_read ( & handle - > malloc_count ) ,
atomic_read ( & handle - > mbufalloc_count ) ) ;
}
if ( atomic_read ( & handle - > malloc_cons_count ) ) {
PRINTM ( MERROR ,
" mlan has memory leak: malloc_cons_count=%d \n " ,
atomic_read ( & handle - > malloc_cons_count ) ) ;
}
handle - > pmlan_adapter = NULL ;
}
goto exit ;
perform_init :
handle - > priv_num = 0 ;
/* Init SW */
if ( woal_init_sw ( handle ) ) {
PRINTM ( MFATAL , " Software Init Failed \n " ) ;
goto err_init_fw ;
}
/* Update pcie_int_mode in mlan adapter */
mlan_set_int_mode ( handle - > pmlan_adapter , pcie_int_mode ) ;
/* Init FW and HW */
/* Load wlan only binary */
fw_serial_bkp = fw_serial ;
fw_serial = 0 ;
woal_update_firmware_name ( handle ) ;
if ( woal_init_fw ( handle ) ) {
PRINTM ( MFATAL , " Firmware Init Failed \n " ) ;
woal_pcie_reg_dbg ( handle ) ;
fw_serial = fw_serial_bkp ;
goto err_init_fw ;
}
fw_serial = fw_serial_bkp ;
exit :
MOAL_REL_SEMAPHORE ( & AddRemoveCardSem ) ;
exit_sem_err :
LEAVE ( ) ;
return status ;
err_init_fw :
if ( ( handle - > hardware_status = = HardwareStatusFwReady ) | |
( handle - > hardware_status = = HardwareStatusReady ) ) {
PRINTM ( MINFO , " shutdown mlan \n " ) ;
handle - > init_wait_q_woken = MFALSE ;
status = mlan_shutdown_fw ( handle - > pmlan_adapter ) ;
if ( status = = MLAN_STATUS_PENDING )
wait_event_interruptible ( handle - > init_wait_q ,
handle - > init_wait_q_woken ) ;
}
# ifdef ANDROID_KERNEL
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
wakeup_source_trash ( & handle - > ws ) ;
# else
wake_lock_destroy ( & handle - > wake_lock ) ;
# endif
# endif
# ifdef CONFIG_PROC_FS
woal_proc_exit ( handle ) ;
# endif
/* Unregister device */
PRINTM ( MINFO , " unregister device \n " ) ;
woal_unregister_dev ( handle ) ;
handle - > surprise_removed = MTRUE ;
# ifdef REASSOCIATION
if ( handle - > reassoc_thread . pid )
wake_up_interruptible ( & handle - > reassoc_thread . wait_q ) ;
/* waiting for main thread quit */
while ( handle - > reassoc_thread . pid )
woal_sched_timeout ( 2 ) ;
# endif /* REASSOCIATION */
woal_terminate_workqueue ( handle ) ;
woal_free_moal_handle ( handle ) ;
for ( index = 0 ; index < MAX_MLAN_ADAPTER ; index + + ) {
if ( m_handle [ index ] = = handle )
break ;
}
if ( index < MAX_MLAN_ADAPTER )
m_handle [ index ] = NULL ;
card = handle - > card ;
( ( pcie_service_card * ) card ) - > handle = NULL ;
MOAL_REL_SEMAPHORE ( & AddRemoveCardSem ) ;
LEAVE ( ) ;
return ( mlan_status ) MLAN_STATUS_FAILURE ;
}
# endif
/********************************************************
Global Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ brief This function opens the network device
*
* @ param dev A pointer to net_device structure
*
* @ return 0 - - success , otherwise fail
*/
int
woal_open ( struct net_device * dev )
{
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
t_u8 carrier_on = MFALSE ;
ENTER ( ) ;
if ( priv - > phandle - > surprise_removed = = MTRUE ) {
PRINTM ( MERROR ,
" open is not allowed in surprise remove state. \n " ) ;
LEAVE ( ) ;
return - EFAULT ;
}
# if defined(SYSKT)
/* On some systems the device open handler will be called before HW ready.
Use the following flag check and wait function to work around the issue . */
{
int i = 0 ;
while ( ( priv - > phandle - > hardware_status ! = HardwareStatusReady )
& & ( i < MAX_WAIT_DEVICE_READY_COUNT ) ) {
i + + ;
woal_sched_timeout ( 100 ) ;
}
if ( i > = MAX_WAIT_DEVICE_READY_COUNT ) {
PRINTM ( MFATAL ,
" HW not ready, wlan_open() return failure \n " ) ;
LEAVE ( ) ;
return - EFAULT ;
}
}
# endif /* USB || SYSKT || SYSKT_MULTI */
if ( ! MODULE_GET ) {
LEAVE ( ) ;
return - EFAULT ;
}
# ifdef UAP_SUPPORT
if ( ( GET_BSS_ROLE ( priv ) = = MLAN_BSS_ROLE_UAP ) & &
( priv - > media_connected ) )
carrier_on = MTRUE ;
# endif
# ifdef STA_SUPPORT
if ( ( GET_BSS_ROLE ( priv ) = = MLAN_BSS_ROLE_STA ) & &
( priv - > media_connected | | priv - > is_adhoc_link_sensed ) )
carrier_on = MTRUE ;
# endif
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
if ( ! p2p_enh ) {
if ( priv - > bss_type = = MLAN_BSS_TYPE_WIFIDIRECT & &
IS_STA_CFG80211 ( cfg80211_wext ) ) {
priv - > phandle - > wiphy - > interface_modes | =
MBIT ( NL80211_IFTYPE_P2P_GO ) |
MBIT ( NL80211_IFTYPE_P2P_CLIENT ) ;
}
}
# endif
# endif
# endif
if ( carrier_on = = MTRUE ) {
if ( ! netif_carrier_ok ( priv - > netdev ) )
netif_carrier_on ( priv - > netdev ) ;
woal_wake_queue ( priv - > netdev ) ;
} else {
if ( netif_carrier_ok ( priv - > netdev ) )
netif_carrier_off ( priv - > netdev ) ;
}
LEAVE ( ) ;
return 0 ;
}
/**
* @ brief This function closes the network device
*
* @ param dev A pointer to net_device structure
*
* @ return 0
*/
int
woal_close ( struct net_device * dev )
{
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
ENTER ( ) ;
woal_flush_tx_stat_queue ( priv ) ;
# ifdef STA_SUPPORT
# ifdef STA_CFG80211
if ( IS_STA_CFG80211 ( cfg80211_wext ) & &
( priv - > bss_type = = MLAN_BSS_TYPE_STA ) )
woal_clear_conn_params ( priv ) ;
woal_cancel_scan ( priv , MOAL_IOCTL_WAIT ) ;
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
if ( IS_STA_CFG80211 ( cfg80211_wext ) & & priv - > wdev - > current_bss )
cfg80211_disconnected ( priv - > netdev , 0 , NULL , 0 ,
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
true ,
# endif
GFP_KERNEL ) ;
# endif
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
if ( IS_STA_CFG80211 ( cfg80211_wext ) & & priv - > sched_scanning ) {
woal_stop_bg_scan ( priv , MOAL_IOCTL_WAIT ) ;
priv - > bg_scan_start = MFALSE ;
priv - > bg_scan_reported = MFALSE ;
cfg80211_sched_scan_stopped ( priv - > wdev - > wiphy
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
, priv - > bg_scan_reqid
# endif
) ;
priv - > sched_scanning = MFALSE ;
}
# endif
# endif
# endif
if ( ! priv - > bss_virtual )
woal_stop_queue ( priv - > netdev ) ;
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
if ( ! p2p_enh ) {
if ( priv - > bss_type = = MLAN_BSS_TYPE_WIFIDIRECT & &
! priv - > bss_virtual & &
IS_STA_CFG80211 ( cfg80211_wext ) & &
IS_UAP_CFG80211 ( cfg80211_wext ) ) {
priv - > phandle - > wiphy - > interface_modes & =
~ ( MBIT ( NL80211_IFTYPE_P2P_GO ) |
MBIT ( NL80211_IFTYPE_P2P_CLIENT ) ) ;
}
}
# endif
# endif
# endif
MODULE_PUT ;
LEAVE ( ) ;
return 0 ;
}
/**
* @ brief This function sets the MAC address to firmware .
*
* @ param dev A pointer to mlan_private structure
* @ param addr MAC address to set
*
* @ return 0 - - success , otherwise fail
*/
int
woal_set_mac_address ( struct net_device * dev , void * addr )
{
int ret = 0 ;
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
struct sockaddr * phw_addr = ( struct sockaddr * ) addr ;
t_u8 prev_addr [ ETH_ALEN ] ;
ENTER ( ) ;
if ( priv - > phandle - > surprise_removed = = MTRUE ) {
PRINTM ( MERROR ,
" Set mac address is not allowed in surprise remove state. \n " ) ;
LEAVE ( ) ;
return - EFAULT ;
}
memcpy ( prev_addr , priv - > current_addr , ETH_ALEN ) ;
memset ( priv - > current_addr , 0 , ETH_ALEN ) ;
/* dev->dev_addr is 6 bytes */
HEXDUMP ( " dev->dev_addr: " , dev - > dev_addr , ETH_ALEN ) ;
HEXDUMP ( " addr: " , ( t_u8 * ) phw_addr - > sa_data , ETH_ALEN ) ;
memcpy ( priv - > current_addr , phw_addr - > sa_data , ETH_ALEN ) ;
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
if ( priv - > bss_type = = MLAN_BSS_TYPE_WIFIDIRECT ) {
priv - > current_addr [ 0 ] | = 0x02 ;
PRINTM ( MCMND , " Set WFD device addr: " MACSTR " \n " ,
MAC2STR ( priv - > current_addr ) ) ;
}
# endif
# endif
# endif
if ( MLAN_STATUS_SUCCESS ! = woal_request_set_mac_address ( priv ) ) {
PRINTM ( MERROR , " Set MAC address failed \n " ) ;
/* For failure restore the MAC address */
memcpy ( priv - > current_addr , prev_addr , ETH_ALEN ) ;
ret = - EFAULT ;
goto done ;
}
HEXDUMP ( " priv->MacAddr: " , priv - > current_addr , ETH_ALEN ) ;
memcpy ( dev - > dev_addr , priv - > current_addr , ETH_ALEN ) ;
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief Check driver status
*
* @ param handle A pointer to moal_handle
*
* @ return MTRUE / MFALSE
*/
t_u8
woal_check_driver_status ( moal_handle * handle )
{
moal_private * priv = NULL ;
struct timeval t ;
int i = 0 ;
ENTER ( ) ;
priv = woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ;
if ( ! priv | | woal_get_debug_info ( priv , MOAL_IOCTL_WAIT , & info ) ) {
PRINTM ( MERROR ,
" Could not retrieve debug information from MLAN \n " ) ;
LEAVE ( ) ;
return MTRUE ;
}
# define MOAL_CMD_TIMEOUT_MAX 9
# define MOAL_CMD_TIMEOUT 20
woal_get_monotonic_time ( & t ) ;
if ( info . pending_cmd & &
( t . tv_sec > ( info . dnld_cmd_in_secs + MOAL_CMD_TIMEOUT_MAX ) ) ) {
if ( t . tv_sec > ( info . dnld_cmd_in_secs + MOAL_CMD_TIMEOUT ) & &
! info . num_cmd_timeout ) {
PRINTM ( MERROR , " Ignore invalid time, wait=%d \n " ,
( int ) ( t . tv_sec - info . dnld_cmd_in_secs ) ) ;
} else {
PRINTM ( MERROR , " Timeout cmd id = 0x%x wait=%d \n " ,
info . pending_cmd ,
( int ) ( t . tv_sec - info . dnld_cmd_in_secs ) ) ;
LEAVE ( ) ;
return MTRUE ;
}
}
if ( info . num_cmd_timeout ) {
PRINTM ( MERROR , " num_cmd_timeout = %d \n " , info . num_cmd_timeout ) ;
PRINTM ( MERROR , " Timeout cmd id = 0x%x, act = 0x%x \n " ,
info . timeout_cmd_id , info . timeout_cmd_act ) ;
LEAVE ( ) ;
return MTRUE ;
}
if ( info . num_cmd_host_to_card_failure ) {
PRINTM ( MERROR , " num_cmd_host_to_card_failure = %d \n " ,
info . num_cmd_host_to_card_failure ) ;
LEAVE ( ) ;
return MTRUE ;
}
if ( info . num_no_cmd_node ) {
PRINTM ( MERROR , " num_no_cmd_node = %d \n " , info . num_no_cmd_node ) ;
LEAVE ( ) ;
return MTRUE ;
}
for ( i = 0 ; i < handle - > priv_num ; i + + ) {
priv = handle - > priv [ i ] ;
if ( priv ) {
if ( priv - > num_tx_timeout > = NUM_TX_TIMEOUT_THRESHOLD ) {
PRINTM ( MERROR , " num_tx_timeout = %d \n " ,
priv - > num_tx_timeout ) ;
LEAVE ( ) ;
return MTRUE ;
}
}
}
if ( info . pm_wakeup_card_req & & info . pm_wakeup_fw_try ) {
# define MAX_WAIT_TIME 3
if ( t . tv_sec > ( info . pm_wakeup_in_secs + MAX_WAIT_TIME ) ) {
PRINTM ( MERROR ,
" wakeup_dev_req=%d wakeup_tries=%d wait=%d \n " ,
info . pm_wakeup_card_req , info . pm_wakeup_fw_try ,
( int ) ( t . tv_sec - info . pm_wakeup_in_secs ) ) ;
LEAVE ( ) ;
return MTRUE ;
}
}
if ( info . fw_hang_report ) {
PRINTM ( MERROR , " fw_hang_report = %d \n " , info . fw_hang_report ) ;
LEAVE ( ) ;
return MTRUE ;
}
if ( priv - > phandle - > driver_state ) {
LEAVE ( ) ;
return MTRUE ;
}
LEAVE ( ) ;
return MFALSE ;
}
/**
* @ brief Display MLAN debug information
*
* @ param priv A pointer to moal_private
*
* @ return N / A
*/
void
woal_mlan_debug_info ( moal_private * priv )
{
int i ;
char str [ 512 ] = { 0 } ;
char * s ;
ENTER ( ) ;
if ( ! priv | | woal_get_debug_info ( priv , MOAL_IOCTL_WAIT , & info ) ) {
PRINTM ( MERROR ,
" Could not retrieve debug information from MLAN \n " ) ;
LEAVE ( ) ;
return ;
}
PRINTM ( MERROR , " ------------mlan_debug_info------------- \n " ) ;
PRINTM ( MERROR , " mlan_processing =%d \n " , info . mlan_processing ) ;
PRINTM ( MERROR , " main_lock_flag =%d \n " , info . main_lock_flag ) ;
PRINTM ( MERROR , " main_process_cnt =%d \n " , info . main_process_cnt ) ;
PRINTM ( MERROR , " delay_task_flag =%d \n " , info . delay_task_flag ) ;
PRINTM ( MERROR , " mlan_rx_processing =%d \n " , info . mlan_rx_processing ) ;
PRINTM ( MERROR , " rx_pkts_queued=%d \n " , info . rx_pkts_queued ) ;
PRINTM ( MERROR , " tx_pkts_queued=%d \n " , info . tx_pkts_queued ) ;
PRINTM ( MERROR , " num_cmd_timeout = %d \n " , info . num_cmd_timeout ) ;
PRINTM ( MERROR , " dbg.num_cmd_timeout = %d \n " , info . dbg_num_cmd_timeout ) ;
PRINTM ( MERROR , " Timeout cmd id = 0x%x, act = 0x%x \n " ,
info . timeout_cmd_id , info . timeout_cmd_act ) ;
PRINTM ( MERROR , " last_cmd_index = %d \n " , info . last_cmd_index ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_cmd_id [ i ] ) ;
PRINTM ( MERROR , " last_cmd_id = %s \n " , str ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_cmd_act [ i ] ) ;
PRINTM ( MERROR , " last_cmd_act = %s \n " , str ) ;
PRINTM ( MERROR , " last_cmd_resp_index = %d \n " , info . last_cmd_resp_index ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_cmd_resp_id [ i ] ) ;
PRINTM ( MERROR , " last_cmd_resp_id = %s \n " , str ) ;
PRINTM ( MERROR , " last_event_index = %d \n " , info . last_event_index ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_event [ i ] ) ;
PRINTM ( MERROR , " last_event = %s " , str ) ;
PRINTM ( MERROR , " num_data_h2c_failure = %d \n " ,
info . num_tx_host_to_card_failure ) ;
PRINTM ( MERROR , " num_cmd_h2c_failure = %d \n " ,
info . num_cmd_host_to_card_failure ) ;
PRINTM ( MERROR , " num_alloc_buffer_failure = %d \n " ,
info . num_alloc_buffer_failure ) ;
PRINTM ( MERROR , " num_pkt_dropped = %d \n " , info . num_pkt_dropped ) ;
PRINTM ( MERROR , " num_event_deauth = %d \n " , info . num_event_deauth ) ;
PRINTM ( MERROR , " num_event_disassoc = %d \n " , info . num_event_disassoc ) ;
PRINTM ( MERROR , " num_event_link_lost = %d \n " , info . num_event_link_lost ) ;
PRINTM ( MERROR , " num_cmd_deauth = %d \n " , info . num_cmd_deauth ) ;
PRINTM ( MERROR , " num_cmd_assoc_success = %d \n " ,
info . num_cmd_assoc_success ) ;
PRINTM ( MERROR , " num_cmd_assoc_failure = %d \n " ,
info . num_cmd_assoc_failure ) ;
PRINTM ( MERROR , " cmd_resp_received = %d \n " , info . cmd_resp_received ) ;
PRINTM ( MERROR , " event_received = %d \n " , info . event_received ) ;
PRINTM ( MERROR , " max_tx_buf_size = %d \n " , info . max_tx_buf_size ) ;
PRINTM ( MERROR , " tx_buf_size = %d \n " , info . tx_buf_size ) ;
PRINTM ( MERROR , " curr_tx_buf_size = %d \n " , info . curr_tx_buf_size ) ;
PRINTM ( MERROR , " data_sent=%d cmd_sent=%d \n " , info . data_sent ,
info . cmd_sent ) ;
PRINTM ( MERROR , " ps_mode=%d ps_state=%d \n " , info . ps_mode , info . ps_state ) ;
PRINTM ( MERROR , " wakeup_dev_req=%d wakeup_tries=%d \n " ,
info . pm_wakeup_card_req , info . pm_wakeup_fw_try ) ;
PRINTM ( MERROR , " hs_configured=%d hs_activated=%d \n " ,
info . is_hs_configured , info . hs_activated ) ;
PRINTM ( MERROR , " pps_uapsd_mode=%d sleep_pd=%d \n " ,
info . pps_uapsd_mode , info . sleep_pd ) ;
PRINTM ( MERROR , " tx_lock_flag = %d \n " , info . tx_lock_flag ) ;
PRINTM ( MERROR , " port_open = %d \n " , info . port_open ) ;
PRINTM ( MERROR , " scan_processing = %d \n " , info . scan_processing ) ;
for ( i = 0 ; i < info . ralist_num ; i + + ) {
PRINTM ( MERROR ,
" ralist ra: %02x:%02x:%02x:%02x:%02x:%02x tid=%d pkts=%d pause=%d \n " ,
info . ralist [ i ] . ra [ 0 ] , info . ralist [ i ] . ra [ 1 ] ,
info . ralist [ i ] . ra [ 2 ] , info . ralist [ i ] . ra [ 3 ] ,
info . ralist [ i ] . ra [ 4 ] , info . ralist [ i ] . ra [ 5 ] ,
info . ralist [ i ] . tid , info . ralist [ i ] . total_pkts ,
info . ralist [ i ] . tx_pause ) ;
}
PRINTM ( MERROR , " txbd: rdptr=0x%x wrptr=0x%x \n " ,
info . txbd_rdptr , info . txbd_wrptr ) ;
PRINTM ( MERROR , " rxbd: rdptr=0x%x wrptr=0x%x \n " ,
info . rxbd_rdptr , info . rxbd_wrptr ) ;
PRINTM ( MERROR , " eventbd: rdptr=0x%x wrptr=0x%x \n " ,
info . eventbd_rdptr , info . eventbd_wrptr ) ;
PRINTM ( MERROR , " ------------mlan_debug_info End------------- \n " ) ;
LEAVE ( ) ;
}
/**
* @ brief This function handle the shutdown timeout issue
*
* @ param handle Pointer to structure moal_handle
*
* @ return N / A
*/
void
woal_ioctl_timeout ( moal_handle * handle )
{
moal_private * priv = NULL ;
ENTER ( ) ;
PRINTM ( MMSG , " woal_ioctl_timout. \n " ) ;
priv = woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ;
if ( priv ) {
woal_mlan_debug_info ( priv ) ;
woal_moal_debug_info ( priv , NULL , MFALSE ) ;
}
LEAVE ( ) ;
return ;
}
/**
* @ brief This function handles the timeout of packet
* transmission
*
* @ param dev A pointer to net_device structure
*
* @ return N / A
*/
void
woal_tx_timeout ( struct net_device * dev )
{
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
ENTER ( ) ;
priv - > num_tx_timeout + + ;
PRINTM ( MERROR , " %lu : %s (bss=%d): Tx timeout (%d) \n " ,
jiffies , dev - > name , priv - > bss_index , priv - > num_tx_timeout ) ;
woal_set_trans_start ( dev ) ;
if ( priv - > num_tx_timeout = = NUM_TX_TIMEOUT_THRESHOLD ) {
woal_mlan_debug_info ( priv ) ;
woal_moal_debug_info ( priv , NULL , MFALSE ) ;
woal_broadcast_event ( priv , CUS_EVT_DRIVER_HANG ,
strlen ( CUS_EVT_DRIVER_HANG ) ) ;
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
if ( IS_STA_OR_UAP_CFG80211 ( cfg80211_wext ) )
woal_cfg80211_vendor_event ( priv , event_hang ,
CUS_EVT_DRIVER_HANG ,
strlen ( CUS_EVT_DRIVER_HANG ) ) ;
# endif
# endif
priv - > phandle - > driver_state = MTRUE ;
woal_process_hang ( priv - > phandle ) ;
}
LEAVE ( ) ;
}
/**
* @ brief This function returns the network statistics
*
* @ param dev A pointer to net_device structure
*
* @ return A pointer to net_device_stats structure
*/
struct net_device_stats *
woal_get_stats ( struct net_device * dev )
{
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
return & priv - > stats ;
}
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
/**
* @ brief This function handles wmm queue select
*
* @ param dev A pointer to net_device structure
* @ param skb A pointer to sk_buff structure
*
* @ return tx_queue index ( 0 - 3 )
*/
u16
woal_select_queue ( struct net_device * dev , struct sk_buff * skb
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
, struct net_device * sb_dev
# else
, void * accel_priv
# endif
2020-01-13 02:21:55 +00:00
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0))
2020-01-13 02:09:32 +00:00
, select_queue_fallback_t fallback
# endif
# endif
)
{
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
struct ethhdr * eth = NULL ;
t_u8 tid = 0 ;
t_u8 index = 0 ;
ENTER ( ) ;
/*
* skb - > priority values from 256 - > 263 are magic values to
* directly indicate a specific 802.1 d priority . This is used
* to allow 802.1 d priority to be passed directly in from VLAN
* tags , etc .
*/
if ( IS_SKB_MAGIC_VLAN ( skb ) ) {
tid = GET_VLAN_PRIO ( skb ) ;
} else {
eth = ( struct ethhdr * ) skb - > data ;
switch ( eth - > h_proto ) {
case __constant_htons ( ETH_P_IP ) :
tid = priv - > dscp_map [ SKB_TOS ( skb ) > > DSCP_OFFSET ] ;
if ( tid = = 0xFF )
tid = ( IPTOS_PREC ( SKB_TOS ( skb ) ) > >
IPTOS_OFFSET ) ;
break ;
case __constant_htons ( ETH_P_IPV6 ) :
tid = SKB_TIDV6 ( skb ) ;
break ;
case __constant_htons ( ETH_P_ARP ) :
default :
break ;
}
}
index = mlan_select_wmm_queue ( priv - > phandle - > pmlan_adapter ,
priv - > bss_index , tid ) ;
PRINTM ( MDATA , " select queue: tid=%d, index=%d \n " , tid , index ) ;
LEAVE ( ) ;
return index ;
}
# endif
/**
* @ brief This function flush tx status queue
*
* @ param priv A pointer to moal_private structure
*
* @ return N / A
*/
void
woal_flush_tx_stat_queue ( moal_private * priv )
{
struct tx_status_info * tx_info = NULL , * tmp_node ;
unsigned long flags ;
struct sk_buff * skb = NULL ;
spin_lock_irqsave ( & priv - > tx_stat_lock , flags ) ;
list_for_each_entry_safe ( tx_info , tmp_node , & priv - > tx_stat_queue , link ) {
list_del ( & tx_info - > link ) ;
spin_unlock_irqrestore ( & priv - > tx_stat_lock , flags ) ;
skb = ( struct sk_buff * ) tx_info - > tx_skb ;
if ( tx_info - > tx_cookie ) {
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
# if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
cfg80211_mgmt_tx_status ( priv - > netdev ,
tx_info - > tx_cookie , skb - > data ,
skb - > len , true , GFP_ATOMIC ) ;
# else
cfg80211_mgmt_tx_status ( priv - > wdev , tx_info - > tx_cookie ,
skb - > data , skb - > len , true ,
GFP_ATOMIC ) ;
# endif
# endif
# endif
}
dev_kfree_skb_any ( skb ) ;
kfree ( tx_info ) ;
spin_lock_irqsave ( & priv - > tx_stat_lock , flags ) ;
}
INIT_LIST_HEAD ( & priv - > tx_stat_queue ) ;
spin_unlock_irqrestore ( & priv - > tx_stat_lock , flags ) ;
}
/**
* @ brief This function gets tx info from tx_stat_queue
*
* @ param priv A pointer to moal_private structure
* @ param tx_seq_num tx seq number
*
* @ return A pointer to the tcp tx_status_info structure , if found .
* Otherwise , null
*/
struct tx_status_info *
woal_get_tx_info ( moal_private * priv , t_u8 tx_seq_num )
{
struct tx_status_info * tx_info = NULL ;
ENTER ( ) ;
list_for_each_entry ( tx_info , & priv - > tx_stat_queue , link ) {
if ( tx_info - > tx_seq_num = = tx_seq_num ) {
LEAVE ( ) ;
return tx_info ;
}
}
LEAVE ( ) ;
return NULL ;
}
/**
* @ brief This function remove tx info from queue
*
* @ param priv A pointer to moal_private structure
* @ param tx_seq_num tx seq number
*
* @ return N / A
*/
void
woal_remove_tx_info ( moal_private * priv , t_u8 tx_seq_num )
{
struct tx_status_info * tx_info , * tmp = NULL ;
unsigned long flags ;
ENTER ( ) ;
spin_lock_irqsave ( & priv - > tx_stat_lock , flags ) ;
list_for_each_entry_safe ( tx_info , tmp , & priv - > tx_stat_queue , link ) {
if ( tx_info - > tx_seq_num = = tx_seq_num ) {
list_del ( & tx_info - > link ) ;
dev_kfree_skb_any ( ( struct sk_buff * ) tx_info - > tx_skb ) ;
kfree ( tx_info ) ;
break ;
}
}
spin_unlock_irqrestore ( & priv - > tx_stat_lock , flags ) ;
LEAVE ( ) ;
}
/**
* @ brief This function flush tcp session queue
*
* @ param priv A pointer to moal_private structure
*
* @ return N / A
*/
void
woal_flush_tdls_list ( moal_private * priv )
{
struct tdls_peer * peer = NULL , * tmp_node ;
unsigned long flags ;
spin_lock_irqsave ( & priv - > tdls_lock , flags ) ;
list_for_each_entry_safe ( peer , tmp_node , & priv - > tdls_list , link ) {
list_del ( & peer - > link ) ;
kfree ( peer ) ;
}
INIT_LIST_HEAD ( & priv - > tdls_list ) ;
spin_unlock_irqrestore ( & priv - > tdls_lock , flags ) ;
priv - > tdls_check_tx = MFALSE ;
}
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
/**
* @ brief check the tx packet for tdls auto set up
*
* @ param priv A pointer to moal_private structure
* @ param skb A pointer to skb buffer .
*
* @ return N / A
*/
void
woal_tdls_check_tx ( moal_private * priv , struct sk_buff * skb )
{
struct tdls_peer * peer = NULL ;
unsigned long flags ;
t_u8 ra [ MLAN_MAC_ADDR_LENGTH ] ;
ENTER ( ) ;
memcpy ( ra , skb - > data , MLAN_MAC_ADDR_LENGTH ) ;
spin_lock_irqsave ( & priv - > tdls_lock , flags ) ;
list_for_each_entry ( peer , & priv - > tdls_list , link ) {
if ( ! memcmp ( peer - > peer_addr , ra , ETH_ALEN ) ) {
if ( peer - > rssi & &
( peer - > rssi < = TDLS_RSSI_HIGH_THRESHOLD ) ) {
if ( ( peer - > link_status = = TDLS_NOT_SETUP ) & &
( peer - > num_failure <
TDLS_MAX_FAILURE_COUNT ) ) {
peer - > link_status =
TDLS_SETUP_INPROGRESS ;
PRINTM ( MMSG ,
" Wlan: Set up TDLS link,peer= "
MACSTR " rssi=%d \n " ,
MAC2STR ( peer - > peer_addr ) ,
- peer - > rssi ) ;
cfg80211_tdls_oper_request ( priv - > netdev ,
peer - >
peer_addr ,
NL80211_TDLS_SETUP ,
0 ,
GFP_ATOMIC ) ;
priv - > tdls_check_tx = MFALSE ;
}
}
break ;
}
}
spin_unlock_irqrestore ( & priv - > tdls_lock , flags ) ;
LEAVE ( ) ;
}
# endif
/**
* @ brief This function flush tcp session queue
*
* @ param priv A pointer to moal_private structure
*
* @ return N / A
*/
void
woal_flush_tcp_sess_queue ( moal_private * priv )
{
struct tcp_sess * tcp_sess = NULL , * tmp_node ;
unsigned long flags ;
struct sk_buff * skb ;
spin_lock_irqsave ( & priv - > tcp_sess_lock , flags ) ;
list_for_each_entry_safe ( tcp_sess , tmp_node , & priv - > tcp_sess_queue ,
link ) {
list_del ( & tcp_sess - > link ) ;
if ( tcp_sess - > is_timer_set )
woal_cancel_timer ( & tcp_sess - > ack_timer ) ;
skb = ( struct sk_buff * ) tcp_sess - > ack_skb ;
if ( skb )
dev_kfree_skb_any ( skb ) ;
kfree ( tcp_sess ) ;
}
INIT_LIST_HEAD ( & priv - > tcp_sess_queue ) ;
priv - > tcp_ack_drop_cnt = 0 ;
priv - > tcp_ack_cnt = 0 ;
spin_unlock_irqrestore ( & priv - > tcp_sess_lock , flags ) ;
}
/**
* @ brief This function gets tcp session from the tcp session queue
*
* @ param priv A pointer to moal_private structure
* @ param src_ip IP address of the device
* @ param src_port TCP port of the device
* @ param dst_ip IP address of the client
* @ param dst_port TCP port of the client
*
* @ return A pointer to the tcp session data structure , if found .
* Otherwise , null
*/
static inline struct tcp_sess *
woal_get_tcp_sess ( moal_private * priv ,
t_u32 src_ip , t_u16 src_port , t_u32 dst_ip , t_u16 dst_port )
{
struct tcp_sess * tcp_sess = NULL ;
ENTER ( ) ;
list_for_each_entry ( tcp_sess , & priv - > tcp_sess_queue , link ) {
if ( ( tcp_sess - > src_ip_addr = = src_ip ) & &
( tcp_sess - > src_tcp_port = = src_port ) & &
( tcp_sess - > dst_ip_addr = = dst_ip ) & &
( tcp_sess - > dst_tcp_port = = dst_port ) ) {
LEAVE ( ) ;
return tcp_sess ;
}
}
LEAVE ( ) ;
return NULL ;
}
/**
* @ brief This function send the holding tcp ack packet
* re - assoc thread .
*
* @ param context A pointer to context
* @ return N / A
*/
void
woal_tcp_ack_timer_func ( void * context )
{
struct tcp_sess * tcp_session = ( struct tcp_sess * ) context ;
moal_private * priv = ( moal_private * ) tcp_session - > priv ;
unsigned long flags ;
mlan_buffer * pmbuf ;
struct sk_buff * skb ;
mlan_status status ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
t_u32 index = 0 ;
# endif
ENTER ( ) ;
spin_lock_irqsave ( & priv - > tcp_sess_lock , flags ) ;
tcp_session - > is_timer_set = MFALSE ;
skb = ( struct sk_buff * ) tcp_session - > ack_skb ;
pmbuf = ( mlan_buffer * ) tcp_session - > pmbuf ;
tcp_session - > ack_skb = NULL ;
tcp_session - > pmbuf = NULL ;
spin_unlock_irqrestore ( & priv - > tcp_sess_lock , flags ) ;
if ( skb & & pmbuf ) {
status = mlan_send_packet ( priv - > phandle - > pmlan_adapter , pmbuf ) ;
switch ( status ) {
case MLAN_STATUS_PENDING :
atomic_inc ( & priv - > phandle - > tx_pending ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
index = skb_get_queue_mapping ( skb ) ;
atomic_inc ( & priv - > wmm_tx_pending [ index ] ) ;
if ( atomic_read ( & priv - > wmm_tx_pending [ index ] ) > =
MAX_TX_PENDING ) {
struct netdev_queue * txq =
netdev_get_tx_queue ( priv - > netdev ,
index ) ;
netif_tx_stop_queue ( txq ) ;
PRINTM ( MINFO , " Stop Kernel Queue : %d \n " ,
index ) ;
}
# else
if ( atomic_read ( & priv - > phandle - > tx_pending ) > =
MAX_TX_PENDING )
woal_stop_queue ( priv - > netdev ) ;
# endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
queue_work ( priv - > phandle - > workqueue ,
& priv - > phandle - > main_work ) ;
break ;
case MLAN_STATUS_SUCCESS :
priv - > stats . tx_packets + + ;
priv - > stats . tx_bytes + = skb - > len ;
dev_kfree_skb_any ( skb ) ;
break ;
case MLAN_STATUS_FAILURE :
default :
priv - > stats . tx_dropped + + ;
dev_kfree_skb_any ( skb ) ;
break ;
}
}
LEAVE ( ) ;
return ;
}
/**
* @ brief This function send the tcp ack
*
*
* @ param priv A pointer to moal_private structure
* @ param tcp_session A pointer to tcp_session
* @ return N / A
*/
void
woal_send_tcp_ack ( moal_private * priv , struct tcp_sess * tcp_session )
{
mlan_status status ;
struct sk_buff * skb = ( struct sk_buff * ) tcp_session - > ack_skb ;
mlan_buffer * pmbuf = ( mlan_buffer * ) tcp_session - > pmbuf ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
t_u32 index = 0 ;
# endif
ENTER ( ) ;
if ( tcp_session - > is_timer_set ) {
woal_cancel_timer ( & tcp_session - > ack_timer ) ;
tcp_session - > is_timer_set = MFALSE ;
}
tcp_session - > ack_skb = NULL ;
tcp_session - > pmbuf = NULL ;
status = mlan_send_packet ( priv - > phandle - > pmlan_adapter , pmbuf ) ;
switch ( status ) {
case MLAN_STATUS_PENDING :
atomic_inc ( & priv - > phandle - > tx_pending ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
index = skb_get_queue_mapping ( skb ) ;
atomic_inc ( & priv - > wmm_tx_pending [ index ] ) ;
if ( atomic_read ( & priv - > wmm_tx_pending [ index ] ) > = MAX_TX_PENDING ) {
struct netdev_queue * txq =
netdev_get_tx_queue ( priv - > netdev , index ) ;
netif_tx_stop_queue ( txq ) ;
PRINTM ( MINFO , " Stop Kernel Queue : %d \n " , index ) ;
}
# else
if ( atomic_read ( & priv - > phandle - > tx_pending ) > = MAX_TX_PENDING )
woal_stop_queue ( priv - > netdev ) ;
# endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
queue_work ( priv - > phandle - > workqueue , & priv - > phandle - > main_work ) ;
break ;
case MLAN_STATUS_SUCCESS :
priv - > stats . tx_packets + + ;
priv - > stats . tx_bytes + = skb - > len ;
dev_kfree_skb_any ( skb ) ;
break ;
case MLAN_STATUS_FAILURE :
default :
priv - > stats . tx_dropped + + ;
dev_kfree_skb_any ( skb ) ;
break ;
}
LEAVE ( ) ;
}
/**
* @ brief This function get the tcp ack session node
*
* @ param priv A pointer to moal_private structure
* @ param pmbuf A pointer to mlan_buffer associated with a skb
*
* @ return 1 , if it ' s dropped ; 0 , if not dropped
*/
int
woal_process_tcp_ack ( moal_private * priv , mlan_buffer * pmbuf )
{
int ret = 0 ;
unsigned long flags ;
struct tcp_sess * tcp_session ;
struct ethhdr * ethh = NULL ;
struct iphdr * iph = NULL ;
struct tcphdr * tcph = NULL ;
t_u32 ack_seq ;
struct sk_buff * skb ;
ENTER ( ) ;
/** check the tcp packet */
ethh = ( struct ethhdr * ) ( pmbuf - > pbuf + pmbuf - > data_offset ) ;
if ( ntohs ( ethh - > h_proto ) ! = ETH_P_IP ) {
LEAVE ( ) ;
return 0 ;
}
iph = ( struct iphdr * ) ( ( t_u8 * ) ethh + sizeof ( struct ethhdr ) ) ;
if ( iph - > protocol ! = IPPROTO_TCP ) {
LEAVE ( ) ;
return 0 ;
}
tcph = ( struct tcphdr * ) ( ( t_u8 * ) iph + iph - > ihl * 4 ) ;
if ( * ( ( t_u8 * ) tcph + 13 ) = = 0x10 ) {
/* Only replace ACK */
if ( ntohs ( iph - > tot_len ) > ( iph - > ihl + tcph - > doff ) * 4 ) {
/* Don't drop ACK with payload */
/* TODO: should we delete previous TCP session */
LEAVE ( ) ;
return ret ;
}
priv - > tcp_ack_cnt + + ;
spin_lock_irqsave ( & priv - > tcp_sess_lock , flags ) ;
tcp_session = woal_get_tcp_sess ( priv , iph - > saddr ,
tcph - > source , iph - > daddr ,
tcph - > dest ) ;
if ( ! tcp_session ) {
tcp_session =
kmalloc ( sizeof ( struct tcp_sess ) , GFP_ATOMIC ) ;
if ( ! tcp_session ) {
PRINTM ( MERROR , " Fail to allocate tcp_sess. \n " ) ;
spin_unlock_irqrestore ( & priv - > tcp_sess_lock ,
flags ) ;
goto done ;
}
tcp_session - > ack_skb = pmbuf - > pdesc ;
tcp_session - > pmbuf = pmbuf ;
pmbuf - > flags | = MLAN_BUF_FLAG_TCP_ACK ;
tcp_session - > src_ip_addr = iph - > saddr ;
tcp_session - > dst_ip_addr = iph - > daddr ;
tcp_session - > src_tcp_port = tcph - > source ;
tcp_session - > dst_tcp_port = tcph - > dest ;
tcp_session - > ack_seq = ntohl ( tcph - > ack_seq ) ;
tcp_session - > priv = ( void * ) priv ;
skb = ( struct sk_buff * ) pmbuf - > pdesc ;
skb - > cb [ 0 ] = 0 ;
/* Initialize the timer for tcp ack */
woal_initialize_timer ( & tcp_session - > ack_timer ,
woal_tcp_ack_timer_func ,
tcp_session ) ;
tcp_session - > is_timer_set = MTRUE ;
woal_mod_timer ( & tcp_session - > ack_timer , MOAL_TIMER_1MS ) ;
list_add_tail ( & tcp_session - > link ,
& priv - > tcp_sess_queue ) ;
spin_unlock_irqrestore ( & priv - > tcp_sess_lock , flags ) ;
ret = HOLD_TCP_ACK ;
LEAVE ( ) ;
return ret ;
} else if ( ! tcp_session - > ack_skb ) {
tcp_session - > ack_skb = pmbuf - > pdesc ;
tcp_session - > pmbuf = pmbuf ;
pmbuf - > flags | = MLAN_BUF_FLAG_TCP_ACK ;
tcp_session - > ack_seq = ntohl ( tcph - > ack_seq ) ;
tcp_session - > priv = ( void * ) priv ;
skb = ( struct sk_buff * ) pmbuf - > pdesc ;
skb - > cb [ 0 ] = 0 ;
tcp_session - > is_timer_set = MTRUE ;
woal_mod_timer ( & tcp_session - > ack_timer , MOAL_TIMER_1MS ) ;
spin_unlock_irqrestore ( & priv - > tcp_sess_lock , flags ) ;
ret = HOLD_TCP_ACK ;
LEAVE ( ) ;
return ret ;
}
ack_seq = ntohl ( tcph - > ack_seq ) ;
skb = ( struct sk_buff * ) tcp_session - > ack_skb ;
if ( likely ( ack_seq > tcp_session - > ack_seq ) & &
( skb - > len = = pmbuf - > data_len ) ) {
memcpy ( skb - > data , pmbuf - > pbuf + pmbuf - > data_offset ,
pmbuf - > data_len ) ;
tcp_session - > ack_seq = ack_seq ;
ret = DROP_TCP_ACK ;
skb - > cb [ 0 ] + + ;
//We will drop 90% tcp ack
# define TCP_ACK_MAX_HOLD 9
if ( skb - > cb [ 0 ] > = TCP_ACK_MAX_HOLD )
woal_send_tcp_ack ( priv , tcp_session ) ;
spin_unlock_irqrestore ( & priv - > tcp_sess_lock , flags ) ;
skb = ( struct sk_buff * ) pmbuf - > pdesc ;
dev_kfree_skb_any ( skb ) ;
priv - > tcp_ack_drop_cnt + + ;
} else {
pmbuf - > flags | = MLAN_BUF_FLAG_TCP_ACK ;
spin_unlock_irqrestore ( & priv - > tcp_sess_lock , flags ) ;
LEAVE ( ) ;
return ret ;
}
}
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function handles packet transmission
*
* @ param skb A pointer to sk_buff structure
* @ param dev A pointer to net_device structure
*
* @ return 0 - - success
*/
int
woal_hard_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
mlan_buffer * pmbuf = NULL ;
mlan_status status ;
struct sk_buff * new_skb = NULL ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
t_u32 index = 0 ;
# endif
int ret = 0 ;
ENTER ( ) ;
PRINTM ( MDATA , " %lu : %s (bss=%d): Data <= kernel \n " ,
jiffies , dev - > name , priv - > bss_index ) ;
if ( priv - > phandle - > surprise_removed = = MTRUE ) {
dev_kfree_skb_any ( skb ) ;
priv - > stats . tx_dropped + + ;
goto done ;
}
priv - > num_tx_timeout = 0 ;
if ( ! skb - > len | | ( skb - > len > ETH_FRAME_LEN ) ) {
PRINTM ( MERROR , " Tx Error: Bad skb length %d : %d \n " ,
skb - > len , ETH_FRAME_LEN ) ;
dev_kfree_skb_any ( skb ) ;
priv - > stats . tx_dropped + + ;
goto done ;
}
if ( skb - > cloned | | ( skb_headroom ( skb ) < ( MLAN_MIN_DATA_HEADER_LEN +
sizeof ( mlan_buffer ) +
priv - > extra_tx_head_len ) ) ) {
PRINTM ( MWARN ,
" Tx: skb cloned %d or Insufficient skb headroom %d \n " ,
skb - > cloned , skb_headroom ( skb ) ) ;
/* Insufficient skb headroom - allocate a new skb */
new_skb = skb_realloc_headroom ( skb , MLAN_MIN_DATA_HEADER_LEN +
sizeof ( mlan_buffer ) +
priv - > extra_tx_head_len ) ;
if ( unlikely ( ! new_skb ) ) {
PRINTM ( MERROR , " Tx: Cannot allocate skb \n " ) ;
dev_kfree_skb_any ( skb ) ;
priv - > stats . tx_dropped + + ;
goto done ;
}
if ( new_skb ! = skb )
dev_kfree_skb_any ( skb ) ;
skb = new_skb ;
PRINTM ( MINFO , " new skb headroom %d \n " , skb_headroom ( skb ) ) ;
}
pmbuf = ( mlan_buffer * ) skb - > head ;
memset ( ( t_u8 * ) pmbuf , 0 , sizeof ( mlan_buffer ) ) ;
pmbuf - > bss_index = priv - > bss_index ;
woal_fill_mlan_buffer ( priv , pmbuf , skb ) ;
if ( priv - > enable_tcp_ack_enh = = MTRUE ) {
ret = woal_process_tcp_ack ( priv , pmbuf ) ;
if ( ret )
goto done ;
}
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
if ( priv - > enable_auto_tdls & & priv - > tdls_check_tx )
woal_tdls_check_tx ( priv , skb ) ;
# endif
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
index = skb_get_queue_mapping ( skb ) ;
# endif
status = mlan_send_packet ( priv - > phandle - > pmlan_adapter , pmbuf ) ;
switch ( status ) {
case MLAN_STATUS_PENDING :
atomic_inc ( & priv - > phandle - > tx_pending ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
atomic_inc ( & priv - > wmm_tx_pending [ index ] ) ;
if ( atomic_read ( & priv - > wmm_tx_pending [ index ] ) > = MAX_TX_PENDING ) {
struct netdev_queue * txq =
netdev_get_tx_queue ( priv - > netdev , index ) ;
netif_tx_stop_queue ( txq ) ;
PRINTM ( MINFO , " Stop Kernel Queue : %d \n " , index ) ;
}
# else
if ( atomic_read ( & priv - > phandle - > tx_pending ) > = MAX_TX_PENDING )
woal_stop_queue ( priv - > netdev ) ;
# endif /*#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) */
if ( ! mlan_is_main_process_running ( priv - > phandle - > pmlan_adapter ) )
queue_work ( priv - > phandle - > workqueue ,
& priv - > phandle - > main_work ) ;
break ;
case MLAN_STATUS_SUCCESS :
priv - > stats . tx_packets + + ;
priv - > stats . tx_bytes + = skb - > len ;
dev_kfree_skb_any ( skb ) ;
break ;
case MLAN_STATUS_FAILURE :
default :
priv - > stats . tx_dropped + + ;
dev_kfree_skb_any ( skb ) ;
break ;
}
done :
LEAVE ( ) ;
return 0 ;
}
/**
* @ brief Convert ascii string to Hex integer
*
* @ param d A pointer to integer buf
* @ param s A pointer to ascii string
* @ param dlen The byte number of ascii string in hex
*
* @ return Number of integer
*/
int
woal_ascii2hex ( t_u8 * d , char * s , t_u32 dlen )
{
unsigned int i ;
t_u8 n ;
ENTER ( ) ;
memset ( d , 0x00 , dlen ) ;
for ( i = 0 ; i < dlen * 2 ; i + + ) {
if ( ( s [ i ] > = 48 ) & & ( s [ i ] < = 57 ) )
n = s [ i ] - 48 ;
else if ( ( s [ i ] > = 65 ) & & ( s [ i ] < = 70 ) )
n = s [ i ] - 55 ;
else if ( ( s [ i ] > = 97 ) & & ( s [ i ] < = 102 ) )
n = s [ i ] - 87 ;
else
break ;
if ( ! ( i % 2 ) )
n = n * 16 ;
d [ i / 2 ] + = n ;
}
LEAVE ( ) ;
return i ;
}
/**
* @ brief Return integer value of a given ascii string
*
* @ param data Converted data to be returned
* @ param a String to be converted
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
woal_atoi ( int * data , char * a )
{
int i , val = 0 , len ;
int mul = 1 ;
ENTER ( ) ;
len = strlen ( a ) ;
if ( len > 2 ) {
if ( ! strncmp ( a , " 0x " , 2 ) ) {
a = a + 2 ;
len - = 2 ;
* data = woal_atox ( a ) ;
LEAVE ( ) ;
return MLAN_STATUS_SUCCESS ;
}
}
for ( i = 0 ; i < len ; i + + ) {
if ( isdigit ( a [ i ] ) ) {
val = val * 10 + ( a [ i ] - ' 0 ' ) ;
} else {
if ( ( i = = 0 ) & & ( a [ i ] = = ' - ' ) ) {
mul = - 1 ;
} else {
PRINTM ( MERROR , " Invalid char %c in string %s \n " ,
a [ i ] , a ) ;
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
}
}
* data = ( mul * val ) ;
LEAVE ( ) ;
return MLAN_STATUS_SUCCESS ;
}
/**
* @ brief Return hex value of a given ascii string
*
* @ param a String to be converted to ascii
*
* @ return The converted character if a is a valid hex , else 0
*/
int
woal_atox ( char * a )
{
int i = 0 ;
ENTER ( ) ;
while ( isxdigit ( * a ) )
i = i * 16 + woal_hexval ( * a + + ) ;
LEAVE ( ) ;
return i ;
}
/**
* @ brief Extension of strsep lib command . This function will also take care
* escape character
*
* @ param s A pointer to array of chars to process
* @ param delim The delimiter character to end the string
* @ param esc The escape character to ignore for delimiter
*
* @ return Pointer to the separated string if delim found , else NULL
*/
char *
woal_strsep ( char * * s , char delim , char esc )
{
char * se = * s , * sb ;
ENTER ( ) ;
if ( ! ( * s ) | | ( * se = = ' \0 ' ) ) {
LEAVE ( ) ;
return NULL ;
}
for ( sb = * s ; * sb ! = ' \0 ' ; + + sb ) {
if ( * sb = = esc & & * ( sb + 1 ) = = esc ) {
/*
* We get a esc + esc seq then keep the one esc
* and chop off the other esc character
*/
memmove ( sb , sb + 1 , strlen ( sb ) ) ;
continue ;
}
if ( * sb = = esc & & * ( sb + 1 ) = = delim ) {
/*
* We get a delim + esc seq then keep the delim
* and chop off the esc character
*/
memmove ( sb , sb + 1 , strlen ( sb ) ) ;
continue ;
}
if ( * sb = = delim )
break ;
}
if ( * sb = = ' \0 ' )
sb = NULL ;
else
* sb + + = ' \0 ' ;
* s = sb ;
LEAVE ( ) ;
return se ;
}
/**
* @ brief Convert mac address from string to t_u8 buffer .
*
* @ param mac_addr The buffer to store the mac address in .
* @ param buf The source of mac address which is a string .
*
* @ return N / A
*/
void
woal_mac2u8 ( t_u8 * mac_addr , char * buf )
{
char * begin , * end , * mac_buff ;
int i ;
ENTER ( ) ;
if ( ! buf ) {
LEAVE ( ) ;
return ;
}
mac_buff = kzalloc ( strlen ( buf ) + 1 , GFP_KERNEL ) ;
if ( ! mac_buff ) {
LEAVE ( ) ;
return ;
}
memcpy ( mac_buff , buf , strlen ( buf ) ) ;
begin = mac_buff ;
for ( i = 0 ; i < ETH_ALEN ; + + i ) {
end = woal_strsep ( & begin , ' : ' , ' / ' ) ;
if ( end )
mac_addr [ i ] = woal_atox ( end ) ;
}
kfree ( mac_buff ) ;
LEAVE ( ) ;
}
# ifdef STA_SUPPORT
/**
* @ brief This function sets multicast addresses to firmware
*
* @ param dev A pointer to net_device structure
*
* @ return N / A
*/
void
woal_set_multicast_list ( struct net_device * dev )
{
moal_private * priv = ( moal_private * ) netdev_priv ( dev ) ;
ENTER ( ) ;
woal_request_set_multicast_list ( priv , dev ) ;
LEAVE ( ) ;
}
# endif
/**
* @ brief This function initializes the private structure
* and set default value to the member of moal_private .
*
* @ param priv A pointer to moal_private structure
* @ param wait_option Wait option
*
* @ return N / A
*/
void
woal_init_priv ( moal_private * priv , t_u8 wait_option )
{
ENTER ( ) ;
# ifdef STA_SUPPORT
if ( GET_BSS_ROLE ( priv ) = = MLAN_BSS_ROLE_STA ) {
priv - > current_key_index = 0 ;
priv - > rate_index = AUTO_RATE ;
priv - > is_adhoc_link_sensed = MFALSE ;
priv - > scan_type = MLAN_SCAN_TYPE_ACTIVE ;
priv - > bg_scan_start = MFALSE ;
priv - > bg_scan_reported = MFALSE ;
memset ( & priv - > nick_name , 0 , sizeof ( priv - > nick_name ) ) ;
priv - > num_tx_timeout = 0 ;
priv - > rx_filter = 0 ;
# ifdef REASSOCIATION
priv - > reassoc_on = MFALSE ;
priv - > set_asynced_essid_flag = MFALSE ;
# endif
# ifdef STA_CFG80211
memset ( & priv - > sme_current , 0 ,
sizeof ( struct cfg80211_connect_params ) ) ;
# endif
}
# endif /* STA_SUPPORT */
# ifdef UAP_SUPPORT
if ( GET_BSS_ROLE ( priv ) = = MLAN_BSS_ROLE_UAP ) {
priv - > bss_started = MFALSE ;
# ifdef UAP_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
memset ( & priv - > chan , 0 , sizeof ( struct cfg80211_chan_def ) ) ;
memset ( & priv - > csa_chan , 0 , sizeof ( struct cfg80211_chan_def ) ) ;
priv - > uap_tx_blocked = MFALSE ;
memset ( & priv - > beacon_after , 0 ,
sizeof ( struct cfg80211_beacon_data ) ) ;
# endif
# endif
}
# endif
memset ( & priv - > tx_protocols , 0 , sizeof ( dot11_protocol ) ) ;
memset ( & priv - > rx_protocols , 0 , sizeof ( dot11_protocol ) ) ;
priv - > media_connected = MFALSE ;
memset ( priv - > dscp_map , 0xFF , sizeof ( priv - > dscp_map ) ) ;
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
priv - > probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
priv - > beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
priv - > proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
priv - > assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
priv - > beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
priv - > proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
priv - > assocresp_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
priv - > beacon_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK ;
# endif
# ifdef STA_SUPPORT
priv - > pmk_saved = MFALSE ;
memset ( & priv - > pmk , 0 , sizeof ( mlan_pmk_t ) ) ;
# endif
priv - > enable_tcp_ack_enh = MTRUE ;
priv - > enable_auto_tdls = MFALSE ;
priv - > tdls_check_tx = MFALSE ;
priv - > gtk_data_ready = MFALSE ;
memset ( & priv - > gtk_rekey_data , 0 , sizeof ( mlan_ds_misc_gtk_rekey_data ) ) ;
woal_request_get_fw_info ( priv , wait_option , NULL ) ;
/* Set MAC address from the insmod command line */
if ( priv - > phandle - > set_mac_addr ) {
memset ( priv - > current_addr , 0 , ETH_ALEN ) ;
memcpy ( priv - > current_addr , priv - > phandle - > mac_addr , ETH_ALEN ) ;
}
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
# ifdef MFG_CMD_SUPPORT
if ( mfg_mode ! = MLAN_INIT_PARA_ENABLED )
# endif
if ( priv - > bss_type = = MLAN_BSS_TYPE_WIFIDIRECT ) {
if ( priv - > bss_virtual ) {
if ( priv - > pa_netdev ) {
memcpy ( priv - > current_addr ,
priv - > pa_netdev - > dev_addr ,
ETH_ALEN ) ;
priv - > current_addr [ 4 ] ^ = 0x80 ;
PRINTM ( MCMND ,
" Set WFD interface addr: " MACSTR
" \n " ,
MAC2STR ( priv - > current_addr ) ) ;
}
} else {
priv - > current_addr [ 0 ] | = 0x02 ;
PRINTM ( MCMND ,
" Set WFD device addr: " MACSTR " \n " ,
MAC2STR ( priv - > current_addr ) ) ;
}
}
# endif
# endif
# endif
/* Set MAC address for UAPx/MLANx/WFDx and let them different with each other */
if ( priv - > bss_index > 0
# ifdef WIFI_DIRECT_SUPPORT
& & priv - > bss_type ! = MLAN_BSS_TYPE_WIFIDIRECT
# endif
) {
priv - > current_addr [ 4 ] + = priv - > bss_index ;
PRINTM ( MCMND , " Set %s device addr: " MACSTR " \n " ,
priv - > netdev - > name , MAC2STR ( priv - > current_addr ) ) ;
}
/* Set MAC address to fw */
woal_request_set_mac_address ( priv ) ;
memcpy ( priv - > netdev - > dev_addr , priv - > current_addr , ETH_ALEN ) ;
# ifdef UAP_SUPPORT
# if defined(DFS_TESTING_SUPPORT)
priv - > user_cac_period_msec = 0 ;
# endif
# endif
LEAVE ( ) ;
}
/**
* @ brief Reset all interfaces if all_intf flag is TRUE ,
* otherwise specified interface only
*
* @ param priv A pointer to moal_private structure
* @ param wait_option Wait option
* @ param all_intf TRUE : all interfaces
* FALSE : current interface only
*
* @ return MLAN_STATUS_SUCCESS - - success , otherwise fail
*/
int
woal_reset_intf ( moal_private * priv , t_u8 wait_option , int all_intf )
{
int ret = MLAN_STATUS_SUCCESS ;
int intf_num ;
moal_handle * handle = NULL ;
mlan_bss_info bss_info ;
ENTER ( ) ;
if ( ! priv ) {
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
handle = priv - > phandle ;
/* Stop queue and detach device */
if ( ! all_intf ) {
woal_stop_queue ( priv - > netdev ) ;
netif_device_detach ( priv - > netdev ) ;
} else {
for ( intf_num = 0 ; intf_num < handle - > priv_num ; intf_num + + ) {
woal_stop_queue ( handle - > priv [ intf_num ] - > netdev ) ;
netif_device_detach ( handle - > priv [ intf_num ] - > netdev ) ;
}
}
/* Get BSS info */
memset ( & bss_info , 0 , sizeof ( bss_info ) ) ;
woal_get_bss_info ( priv , wait_option , & bss_info ) ;
# ifdef STA_SUPPORT
woal_cancel_scan ( priv , wait_option ) ;
# endif
/* Cancel host sleep */
if ( bss_info . is_hs_configured ) {
if ( MLAN_STATUS_SUCCESS ! = woal_cancel_hs ( priv , wait_option ) ) {
ret = - EFAULT ;
goto done ;
}
}
/* Disconnect from network */
if ( ! all_intf ) {
/* Disconnect specified interface only */
if ( ( priv - > media_connected = = MTRUE )
# ifdef UAP_SUPPORT
| | ( GET_BSS_ROLE ( priv ) = = MLAN_BSS_ROLE_UAP )
# endif
) {
woal_disconnect ( priv , wait_option , NULL ,
DEF_DEAUTH_REASON_CODE ) ;
priv - > media_connected = MFALSE ;
}
} else {
/* Disconnect all interfaces */
for ( intf_num = 0 ; intf_num < handle - > priv_num ; intf_num + + ) {
if ( handle - > priv [ intf_num ] - > media_connected = = MTRUE
# ifdef UAP_SUPPORT
| | ( GET_BSS_ROLE ( handle - > priv [ intf_num ] ) = =
MLAN_BSS_ROLE_UAP )
# endif
) {
woal_disconnect ( handle - > priv [ intf_num ] ,
wait_option , NULL ,
DEF_DEAUTH_REASON_CODE ) ;
handle - > priv [ intf_num ] - > media_connected =
MFALSE ;
}
}
}
# ifdef REASSOCIATION
/* Reset the reassoc timer and status */
if ( ! all_intf ) {
handle - > reassoc_on & = ~ MBIT ( priv - > bss_index ) ;
priv - > reassoc_on = MFALSE ;
priv - > set_asynced_essid_flag = MFALSE ;
} else {
handle - > reassoc_on = 0 ;
for ( intf_num = 0 ; intf_num < handle - > priv_num ; intf_num + + ) {
handle - > priv [ intf_num ] - > reassoc_on = MFALSE ;
handle - > priv [ intf_num ] - > set_asynced_essid_flag = MFALSE ;
}
}
if ( ! handle - > reassoc_on & & handle - > is_reassoc_timer_set ) {
woal_cancel_timer ( & handle - > reassoc_timer ) ;
handle - > is_reassoc_timer_set = MFALSE ;
}
# endif /* REASSOCIATION */
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
if ( handle - > is_go_timer_set ) {
woal_cancel_timer ( & handle - > go_timer ) ;
handle - > is_go_timer_set = MFALSE ;
}
# endif
# endif
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
if ( handle - > is_remain_timer_set ) {
woal_cancel_timer ( & handle - > remain_timer ) ;
woal_remain_timer_func ( handle ) ;
}
# endif
# endif
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function return the point to structure moal_private
*
* @ param handle Pointer to structure moal_handle
* @ param bss_index BSS index number
*
* @ return moal_private pointer or NULL
*/
moal_private *
woal_bss_index_to_priv ( moal_handle * handle , t_u8 bss_index )
{
int i ;
ENTER ( ) ;
if ( ! handle ) {
LEAVE ( ) ;
return NULL ;
}
for ( i = 0 ; i < MLAN_MAX_BSS_NUM ; i + + ) {
if ( handle - > priv [ i ] & &
( handle - > priv [ i ] - > bss_index = = bss_index ) ) {
LEAVE ( ) ;
return handle - > priv [ i ] ;
}
}
LEAVE ( ) ;
return NULL ;
}
/**
* @ brief This function alloc mlan_buffer .
* @ param handle A pointer to moal_handle structure
* @ param size buffer size to allocate
*
* @ return mlan_buffer pointer or NULL
*/
pmlan_buffer
woal_alloc_mlan_buffer ( moal_handle * handle , int size )
{
mlan_buffer * pmbuf = NULL ;
struct sk_buff * skb ;
gfp_t flag ;
ENTER ( ) ;
flag = ( in_atomic ( ) | | irqs_disabled ( ) ) ? GFP_ATOMIC : GFP_KERNEL ;
if ( size < = 0 ) {
PRINTM ( MERROR , " Buffer size must be positive \n " ) ;
LEAVE ( ) ;
return NULL ;
}
skb = __dev_alloc_skb ( size + sizeof ( mlan_buffer ) , flag ) ;
if ( ! skb ) {
PRINTM ( MERROR , " %s: No free skb \n " , __func__ ) ;
LEAVE ( ) ;
return NULL ;
}
skb_reserve ( skb , sizeof ( mlan_buffer ) ) ;
pmbuf = ( mlan_buffer * ) skb - > head ;
memset ( ( u8 * ) pmbuf , 0 , sizeof ( mlan_buffer ) ) ;
pmbuf - > pdesc = ( t_void * ) skb ;
pmbuf - > pbuf = ( t_u8 * ) skb - > data ;
atomic_inc ( & handle - > mbufalloc_count ) ;
LEAVE ( ) ;
return pmbuf ;
}
/**
* @ brief This function alloc mlan_ioctl_req .
*
* @ param size buffer size to allocate
*
* @ return mlan_ioctl_req pointer or NULL
*/
pmlan_ioctl_req
woal_alloc_mlan_ioctl_req ( int size )
{
mlan_ioctl_req * req = NULL ;
gfp_t flag ;
ENTER ( ) ;
flag = ( in_atomic ( ) | | irqs_disabled ( ) ) ? GFP_ATOMIC : GFP_KERNEL ;
req = kzalloc ( ( sizeof ( mlan_ioctl_req ) + size + sizeof ( int ) +
sizeof ( wait_queue ) ) , flag ) ;
if ( ! req ) {
PRINTM ( MERROR , " %s: Fail to alloc ioctl buffer \n " , __func__ ) ;
LEAVE ( ) ;
return NULL ;
}
req - > pbuf = ( t_u8 * ) req + sizeof ( mlan_ioctl_req ) + sizeof ( wait_queue ) ;
req - > buf_len = ( t_u32 ) size ;
req - > reserved_1 = ( t_ptr ) ( ( t_u8 * ) req + sizeof ( mlan_ioctl_req ) ) ;
LEAVE ( ) ;
return req ;
}
/**
* @ brief This function frees mlan_buffer .
* @ param handle A pointer to moal_handle structure
* @ param pmbuf Pointer to mlan_buffer
*
* @ return N / A
*/
void
woal_free_mlan_buffer ( moal_handle * handle , pmlan_buffer pmbuf )
{
ENTER ( ) ;
if ( ! pmbuf ) {
LEAVE ( ) ;
return ;
}
if ( pmbuf - > pdesc )
dev_kfree_skb_any ( ( struct sk_buff * ) pmbuf - > pdesc ) ;
else
PRINTM ( MERROR , " free mlan buffer without pdesc \n " ) ;
atomic_dec ( & handle - > mbufalloc_count ) ;
LEAVE ( ) ;
return ;
}
# ifdef STA_SUPPORT
# endif /* STA_SUPPORT */
/**
* @ brief This function handles events generated by firmware
*
* @ param priv A pointer to moal_private structure
* @ param payload A pointer to payload buffer
* @ param len Length of the payload
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
woal_broadcast_event ( moal_private * priv , t_u8 * payload , t_u32 len )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
struct sk_buff * skb = NULL ;
struct nlmsghdr * nlh = NULL ;
moal_handle * handle = priv - > phandle ;
struct net_device * netdev = priv - > netdev ;
struct sock * sk = handle - > nl_sk ;
ENTER ( ) ;
/* interface name to be prepended to event */
if ( ( len + IFNAMSIZ ) > NL_MAX_PAYLOAD
# ifdef WIFI_DIRECT_SUPPORT
* 2
# endif
) {
PRINTM ( MERROR , " event size is too big, len=%d \n " , ( int ) len ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
if ( sk ) {
/* Allocate skb */
# ifdef WIFI_DIRECT_SUPPORT
if ( ( len + IFNAMSIZ ) > NL_MAX_PAYLOAD ) {
skb = alloc_skb ( NLMSG_SPACE ( NL_MAX_PAYLOAD * 2 ) ,
GFP_ATOMIC ) ;
if ( ! skb ) {
PRINTM ( MERROR ,
" Could not allocate skb for netlink \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
} else {
# endif
skb = alloc_skb ( NLMSG_SPACE ( NL_MAX_PAYLOAD ) ,
GFP_ATOMIC ) ;
if ( ! skb ) {
PRINTM ( MERROR ,
" Could not allocate skb for netlink \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
# ifdef WIFI_DIRECT_SUPPORT
}
# endif
memset ( skb - > data , 0 , NLMSG_SPACE ( NL_MAX_PAYLOAD ) ) ;
nlh = ( struct nlmsghdr * ) skb - > data ;
nlh - > nlmsg_len = NLMSG_SPACE ( len + IFNAMSIZ ) ;
/* From kernel */
nlh - > nlmsg_pid = 0 ;
nlh - > nlmsg_flags = 0 ;
/* Data */
skb_put ( skb , nlh - > nlmsg_len ) ;
memcpy ( NLMSG_DATA ( nlh ) , netdev - > name , IFNAMSIZ ) ;
memcpy ( ( ( t_u8 * ) ( NLMSG_DATA ( nlh ) ) ) + IFNAMSIZ , payload , len ) ;
/* From Kernel */
# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
NETLINK_CB ( skb ) . pid = 0 ;
# else
NETLINK_CB ( skb ) . portid = 0 ;
# endif
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
/* Multicast message */
NETLINK_CB ( skb ) . dst_pid = 0 ;
# endif
/* Multicast group number */
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
NETLINK_CB ( skb ) . dst_groups = NL_MULTICAST_GROUP ;
# else
NETLINK_CB ( skb ) . dst_group = NL_MULTICAST_GROUP ;
# endif
/* Send message */
ret = netlink_broadcast ( sk , skb , 0 , NL_MULTICAST_GROUP ,
GFP_ATOMIC ) ;
if ( ret ) {
PRINTM ( MWARN , " netlink_broadcast failed: ret=%d \n " ,
ret ) ;
goto done ;
}
ret = MLAN_STATUS_SUCCESS ;
} else {
PRINTM ( MERROR ,
" Could not send event through NETLINK. Link down. \n " ) ;
ret = MLAN_STATUS_FAILURE ;
}
done :
LEAVE ( ) ;
return ret ;
}
# ifdef REASSOCIATION
/**
* @ brief This function handles re - association . it is triggered
* by re - assoc timer .
*
* @ param data A pointer to wlan_thread structure
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
int
woal_reassociation_thread ( void * data )
{
moal_thread * pmoal_thread = data ;
moal_private * priv = NULL ;
moal_handle * handle = ( moal_handle * ) pmoal_thread - > handle ;
# if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
wait_queue_t wait ;
# else
wait_queue_entry_t wait ;
# endif
int i ;
BOOLEAN reassoc_timer_req ;
mlan_802_11_ssid req_ssid ;
mlan_ssid_bssid ssid_bssid ;
mlan_status status ;
mlan_bss_info bss_info ;
t_u32 timer_val = MOAL_TIMER_10S ;
t_u8 zero_mac [ ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
ENTER ( ) ;
woal_activate_thread ( pmoal_thread ) ;
init_waitqueue_entry ( & wait , current ) ;
current - > flags | = PF_NOFREEZE ;
for ( ; ; ) {
add_wait_queue ( & pmoal_thread - > wait_q , & wait ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule ( ) ;
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( & pmoal_thread - > wait_q , & wait ) ;
/* Cancel re-association timer */
if ( handle - > is_reassoc_timer_set = = MTRUE ) {
woal_cancel_timer ( & handle - > reassoc_timer ) ;
handle - > is_reassoc_timer_set = MFALSE ;
}
if ( handle - > surprise_removed )
break ;
if ( kthread_should_stop ( ) )
break ;
if ( handle - > hardware_status ! = HardwareStatusReady ) {
PRINTM ( MINFO ,
" Reassoc: Hardware status is not correct \n " ) ;
continue ;
}
PRINTM ( MEVENT , " Reassoc: Thread waking up... \n " ) ;
reassoc_timer_req = MFALSE ;
# ifdef STA_CFG80211
for ( i = 0 ;
i < MIN ( handle - > priv_num , MLAN_MAX_BSS_NUM ) & &
( priv = handle - > priv [ i ] ) ; i + + ) {
if ( priv - > roaming_required ) {
priv - > roaming_required = MFALSE ;
PRINTM ( MEVENT , " Try to roaming...... \n " ) ;
woal_start_roaming ( priv ) ;
break ;
}
}
# endif
for ( i = 0 ;
i < MIN ( handle - > priv_num , MLAN_MAX_BSS_NUM ) & &
( priv = handle - > priv [ i ] ) ; i + + ) {
if ( priv - > reassoc_required = = MFALSE ) {
priv - > set_asynced_essid_flag = MFALSE ;
continue ;
}
memset ( & bss_info , 0x00 , sizeof ( bss_info ) ) ;
if ( MLAN_STATUS_SUCCESS ! = woal_get_bss_info ( priv ,
MOAL_IOCTL_WAIT ,
& bss_info ) )
{
PRINTM ( MINFO , " Ressoc: Fail to get bss info \n " ) ;
priv - > reassoc_required = MFALSE ;
priv - > set_asynced_essid_flag = MFALSE ;
continue ;
}
if ( bss_info . bss_mode ! = MLAN_BSS_MODE_INFRA | |
priv - > media_connected ! = MFALSE ) {
PRINTM ( MINFO ,
" Reassoc: ad-hoc mode or media connected \n " ) ;
priv - > reassoc_required = MFALSE ;
priv - > set_asynced_essid_flag = MFALSE ;
continue ;
}
/** avoid on going scan from other thread */
if ( handle - > scan_pending_on_block ) {
reassoc_timer_req = MTRUE ;
break ;
}
/* The semaphore is used to avoid reassociation thread and
wlan_set_scan / wlan_set_essid interrupting each other .
Reassociation should be disabled completely by application if
wlan_set_user_scan_ioctl / wlan_set_wap is used .
*/
if ( MOAL_ACQ_SEMAPHORE_BLOCK ( & handle - > reassoc_sem ) ) {
PRINTM ( MERROR ,
" Acquire semaphore error, reassociation thread \n " ) ;
reassoc_timer_req = MTRUE ;
break ;
}
PRINTM ( MINFO , " Reassoc: Required ESSID: %s \n " ,
priv - > prev_ssid_bssid . ssid . ssid ) ;
PRINTM ( MINFO , " Reassoc: Performing Active Scan \n " ) ;
memset ( & req_ssid , 0x00 , sizeof ( mlan_802_11_ssid ) ) ;
memcpy ( & req_ssid ,
& priv - > prev_ssid_bssid . ssid ,
sizeof ( mlan_802_11_ssid ) ) ;
/* Do specific SSID scanning */
if ( MLAN_STATUS_SUCCESS ! =
woal_request_scan ( priv , MOAL_IOCTL_WAIT ,
& req_ssid ) ) {
PRINTM ( MERROR ,
" Reassoc: Fail to do specific scan \n " ) ;
reassoc_timer_req = MTRUE ;
MOAL_REL_SEMAPHORE ( & handle - > reassoc_sem ) ;
break ;
}
if ( handle - > surprise_removed ) {
MOAL_REL_SEMAPHORE ( & handle - > reassoc_sem ) ;
break ;
}
memset ( & ssid_bssid , 0 , sizeof ( mlan_ssid_bssid ) ) ;
if ( priv - > set_asynced_essid_flag = = MTRUE ) {
if ( priv - > assoc_with_mac & &
memcmp ( priv - > prev_ssid_bssid . bssid ,
zero_mac , MLAN_MAC_ADDR_LENGTH ) ) {
/* Search AP by BSSID & SSID */
PRINTM ( MINFO ,
" Reassoc: Search AP by BSSID & SSID \n " ) ;
memcpy ( & ssid_bssid . bssid ,
& priv - > prev_ssid_bssid . bssid ,
MLAN_MAC_ADDR_LENGTH ) ;
} else {
/* Search AP by ESSID for asynced essid setting */
PRINTM ( MINFO ,
" Set asynced essid: Search AP by ESSID \n " ) ;
}
memcpy ( & ssid_bssid . ssid ,
& priv - > prev_ssid_bssid . ssid ,
sizeof ( mlan_802_11_ssid ) ) ;
} else {
/* Search AP by BSSID first */
PRINTM ( MINFO ,
" Reassoc: Search AP by BSSID first \n " ) ;
memcpy ( & ssid_bssid . bssid ,
& priv - > prev_ssid_bssid . bssid ,
MLAN_MAC_ADDR_LENGTH ) ;
}
status = woal_find_best_network ( priv , MOAL_IOCTL_WAIT ,
& ssid_bssid ) ;
# ifdef STA_WEXT
if ( status = = MLAN_STATUS_SUCCESS ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_11d_check_ap_channel ( priv ,
MOAL_IOCTL_WAIT ,
& ssid_bssid ) ) {
PRINTM ( MERROR ,
" Reassoc: The AP's channel is invalid for current region \n " ) ;
status = MLAN_STATUS_FAILURE ;
}
}
# endif
/** The find AP without ssid, we need re-search */
if ( status = = MLAN_STATUS_SUCCESS & &
! ssid_bssid . ssid . ssid_len ) {
PRINTM ( MINFO ,
" Reassoc: Skip AP without ssid \n " ) ;
status = MLAN_STATUS_FAILURE ;
}
if ( priv - > set_asynced_essid_flag ! = MTRUE & &
MLAN_STATUS_SUCCESS ! = status ) {
PRINTM ( MINFO ,
" Reassoc: AP not found in scan list \n " ) ;
PRINTM ( MINFO , " Reassoc: Search AP by SSID \n " ) ;
/* Search AP by SSID */
memset ( & ssid_bssid , 0 , sizeof ( mlan_ssid_bssid ) ) ;
memcpy ( & ssid_bssid . ssid ,
& priv - > prev_ssid_bssid . ssid ,
sizeof ( mlan_802_11_ssid ) ) ;
status = woal_find_best_network ( priv ,
MOAL_IOCTL_WAIT ,
& ssid_bssid ) ;
# ifdef STA_WEXT
if ( status = = MLAN_STATUS_SUCCESS ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_11d_check_ap_channel ( priv ,
MOAL_IOCTL_WAIT ,
& ssid_bssid ) )
{
PRINTM ( MERROR ,
" Reassoc: The AP's channel is invalid for current region \n " ) ;
status = MLAN_STATUS_FAILURE ;
}
}
# endif
}
if ( status = = MLAN_STATUS_SUCCESS ) {
/* set the wep key */
if ( bss_info . wep_status )
woal_enable_wep_key ( priv ,
MOAL_IOCTL_WAIT ) ;
/* Zero SSID implies use BSSID to connect */
memset ( & ssid_bssid . ssid , 0 ,
sizeof ( mlan_802_11_ssid ) ) ;
status = woal_bss_start ( priv , MOAL_IOCTL_WAIT ,
& ssid_bssid ) ;
}
if ( priv - > media_connected = = MFALSE )
reassoc_timer_req = MTRUE ;
else {
mlan_ds_rate * rate = NULL ;
mlan_ioctl_req * req = NULL ;
reassoc_timer_req = MFALSE ;
if ( priv - > set_asynced_essid_flag = = MTRUE ) {
memset ( & bss_info , 0 , sizeof ( bss_info ) ) ;
if ( MLAN_STATUS_SUCCESS ! =
woal_get_bss_info ( priv ,
MOAL_IOCTL_WAIT ,
& bss_info ) ) {
PRINTM ( MINFO ,
" Set asynced essid: Fail to get bss info after assoc \n " ) ;
} else {
memcpy ( & priv - > prev_ssid_bssid .
ssid , & bss_info . ssid ,
sizeof
( mlan_802_11_ssid ) ) ;
memcpy ( & priv - > prev_ssid_bssid .
bssid , & bss_info . bssid ,
MLAN_MAC_ADDR_LENGTH ) ;
}
priv - > set_asynced_essid_flag = MFALSE ;
}
if ( priv - > rate_index ! = AUTO_RATE ) {
req = woal_alloc_mlan_ioctl_req ( sizeof
( mlan_ds_rate ) ) ;
if ( req = = NULL ) {
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
rate = ( mlan_ds_rate * ) req - > pbuf ;
rate - > param . rate_cfg . rate_type =
MLAN_RATE_INDEX ;
rate - > sub_command = MLAN_OID_RATE_CFG ;
req - > req_id = MLAN_IOCTL_RATE ;
req - > action = MLAN_ACT_SET ;
rate - > param . rate_cfg . rate =
priv - > rate_index ;
status = woal_request_ioctl ( priv , req ,
MOAL_IOCTL_WAIT ) ;
if ( status ! = MLAN_STATUS_SUCCESS ) {
if ( status ! =
MLAN_STATUS_PENDING )
kfree ( req ) ;
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
kfree ( req ) ;
}
}
MOAL_REL_SEMAPHORE ( & handle - > reassoc_sem ) ;
}
if ( handle - > surprise_removed )
break ;
if ( reassoc_timer_req = = MTRUE ) {
handle - > is_reassoc_timer_set = MTRUE ;
if ( priv & & ( priv - > set_asynced_essid_flag = = MTRUE ) ) {
PRINTM ( MERROR ,
" Set Async ESSID: No AP found or assoc failed. \n " ) ;
priv - > set_asynced_essid_flag = MFALSE ;
} else {
PRINTM ( MEVENT ,
" Reassoc: No AP found or assoc failed. "
" Restarting re-assoc Timer: %d \n " ,
( int ) timer_val ) ;
woal_mod_timer ( & handle - > reassoc_timer ,
timer_val ) ;
}
} else {
if ( priv ) {
priv - > set_asynced_essid_flag = MFALSE ;
}
}
}
woal_deactivate_thread ( pmoal_thread ) ;
LEAVE ( ) ;
return MLAN_STATUS_SUCCESS ;
}
/**
* @ brief This function triggers re - association by waking up
* re - assoc thread .
*
* @ param context A pointer to context
* @ return N / A
*/
void
woal_reassoc_timer_func ( void * context )
{
moal_handle * handle = ( moal_handle * ) context ;
ENTER ( ) ;
PRINTM ( MINFO , " reassoc_timer fired. \n " ) ;
handle - > is_reassoc_timer_set = MFALSE ;
PRINTM ( MINFO , " Waking Up the Reassoc Thread \n " ) ;
wake_up_interruptible ( & handle - > reassoc_thread . wait_q ) ;
LEAVE ( ) ;
return ;
}
# endif /* REASSOCIATION */
# ifdef STA_SUPPORT
/**
* @ brief update dscp mapping from assoc_resp / reassoc_resp
*
* @ param priv Pointer to the moal_private driver data struct
*
* @ return N / A
*/
void
woal_update_dscp_mapping ( moal_private * priv )
{
mlan_ds_misc_assoc_rsp assoc_rsp ;
IEEEtypes_AssocRsp_t * passoc_rsp = NULL ;
IEEEtypes_Header_t * qos_mapping_ie = NULL ;
DSCP_Range_t * pdscp_range = NULL ;
t_u8 dscp_except_num = 0 ;
DSCP_Exception_t dscp_except [ MAX_DSCP_EXCEPTION_NUM ] ;
int i , j ;
ENTER ( ) ;
memset ( & assoc_rsp , 0 , sizeof ( mlan_ds_misc_assoc_rsp ) ) ;
woal_get_assoc_rsp ( priv , & assoc_rsp , MOAL_NO_WAIT ) ;
passoc_rsp = ( IEEEtypes_AssocRsp_t * ) assoc_rsp . assoc_resp_buf ;
memset ( priv - > dscp_map , 0xFF , sizeof ( priv - > dscp_map ) ) ;
qos_mapping_ie =
( IEEEtypes_Header_t * ) woal_parse_ie_tlv ( passoc_rsp - > ie_buffer ,
assoc_rsp .
assoc_resp_len -
ASSOC_RESP_FIXED_SIZE ,
QOS_MAPPING ) ;
if ( qos_mapping_ie & &
( qos_mapping_ie - > len > = ( sizeof ( DSCP_Range_t ) * MAX_NUM_TID ) ) ) {
dscp_except_num =
( qos_mapping_ie - > len -
sizeof ( DSCP_Range_t ) * MAX_NUM_TID ) /
sizeof ( DSCP_Exception_t ) ;
if ( dscp_except_num > MAX_DSCP_EXCEPTION_NUM ) {
PRINTM ( MERROR , " dscp_except_num exceeds MAX limit \n " ) ;
LEAVE ( ) ;
return ;
}
memcpy ( dscp_except ,
( t_u8 * ) qos_mapping_ie + sizeof ( IEEEtypes_Header_t ) ,
dscp_except_num * sizeof ( DSCP_Exception_t ) ) ;
pdscp_range =
( DSCP_Range_t * ) ( ( t_u8 * ) qos_mapping_ie +
sizeof ( IEEEtypes_Header_t ) +
dscp_except_num *
sizeof ( DSCP_Exception_t ) ) ;
for ( i = 0 ; i < MAX_NUM_TID ; i + + ) {
PRINTM ( MEVENT , " TID %d: dscp_low=%d, dscp_high=%d \n " , i ,
pdscp_range - > dscp_low_value ,
pdscp_range - > dscp_high_value ) ;
if ( pdscp_range - > dscp_low_value ! = 0xff & &
pdscp_range - > dscp_high_value ! = 0xff & &
pdscp_range - > dscp_high_value < = 63 ) {
for ( j = pdscp_range - > dscp_low_value ;
j < = pdscp_range - > dscp_high_value ; j + + )
priv - > dscp_map [ j ] = i ;
}
pdscp_range + + ;
}
for ( i = 0 ; i < dscp_except_num ; i + + ) {
if ( ( dscp_except [ i ] . dscp_value < = 63 ) & &
( dscp_except [ i ] . user_priority < = 7 ) ) {
PRINTM ( MEVENT ,
" dscp excpt: value=%d priority=%d \n " ,
dscp_except [ i ] . dscp_value ,
dscp_except [ i ] . user_priority ) ;
priv - > dscp_map [ dscp_except [ i ] . dscp_value ] =
dscp_except [ i ] . user_priority ;
}
}
}
LEAVE ( ) ;
}
/**
* @ brief Sends disconnect event
*
* @ param priv A pointer to moal_private struct
* @ param disconnect_reason disconnect reason code
* @ return N / A
*/
t_void
woal_send_disconnect_to_system ( moal_private * priv , t_u16 disconnect_reason )
{
int custom_len = 0 ;
t_u8 event_buf [ 32 ] ;
# ifdef STA_WEXT
union iwreq_data wrqu ;
# endif
# ifdef STA_CFG80211
unsigned long flags ;
# endif
mlan_ds_misc_gtk_rekey_data zero_gtk ;
t_u16 reason_code = 0 ;
ENTER ( ) ;
priv - > media_connected = MFALSE ;
if ( ! disconnect_reason )
reason_code = MLAN_REASON_DEAUTH_LEAVING ;
else
reason_code = disconnect_reason ;
woal_stop_queue ( priv - > netdev ) ;
if ( netif_carrier_ok ( priv - > netdev ) )
netif_carrier_off ( priv - > netdev ) ;
woal_flush_tcp_sess_queue ( priv ) ;
priv - > gtk_data_ready = MFALSE ;
memset ( & zero_gtk , 0x00 , sizeof ( zero_gtk ) ) ;
if ( gtk_rekey_offload = = GTK_REKEY_OFFLOAD_ENABLE & &
memcmp ( & priv - > gtk_rekey_data , & zero_gtk ,
sizeof ( priv - > gtk_rekey_data ) ) ! = 0 ) {
PRINTM ( MCMND , " clear GTK in woal_send_disconnect_to_system \n " ) ;
woal_set_rekey_data ( priv , NULL , MLAN_ACT_CLEAR ) ;
}
memset ( & priv - > gtk_rekey_data , 0 , sizeof ( mlan_ds_misc_gtk_rekey_data ) ) ;
if ( priv - > bss_type = = MLAN_BSS_TYPE_STA )
woal_flush_tdls_list ( priv ) ;
# ifdef STA_CFG80211
if ( priv - > bss_type = = MLAN_BSS_TYPE_STA & &
IS_STA_CFG80211 ( cfg80211_wext ) ) {
woal_flush_pmksa_list ( priv ) ;
if ( priv - > okc_roaming_ie ) {
kfree ( priv - > okc_roaming_ie ) ;
priv - > okc_roaming_ie = NULL ;
priv - > okc_ie_len = 0 ;
}
}
# endif
if ( priv - > bss_type = = MLAN_BSS_TYPE_STA & & priv - > hist_data )
woal_hist_data_reset ( priv ) ;
# ifdef STA_WEXT
if ( IS_STA_WEXT ( cfg80211_wext ) ) {
memset ( wrqu . ap_addr . sa_data , 0x00 , ETH_ALEN ) ;
wrqu . ap_addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( priv - > netdev , SIOCGIWAP , & wrqu , NULL ) ;
}
# endif
# ifdef STA_CFG80211
if ( IS_STA_CFG80211 ( cfg80211_wext ) ) {
spin_lock_irqsave ( & priv - > connect_lock , flags ) ;
if ( ! priv - > cfg_disconnect & & ! priv - > cfg_connect & &
priv - > wdev & & priv - > wdev - > current_bss ) {
PRINTM ( MMSG ,
" wlan: Disconnected from " MACSTR
" : Reason code %d \n " , MAC2STR ( priv - > cfg_bssid ) ,
reason_code ) ;
spin_unlock_irqrestore ( & priv - > connect_lock , flags ) ;
/* This function must be called only when disconnect issued by
the FW , i . e . disconnected by AP . For IBSS mode this call is
not valid */
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
if ( priv - > host_mlme )
woal_host_mlme_disconnect ( priv , reason_code ) ;
else
# endif
cfg80211_disconnected ( priv - > netdev ,
reason_code , NULL , 0 ,
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
false ,
# endif
GFP_KERNEL ) ;
} else {
spin_unlock_irqrestore ( & priv - > connect_lock , flags ) ;
}
if ( ! woal_is_any_interface_active ( priv - > phandle ) )
woal_set_scan_time ( priv , ACTIVE_SCAN_CHAN_TIME ,
PASSIVE_SCAN_CHAN_TIME ,
SPECIFIC_SCAN_CHAN_TIME ) ;
priv - > ft_ie_len = 0 ;
priv - > ft_pre_connect = MFALSE ;
memset ( priv - > dscp_map , 0xFF , sizeof ( priv - > dscp_map ) ) ;
}
# endif /* STA_CFG80211 */
memset ( event_buf , 0 , sizeof ( event_buf ) ) ;
custom_len = strlen ( CUS_EVT_AP_CONNECTED ) ;
strncpy ( event_buf , CUS_EVT_AP_CONNECTED ,
MIN ( ( sizeof ( event_buf ) - 1 ) , custom_len ) ) ;
woal_broadcast_event ( priv , event_buf , custom_len + ETH_ALEN ) ;
LEAVE ( ) ;
}
# endif /* STA_SUPPORT */
# define OFFSET_SEQNUM 4
/**
* @ brief This function stores the FW dumps received from events
*
* @ param phandle A pointer to moal_handle
* @ param pmevent A pointer to mlan_event structure
*
* @ return N / A
*/
t_void
woal_store_firmware_dump ( moal_handle * phandle , mlan_event * pmevent )
{
struct file * pfile_fwdump = NULL ;
loff_t pos = 0 ;
t_u16 seqnum ;
t_u8 path_name [ 64 ] ;
ENTER ( ) ;
if ( phandle - > fwdump_fname )
pfile_fwdump =
filp_open ( phandle - > fwdump_fname ,
O_CREAT | O_WRONLY | O_APPEND , 0644 ) ;
else {
seqnum = woal_le16_to_cpu ( * ( t_u16 * )
( pmevent - > event_buf + OFFSET_SEQNUM ) ) ;
if ( seqnum = = 1 ) {
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
/** Create dump directort*/
woal_create_dump_dir ( phandle , path_name ,
sizeof ( path_name ) ) ;
# else
memset ( path_name , 0 , sizeof ( path_name ) ) ;
strcpy ( path_name , " /data " ) ;
# endif
PRINTM ( MMSG , " Firmware Dump directory name is %s \n " ,
path_name ) ;
woal_dump_drv_info ( phandle , path_name ) ;
if ( fwdump_fname ) {
memset ( fwdump_fname , 0 , 64 ) ;
} else {
gfp_t flag ;
flag = ( in_atomic ( ) | |
irqs_disabled ( ) ) ? GFP_ATOMIC :
GFP_KERNEL ;
fwdump_fname = kzalloc ( 64 , flag ) ;
}
sprintf ( fwdump_fname , " %s/file_fwdump " , path_name ) ;
pfile_fwdump =
filp_open ( fwdump_fname ,
O_CREAT | O_WRONLY | O_APPEND , 0644 ) ;
if ( IS_ERR ( pfile_fwdump ) ) {
memset ( fwdump_fname , 0 , 64 ) ;
sprintf ( fwdump_fname , " %s/%s " , " /var " ,
" file_fwdump " ) ;
pfile_fwdump =
filp_open ( fwdump_fname ,
O_CREAT | O_WRONLY | O_APPEND ,
0644 ) ;
}
} else
pfile_fwdump =
filp_open ( fwdump_fname ,
O_CREAT | O_WRONLY | O_APPEND , 0644 ) ;
}
if ( IS_ERR ( pfile_fwdump ) ) {
PRINTM ( MERROR , " Cannot create firmware dump file \n " ) ;
LEAVE ( ) ;
return ;
}
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
vfs_write ( pfile_fwdump , pmevent - > event_buf , pmevent - > event_len , & pos ) ;
# else
kernel_write ( pfile_fwdump , pmevent - > event_buf , pmevent - > event_len ,
& pos ) ;
# endif
filp_close ( pfile_fwdump , NULL ) ;
LEAVE ( ) ;
return ;
}
# define DRV_INFO_SIZE 0x60000
# define ROW_SIZE_16 16
# define ROW_SIZE_32 32
/**
* @ brief This function save moal_priv ' s debug log
*
* @ param phandle A pointer to moal_handle
* @ param buf A pointer buffer saving log
*
* @ return The length of this log
*/
static int
woal_dump_priv_drv_info ( moal_handle * handle , t_u8 * buf )
{
char * ptr = ( char * ) buf ;
int index ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
int i = 0 ;
# endif
moal_private * priv ;
ENTER ( ) ;
if ( ! handle | | ! buf ) {
PRINTM ( MMSG , " %s: can't retreive info \n " , __func__ ) ;
LEAVE ( ) ;
return 0 ;
}
for ( index = 0 ; index < MIN ( handle - > priv_num , MLAN_MAX_BSS_NUM ) ;
index + + ) {
priv = handle - > priv [ index ] ;
if ( priv ) {
ptr + = sprintf ( ptr , " [Interface : %s] \n " ,
priv - > proc_entry_name ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
ptr + = sprintf ( ptr , " wmm_tx_pending[0] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 0 ] ) ) ;
ptr + = sprintf ( ptr , " wmm_tx_pending[1] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 1 ] ) ) ;
ptr + = sprintf ( ptr , " wmm_tx_pending[2] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 2 ] ) ) ;
ptr + = sprintf ( ptr , " wmm_tx_pending[3] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 3 ] ) ) ;
# endif
ptr + = sprintf ( ptr , " Media state = \" %s \" \n " ,
( ( priv - > media_connected = =
MFALSE ) ? " Disconnected " :
" Connected " ) ) ;
ptr + = sprintf ( ptr , " carrier %s \n " ,
( ( netif_carrier_ok ( priv - > netdev ) ) ? " on "
: " off " ) ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
for ( i = 0 ; i < ( priv - > netdev - > num_tx_queues ) ; i + + ) {
ptr + = sprintf ( ptr , " tx queue %d: %s \n " , i ,
( ( netif_tx_queue_stopped
( netdev_get_tx_queue
( priv - > netdev ,
i ) ) ) ? " stopped " :
" started " ) ) ;
}
# else
ptr + = sprintf ( ptr , " tx queue %s \n " ,
( ( netif_queue_stopped ( priv - > netdev ) ) ?
" stopped " : " started " ) ) ;
# endif
ptr + = sprintf ( ptr , " %s: num_tx_timeout = %d \n " ,
priv - > netdev - > name ,
priv - > num_tx_timeout ) ;
}
}
LEAVE ( ) ;
return ptr - ( char * ) buf ;
}
/**
* @ brief This function save moal_handle ' s info
*
* @ param phandle A pointer to moal_handle
* @ param buf A pointer buffer saving log
*
* @ return The length of this log
*/
static int
woal_dump_moal_drv_info ( moal_handle * phandle , t_u8 * buf )
{
char * ptr ;
char str_buf [ MLAN_MAX_VER_STR_LEN ] ;
ENTER ( ) ;
if ( ! phandle | | ! buf ) {
PRINTM ( MMSG , " %s: can't retreive info \n " , __func__ ) ;
LEAVE ( ) ;
return 0 ;
}
ptr = ( char * ) buf ;
ptr + = sprintf ( ptr , " ------------moal_debug_info------------- \n " ) ;
woal_get_version ( phandle , str_buf , sizeof ( str_buf ) - 1 ) ;
ptr + = sprintf ( ptr , " Driver version = %s \n " , str_buf ) ;
ptr + = sprintf ( ptr , " main_state = %d \n " , phandle - > main_state ) ;
ptr + = sprintf ( ptr , " ioctl_pending = %d \n " ,
atomic_read ( & phandle - > ioctl_pending ) ) ;
ptr + = sprintf ( ptr , " tx_pending = %d \n " ,
atomic_read ( & phandle - > tx_pending ) ) ;
ptr + = sprintf ( ptr , " rx_pending = %d \n " ,
atomic_read ( & phandle - > rx_pending ) ) ;
ptr + = sprintf ( ptr , " lock_count = %d \n " ,
atomic_read ( & phandle - > lock_count ) ) ;
ptr + = sprintf ( ptr , " malloc_count = %d \n " ,
atomic_read ( & phandle - > malloc_count ) ) ;
ptr + = sprintf ( ptr , " mbufalloc_count = %d \n " ,
atomic_read ( & phandle - > mbufalloc_count ) ) ;
ptr + = sprintf ( ptr , " malloc_cons_count = %d \n " ,
atomic_read ( & phandle - > malloc_cons_count ) ) ;
ptr + = sprintf ( ptr , " hs_skip_count = %u \n " , phandle - > hs_skip_count ) ;
ptr + = sprintf ( ptr , " hs_force_count = %u \n " , phandle - > hs_force_count ) ;
ptr + = woal_dump_priv_drv_info ( phandle , ptr ) ;
ptr + = sprintf ( ptr , " ------------moal_debug_info End------------- \n " ) ;
ptr + = woal_dump_pcie_reg_info ( phandle , ptr ) ;
LEAVE ( ) ;
return ptr - ( char * ) buf ;
}
/**
* @ brief This function save mlan ' s info
*
* @ param phandle A pointer to moal_handle
* @ param buf A pointer buffer saving log
*
* @ return The length of this log
*/
static int
woal_dump_mlan_drv_info ( moal_private * priv , t_u8 * buf )
{
char * ptr = ( char * ) buf ;
int i ;
char str [ 11 * DBG_CMD_NUM + 1 ] = { 0 } ;
char * s ;
ENTER ( ) ;
if ( ! priv | | woal_get_debug_info ( priv , MOAL_IOCTL_WAIT , & info ) ) {
PRINTM ( MERROR ,
" Could not retrieve debug information from MLAN \n " ) ;
LEAVE ( ) ;
return 0 ;
}
ptr + = sprintf ( ptr , " ------------mlan_debug_info------------- \n " ) ;
ptr + = sprintf ( ptr , " mlan_processing =%d \n " , info . mlan_processing ) ;
ptr + = sprintf ( ptr , " main_lock_flag =%d \n " , info . main_lock_flag ) ;
ptr + = sprintf ( ptr , " main_process_cnt =%d \n " , info . main_process_cnt ) ;
ptr + = sprintf ( ptr , " delay_task_flag =%d \n " , info . delay_task_flag ) ;
ptr + = sprintf ( ptr , " mlan_rx_processing =%d \n " ,
info . mlan_rx_processing ) ;
ptr + = sprintf ( ptr , " rx_pkts_queued =%d \n " , info . rx_pkts_queued ) ;
ptr + = sprintf ( ptr , " tx_pkts_queued =%d \n " , info . tx_pkts_queued ) ;
ptr + = sprintf ( ptr , " num_cmd_timeout = %d \n " , info . num_cmd_timeout ) ;
ptr + = sprintf ( ptr , " dbg.num_cmd_timeout = %d \n " ,
info . dbg_num_cmd_timeout ) ;
ptr + = sprintf ( ptr , " Timeout cmd id = 0x%x, act = 0x%x \n " ,
info . timeout_cmd_id , info . timeout_cmd_act ) ;
ptr + = sprintf ( ptr , " last_cmd_index = %d \n " , info . last_cmd_index ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_cmd_id [ i ] ) ;
ptr + = sprintf ( ptr , " last_cmd_id = %s \n " , str ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_cmd_act [ i ] ) ;
ptr + = sprintf ( ptr , " last_cmd_act = %s \n " , str ) ;
ptr + = sprintf ( ptr , " last_cmd_resp_index = %d \n " ,
info . last_cmd_resp_index ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_cmd_resp_id [ i ] ) ;
ptr + = sprintf ( ptr , " last_cmd_resp_id = %s \n " , str ) ;
ptr + = sprintf ( ptr , " last_event_index = %d \n " , info . last_event_index ) ;
for ( s = str , i = 0 ; i < DBG_CMD_NUM ; i + + )
s + = sprintf ( s , " 0x%x " , info . last_event [ i ] ) ;
ptr + = sprintf ( ptr , " last_event = %s \n " , str ) ;
ptr + = sprintf ( ptr , " num_data_h2c_failure = %d \n " ,
info . num_tx_host_to_card_failure ) ;
ptr + = sprintf ( ptr , " num_cmd_h2c_failure = %d \n " ,
info . num_cmd_host_to_card_failure ) ;
ptr + = sprintf ( ptr , " num_alloc_buffer_failure = %d \n " ,
info . num_alloc_buffer_failure ) ;
ptr + = sprintf ( ptr , " num_pkt_dropped = %d \n " , info . num_pkt_dropped ) ;
ptr + = sprintf ( ptr , " num_event_deauth = %d \n " , info . num_event_deauth ) ;
ptr + = sprintf ( ptr , " num_event_disassoc = %d \n " ,
info . num_event_disassoc ) ;
ptr + = sprintf ( ptr , " num_event_link_lost = %d \n " ,
info . num_event_link_lost ) ;
ptr + = sprintf ( ptr , " num_cmd_deauth = %d \n " , info . num_cmd_deauth ) ;
ptr + = sprintf ( ptr , " num_cmd_assoc_success = %d \n " ,
info . num_cmd_assoc_success ) ;
ptr + = sprintf ( ptr , " num_cmd_assoc_failure = %d \n " ,
info . num_cmd_assoc_failure ) ;
ptr + = sprintf ( ptr , " cmd_resp_received = %d \n " , info . cmd_resp_received ) ;
ptr + = sprintf ( ptr , " event_received = %d \n " , info . event_received ) ;
ptr + = sprintf ( ptr , " max_tx_buf_size = %d \n " , info . max_tx_buf_size ) ;
ptr + = sprintf ( ptr , " tx_buf_size = %d \n " , info . tx_buf_size ) ;
ptr + = sprintf ( ptr , " curr_tx_buf_size = %d \n " , info . curr_tx_buf_size ) ;
ptr + = sprintf ( ptr , " data_sent=%d cmd_sent=%d \n " , info . data_sent ,
info . cmd_sent ) ;
ptr + = sprintf ( ptr , " ps_mode=%d ps_state=%d \n " , info . ps_mode ,
info . ps_state ) ;
ptr + = sprintf ( ptr , " wakeup_dev_req=%d wakeup_tries=%d \n " ,
info . pm_wakeup_card_req , info . pm_wakeup_fw_try ) ;
ptr + = sprintf ( ptr , " hs_configured=%d hs_activated=%d \n " ,
info . is_hs_configured , info . hs_activated ) ;
ptr + = sprintf ( ptr , " pps_uapsd_mode=%d sleep_pd=%d \n " ,
info . pps_uapsd_mode , info . sleep_pd ) ;
ptr + = sprintf ( ptr , " tx_lock_flag = %d \n " , info . tx_lock_flag ) ;
ptr + = sprintf ( ptr , " port_open = %d \n " , info . port_open ) ;
ptr + = sprintf ( ptr , " scan_processing = %d \n " , info . scan_processing ) ;
ptr + = sprintf ( ptr , " txbd: rdptr=0x%x wrptr=0x%x \n " ,
info . txbd_rdptr , info . txbd_wrptr ) ;
ptr + = sprintf ( ptr , " rxbd: rdptr=0x%x wrptr=0x%x \n " ,
info . rxbd_rdptr , info . rxbd_wrptr ) ;
ptr + = sprintf ( ptr , " eventbd: rdptr=0x%x wrptr=0x%x \n " ,
info . eventbd_rdptr , info . eventbd_wrptr ) ;
ptr + = sprintf ( ptr , " ------------mlan_debug_info End------------- \n " ) ;
LEAVE ( ) ;
return ptr - ( char * ) buf ;
}
/**
* @ brief This function dump hex to file
*
* @ param phandle A pointer to moal_handle
* @ param buf A pointer to buffer to dump
* @ param len lengh of buf
* @ param ascii Whether add ascii at the end
* @ param save_buf Buffer which is saved to
*
* @ return The length of this log
*/
static int
woal_save_hex_dump ( int rowsize , const void * buf , size_t len ,
bool ascii , t_u8 * save_buf )
{
const u8 * ptr = buf ;
int i , linelen , remaining = len ;
unsigned char linebuf [ ROW_SIZE_32 * 3 + 2 + ROW_SIZE_32 + 1 ] ;
char * pos = ( char * ) save_buf ;
if ( rowsize ! = ROW_SIZE_16 & & rowsize ! = ROW_SIZE_32 )
rowsize = ROW_SIZE_16 ;
for ( i = 0 ; i < len ; i + = rowsize ) {
linelen = min ( remaining , rowsize ) ;
remaining - = rowsize ;
hex_dump_to_buffer ( ptr + i , linelen , rowsize , 1 , linebuf ,
sizeof ( linebuf ) , ascii ) ;
pos + = sprintf ( pos , " %s \n " , linebuf ) ;
}
return pos - ( char * ) save_buf ;
}
# define HostCmd_CMD_CFG_DATA 0x008f
# define DEF_FW_PATH " / lib / firmware / "
# define DEF_HOSTCMD_PATH " / lib / firmware / mrvl / hostcmd.conf"
/**
* @ brief This function save the hostcmd response to file
*
* @ param phandle A pointer to moal_handle
* @ param pevent A pointer to mlan_cmdresp_event
*
* @ return N / A
*/
t_void
woal_save_host_cmdresp ( moal_handle * phandle , mlan_cmdresp_event * pevent )
{
HostCmd_DS_GEN * resp ;
char file_path [ 256 ] ;
struct file * pfile = NULL ;
int ret ;
t_u8 * buf ;
t_u16 command ;
int len = 0 ;
char * ptr ;
loff_t pos = 0 ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
mm_segment_t fs ;
# endif
resp = ( HostCmd_DS_GEN * ) pevent - > resp ;
command = woal_le16_to_cpu ( resp - > command ) ;
memset ( file_path , 0 , sizeof ( file_path ) ) ;
ret = moal_vmalloc ( phandle , pevent - > event_len * 5 , & buf ) ;
if ( ret ! = MLAN_STATUS_SUCCESS | | ! buf ) {
PRINTM ( MERROR , " Fail to allocate memory to save hostcmd \n " ) ;
return ;
}
memset ( buf , 0 , pevent - > event_len * 5 ) ;
ptr = ( char * ) buf ;
switch ( command ) {
case HostCmd_CMD_CFG_DATA :
if ( dpd_data_cfg )
sprintf ( file_path , " %s%s " , DEF_FW_PATH , dpd_data_cfg ) ;
else
sprintf ( file_path , " %s " , DEF_HOSTCMD_PATH ) ;
break ;
default :
sprintf ( file_path , " %s " , DEF_HOSTCMD_PATH ) ;
break ;
}
pfile = filp_open ( file_path , O_CREAT | O_WRONLY | O_APPEND , 0644 ) ;
if ( IS_ERR ( pfile ) ) {
PRINTM ( MERROR , " Cannot create file %s \n " , file_path ) ;
moal_vfree ( phandle , buf ) ;
return ;
}
ptr + = sprintf ( ptr , " hostcmd_%02x=={ \n " , command ) ;
ptr + = woal_save_hex_dump ( ROW_SIZE_16 , resp , pevent - > event_len , MFALSE ,
ptr ) ;
ptr + = sprintf ( ptr , " } \n " ) ;
len = ptr - ( char * ) buf ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
vfs_write ( pfile , buf , len , & pos ) ;
set_fs ( fs ) ;
# else
kernel_write ( pfile , buf , len , & pos ) ;
# endif
PRINTM ( MMSG , " Save hostcmd 0x%02x, cmd len=%d file len=%d to file %s \n " ,
command , pevent - > event_len , len , file_path ) ;
if ( buf )
moal_vfree ( phandle , buf ) ;
filp_close ( pfile , NULL ) ;
return ;
}
/**
* @ brief This function dump moal hex to file
*
* @ param phandle A pointer to moal_handle
* @ param buf A pointer to buffer
*
* @ return The length of this log
*/
static int
woal_dump_moal_hex ( moal_handle * phandle , t_u8 * buf )
{
char * ptr = ( char * ) buf ;
int i ;
ENTER ( ) ;
if ( ! phandle | | ! buf ) {
PRINTM ( MMSG , " %s: can't retreive info \n " , __func__ ) ;
LEAVE ( ) ;
return 0 ;
}
ptr + = sprintf ( ptr , " <--moal_handle--> \n " ) ;
ptr + = sprintf ( ptr , " moal_handle=%p, size=%ld(0x%lx) \n " , phandle ,
( long int ) sizeof ( * phandle ) ,
( long unsigned int ) sizeof ( * phandle ) ) ;
ptr + = woal_save_hex_dump ( ROW_SIZE_16 , phandle , sizeof ( * phandle ) , MTRUE ,
ptr ) ;
ptr + = sprintf ( ptr , " <--moal_handle End--> \n " ) ;
for ( i = 0 ; i < phandle - > priv_num ; i + + ) {
ptr + = sprintf ( ptr , " <--moal_private(%d)--> \n " , i ) ;
ptr + = sprintf ( ptr , " moal_private=%p, size=%ld(0x%lx) \n " ,
phandle - > priv [ i ] ,
( long int ) sizeof ( * ( phandle - > priv [ i ] ) ) ,
( long unsigned int ) sizeof ( * ( phandle - > priv [ i ] ) ) ) ;
ptr + = woal_save_hex_dump ( ROW_SIZE_16 , phandle - > priv [ i ] ,
sizeof ( * ( phandle - > priv [ i ] ) ) , MTRUE ,
ptr ) ;
ptr + = sprintf ( ptr , " <--moal_private(%d) End--> \n " , i ) ;
}
LEAVE ( ) ;
return ptr - ( char * ) buf ;
}
/**
* @ brief This function dump mlan hex to file
*
* @ param priv A pointer to moal_private structure
* @ param buf A pointer to buffer
*
* @ return The length of this log
*/
static int
woal_dump_mlan_hex ( moal_private * priv , t_u8 * buf )
{
char * ptr = ( char * ) buf ;
int i ;
ENTER ( ) ;
if ( ! buf | | ! priv | | woal_get_debug_info ( priv , MOAL_IOCTL_WAIT , & info ) ) {
PRINTM ( MMSG , " %s: can't retreive info \n " , __func__ ) ;
LEAVE ( ) ;
return 0 ;
}
ptr + = sprintf ( ptr , " <--mlan_adapter--> \n " ) ;
ptr + = sprintf ( ptr , " mlan_adapter=%p, size=%d(0x%x) \n " ,
info . mlan_adapter , info . mlan_adapter_size ,
info . mlan_adapter_size ) ;
ptr + = woal_save_hex_dump ( ROW_SIZE_16 , info . mlan_adapter ,
info . mlan_adapter_size , MTRUE , ptr ) ;
ptr + = sprintf ( ptr , " <--mlan_adapter End--> \n " ) ;
for ( i = 0 ; i < info . mlan_priv_num ; i + + ) {
ptr + = sprintf ( ptr , " <--mlan_private(%d)--> \n " , i ) ;
ptr + = sprintf ( ptr , " mlan_private=%p, size=%d(0x%x) \n " ,
info . mlan_priv [ i ] , info . mlan_priv_size [ i ] ,
info . mlan_priv_size [ i ] ) ;
ptr + = woal_save_hex_dump ( ROW_SIZE_16 , info . mlan_priv [ i ] ,
info . mlan_priv_size [ i ] , MTRUE , ptr ) ;
ptr + = sprintf ( ptr , " <--mlan_private(%d) End--> \n " , i ) ;
}
LEAVE ( ) ;
return ptr - ( char * ) buf ;
}
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
/**
* @ brief This function create dump directory
*
* @ param phandle A pointer to moal_handle
* @ param dir_buf A pointer to dir_buf buffer
* @ param buf_size Size of dir_buf buffer
*
* @ return N / A
*/
void
woal_create_dump_dir ( moal_handle * phandle , char * dir_buf , int buf_size )
{
struct dentry * dentry ;
struct path path ;
t_u32 sec , usec ;
int ret ;
ENTER ( ) ;
if ( ! phandle | | ! dir_buf ) {
PRINTM ( MERROR , " Can't create directory \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
moal_get_system_time ( phandle , & sec , & usec ) ;
memset ( dir_buf , 0 , buf_size ) ;
sprintf ( dir_buf , " %s%u " , " /data/dump_ " , sec ) ;
dentry = kern_path_create ( AT_FDCWD , dir_buf , & path , 1 ) ;
if ( IS_ERR ( dentry ) ) {
PRINTM ( MERROR ,
" Create directory %s error, try create dir in /var " ,
dir_buf ) ;
memset ( dir_buf , 0 , buf_size ) ;
sprintf ( dir_buf , " %s%u " , " /var/dump_ " , sec ) ;
dentry = kern_path_create ( AT_FDCWD , dir_buf , & path , 1 ) ;
}
if ( IS_ERR ( dentry ) ) {
PRINTM ( MERROR , " Create directory %s error, use default folder " ,
dir_buf ) ;
goto default_dir ;
}
ret = vfs_mkdir ( path . dentry - > d_inode , dentry , 0777 ) ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
mutex_unlock ( & path . dentry - > d_inode - > i_mutex ) ;
# else
inode_unlock ( path . dentry - > d_inode ) ;
# endif
if ( ret < 0 ) {
PRINTM ( MERROR ,
" Create directory failure, use default folder \n " ) ;
PRINTM ( MERROR , " Create directory failure, ret = %d \n " , ret ) ;
goto default_dir ;
} else {
PRINTM ( MERROR , " Create directory %s successfully \n " , dir_buf ) ;
goto done ;
}
default_dir :
memset ( dir_buf , 0 , buf_size ) ;
sprintf ( dir_buf , " %s " , " /data " ) ;
done :
LEAVE ( ) ;
}
# endif
/**
* @ brief This function save dump buf to file
*
* @ param dir_name A pointer to directory name
* @ param file_name A pointer to file name
* @ param buf A pointer to dump data
* @ param buf_len The length of dump buf
*
* @ return SUCCESS OR FAILURE
*/
mlan_status
woal_save_dump_info_to_file ( char * dir_name , char * file_name , t_u8 * buf ,
t_u32 buf_len )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
struct file * pfile = NULL ;
t_u8 name [ 64 ] ;
loff_t pos ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
mm_segment_t fs ;
# endif
ENTER ( ) ;
if ( ! dir_name | | ! file_name | | ! buf ) {
PRINTM ( MERROR , " Can't save dump info to file \n " ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
memset ( name , 0 , sizeof ( name ) ) ;
sprintf ( name , " %s/%s " , dir_name , file_name ) ;
pfile = filp_open ( name , O_CREAT | O_RDWR , 0644 ) ;
if ( IS_ERR ( pfile ) ) {
PRINTM ( MERROR ,
" Create file %s error, try to save dump file in /var \n " ,
name ) ;
memset ( name , 0 , sizeof ( name ) ) ;
sprintf ( name , " %s/%s " , " /var " , file_name ) ;
pfile = filp_open ( name , O_CREAT | O_RDWR , 0644 ) ;
}
if ( IS_ERR ( pfile ) ) {
PRINTM ( MERROR , " Create Dump file for %s error \n " , name ) ;
ret = MLAN_STATUS_FAILURE ;
goto done ;
}
PRINTM ( MERROR , " Dump data %s saved in %s \n " , file_name , name ) ;
pos = 0 ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
vfs_write ( pfile , buf , buf_len , & pos ) ;
set_fs ( fs ) ;
# else
kernel_write ( pfile , buf , buf_len , & pos ) ;
# endif
filp_close ( pfile , NULL ) ;
PRINTM ( MERROR , " Dump data %s saved in %s successfully \n " , file_name ,
name ) ;
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function dump drv info to file
*
* @ param phandle A pointer to moal_handle
* @ param dir_name A pointer to directory name
*
* @ return N / A
*/
void
woal_dump_drv_info ( moal_handle * phandle , t_u8 * dir_name )
{
int ret = 0 ;
struct file * pfile = NULL ;
t_u8 * drv_buf ;
t_u8 file_name [ 64 ] ;
t_u32 len = 0 ;
t_u32 total_len = 0 ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
mm_segment_t fs ;
# endif
ENTER ( ) ;
PRINTM ( MERROR , " === START DRIVER INFO DUMP=== " ) ;
ret = moal_vmalloc ( phandle , DRV_INFO_SIZE + 1 , & drv_buf ) ;
if ( ( ret ! = MLAN_STATUS_SUCCESS ) | | ! drv_buf ) {
PRINTM ( MERROR , " Error: vmalloc drv buffer failed! \n " ) ;
goto done ;
}
memset ( file_name , 0 , sizeof ( file_name ) ) ;
sprintf ( file_name , " %s/%s " , dir_name , " file_drv_info " ) ;
pfile = filp_open ( file_name , O_CREAT | O_RDWR , 0644 ) ;
if ( IS_ERR ( pfile ) ) {
PRINTM ( MERROR ,
" Create file %s error, try create /var/file_drv_info " ,
file_name ) ;
pfile = filp_open ( " /var/file_drv_info " , O_CREAT | O_RDWR , 0644 ) ;
} else {
PRINTM ( MERROR , " DRV dump data in %s \n " , file_name ) ;
}
if ( IS_ERR ( pfile ) ) {
PRINTM ( MERROR , " Create file_drv_info file failed \n " ) ;
goto done ;
}
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
# endif
len = woal_dump_moal_drv_info ( phandle , drv_buf ) ;
total_len + = len ;
len = woal_dump_mlan_drv_info ( woal_get_priv ( phandle , MLAN_BSS_ROLE_ANY ) ,
drv_buf + total_len ) ;
total_len + = len ;
len = woal_dump_moal_hex ( phandle , drv_buf + total_len ) ;
total_len + = len ;
len = woal_dump_mlan_hex ( woal_get_priv ( phandle , MLAN_BSS_ROLE_ANY ) ,
drv_buf + total_len ) ;
total_len + = len ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
vfs_write ( pfile , drv_buf , total_len , & pfile - > f_pos ) ;
# else
kernel_write ( pfile , drv_buf , total_len , & pfile - > f_pos ) ;
# endif
PRINTM ( MERROR , " Drv info total bytes = %ld (0x%lx) \n " ,
( long int ) total_len , ( long unsigned int ) total_len ) ;
filp_close ( pfile , NULL ) ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
set_fs ( fs ) ;
# endif
PRINTM ( MERROR , " === DRIVER INFO DUMP END=== " ) ;
done :
if ( drv_buf )
moal_vfree ( phandle , drv_buf ) ;
LEAVE ( ) ;
}
/**
* @ brief This function displays extra MOAL debug information
*
* @ param priv A pointer to moal_private
* @ param handle A pointer to moal_handle
* @ param flag Indicates whether register read can be done directly
*
* @ return N / A
*/
void
woal_moal_debug_info ( moal_private * priv , moal_handle * handle , u8 flag )
{
moal_handle * phandle = NULL ;
char buf [ MLAN_MAX_VER_STR_LEN ] ;
int i = 0 ;
ENTER ( ) ;
if ( ! priv ) {
if ( handle ) {
phandle = handle ;
} else {
PRINTM ( MERROR ,
" Could not retrieve debug information from MOAL \n " ) ;
LEAVE ( ) ;
return ;
}
} else {
phandle = priv - > phandle ;
}
woal_get_version ( phandle , buf , sizeof ( buf ) - 1 ) ;
PRINTM ( MERROR , " Driver version = %s \n " , buf ) ;
PRINTM ( MERROR , " main_state = %d \n " , phandle - > main_state ) ;
PRINTM ( MERROR , " ioctl_pending = %d \n " ,
atomic_read ( & phandle - > ioctl_pending ) ) ;
PRINTM ( MERROR , " tx_pending = %d \n " , atomic_read ( & phandle - > tx_pending ) ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
if ( priv ) {
PRINTM ( MERROR , " wmm_tx_pending[0] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 0 ] ) ) ;
PRINTM ( MERROR , " wmm_tx_pending[1] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 1 ] ) ) ;
PRINTM ( MERROR , " wmm_tx_pending[2] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 2 ] ) ) ;
PRINTM ( MERROR , " wmm_tx_pending[3] = %d \n " ,
atomic_read ( & priv - > wmm_tx_pending [ 3 ] ) ) ;
}
# endif
PRINTM ( MERROR , " rx_pending = %d \n " , atomic_read ( & phandle - > rx_pending ) ) ;
PRINTM ( MERROR , " lock_count = %d \n " , atomic_read ( & phandle - > lock_count ) ) ;
PRINTM ( MERROR , " malloc_count = %d \n " ,
atomic_read ( & phandle - > malloc_count ) ) ;
PRINTM ( MERROR , " mbufalloc_count = %d \n " ,
atomic_read ( & phandle - > mbufalloc_count ) ) ;
PRINTM ( MERROR , " malloc_cons_count = %d \n " ,
atomic_read ( & phandle - > malloc_cons_count ) ) ;
PRINTM ( MERROR , " hs_skip_count = %u \n " , phandle - > hs_skip_count ) ;
PRINTM ( MERROR , " hs_force_count = %u \n " , phandle - > hs_force_count ) ;
if ( priv ) {
PRINTM ( MERROR , " Media state = \" %s \" \n " ,
( ( priv - > media_connected = =
MFALSE ) ? " Disconnected " : " Connected " ) ) ;
PRINTM ( MERROR , " carrier %s \n " ,
( ( netif_carrier_ok ( priv - > netdev ) ) ? " on " : " off " ) ) ;
# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
for ( i = 0 ; i < ( priv - > netdev - > num_tx_queues ) ; i + + ) {
PRINTM ( MERROR , " tx queue %d: %s \n " , i ,
( ( netif_tx_queue_stopped
( netdev_get_tx_queue ( priv - > netdev , i ) ) ) ?
" stopped " : " started " ) ) ;
}
# else
PRINTM ( MERROR , " tx queue %s \n " ,
( ( netif_queue_stopped ( priv - > netdev ) ) ? " stopped " :
" started " ) ) ;
# endif
}
for ( i = 0 ; i < phandle - > priv_num ; i + + ) {
priv = phandle - > priv [ i ] ;
if ( priv )
PRINTM ( MERROR , " %s: num_tx_timeout = %d \n " ,
priv - > netdev - > name , priv - > num_tx_timeout ) ;
}
if ( phandle - > is_suspended = = MTRUE ) {
LEAVE ( ) ;
return ;
}
woal_pcie_reg_dbg ( phandle ) ;
if ( drvdbg & MFW_D ) {
drvdbg & = ~ MFW_D ;
phandle - > fw_dbg = MTRUE ;
queue_work ( phandle - > workqueue , & phandle - > main_work ) ;
}
LEAVE ( ) ;
return ;
}
/**
* @ brief Download power table to firmware for a specific country
*
* @ param priv A pointer to moal_private
* @ param country ISO 3166 - 1 alpha - 2 country code
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
woal_request_country_power_table ( moal_private * priv , char * country )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
moal_handle * handle = NULL ;
char country_name [ ] = " txpower_XX.bin " ;
char file_path [ 256 ] ;
char * last_slash = NULL ;
ENTER ( ) ;
if ( ! priv | | ! priv - > phandle ) {
PRINTM ( MERROR , " Priv or handle is null \n " ) ;
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
if ( ! country ) {
PRINTM ( MERROR , " Country is null \n " ) ;
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
handle = priv - > phandle ;
/* Replace XX with ISO 3166-1 alpha-2 country code */
strncpy ( strstr ( country_name , " XX " ) , country , strlen ( country ) ) ;
memset ( file_path , 0 , sizeof ( file_path ) ) ;
/* file_path should be Null terminated */
if ( fw_name & & ( strlen ( fw_name ) < sizeof ( file_path ) ) ) {
strncpy ( file_path , fw_name ,
MIN ( ( sizeof ( file_path ) - 1 ) , strlen ( fw_name ) ) ) ;
last_slash = strrchr ( file_path , ' / ' ) ;
if ( last_slash )
memset ( last_slash + 1 , 0 ,
sizeof ( file_path ) - 1 - ( last_slash -
file_path ) ) ;
else
memset ( file_path , 0 , sizeof ( file_path ) ) ;
} else {
strncpy ( file_path , " mrvl/ " , sizeof ( file_path ) ) ;
}
strncpy ( file_path + strlen ( file_path ) , country_name ,
strlen ( country_name ) ) ;
country_txpwrlimit = file_path ;
if ( MLAN_STATUS_SUCCESS ! =
woal_set_user_init_data ( handle , COUNTRY_POWER_TABLE ,
MOAL_IOCTL_WAIT ) ) {
PRINTM ( MFATAL , " Download power table to firmware failed \n " ) ;
ret = MLAN_STATUS_FAILURE ;
}
LEAVE ( ) ;
return ret ;
}
/**
* @ brief napi polling call back function .
*
* @ param napi A pointer to napi_struct
* @ param budget the limit of packets driver should poll
*
* @ return packets received
*/
int
woal_netdev_poll_rx ( struct napi_struct * napi , int budget )
{
moal_handle * handle = container_of ( napi , moal_handle , napi_rx ) ;
t_u8 recv = budget ;
ENTER ( ) ;
if ( handle - > surprise_removed = = MTRUE ) {
napi_complete ( napi ) ;
LEAVE ( ) ;
return 0 ;
}
mlan_rx_process ( handle - > pmlan_adapter , & recv ) ;
if ( recv < budget )
napi_complete ( napi ) ;
LEAVE ( ) ;
return recv ;
}
/**
* @ brief This workqueue function handles rx_process
*
* @ param work A pointer to work_struct
*
* @ return N / A
*/
t_void
woal_rx_work_queue ( struct work_struct * work )
{
moal_handle * handle = container_of ( work , moal_handle , rx_work ) ;
# ifdef STA_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
# if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 14, 6)
moal_private * priv ;
# endif
# endif
# endif
ENTER ( ) ;
if ( handle - > surprise_removed = = MTRUE ) {
LEAVE ( ) ;
return ;
}
# ifdef STA_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
# if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 14, 6)
if ( handle - > rx_bgscan_stop ) {
handle - > rx_bgscan_stop = MFALSE ;
priv = handle - > bg_scan_priv ;
handle - > bg_scan_priv = NULL ;
if ( priv & & priv - > sched_scanning ) {
cfg80211_sched_scan_stopped ( priv - > wdev - > wiphy ) ;
PRINTM ( MEVENT , " Report sched_Scan stopped \n " ) ;
priv - > sched_scanning = MFALSE ;
}
}
# endif
# endif
# endif
mlan_rx_process ( handle - > pmlan_adapter , NULL ) ;
LEAVE ( ) ;
}
/**
* @ brief This workqueue function handles main_process
*
* @ param work A pointer to work_struct
*
* @ return N / A
*/
t_void
woal_main_work_queue ( struct work_struct * work )
{
moal_handle * handle = container_of ( work , moal_handle , main_work ) ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
struct sched_param sp = { . sched_priority = wq_sched_prio } ;
# endif
ENTER ( ) ;
if ( handle - > surprise_removed = = MTRUE ) {
LEAVE ( ) ;
return ;
}
if ( handle - > fw_dbg = = MTRUE ) {
handle - > fw_dbg = MFALSE ;
woal_dump_firmware_info ( handle ) ;
}
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
/* Change the priority and scheduling policy of main work queue */
if ( ( wq_sched_prio ! = current - > rt_priority ) | |
( wq_sched_policy ! = current - > policy ) ) {
PRINTM ( MMSG ,
" Set work queue priority %d and scheduling policy %d \n " ,
wq_sched_prio , wq_sched_policy ) ;
sched_setscheduler ( current , wq_sched_policy , & sp ) ;
}
# endif
handle - > main_state = MOAL_ENTER_WORK_QUEUE ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
handle - > main_state = MOAL_START_MAIN_PROCESS ;
/* Call MLAN main process */
mlan_main_process ( handle - > pmlan_adapter ) ;
handle - > main_state = MOAL_END_MAIN_PROCESS ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
# endif
LEAVE ( ) ;
}
/**
* @ brief Handles interrupt
*
*/
/**
* @ param msg_id A message id
* @ param handle A pointer to moal_handle struct
*
* @ return MLAN_STATUS_FAILURE - - when the interrupt is not for us .
*/
mlan_status
woal_interrupt ( unsigned short msg_id , moal_handle * handle )
{
mlan_status ret = MLAN_STATUS_SUCCESS ;
ENTER ( ) ;
handle - > main_state = MOAL_RECV_INT ;
PRINTM ( MINTR , " * \n " ) ;
if ( handle - > surprise_removed = = MTRUE ) {
LEAVE ( ) ;
return MLAN_STATUS_FAILURE ;
}
ret = mlan_interrupt ( msg_id , handle - > pmlan_adapter ) ;
queue_work ( handle - > workqueue , & handle - > main_work ) ;
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function adds the card . it will probe the
* card , allocate the mlan_private and initialize the device .
*
* @ param card A pointer to card
*
* @ return A pointer to moal_handle structure
*/
moal_handle *
woal_add_card ( void * card )
{
moal_handle * handle = NULL ;
mlan_status status = MLAN_STATUS_SUCCESS ;
int netlink_num = NETLINK_MARVELL ;
int index = 0 ;
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
struct netlink_kernel_cfg cfg = {
. groups = NL_MULTICAST_GROUP ,
} ;
# endif
ENTER ( ) ;
if ( MOAL_ACQ_SEMAPHORE_BLOCK ( & AddRemoveCardSem ) )
goto exit_sem_err ;
/* Allocate buffer for moal_handle */
handle = kzalloc ( sizeof ( moal_handle ) , GFP_KERNEL ) ;
if ( ! handle ) {
PRINTM ( MERROR , " Allocate buffer for moal_handle failed! \n " ) ;
goto err_handle ;
}
/* Init moal_handle */
handle - > card = card ;
/* Save the handle */
for ( index = 0 ; index < MAX_MLAN_ADAPTER ; index + + ) {
if ( m_handle [ index ] = = NULL )
break ;
}
if ( index < MAX_MLAN_ADAPTER ) {
m_handle [ index ] = handle ;
handle - > handle_idx = index ;
} else {
PRINTM ( MERROR , " Exceeded maximum cards supported! \n " ) ;
goto err_kmalloc ;
}
if ( mac_addr
# ifdef MFG_CMD_SUPPORT
& & mfg_mode ! = MLAN_INIT_PARA_ENABLED
# endif
) {
t_u8 temp [ 20 ] ;
t_u8 len = strlen ( mac_addr ) + 1 ;
if ( len < sizeof ( temp ) ) {
memcpy ( temp , mac_addr , len ) ;
handle - > set_mac_addr = 1 ;
/* note: the following function overwrites the temp buffer */
woal_mac2u8 ( handle - > mac_addr , temp ) ;
}
}
handle - > histogram_table_num = 1 ;
# ifdef SPI_SUPPORT
( ( struct woal_spi_card * ) card ) - > handle = handle ;
# endif
( ( pcie_service_card * ) card ) - > handle = handle ;
# ifdef STA_SUPPORT
handle - > scan_pending_on_block = MFALSE ;
MOAL_INIT_SEMAPHORE ( & handle - > async_sem ) ;
# endif
/* Init SW */
if ( MLAN_STATUS_SUCCESS ! = woal_init_sw ( handle ) ) {
PRINTM ( MFATAL , " Software Init Failed \n " ) ;
goto err_kmalloc ;
}
do {
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
handle - > nl_sk = netlink_kernel_create ( netlink_num , NULL ) ;
# else
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
handle - > nl_sk =
netlink_kernel_create ( netlink_num , NL_MULTICAST_GROUP ,
NULL , THIS_MODULE ) ;
# else
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
handle - > nl_sk =
netlink_kernel_create ( netlink_num , NL_MULTICAST_GROUP ,
NULL , NULL , THIS_MODULE ) ;
# else
# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
handle - > nl_sk =
netlink_kernel_create ( & init_net , netlink_num ,
NL_MULTICAST_GROUP , NULL , NULL ,
THIS_MODULE ) ;
# else
# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
handle - > nl_sk =
netlink_kernel_create ( & init_net , netlink_num ,
THIS_MODULE , & cfg ) ;
# else
handle - > nl_sk =
netlink_kernel_create ( & init_net , netlink_num , & cfg ) ;
# endif
# endif
# endif
# endif
# endif
if ( handle - > nl_sk ) {
PRINTM ( MINFO , " Netlink number = %d \n " , netlink_num ) ;
handle - > netlink_num = netlink_num ;
break ;
}
netlink_num - - ;
} while ( netlink_num > 0 ) ;
if ( handle - > nl_sk = = NULL ) {
PRINTM ( MERROR ,
" Could not initialize netlink event passing mechanism! \n " ) ;
goto err_kmalloc ;
}
/* Create workqueue for main process */
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
/* For kernel less than 2.6.14 name can not be
* greater than 10 characters */
handle - > workqueue = create_workqueue ( " MOAL_WORKQ " ) ;
# else
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
handle - > workqueue =
alloc_workqueue ( " MOAL_WORK_QUEUE " ,
WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND , 1 ) ;
# else
handle - > workqueue = create_workqueue ( " MOAL_WORK_QUEUE " ) ;
# endif
# endif
if ( ! handle - > workqueue )
goto err_kmalloc ;
MLAN_INIT_WORK ( & handle - > main_work , woal_main_work_queue ) ;
if ( ! napi ) {
/* Create workqueue for rx process */
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
/* For kernel less than 2.6.14 name can not be
* greater than 10 characters */
handle - > rx_workqueue = create_workqueue ( " MOAL_RX_WORKQ " ) ;
# else
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
handle - > rx_workqueue =
alloc_workqueue ( " MOAL_RX_WORK_QUEUE " ,
WQ_HIGHPRI | WQ_MEM_RECLAIM |
WQ_UNBOUND , 1 ) ;
# else
handle - > rx_workqueue = create_workqueue ( " MOAL_RX_WORK_QUEUE " ) ;
# endif
# endif
if ( ! handle - > rx_workqueue ) {
woal_terminate_workqueue ( handle ) ;
goto err_kmalloc ;
}
MLAN_INIT_WORK ( & handle - > rx_work , woal_rx_work_queue ) ;
}
# define NAPI_BUDGET 64
if ( napi ) {
init_dummy_netdev ( & handle - > napi_dev ) ;
netif_napi_add ( & handle - > napi_dev , & handle - > napi_rx ,
woal_netdev_poll_rx , NAPI_BUDGET ) ;
napi_enable ( & handle - > napi_rx ) ;
}
atomic_set ( & handle - > int_flag , 0 ) ;
# ifdef REASSOCIATION
PRINTM ( MINFO , " Starting re-association thread... \n " ) ;
handle - > reassoc_thread . handle = handle ;
woal_create_thread ( woal_reassociation_thread ,
& handle - > reassoc_thread , " woal_reassoc_service " ) ;
while ( ! handle - > reassoc_thread . pid )
woal_sched_timeout ( 2 ) ;
# endif /* REASSOCIATION */
/* Register the device. Fill up the private data structure with
* relevant information from the card and request for the required
* IRQ .
*/
if ( woal_register_dev ( handle ) ! = MLAN_STATUS_SUCCESS ) {
PRINTM ( MFATAL , " Failed to register wlan device! \n " ) ;
goto err_registerdev ;
}
# ifdef ANDROID_KERNEL
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
wakeup_source_init ( & handle - > ws , " mwlan " ) ;
# else
wake_lock_init ( & handle - > wake_lock , WAKE_LOCK_SUSPEND , " mwlan " ) ;
# endif
# endif
/* Init FW and HW */
if ( MLAN_STATUS_SUCCESS ! = woal_init_fw ( handle ) ) {
PRINTM ( MFATAL , " Firmware Init Failed \n " ) ;
goto err_init_fw ;
}
LEAVE ( ) ;
return handle ;
err_init_fw :
if ( ( handle - > hardware_status = = HardwareStatusFwReady ) | |
( handle - > hardware_status = = HardwareStatusReady ) ) {
PRINTM ( MINFO , " shutdown mlan \n " ) ;
handle - > init_wait_q_woken = MFALSE ;
status = mlan_shutdown_fw ( handle - > pmlan_adapter ) ;
if ( status = = MLAN_STATUS_PENDING )
wait_event_interruptible ( handle - > init_wait_q ,
handle - > init_wait_q_woken ) ;
}
# ifdef ANDROID_KERNEL
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
wakeup_source_trash ( & handle - > ws ) ;
# else
wake_lock_destroy ( & handle - > wake_lock ) ;
# endif
# endif
/* Unregister device */
PRINTM ( MINFO , " unregister device \n " ) ;
woal_unregister_dev ( handle ) ;
err_registerdev :
handle - > surprise_removed = MTRUE ;
# ifdef REASSOCIATION
if ( handle - > reassoc_thread . pid )
wake_up_interruptible ( & handle - > reassoc_thread . wait_q ) ;
/* waiting for main thread quit */
while ( handle - > reassoc_thread . pid )
woal_sched_timeout ( 2 ) ;
# endif /* REASSOCIATION */
if ( napi )
netif_napi_del ( & handle - > napi_rx ) ;
woal_terminate_workqueue ( handle ) ;
err_kmalloc :
woal_free_moal_handle ( handle ) ;
if ( index < MAX_MLAN_ADAPTER )
m_handle [ index ] = NULL ;
( ( pcie_service_card * ) card ) - > handle = NULL ;
err_handle :
MOAL_REL_SEMAPHORE ( & AddRemoveCardSem ) ;
exit_sem_err :
LEAVE ( ) ;
return NULL ;
}
/**
* @ brief This function removes the card .
*
* @ param card A pointer to card
*
* @ return MLAN_STATUS_SUCCESS
*/
mlan_status
woal_remove_card ( void * card )
{
moal_handle * handle = NULL ;
moal_private * priv = NULL ;
mlan_status status ;
int i ;
int index = 0 ;
ENTER ( ) ;
if ( MOAL_ACQ_SEMAPHORE_BLOCK ( & AddRemoveCardSem ) )
goto exit_sem_err ;
# ifdef MFG_CMD_SUPPORT
if ( mfg_mode = = MLAN_INIT_PARA_ENABLED ) {
fw_name = NULL ;
mfg_mode = 0 ;
}
# endif
/* Find the correct handle */
for ( index = 0 ; index < MAX_MLAN_ADAPTER ; index + + ) {
if ( m_handle [ index ] & & ( m_handle [ index ] - > card = = card ) ) {
handle = m_handle [ index ] ;
break ;
}
}
if ( ! handle )
goto exit_remove ;
handle - > surprise_removed = MTRUE ;
flush_workqueue ( handle - > workqueue ) ;
if ( handle - > rx_workqueue )
flush_workqueue ( handle - > rx_workqueue ) ;
if ( napi ) {
napi_disable ( & handle - > napi_rx ) ;
netif_napi_del ( & handle - > napi_rx ) ;
}
/* Stop data */
for ( i = 0 ; i < MIN ( handle - > priv_num , MLAN_MAX_BSS_NUM ) ; i + + ) {
priv = handle - > priv [ i ] ;
if ( priv ) {
woal_stop_queue ( priv - > netdev ) ;
if ( netif_carrier_ok ( priv - > netdev ) )
netif_carrier_off ( priv - > netdev ) ;
}
}
if ( ( handle - > hardware_status = = HardwareStatusFwReady ) | |
( handle - > hardware_status = = HardwareStatusReady ) ) {
/* Shutdown firmware */
PRINTM ( MIOCTL , " mlan_shutdown_fw..... \n " ) ;
handle - > init_wait_q_woken = MFALSE ;
status = mlan_shutdown_fw ( handle - > pmlan_adapter ) ;
if ( status = = MLAN_STATUS_PENDING )
wait_event_interruptible ( handle - > init_wait_q ,
handle - > init_wait_q_woken ) ;
PRINTM ( MIOCTL , " mlan_shutdown_fw done! \n " ) ;
}
if ( atomic_read ( & handle - > rx_pending ) | | atomic_read ( & handle - > tx_pending )
| | atomic_read ( & handle - > ioctl_pending ) ) {
PRINTM ( MERROR ,
" ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d \n " ,
atomic_read ( & handle - > rx_pending ) ,
atomic_read ( & handle - > tx_pending ) ,
atomic_read ( & handle - > ioctl_pending ) ) ;
}
unregister_inetaddr_notifier ( & handle - > woal_notifier ) ;
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
if ( handle - > is_remain_timer_set ) {
woal_cancel_timer ( & handle - > remain_timer ) ;
woal_remain_timer_func ( handle ) ;
}
# endif
# endif
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
if ( handle - > is_go_timer_set ) {
woal_cancel_timer ( & handle - > go_timer ) ;
handle - > is_go_timer_set = MFALSE ;
}
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
/* Remove virtual interface */
woal_remove_virtual_interface ( handle ) ;
# endif
# endif
# endif
/* Remove interface */
for ( i = 0 ; i < MIN ( MLAN_MAX_BSS_NUM , handle - > priv_num ) ; i + + )
woal_remove_interface ( handle , i ) ;
woal_terminate_workqueue ( handle ) ;
# ifdef UAP_CFG80211
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
if ( handle - > is_cac_timer_set ) {
woal_cancel_timer ( & handle - > cac_timer ) ;
handle - > is_cac_timer_set = MFALSE ;
}
# endif
# endif
# ifdef REASSOCIATION
PRINTM ( MINFO , " Free reassoc_timer \n " ) ;
if ( handle - > is_reassoc_timer_set ) {
woal_cancel_timer ( & handle - > reassoc_timer ) ;
handle - > is_reassoc_timer_set = MFALSE ;
}
if ( handle - > reassoc_thread . pid )
wake_up_interruptible ( & handle - > reassoc_thread . wait_q ) ;
/* waiting for main thread quit */
while ( handle - > reassoc_thread . pid )
woal_sched_timeout ( 2 ) ;
# endif /* REASSOCIATION */
# ifdef CONFIG_PROC_FS
woal_proc_exit ( handle ) ;
# endif
/* Unregister device */
PRINTM ( MINFO , " unregister device \n " ) ;
woal_unregister_dev ( handle ) ;
# ifdef ANDROID_KERNEL
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
wakeup_source_trash ( & handle - > ws ) ;
# else
wake_lock_destroy ( & handle - > wake_lock ) ;
# endif
# endif
/* Free adapter structure */
PRINTM ( MINFO , " Free Adapter \n " ) ;
woal_free_moal_handle ( handle ) ;
for ( index = 0 ; index < MAX_MLAN_ADAPTER ; index + + ) {
if ( m_handle [ index ] = = handle ) {
m_handle [ index ] = NULL ;
break ;
}
}
exit_remove :
MOAL_REL_SEMAPHORE ( & AddRemoveCardSem ) ;
exit_sem_err :
LEAVE ( ) ;
return MLAN_STATUS_SUCCESS ;
}
# ifdef CONFIG_PROC_FS
/**
* @ brief This function switch the drv_mode
*
* @ param handle A pointer to moal_handle structure
* @ param mode new drv_mode to switch .
*
* @ return MLAN_STATUS_SUCCESS / MLAN_STATUS_FAILURE / MLAN_STATUS_PENDING
*/
mlan_status
woal_switch_drv_mode ( moal_handle * handle , t_u32 mode )
{
unsigned int i ;
mlan_status status = MLAN_STATUS_SUCCESS ;
moal_private * priv = NULL ;
ENTER ( ) ;
if ( MOAL_ACQ_SEMAPHORE_BLOCK ( & AddRemoveCardSem ) )
goto exit_sem_err ;
if ( woal_update_drv_tbl ( handle , mode ) ! = MLAN_STATUS_SUCCESS ) {
PRINTM ( MERROR , " Could not update driver mode table! \n " ) ;
status = MLAN_STATUS_FAILURE ;
goto exit ;
}
/* Reset all interfaces */
priv = woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ;
woal_reset_intf ( priv , MOAL_IOCTL_WAIT , MTRUE ) ;
status = woal_shutdown_fw ( priv , MOAL_IOCTL_WAIT ) ;
if ( status ! = MLAN_STATUS_SUCCESS ) {
PRINTM ( MERROR , " func shutdown failed! \n " ) ;
goto exit ;
}
/* Shutdown firmware */
PRINTM ( MIOCTL , " mlan_shutdown_fw..... \n " ) ;
handle - > init_wait_q_woken = MFALSE ;
status = mlan_shutdown_fw ( handle - > pmlan_adapter ) ;
if ( status = = MLAN_STATUS_PENDING )
wait_event_interruptible ( handle - > init_wait_q ,
handle - > init_wait_q_woken ) ;
PRINTM ( MIOCTL , " mlan_shutdown_fw done! \n " ) ;
if ( atomic_read ( & handle - > rx_pending ) | | atomic_read ( & handle - > tx_pending )
| | atomic_read ( & handle - > ioctl_pending ) ) {
PRINTM ( MERROR ,
" ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d \n " ,
atomic_read ( & handle - > rx_pending ) ,
atomic_read ( & handle - > tx_pending ) ,
atomic_read ( & handle - > ioctl_pending ) ) ;
}
unregister_inetaddr_notifier ( & handle - > woal_notifier ) ;
/* Remove interface */
for ( i = 0 ; i < MIN ( MLAN_MAX_BSS_NUM , handle - > priv_num ) ; i + + )
woal_remove_interface ( handle , i ) ;
/* Unregister mlan */
if ( handle - > pmlan_adapter ) {
mlan_unregister ( handle - > pmlan_adapter ) ;
if ( atomic_read ( & handle - > lock_count ) | |
atomic_read ( & handle - > malloc_count ) | |
atomic_read ( & handle - > mbufalloc_count ) ) {
PRINTM ( MERROR ,
" mlan has memory leak: lock_count=%d, malloc_count=%d, mbufalloc_count=%d \n " ,
atomic_read ( & handle - > lock_count ) ,
atomic_read ( & handle - > malloc_count ) ,
atomic_read ( & handle - > mbufalloc_count ) ) ;
}
if ( atomic_read ( & handle - > malloc_cons_count ) ) {
PRINTM ( MERROR ,
" mlan has memory leak: malloc_cons_count=%d \n " ,
atomic_read ( & handle - > malloc_cons_count ) ) ;
}
handle - > pmlan_adapter = NULL ;
}
handle - > priv_num = 0 ;
drv_mode = mode ;
/* Init SW */
if ( woal_init_sw ( handle ) ) {
PRINTM ( MFATAL , " Software Init Failed \n " ) ;
goto exit ;
}
/* Init FW and HW */
if ( woal_init_fw ( handle ) ) {
PRINTM ( MFATAL , " Firmware Init Failed \n " ) ;
goto exit ;
}
LEAVE ( ) ;
return status ;
exit :
MOAL_REL_SEMAPHORE ( & AddRemoveCardSem ) ;
exit_sem_err :
LEAVE ( ) ;
return status ;
}
# endif
/**
* @ brief This function reload fw
*
* @ param handle A pointer to moal_handle structure
*
* @ return 0 - - success , otherwise failure
*/
static int
woal_reload_fw ( moal_handle * handle )
{
int ret = 0 ;
ENTER ( ) ;
/* Download FW */
ret = woal_request_fw ( handle ) ;
if ( ret ) {
ret = - EFAULT ;
goto done ;
}
PRINTM ( MMSG , " FW Reload successfully. " ) ;
done :
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function reload fw
*
* @ param handle A pointer to moal_handle structure
* @ param mode FW reload mode
*
* @ return 0 - - success , otherwise failure
*/
void
woal_request_fw_reload ( moal_handle * handle , t_u8 mode )
{
int intf_num ;
int ret = 0 ;
mlan_ioctl_req * req = NULL ;
mlan_ds_misc_cfg * misc = NULL ;
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
# if defined(STA_WEXT) || defined(UAP_WEXT)
t_u8 bss_role = MLAN_BSS_ROLE_STA ;
# endif
# endif
# endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
pcie_service_card * card = NULL ;
struct pci_dev * pdev = NULL ;
ENTER ( ) ;
if ( mode = = FW_RELOAD_PCIE_RESET ) {
card = ( pcie_service_card * ) handle - > card ;
pdev = card - > dev ;
pci_reset_function ( pdev ) ;
LEAVE ( ) ;
return ;
}
/** start block IOCTL */
handle - > driver_state = MTRUE ;
if ( mode = = FW_RELOAD_WITH_EMULATION ) {
fw_reload = FW_RELOAD_WITH_EMULATION ;
PRINTM ( MMSG , " FW reload with re-emulation... \n " ) ;
LEAVE ( ) ;
return ;
}
/** detach network interface */
for ( intf_num = 0 ; intf_num < handle - > priv_num ; intf_num + + ) {
woal_stop_queue ( handle - > priv [ intf_num ] - > netdev ) ;
netif_device_detach ( handle - > priv [ intf_num ] - > netdev ) ;
}
handle - > fw_reload = mode ;
woal_update_firmware_name ( handle ) ;
if ( mode = = FW_RELOAD_NO_EMULATION ) {
ret = woal_reload_fw ( handle ) ;
} else
ret = - EFAULT ;
if ( ret ) {
PRINTM ( MERROR , " FW reload fail \n " ) ;
goto done ;
}
/** un-block IOCTL */
handle - > fw_reload = 0 ;
handle - > driver_state = MFALSE ;
/* Restart the firmware */
req = woal_alloc_mlan_ioctl_req ( sizeof ( mlan_ds_misc_cfg ) ) ;
if ( req ) {
misc = ( mlan_ds_misc_cfg * ) req - > pbuf ;
misc - > sub_command = MLAN_OID_MISC_WARM_RESET ;
misc - > param . fw_reload = MTRUE ;
req - > req_id = MLAN_IOCTL_MISC_CFG ;
req - > action = MLAN_ACT_SET ;
if ( MLAN_STATUS_SUCCESS ! =
woal_request_ioctl ( woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ,
req , MOAL_IOCTL_WAIT ) ) {
ret = - EFAULT ;
kfree ( req ) ;
goto done ;
}
kfree ( req ) ;
}
handle - > hardware_status = HardwareStatusReady ;
/* Reset all interfaces */
ret = woal_reset_intf ( woal_get_priv ( handle , MLAN_BSS_ROLE_ANY ) ,
MOAL_IOCTL_WAIT , MTRUE ) ;
/* Initialize private structures */
for ( intf_num = 0 ; intf_num < handle - > priv_num ; intf_num + + ) {
woal_init_priv ( handle - > priv [ intf_num ] , MOAL_IOCTL_WAIT ) ;
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
# if defined(STA_WEXT) || defined(UAP_WEXT)
if ( ( handle - > priv [ intf_num ] - > bss_type = =
MLAN_BSS_TYPE_WIFIDIRECT ) & &
( GET_BSS_ROLE ( handle - > priv [ intf_num ] ) = =
MLAN_BSS_ROLE_UAP ) ) {
if ( MLAN_STATUS_SUCCESS ! =
woal_bss_role_cfg ( handle - > priv [ intf_num ] ,
MLAN_ACT_SET , MOAL_IOCTL_WAIT ,
& bss_role ) ) {
ret = - EFAULT ;
goto done ;
}
}
# endif /* STA_WEXT || UAP_WEXT */
# endif /* STA_SUPPORT && UAP_SUPPORT */
# endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
}
/* Enable interfaces */
for ( intf_num = 0 ; intf_num < handle - > priv_num ; intf_num + + ) {
netif_device_attach ( handle - > priv [ intf_num ] - > netdev ) ;
woal_start_queue ( handle - > priv [ intf_num ] - > netdev ) ;
}
done :
LEAVE ( ) ;
return ;
}
/**
* @ brief This function initializes module .
*
* @ return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static int
woal_init_module ( void )
{
int ret = ( int ) MLAN_STATUS_SUCCESS ;
int index = 0 ;
ENTER ( ) ;
PRINTM ( MMSG , " wlan: Loading MWLAN driver \n " ) ;
/* Init the wlan_private pointer array first */
for ( index = 0 ; index < MAX_MLAN_ADAPTER ; index + + )
m_handle [ index ] = NULL ;
/* Init mutex */
MOAL_INIT_SEMAPHORE ( & AddRemoveCardSem ) ;
# ifdef CONFIG_OF
woal_init_from_dev_tree ( ) ;
# endif
/* Create workqueue for hang process */
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
/* For kernel less than 2.6.14 name can not be greater than 10
characters */
hang_workqueue = create_workqueue ( " MOAL_HANG_WORKQ " ) ;
# else
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
hang_workqueue = alloc_workqueue ( " MOAL_HANG_WORK_QUEUE " ,
WQ_HIGHPRI | WQ_MEM_RECLAIM |
WQ_UNBOUND , 1 ) ;
# else
hang_workqueue = create_workqueue ( " MOAL_HANG_WORK_QUEUE " ) ;
# endif
# endif
MLAN_INIT_WORK ( & hang_work , woal_hang_work_queue ) ;
/* Register with bus */
ret = woal_bus_register ( ) ;
if ( ret = = MLAN_STATUS_SUCCESS )
PRINTM ( MMSG , " wlan: Driver loaded successfully \n " ) ;
else
PRINTM ( MMSG , " wlan: Driver loading failed \n " ) ;
LEAVE ( ) ;
return ret ;
}
/**
* @ brief This function cleans module
*
* @ return N / A
*/
static void
woal_cleanup_module ( void )
{
moal_handle * handle = NULL ;
int index = 0 ;
int i ;
# if defined(STA_SUPPORT) && defined(STA_CFG80211)
unsigned long flags ;
# endif
ENTER ( ) ;
PRINTM ( MMSG , " wlan: Unloading MWLAN driver \n " ) ;
if ( MOAL_ACQ_SEMAPHORE_BLOCK ( & AddRemoveCardSem ) )
goto exit_sem_err ;
for ( index = 0 ; index < MAX_MLAN_ADAPTER ; index + + ) {
handle = m_handle [ index ] ;
if ( ! handle )
continue ;
if ( ! handle - > priv_num )
goto exit ;
if ( MTRUE = = woal_check_driver_status ( handle ) )
goto exit ;
/* Unregister all connected radiotap net devices */
if ( handle - > mon_if ) {
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
woal_set_net_monitor ( handle - > mon_if - > priv ,
MOAL_IOCTL_WAIT , MFALSE , 0 , NULL ) ;
if ( handle - > ioctl_timeout ) {
woal_ioctl_timeout ( handle ) ;
goto exit ;
}
# endif
netif_device_detach ( handle - > mon_if - > mon_ndev ) ;
if ( handle - > mon_if - > mon_ndev - > reg_state = =
NETREG_REGISTERED )
unregister_netdev ( handle - > mon_if - > mon_ndev ) ;
handle - > mon_if = NULL ;
}
for ( i = 0 ; i < handle - > priv_num ; i + + ) {
# ifdef STA_SUPPORT
if ( GET_BSS_ROLE ( handle - > priv [ i ] ) = = MLAN_BSS_ROLE_STA ) {
if ( handle - > priv [ i ] - > media_connected = = MTRUE ) {
woal_disconnect ( handle - > priv [ i ] ,
MOAL_IOCTL_WAIT_TIMEOUT ,
NULL ,
DEF_DEAUTH_REASON_CODE ) ;
if ( handle - > ioctl_timeout ) {
woal_ioctl_timeout ( handle ) ;
goto exit ;
}
}
# ifdef STA_CFG80211
if ( IS_STA_CFG80211 ( cfg80211_wext ) & &
( handle - > priv [ i ] - > bss_type = =
MLAN_BSS_TYPE_STA ) )
woal_clear_conn_params ( handle - > priv [ i ] ) ;
spin_lock_irqsave ( & handle - > scan_req_lock ,
flags ) ;
if ( IS_STA_CFG80211 ( cfg80211_wext ) & &
handle - > scan_request ) {
woal_cfg80211_scan_done ( handle - >
scan_request ,
MTRUE ) ;
handle - > scan_request = NULL ;
handle - > scan_priv = NULL ;
}
spin_unlock_irqrestore ( & handle - > scan_req_lock ,
flags ) ;
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
if ( IS_STA_CFG80211 ( cfg80211_wext ) & &
handle - > priv [ i ] - > sched_scanning ) {
woal_stop_bg_scan ( handle - > priv [ i ] ,
MOAL_IOCTL_WAIT_TIMEOUT ) ;
if ( handle - > ioctl_timeout ) {
woal_ioctl_timeout ( handle ) ;
goto exit ;
}
handle - > priv [ i ] - > bg_scan_start = MFALSE ;
handle - > priv [ i ] - > bg_scan_reported =
MFALSE ;
cfg80211_sched_scan_stopped ( handle - >
priv [ i ] - >
wdev - > wiphy
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
,
handle - >
priv [ i ] - >
bg_scan_reqid
# endif
) ;
handle - > priv [ i ] - > sched_scanning =
MFALSE ;
}
# endif
# endif
}
# endif
# ifdef UAP_SUPPORT
if ( GET_BSS_ROLE ( handle - > priv [ i ] ) = = MLAN_BSS_ROLE_UAP ) {
# ifdef MFG_CMD_SUPPORT
if ( mfg_mode ! = MLAN_INIT_PARA_ENABLED )
# endif
woal_disconnect ( handle - > priv [ i ] ,
MOAL_IOCTL_WAIT_TIMEOUT ,
NULL ,
DEF_DEAUTH_REASON_CODE ) ;
if ( handle - > ioctl_timeout ) {
woal_ioctl_timeout ( handle ) ;
goto exit ;
}
}
# endif
# if defined(STA_CFG80211) || defined(UAP_CFG80211)
woal_clear_all_mgmt_ies ( handle - > priv [ i ] ,
MOAL_IOCTL_WAIT_TIMEOUT ) ;
if ( handle - > ioctl_timeout ) {
woal_ioctl_timeout ( handle ) ;
goto exit ;
}
woal_flush_tx_stat_queue ( handle - > priv [ i ] ) ;
# endif
}
# ifdef MFG_CMD_SUPPORT
if ( mfg_mode ! = MLAN_INIT_PARA_ENABLED )
# endif
woal_set_deep_sleep ( woal_get_priv
( handle , MLAN_BSS_ROLE_ANY ) ,
MOAL_IOCTL_WAIT_TIMEOUT , MFALSE , 0 ) ;
# ifdef MFG_CMD_SUPPORT
if ( mfg_mode ! = MLAN_INIT_PARA_ENABLED )
# endif
woal_shutdown_fw ( woal_get_priv
( handle , MLAN_BSS_ROLE_ANY ) ,
MOAL_IOCTL_WAIT_TIMEOUT ) ;
if ( handle - > ioctl_timeout ) {
woal_ioctl_timeout ( handle ) ;
goto exit ;
}
}
exit :
MOAL_REL_SEMAPHORE ( & AddRemoveCardSem ) ;
exit_sem_err :
/* Unregister from bus */
woal_bus_unregister ( ) ;
PRINTM ( MMSG , " wlan: Driver unloaded \n " ) ;
if ( hang_workqueue ) {
flush_workqueue ( hang_workqueue ) ;
destroy_workqueue ( hang_workqueue ) ;
hang_workqueue = NULL ;
}
LEAVE ( ) ;
}
# ifndef MODULE
# ifdef MFG_CMD_SUPPORT
/**
* @ brief This function handle the mfg_mode from kernel boot command
*
* @ param str buffer for mfg_mode
* @ return N / A
*/
static int __init
mfg_mode_setup ( char * str )
{
int val = - 1 ;
get_option ( & str , & val ) ;
if ( val > 0 )
mfg_mode = 1 ;
PRINTM ( MMSG , " mfg_mode=%d \n " , mfg_mode ) ;
return 1 ;
}
__setup ( " mfg_mode= " , mfg_mode_setup ) ;
# endif
# endif
module_init ( woal_init_module ) ;
module_exit ( woal_cleanup_module ) ;
module_param ( hw_test , int , 0660 ) ;
MODULE_PARM_DESC ( hw_test , " 0: Disable hardware test; 1: Enable hardware test " ) ;
# ifdef CONFIG_OF
module_param ( dts_enable , int , 0 ) ;
MODULE_PARM_DESC ( dts_enable , " 0: Disable DTS; 1: Enable DTS " ) ;
# endif
module_param ( fw_name , charp , 0660 ) ;
MODULE_PARM_DESC ( fw_name , " Firmware name " ) ;
module_param ( req_fw_nowait , int , 0 ) ;
MODULE_PARM_DESC ( req_fw_nowait ,
" 0: Use request_firmware API; 1: Use request_firmware_nowait API " ) ;
module_param ( fw_reload , int , 0 ) ;
MODULE_PARM_DESC ( fw_reload ,
" 0: disable fw_reload; 1: enable fw reload feature " ) ;
module_param ( fw_serial , int , 0 ) ;
MODULE_PARM_DESC ( fw_serial ,
" 0: support parallel download FW; 1: support serial download FW " ) ;
module_param ( fw_region , int , 0 ) ;
MODULE_PARM_DESC ( fw_region , " 1: create channel regulatory domain from FW " ) ;
module_param ( mac_addr , charp , 0660 ) ;
MODULE_PARM_DESC ( mac_addr , " MAC address " ) ;
# ifdef MFG_CMD_SUPPORT
module_param ( mfg_mode , int , 0660 ) ;
MODULE_PARM_DESC ( mfg_mode ,
" 0: Download normal firmware; 1/2: Download MFG firmware " ) ;
# endif /* MFG_CMD_SUPPORT */
module_param ( drv_mode , int , 0660 ) ;
# if defined(WIFI_DIRECT_SUPPORT)
MODULE_PARM_DESC ( drv_mode ,
" Bit 0: STA; Bit 1: uAP; Bit 2: WIFIDIRECT; Bit 4: NAN " ) ;
# else
MODULE_PARM_DESC ( drv_mode , " Bit 0: STA; Bit 1: uAP; Bit 4: NAN " ) ;
# endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
# ifdef STA_SUPPORT
module_param ( max_sta_bss , int , 0 ) ;
MODULE_PARM_DESC ( max_sta_bss , " Number of STA interfaces (1) " ) ;
module_param ( sta_name , charp , 0 ) ;
MODULE_PARM_DESC ( sta_name , " STA interface name " ) ;
# endif /* STA_SUPPORT */
# ifdef UAP_SUPPORT
module_param ( max_uap_bss , int , 0 ) ;
MODULE_PARM_DESC ( max_uap_bss , " Number of uAP interfaces (1) " ) ;
module_param ( uap_name , charp , 0 ) ;
MODULE_PARM_DESC ( uap_name , " uAP interface name " ) ;
# endif /* UAP_SUPPORT */
# if defined(WIFI_DIRECT_SUPPORT)
module_param ( max_wfd_bss , int , 0 ) ;
MODULE_PARM_DESC ( max_wfd_bss , " Number of WIFIDIRECT interfaces (1) " ) ;
module_param ( wfd_name , charp , 0 ) ;
MODULE_PARM_DESC ( wfd_name , " WIFIDIRECT interface name " ) ;
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
module_param ( max_vir_bss , int , 0 ) ;
MODULE_PARM_DESC ( max_vir_bss , " Number of Virtual interfaces (0) " ) ;
# endif
# endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
module_param ( nan_name , charp , 0 ) ;
MODULE_PARM_DESC ( nan_name , " NAN interface name " ) ;
module_param ( max_nan_bss , int , 0 ) ;
MODULE_PARM_DESC ( max_nan_bss , " Number of NAN interfaces (1) " ) ;
# ifdef DEBUG_LEVEL1
module_param ( drvdbg , uint , 0660 ) ;
MODULE_PARM_DESC ( drvdbg , " Driver debug " ) ;
# endif /* DEBUG_LEVEL1 */
module_param ( auto_ds , int , 0660 ) ;
MODULE_PARM_DESC ( auto_ds ,
" 0: MLAN default; 1: Enable auto deep sleep; 2: Disable auto deep sleep " ) ;
module_param ( ps_mode , int , 0660 ) ;
MODULE_PARM_DESC ( ps_mode ,
" 0: MLAN default; 1: Enable IEEE PS mode; 2: Disable IEEE PS mode " ) ;
module_param ( max_tx_buf , int , 0 ) ;
MODULE_PARM_DESC ( max_tx_buf , " Maximum Tx buffer size (2048/4096/8192) " ) ;
# if defined(STA_SUPPORT)
module_param ( cfg_11d , int , 0 ) ;
MODULE_PARM_DESC ( cfg_11d ,
" 0: MLAN default; 1: Enable 802.11d; 2: Disable 802.11d " ) ;
# endif
module_param ( dpd_data_cfg , charp , 0 ) ;
MODULE_PARM_DESC ( dpd_data_cfg , " DPD data file name " ) ;
module_param ( init_cfg , charp , 0 ) ;
MODULE_PARM_DESC ( init_cfg , " Init config file name " ) ;
module_param ( cal_data_cfg , charp , 0 ) ;
MODULE_PARM_DESC ( cal_data_cfg , " Calibration data file name " ) ;
module_param ( txpwrlimit_cfg , charp , 0 ) ;
MODULE_PARM_DESC ( txpwrlimit_cfg ,
" Set configuration data of Tx power limitation " ) ;
module_param ( cntry_txpwr , int , 0 ) ;
MODULE_PARM_DESC ( cntry_txpwr ,
" Allow setting tx power table of country; 0: disable (default), 1: enable. " ) ;
module_param ( init_hostcmd_cfg , charp , 0 ) ;
MODULE_PARM_DESC ( init_hostcmd_cfg , " Init hostcmd file name " ) ;
module_param ( cfg80211_wext , int , 0660 ) ;
MODULE_PARM_DESC ( cfg80211_wext ,
# ifdef STA_WEXT
" Bit 0: STA WEXT; "
# endif
# ifdef UAP_WEXT
" Bit 1: UAP WEXT; "
# endif
# ifdef STA_CFG80211
" Bit 2: STA CFG80211; "
# endif
# ifdef UAP_CFG80211
" Bit 3: UAP CFG80211; "
# endif
) ;
module_param ( wq_sched_prio , int , 0 ) ;
module_param ( wq_sched_policy , int , 0 ) ;
MODULE_PARM_DESC ( wq_sched_prio , " Priority of work queue " ) ;
MODULE_PARM_DESC ( wq_sched_policy ,
" 0: SCHED_NORMAL; 1: SCHED_FIFO; 2: SCHED_RR; 3: SCHED_BATCH; 5: SCHED_IDLE " ) ;
module_param ( rx_work , int , 0 ) ;
MODULE_PARM_DESC ( rx_work ,
" 0: default; 1: Enable rx_work_queue; 2: Disable rx_work_queue " ) ;
# if defined(WIFI_DIRECT_SUPPORT)
# if defined(STA_CFG80211) && defined(UAP_CFG80211)
# if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
module_param ( p2p_enh , int , 0 ) ;
MODULE_PARM_DESC ( p2p_enh , " 1: Enable enhanced P2P; 0: Disable enhanced P2P " ) ;
# endif
# endif
# endif
module_param ( pcie_int_mode , int , 0 ) ;
MODULE_PARM_DESC ( pcie_int_mode , " 0: Legacy mode; 1: MSI mode; 2: MSI-X mode " ) ;
# ifdef ANDROID_KERNEL
module_param ( wakelock_timeout , int , 0 ) ;
MODULE_PARM_DESC ( wakelock_timeout , " set wakelock_timeout value (ms) " ) ;
# endif
module_param ( dev_cap_mask , uint , 0 ) ;
MODULE_PARM_DESC ( dev_cap_mask , " Device capability mask " ) ;
module_param ( pmic , int , 0 ) ;
MODULE_PARM_DESC ( pmic ,
" 1: Send pmic configure cmd to firmware; 0: No pmic configure cmd sent to firmware " ) ;
module_param ( uap_oper_ctrl , uint , 0 ) ;
MODULE_PARM_DESC ( uap_oper_ctrl , " 0:default; 0x20001:uap restarts on channel 6 " ) ;
module_param ( hs_wake_interval , int , 0660 ) ;
MODULE_PARM_DESC ( hs_wake_interval ,
" Host sleep wakeup interval,it will round to nearest multiple dtim*beacon_period in fw " ) ;
module_param ( indication_gpio , int , 0 ) ;
MODULE_PARM_DESC ( indication_gpio ,
" GPIO to indicate wakeup source; high four bits: level for normal wakeup; low four bits: GPIO pin number. " ) ;
module_param ( hs_mimo_switch , int , 0660 ) ;
MODULE_PARM_DESC ( hs_mimo_switch ,
" Dynamic MIMO-SISO switch during host sleep; 0: disable (default), 1: enable " ) ;
module_param ( indrstcfg , int , 0 ) ;
MODULE_PARM_DESC ( indrstcfg ,
" Independent reset configuration; high byte: GPIO pin number; low byte: IR mode " ) ;
module_param ( fixed_beacon_buffer , int , 0 ) ;
MODULE_PARM_DESC ( fixed_beacon_buffer ,
" 0: allocate default buffer size; 1: allocate max buffer size. " ) ;
# ifdef WIFI_DIRECT_SUPPORT
module_param ( GoAgeoutTime , int , 0 ) ;
MODULE_PARM_DESC ( GoAgeoutTime ,
" 0: use default ageout time; set Go age out time (TU 100ms) " ) ;
# endif
module_param ( gtk_rekey_offload , int , 0 ) ;
MODULE_PARM_DESC ( gtk_rekey_offload ,
" 0: disable gtk_rekey_offload; 1: enable gtk_rekey_offload (default); 2: enable gtk_rekey_offload in suspend mode only; " ) ;
module_param ( multi_dtim , ushort , 0 ) ;
MODULE_PARM_DESC ( multi_dtim , " DTIM interval " ) ;
module_param ( inact_tmo , ushort , 0 ) ;
MODULE_PARM_DESC ( inact_tmo , " IEEE ps inactivity timout value " ) ;
module_param ( napi , int , 0 ) ;
MODULE_PARM_DESC ( napi , " 1: enable napi api; 0: disable napi " ) ;
# if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
module_param ( dfs_offload , int , 0 ) ;
MODULE_PARM_DESC ( dfs_offload , " 1: enable dfs offload; 0: disable dfs offload. " ) ;
# endif
module_param ( drcs_chantime_mode , int , 0 ) ;
MODULE_PARM_DESC ( drcs_chantime_mode ,
" 0: use default value;Bit31~Bit24:Channel time for channel index0;Bit23~Bit16:mode for channel index0;Bit15~Bit8:Channel time for channel index1;Bit7~Bit0:mode for channel index1; mode:0--PM1,1--Null2Self. " ) ;
module_param ( roamoffload_in_hs , int , 0 ) ;
MODULE_PARM_DESC ( roamoffload_in_hs ,
" 1: enable fw roaming only when host suspend; 0: always enable fw roaming. " ) ;
# ifdef UAP_SUPPORT
module_param ( uap_max_sta , int , 0 ) ;
MODULE_PARM_DESC ( uap_max_sta , " Maximum station number for UAP/GO. " ) ;
# endif
MODULE_DESCRIPTION ( " M-WLAN Driver " ) ;
MODULE_AUTHOR ( " Marvell International Ltd. " ) ;
MODULE_VERSION ( MLAN_RELEASE_VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;