luckfox-pico-sdk/sysdrv/drv_ko/wifi/atbm/hal_apollo/sta.c
luckfox-eng29 8f34c2760d project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between
the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door
for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more
usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp:
Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for
compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem.
sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device
tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately.
sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick
boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades.
sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for
fastboot.

Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
2024-10-14 09:47:04 +08:00

5119 lines
152 KiB
C

/*
* Mac80211 STA API for altobeam APOLLO drivers
*
* Copyright (c) 2016, altobeam
*
* Based on:
* Copyright (c) 2010, stericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/firmware.h>
#include <linux/if_arp.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <net/ndisc.h>
#include "apollo.h"
#include "sta.h"
#include "ap.h"
#include "fwio.h"
#include "bh.h"
#include "debug.h"
#include "wsm.h"
#include "hwio.h"
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
#include <net/netlink.h>
#endif /*ROAM_OFFLOAD*/
#endif
//#ifdef CONFIG_ATBM_APOLLO_TESTMODE
#include "atbm_testmode.h"
#include <net/netlink.h>
//#endif /* CONFIG_ATBM_APOLLO_TESTMODE */
#include "net/atbm_mac80211.h"
#include "dbg_event.h"
#include "smartconfig.h"
#if defined(CONFIG_ATBM_APOLLO_STA_DEBUG)
#define sta_printk(...) atbm_printk_always(__VA_ARGS__)
#else
#define sta_printk(...)
#endif
extern int start_choff;
#include "mac80211/ieee80211_i.h"
#define WEP_ENCRYPT_HDR_SIZE 4
#define WEP_ENCRYPT_TAIL_SIZE 4
#define WPA_ENCRYPT_HDR_SIZE 8
#define WPA_ENCRYPT_TAIL_SIZE 12
#define WPA2_ENCRYPT_HDR_SIZE 8
#define WPA2_ENCRYPT_TAIL_SIZE 8
#define WAPI_ENCRYPT_HDR_SIZE 18
#define WAPI_ENCRYPT_TAIL_SIZE 16
#define MAX_ARP_REPLY_TEMPLATE_SIZE 120
/**************start_tx start_rx globla variable*******************/
#if defined(CONFIG_NL80211_TESTMODE) && defined(CONFIG_ATBM_TEST_TOOL)
static u8 ETF_bStart_Tx = 0;
static u8 ETF_bStart_Rx = 0;
static char ch_and_type[20] = {0};
#endif
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
const int atbm_1d_to_ac[8] = {
IEEE80211_AC_BE,
IEEE80211_AC_BK,
IEEE80211_AC_BK,
IEEE80211_AC_BE,
IEEE80211_AC_VI,
IEEE80211_AC_VI,
IEEE80211_AC_VO,
IEEE80211_AC_VO
};
/**
* enum atbm_ac_numbers - AC numbers as used in apollo
* @ATBM_APOLLO_AC_VO: voice
* @ATBM_APOLLO_AC_VI: video
* @ATBM_APOLLO_AC_BE: best effort
* @ATBM_APOLLO_AC_BK: background
*/
enum atbm_ac_numbers {
ATBM_APOLLO_AC_VO = 0,
ATBM_APOLLO_AC_VI = 1,
ATBM_APOLLO_AC_BE = 2,
ATBM_APOLLO_AC_BK = 3,
};
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
#ifdef IPV6_FILTERING
#define MAX_NEIGHBOR_ADVERTISEMENT_TEMPLATE_SIZE 144
#endif /*IPV6_FILTERING*/
static inline void __atbm_free_event_queue(struct list_head *list)
{
while (!list_empty(list)) {
struct atbm_wsm_event *event =
list_first_entry(list, struct atbm_wsm_event,
link);
list_del(&event->link);
atbm_kfree(event);
}
}
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
/* User priority to WSM queue mapping */
const int atbm_priority_to_queueId[8] = {
WSM_QUEUE_BEST_EFFORT,
WSM_QUEUE_BACKGROUND,
WSM_QUEUE_BACKGROUND,
WSM_QUEUE_BEST_EFFORT,
WSM_QUEUE_VIDEO,
WSM_QUEUE_VIDEO,
WSM_QUEUE_VOICE,
WSM_QUEUE_VOICE
};
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
static inline void __atbm_bf_configure(struct atbm_vif *priv)
{
priv->bf_table.numOfIEs = __cpu_to_le32(3);
priv->bf_table.entry[0].ieId = ATBM_WLAN_EID_VENDOR_SPECIFIC;
priv->bf_table.entry[0].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED |
WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT |
WSM_BEACON_FILTER_IE_HAS_APPEARED;
priv->bf_table.entry[0].oui[0] = 0x50;
priv->bf_table.entry[0].oui[1] = 0x6F;
priv->bf_table.entry[0].oui[2] = 0x9A;
priv->bf_table.entry[1].ieId = ATBM_WLAN_EID_ERP_INFO;
priv->bf_table.entry[1].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED |
WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT |
WSM_BEACON_FILTER_IE_HAS_APPEARED;
priv->bf_table.entry[2].ieId = ATBM_WLAN_EID_HT_INFORMATION;
priv->bf_table.entry[2].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED |
WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT |
WSM_BEACON_FILTER_IE_HAS_APPEARED;
priv->bf_control.enabled = WSM_BEACON_FILTER_ENABLE;
}
/* ******************************************************************** */
/* STA API */
int atbm_start(struct ieee80211_hw *dev)
{
struct atbm_common *hw_priv = dev->priv;
int ret = 0;
if(atbm_bh_is_term(hw_priv)){
return ret;
}
/* Assign Max SSIDs supported based on the firmware revision*/
mutex_lock(&hw_priv->conf_mutex);
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
spin_lock_bh(&hw_priv->tsm_lock);
memset(&hw_priv->tsm_stats, 0, sizeof(struct atbm_tsm_stats));
memset(hw_priv->atbm_tsm_stats, 0, 4 * sizeof(struct atbm_tsm_stats));
memset(&hw_priv->tsm_info, 0, sizeof(struct atbm_tsm_info));
spin_unlock_bh(&hw_priv->tsm_lock);
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
memcpy(hw_priv->mac_addr, dev->wiphy->perm_addr, ETH_ALEN);
hw_priv->softled_state = 0;
ret = atbm_setup_mac(hw_priv);
if (WARN_ON(ret))
goto out;
out:
mutex_unlock(&hw_priv->conf_mutex);
return ret;
}
void atbm_stop(struct ieee80211_hw *dev)
{
struct atbm_common *hw_priv = dev->priv;
struct atbm_vif *priv = NULL;
LIST_HEAD(list);
int i;
if(atbm_bh_is_term(hw_priv)){
return;
}
wsm_lock_tx(hw_priv);
while (down_trylock(&hw_priv->scan.lock)) {
/* Scan is in progress. Force it to stop. */
hw_priv->scan.req = NULL;
schedule();
}
up(&hw_priv->scan.lock);
atbm_hw_cancel_delayed_work(&hw_priv->scan.probe_work,true);
atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,true);
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_hw_cancel_delayed_work(&hw_priv->advance_scan_timeout,true);
#endif
atbm_flush_workqueue(hw_priv->workqueue);
#ifdef CONFIG_ATBM_BA_STATUS
atbm_del_timer_sync(&hw_priv->ba_timer);
#endif
mutex_lock(&hw_priv->conf_mutex);
hw_priv->softled_state = 0;
/* atbm_set_leds(hw_priv); */
spin_lock_bh(&hw_priv->event_queue_lock);
list_splice_init(&hw_priv->event_queue, &list);
spin_unlock_bh(&hw_priv->event_queue_lock);
__atbm_free_event_queue(&list);
for (i = 0; i < 4; i++)
atbm_queue_clear(&hw_priv->tx_queue[i], ATBM_WIFI_ALL_IFS);
#if 0
/* HACK! */
if (atomic_xchg(&hw_priv->tx_lock, 1) != 1)
sta_printk( "[STA] TX is force-unlocked "
"due to stop request.\n");
#endif
atbm_for_each_vif(hw_priv, priv, i) {
if (!priv)
continue;
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
priv->listening = false;
#ifndef CONFIG_TX_NO_CONFIRM
priv->delayed_link_loss = 0;
#endif
priv->join_status = ATBM_APOLLO_JOIN_STATUS_PASSIVE;
atbm_hw_cancel_delayed_work(&priv->join_timeout,false);
#ifndef CONFIG_TX_NO_CONFIRM
atbm_hw_cancel_delayed_work(&priv->bss_loss_work,false);
atbm_hw_cancel_delayed_work(&priv->connection_loss_work,false);
#endif
atbm_hw_cancel_delayed_work(&priv->link_id_gc_work,false);
atbm_hw_cancel_delayed_work(&priv->dhcp_retry_work,false);
atbm_del_timer_sync(&priv->mcast_timeout);
}
wsm_unlock_tx(hw_priv);
mutex_unlock(&hw_priv->conf_mutex);
}
int atbm_add_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif)
{
int ret;
struct atbm_common *hw_priv = dev->priv;
struct atbm_vif *priv;
struct atbm_vif **drv_priv = (void *)vif->drv_priv;
#ifndef P2P_MULTIVIF
int i;
if (atomic_read(&hw_priv->num_vifs) >= ATBM_WIFI_MAX_VIFS)
return -EOPNOTSUPP;
#endif
if(atbm_bh_is_term(hw_priv)){
return -EOPNOTSUPP;
}
atbm_printk_sta("%s: vif->type %d, vif->p2p %d, addr %pM\n",
__func__, vif->type, vif->p2p, vif->addr);
priv = ABwifi_get_vif_from_ieee80211(vif);
atomic_set(&priv->enabled, 0);
*drv_priv = priv;
/* __le32 auto_calibration_mode = __cpu_to_le32(1); */
mutex_lock(&hw_priv->conf_mutex);
priv->mode = vif->type;
atbm_hw_vif_write_lock(&hw_priv->vif_list_lock);
if (atomic_read(&hw_priv->num_vifs) < ATBM_WIFI_MAX_VIFS) {
#ifdef P2P_MULTIVIF
if (!memcmp(vif->addr, hw_priv->addresses[0].addr, ETH_ALEN)) {
priv->if_id = 0;
} else if (!memcmp(vif->addr, hw_priv->addresses[1].addr,
ETH_ALEN)) {
priv->if_id = 2;
} else if (!memcmp(vif->addr, hw_priv->addresses[2].addr,
ETH_ALEN)) {
priv->if_id = 1;
}
sta_printk( "%s: if_id %d mac %pM\n",
__func__, priv->if_id, vif->addr);
#else
for (i = 0; i < ATBM_WIFI_MAX_VIFS; i++)
if (!memcmp(vif->addr, hw_priv->addresses[i].addr,
ETH_ALEN))
break;
if (i == ATBM_WIFI_MAX_VIFS) {
atbm_hw_vif_write_unlock(&hw_priv->vif_list_lock);
mutex_unlock(&hw_priv->conf_mutex);
return -EINVAL;
}
priv->if_id = i;
#endif
hw_priv->if_id_slot |= BIT(priv->if_id);
priv->hw_priv = hw_priv;
priv->hw = dev;
priv->vif = vif;
atomic_inc(&hw_priv->num_vifs);
#ifdef ATBM_WIFI_QUEUE_LOCK_BUG
{
/*
*at mac80211,there is 16 queues(local->hw_queue) supported to use by user.
*so if_id = 0 use the first four queues,if_id =1 use second four queues.so
*when add interface ,initing the queue as below.
*/
u8 index = 0;
priv->queue_cap = ATBM_QUEUE_DEFAULT_CAP;
for(index=0;index<IEEE80211_NUM_ACS;index++){
vif->hw_queue[index] = 4*priv->if_id + index;
atbm_printk_sta("%s[%d],hw_queue[%d]=[%d]\n",__func__,priv->if_id,index,vif->hw_queue[index]);
}
}
#endif
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
if(priv->if_id == 0){
atomic_set(&hw_priv->combination,0);
}
#endif
#endif
/*
*BUG!!!!!,we shoud not get priv from vif->drv_priv, because of that at
* some time ,the vif_lock is not inited before called add_interface function,
*but vif->drv_priv has been malloc by mac80211 without inited,so when we get
*priv with spin_lock_bh(&priv->vif_lock),can make the program die.
*To modify the bug,we shoud do as follow:
*1. to make sure priv->vif_lock has been inited,so we judge that
* the i_priv->enabled has been inited as 1;
*/
#ifdef ATBM_PKG_REORDER
atbm_reorder_func_init(priv);
#endif
ret = atbm_debug_init_priv(hw_priv, priv);
WARN_ON(ret);
atbm_vif_setup_params(priv);
WARN_ON(ATBM_HW_VIF_GET(hw_priv->vif_list[priv->if_id]) != NULL);
ATBM_HW_VIF_SET(hw_priv->vif_list[priv->if_id],vif);
} else {
atbm_hw_vif_write_unlock(&hw_priv->vif_list_lock);
mutex_unlock(&hw_priv->conf_mutex);
return -EOPNOTSUPP;
}
atbm_hw_vif_write_unlock(&hw_priv->vif_list_lock);
/* TODO:COMBO :Check if MAC address matches the one expected by FW */
memcpy(hw_priv->mac_addr, vif->addr, ETH_ALEN);
#ifdef ATBM_VIF_LIST_USE_RCU_LOCK
synchronize_rcu();
#endif
/* Enable auto-calibration */
/* Exception in subsequent channel switch; disabled.
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE,
&auto_calibration_mode, sizeof(auto_calibration_mode)));
*/
sta_printk( "[STA] Interface ID:%d of type:%d added\n",
priv->if_id, priv->mode);
if(vif->type == NL80211_IFTYPE_MONITOR){
priv->join_status = ATBM_APOLLO_JOIN_STATUS_SIMPLE_MONITOR;
atbm_printk_sta("%s:start monitor\n",__func__);
}
mutex_unlock(&hw_priv->conf_mutex);
atbm_vif_setup(priv);
ret = WARN_ON(atbm_setup_mac_pvif(priv));
return ret;
}
void atbm_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif)
{
struct atbm_common *hw_priv = dev->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
struct wsm_reset reset = {
.reset_statistics = true,
};
int i;
bool is_htcapie = false;
struct atbm_vif *tmp_priv;
struct wsm_operational_mode mode = {
.power_mode = wsm_power_mode_quiescent,
.disableMoreFlagUsage = true,
};
atbm_printk_sta(" !!! %s: enter, priv=%p type %d p2p %d addr %pM\n",
__func__, priv, vif->type, vif->p2p, vif->addr);
if((atomic_read(&priv->enabled)==0)||(priv->hw_priv != hw_priv)){
atbm_printk_err("[%s] has been removed,dont remove again\n",vif_to_sdata(vif)->name);
return;
}
atomic_set(&priv->enabled, 0);
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
atbm_tx_queues_lock(hw_priv);
/*
*must make sure that there are no pkgs in the lmc.
*/
wsm_lock_tx_async(hw_priv);
if(atbm_bh_is_term(hw_priv)){
goto reset_priv;
}
wsm_flush_tx(hw_priv);
switch (priv->join_status) {
case ATBM_APOLLO_JOIN_STATUS_IBSS:
wsm_reset(hw_priv, &reset, priv->if_id);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 60))
fallthrough;
#endif
case ATBM_APOLLO_JOIN_STATUS_STA:
wsm_lock_tx(hw_priv);
//if (atbm_hw_priv_queue_work(hw_priv, &priv->unjoin_work) <= 0)
// wsm_unlock_tx(hw_priv);
mutex_unlock(&hw_priv->conf_mutex);
atbm_unjoin_work(&priv->unjoin_work);
mutex_lock(&hw_priv->conf_mutex);
break;
case ATBM_APOLLO_JOIN_STATUS_AP:
for (i = 0; priv->link_id_map; ++i) {
if (priv->link_id_map & BIT(i)) {
ABwifi_unmap_link(priv, i);
priv->link_id_map &= ~BIT(i);
}
}
memset(priv->link_id_db, 0,
sizeof(priv->link_id_db));
priv->sta_asleep_mask = 0;
priv->enable_beacon = false;
priv->tx_multicast = false;
priv->aid0_bit_set = false;
priv->buffered_multicasts = false;
priv->pspoll_mask = 0;
reset.link_id = 0;
wsm_reset(hw_priv, &reset, priv->if_id);
WARN_ON(wsm_set_operational_mode(hw_priv, &mode, priv->if_id));
atbm_for_each_vif(hw_priv, tmp_priv, i) {
#ifdef P2P_MULTIVIF
if ((i == (ATBM_WIFI_MAX_VIFS - 1)) || !tmp_priv)
#else
if (!tmp_priv)
#endif
continue;
if ((tmp_priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) && tmp_priv->htcap)
is_htcapie = true;
}
if (is_htcapie) {
hw_priv->vif0_throttle = ATBM_WIFI_HOST_VIF0_11N_THROTTLE;
hw_priv->vif1_throttle = ATBM_WIFI_HOST_VIF1_11N_THROTTLE;
sta_printk(KERN_ERR "AP REMOVE HTCAP 11N %d\n",hw_priv->vif0_throttle);
} else {
hw_priv->vif0_throttle = ATBM_WIFI_HOST_VIF0_11BG_THROTTLE;
hw_priv->vif1_throttle = ATBM_WIFI_HOST_VIF1_11BG_THROTTLE;
sta_printk(KERN_ERR "AP REMOVE 11BG %d\n",hw_priv->vif0_throttle);
}
if(priv->if_id != 0)
{
struct atbm_vif *priv_wlan;
if((priv_wlan=__ABwifi_hwpriv_to_vifpriv(hw_priv,0))!= NULL)
{
if(hw_priv->roc_wlan_pm.pmMode != WSM_PSM_ACTIVE)
memcpy(&priv_wlan->powersave_mode,&hw_priv->roc_wlan_pm,sizeof(struct wsm_set_pm));
atbm_set_pm(priv_wlan,&priv_wlan->powersave_mode);
}
}
break;
case ATBM_APOLLO_JOIN_STATUS_MONITOR:
#if defined(CONFIG_ATBM_STA_LISTEN) || defined(CONFIG_ATBM_SUPPORT_P2P)
atbm_disable_listening(priv);
#endif
break;
case ATBM_APOLLO_JOIN_STATUS_SIMPLE_MONITOR:
atbm_printk_sta("%s:ATBM_APOLLO_JOIN_STATUS_SIMPLE_MONITOR\n",__func__);
atbm_stop_monitor_mode(priv);
break;
#ifdef CONFIG_ATBM_STA_LISTEN
case ATBM_APOLLO_JOIN_STATUS_STA_LISTEN:
WARN_ON(1);
break;
#endif
default:
break;
}
reset_priv:
#ifdef ATBM_PKG_REORDER
atbm_reorder_func_reset(priv,0xff);
#endif
/* TODO:COMBO: Change Queue Module */
sta_printk("%s:priv->if_id(%d)\n",__func__,priv->if_id);
if (!__atbm_flush(hw_priv, true, priv->if_id))
wsm_unlock_tx(hw_priv);
atbm_hw_cancel_delayed_work(&priv->dhcp_retry_work,true);
spin_lock_bh(&priv->dhcp_retry_spinlock);
if(priv->dhcp_retry_skb){
atbm_dev_kfree_skb(priv->dhcp_retry_skb);
priv->dhcp_retry_skb = NULL;
}
spin_unlock_bh(&priv->dhcp_retry_spinlock);
#ifndef CONFIG_TX_NO_CONFIRM
atbm_hw_cancel_delayed_work(&priv->bss_loss_work,false);
atbm_hw_cancel_delayed_work(&priv->connection_loss_work,false);
#endif
atbm_hw_cancel_delayed_work(&priv->link_id_gc_work,false);
atbm_hw_cancel_delayed_work(&priv->join_timeout,false);
#if 0
atbm_hw_cancel_delayed_work(&priv->set_cts_work,false);
#endif
#ifdef CONFIG_ATBM_SUPPORT_P2P
atbm_hw_cancel_delayed_work(&priv->pending_offchanneltx_work,false);
#endif
#ifdef CONFIG_ATBM_MAC80211_NO_USE
atbm_hw_cancel_queue_work(&priv->update_filtering_work,true);
#endif
atbm_hw_cancel_queue_work(&priv->set_beacon_wakeup_period_work,true);
atbm_del_timer_sync(&priv->mcast_timeout);
/* TODO:COMBO: May be reset of these variables "delayed_link_loss and
* join_status to default can be removed as dev_priv will be freed by
* mac80211 */
spin_lock_bh(&priv->ps_state_lock);
if(priv->join_status == ATBM_APOLLO_JOIN_STATUS_AP){
int link_id = 0;
for (link_id = 0; link_id < ATBMWIFI_MAX_STA_IN_AP_MODE; ++link_id) {
if(priv->link_id_db[link_id].status != ATBM_APOLLO_LINK_OFF){
atbm_skb_queue_purge(&priv->link_id_db[link_id].rx_queue);
}
}
}
spin_unlock_bh(&priv->ps_state_lock);
#ifndef CONFIG_TX_NO_CONFIRM
priv->delayed_link_loss = 0;
#endif
priv->join_status = ATBM_APOLLO_JOIN_STATUS_PASSIVE;
wsm_unlock_tx(hw_priv);
if ((priv->if_id ==1) && (priv->mode == NL80211_IFTYPE_AP
|| priv->mode == NL80211_IFTYPE_P2P_GO)) {
hw_priv->is_go_thru_go_neg = false;
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
if((priv->if_id == 1)&&(vif->p2p)){
atbm_printk_sta("%s:reset p2p go save\n",__func__);
atomic_set(&hw_priv->go_bssid_set,0);
atomic_set(&hw_priv->receive_go_resp,0);
atomic_set(&hw_priv->p2p_oper_channel,0);
}
else if(priv->if_id == 0){
atbm_printk_sta("%s:disable combination mode\n",__func__);
atomic_set(&hw_priv->combination,0);
}
#endif
#endif
#ifdef ATBM_WIFI_QUEUE_LOCK_BUG
atbm_clear_priv_queue_cap(priv);
#endif
atbm_hw_vif_write_lock(&hw_priv->vif_list_lock);
atbm_priv_vif_list_write_lock(&priv->vif_lock);
ATBM_HW_VIF_SET(hw_priv->vif_list[priv->if_id],NULL);
hw_priv->if_id_slot &= (~BIT(priv->if_id));
atomic_dec(&hw_priv->num_vifs);
if (atomic_read(&hw_priv->num_vifs) == 0) {
atbm_free_keys(hw_priv);
memset(hw_priv->mac_addr, 0, ETH_ALEN);
}
atbm_priv_vif_list_write_unlock(&priv->vif_lock);
atbm_hw_vif_write_unlock(&hw_priv->vif_list_lock);
priv->listening = false;
atbm_tx_queues_unlock(hw_priv);
#ifdef ATBM_VIF_LIST_USE_RCU_LOCK
synchronize_rcu();
#endif
atbm_debug_release_priv(priv);
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
/*
*flush all work
*/
atbm_flush_workqueue(hw_priv->workqueue);
memset(priv, 0, sizeof(struct atbm_vif));
}
int atbm_change_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif,
enum nl80211_iftype new_type,
bool p2p)
{
int ret = 0;
atbm_printk_sta("atbm_change_interface: type %d (%d), p2p %d (%d)\n",
new_type, vif->type, p2p, vif->p2p);
if (new_type != vif->type || vif->p2p != p2p) {
atbm_remove_interface(dev, vif);
vif->type = new_type;
vif->p2p = p2p;
ret = atbm_add_interface(dev, vif);
}
return ret;
}
int atbm_config(struct ieee80211_hw *dev, u32 changed)
{
int ret = 0;
struct atbm_common *hw_priv = dev->priv;
struct ieee80211_conf *conf = &dev->conf;
bool queue_change_chwork = false;
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
int max_power_level = 0;
int min_power_level = 0;
#endif
u32 support_changed = IEEE80211_CONF_CHANGE_MONITOR|
IEEE80211_CONF_CHANGE_IDLE|
IEEE80211_CONF_CHANGE_POWER|
IEEE80211_CONF_CHANGE_CHANNEL;
/* TODO:COMBO: adjust to multi vif interface
* IEEE80211_CONF_CHANGE_IDLE is still handled per atbm_vif*/
int if_id = 0;
struct atbm_vif *priv;
if(atbm_bh_is_term(hw_priv)){
return 0;
}
if((!!(support_changed & changed)) == 0)
{
atbm_printk_debug( "%s:changed(%x)\n",__func__,changed);
return ret;
}
while (changed &
(IEEE80211_CONF_CHANGE_MONITOR|IEEE80211_CONF_CHANGE_IDLE)) {
struct ieee80211_local *local = hw_to_local(dev);
u8 i = 0;
priv = NULL;
/* TBD: It looks like it's transparent
* there's a monitor interface present -- use this
* to determine for example whether to calculate
* timestamps for packets or not, do not use instead
* of filter flags! */
if(!(changed&IEEE80211_CONF_CHANGE_MONITOR)){
break;
}
if(!(changed&IEEE80211_CONF_CHANGE_CHANNEL)){
break;
}
if(local->monitors == 0){
break;
}
atbm_for_each_vif(hw_priv, priv, i) {
if (priv == NULL)
continue;
if (priv->join_status != ATBM_APOLLO_JOIN_STATUS_SIMPLE_MONITOR)
continue;
break;
}
if(i == ATBM_WIFI_MAX_VIFS){
atbm_printk_debug("%s: no priv is moniter\n",__func__);
break;
}
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
hw_priv->channel = conf->chan_conf->channel;
hw_priv->channel_type = conf->chan_conf->channel_type;
if(hw_priv->monitor_if_id != -1)
atbm_stop_monitor_mode(priv);
if(hw_priv->monitor_if_id == -1){
atbm_start_monitor_mode(priv,hw_priv->channel);
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
return ret;
}
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
sta_printk(
"ignore IEEE80211_CONF_CHANGE_MONITOR (%d)"
"IEEE80211_CONF_CHANGE_IDLE (%d)\n",
(changed & IEEE80211_CONF_CHANGE_MONITOR) ? 1 : 0,
(changed & IEEE80211_CONF_CHANGE_IDLE) ? 1 : 0);
break;
}
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
priv = __ABwifi_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id);
/* TODO: IEEE80211_CONF_CHANGE_QOS */
/* TODO:COMBO:Change when support is available mac80211*/
if (changed & IEEE80211_CONF_CHANGE_POWER) {
/*hw_priv->output_power = conf->power_level;*/
sta_printk("Output power ++%d\n",conf->power_level);
hw_priv->output_power = 20;
sta_printk("Output power --%d\n",hw_priv->output_power);
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
/* Testing if Power Level to set is out of device power range */
if (conf->chan_conf->channel->band ==
IEEE80211_BAND_2GHZ) {
max_power_level = hw_priv->txPowerRange[0].max_power_level;
min_power_level = hw_priv->txPowerRange[0].min_power_level;
} else {
max_power_level = hw_priv->txPowerRange[1].max_power_level;
min_power_level = hw_priv->txPowerRange[1].min_power_level;
}
if (hw_priv->output_power > max_power_level)
hw_priv->output_power = max_power_level;
else if (hw_priv->output_power < min_power_level)
hw_priv->output_power = min_power_level;
#endif /* CONFIG_ATBM_APOLLO_TESTMODE */
sta_printk( "[STA] TX power: %d\n",
hw_priv->output_power);
WARN_ON(wsm_set_output_power(hw_priv,
hw_priv->output_power * 10,
if_id));
}
#ifndef ATBM_SUPPORT_WIDTH_40M
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) &&
(hw_priv->channel != conf->chan_conf->channel)) {
/* Switch Channel commented for CC Mode */
struct ieee80211_channel *ch = conf->chan_conf->channel;
sta_printk( "[STA] Freq %d (wsm ch: %d).\n",
channel_center_freq(ch), channel_hw_value(ch));
/* Earlier there was a call to __atbm_flush().
Removed as deemed unnecessary */
hw_priv->channel = ch;
}
#else
// add change for 40M
/*
*chan_state is used for wlan0 and p2p0 ,because we only surport one channel
*chan_state->tmp_channel and chan_state->tmp_channel_type are usd by sta
*mode when sta is trying to asscoiating with ap and at that time chan_state->conf.offchannel
*will be true.
*chan_state->oper_channel and chan_state->_oper_channel_type is the current channel which
*used by wlan0 or p2p0.
*/
while(changed & IEEE80211_CONF_CHANGE_CHANNEL){
#define CHTYPE_IS_20M(chtype) ((chtype == NL80211_CHAN_HT20)||(chtype == NL80211_CHAN_NO_HT))
u8 new_type;
enum nl80211_channel_type pre_hw_channel_type = hw_priv->channel_type;
struct ieee80211_channel * pre_hw_channel = hw_priv->channel;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local = hw_to_local(dev);
struct ieee80211_channel_state *chan_state = ieee80211_get_channel_state(local, NULL);
/*
*if tmp_channel is used,the channel will be set in the join work.
*/
if((chan_state->tmp_channel == conf->chan_conf->channel)&&
(chan_state->tmp_channel_type == conf->chan_conf->channel_type)&&
(chan_state->conf.offchannel == true)){
atbm_printk_sta("%s:tmp_channel action\n",__func__);
hw_priv->channel = conf->chan_conf->channel;
if(chan_state->_oper_channel_type == conf->chan_conf->channel_type)
hw_priv->channel_type = conf->chan_conf->channel_type;
if(pre_hw_channel == hw_priv->channel)
break;
}
/*
*if oper_channel is used,change both hw_priv->channel and hw_priv->channel_type
*/
if((chan_state->oper_channel == conf->chan_conf->channel)&&
(chan_state->_oper_channel_type == conf->chan_conf->channel_type)&&
(chan_state->conf.offchannel == false)){
atbm_printk_sta("%s:oper_channel action\n",__func__);
hw_priv->channel = conf->chan_conf->channel;
hw_priv->channel_type = conf->chan_conf->channel_type;
}
/*
*here,if hw_priv->channel != conf->chan_conf->channel,must be somethieng
*wrong,only update channel ,do not triger channel switch work
*/
if(hw_priv->channel != conf->chan_conf->channel){
atbm_printk_sta("%s:channel maybe err,must updata\n",__func__);
hw_priv->channel = conf->chan_conf->channel;
hw_priv->channel_type = conf->chan_conf->channel_type;
break;
}
if((pre_hw_channel == hw_priv->channel)&&(pre_hw_channel_type == hw_priv->channel_type)){
atbm_printk_sta("%s:channel not chage(%p)(%d)\n",__func__,hw_priv->channel,hw_priv->channel_type);
break;
}
/*
*search the action sdata to triger the channel workqueue.
*here is safe to search the local->interfaces list
*/
list_for_each_entry(sdata, &local->interfaces, list){
if((sdata->vif.type == NL80211_IFTYPE_MONITOR)||
(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)){
continue;
}
if (!ieee80211_sdata_running(sdata)){
continue;
}
/*
*search the active priv to triger channel switch work
*priv->join_status must has been set and higher than
*ATBM_APOLLO_JOIN_STATUS_MONITOR
*prev channel type is not equal with current channel typer
*and the current channel type must be 40M
*/
if(vif_chw(&sdata->vif) != conf->chan_conf->channel_type){
atbm_printk_sta("[%s]:channel_type(%d),(%d)\n",sdata->name,vif_chw(&sdata->vif),conf->chan_conf->channel_type);
continue;
}
priv = ABwifi_get_vif_from_ieee80211(&sdata->vif);
if(priv == NULL){
atbm_printk_sta("%s:priv == NULL\n",__func__);
continue;
}
if(atomic_read(&priv->enabled)==0){
atbm_printk_sta("%s:priv->enabled = 0\n",__func__);
continue;
}
if(priv->join_status <= ATBM_APOLLO_JOIN_STATUS_MONITOR){
atbm_printk_sta( "%s:not join or not ap mode\n",sdata->name);
continue;
}
hw_priv->channel_type = conf->chan_conf->channel_type;
new_type = CHTYPE_IS_20M(conf->chan_conf->channel_type);
if(pre_hw_channel_type != conf->chan_conf->channel_type){
if(new_type == 0)
queue_change_chwork = true;
else
queue_change_chwork = false;
}
if(sdata->vif.p2p&&(queue_change_chwork == true)){
WARN_ON(ieee80211_chw_is_ht40(vif_chw(&sdata->vif)));
atbm_printk_sta("%s:p2p not suport 40M\n",__func__);
queue_change_chwork = false;
}
if(pre_hw_channel != hw_priv->channel){
atbm_printk_sta("[%s]:%d mode channel change\n",sdata->name,priv->join_status);
queue_change_chwork = true;
}
if(queue_change_chwork == true){
struct wsm_set_chantype set_channtype;
wsm_lock_tx_async(hw_priv);
wsm_flush_tx(hw_priv);
set_channtype.band = (hw_priv->channel->band == IEEE80211_BAND_5GHZ) ?
WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G;
set_channtype.flag = 0;
set_channtype.channelNumber = channel_hw_value(hw_priv->channel);
set_channtype.channelType = (u32)hw_priv->channel_type;
atbm_printk_sta("%s:chatype(%d),channelNumber(%d)\n",__func__,
set_channtype.channelType,set_channtype.channelNumber);
if(wsm_set_chantype_func(hw_priv,&set_channtype,priv->if_id))
{
/*
*if we set channel type err to lmc,send 20 M is safe
*/
atomic_set(&hw_priv->phy_chantype,0);
}else if(ieee80211_chw_is_ht40(hw_priv->channel_type)){
atomic_set(&hw_priv->phy_chantype,1);
atomic_set(&hw_priv->tx_20M_lock,0);
}
else{
atomic_set(&hw_priv->phy_chantype,0);
atomic_set(&hw_priv->tx_20M_lock,1);
}
wsm_unlock_tx(hw_priv);
break;
}
}
break;
}
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
#endif
return ret;
}
void atbm_update_filtering(struct atbm_vif *priv)
{
int ret;
bool bssid_filtering = !priv->rx_filter.bssid;
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_PASSIVE)
return;
else if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_MONITOR)
bssid_filtering = false;
/*
* When acting as p2p client being connected to p2p GO, in order to
* receive frames from a different p2p device, turn off bssid filter.
*
* WARNING: FW dependency!
* This can only be used with FW WSM371 and its successors.
* In that FW version even with bssid filter turned off,
* device will block most of the unwanted frames.
*/
if (priv->vif && priv->vif->p2p)
bssid_filtering = false;
ret = wsm_set_rx_filter(hw_priv, &priv->rx_filter, priv->if_id);
if (!ret)
ret = wsm_set_bssid_filtering(hw_priv, bssid_filtering,
priv->if_id);
#if 0
if (!ret) {
ret = wsm_set_multicast_filter(hw_priv, &priv->multicast_filter,
priv->if_id);
}
#endif
if (ret)
atbm_printk_warn("%s: Update filtering failed: %d.,if(%d)\n",
__func__, ret,priv->if_id);
return;
}
#ifdef CONFIG_ATBM_MAC80211_NO_USE
void atbm_update_filtering_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif,
update_filtering_work);
if(atbm_bh_is_term(priv->hw_priv)){
return;
}
//atbm_update_filtering(priv);
}
#endif
void atbm_set_beacon_wakeup_period_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif,
set_beacon_wakeup_period_work);
if(atbm_bh_is_term(priv->hw_priv)){
// wsm_unlock_tx(priv->hw_priv);
return;
}
WARN_ON(wsm_set_beacon_wakeup_period(priv->hw_priv,
priv->beacon_int * priv->join_dtim_period >
MAX_BEACON_SKIP_TIME_MS ? 1 :
priv->join_dtim_period, 0, priv->if_id));
}
#ifdef ATBM_SUPPORT_WOW
u64 atbm_prepare_multicast(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct netdev_hw_addr_list *mc_list)
{
static u8 broadcast_ipv6[ETH_ALEN] = {
0x33, 0x33, 0x00, 0x00, 0x00, 0x01
};
static u8 broadcast_ipv4[ETH_ALEN] = {
0x01, 0x00, 0x5e, 0x00, 0x00, 0x01
};
struct netdev_hw_addr *ha;
int count = 0;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
if (WARN_ON(!priv))
return netdev_hw_addr_list_count(mc_list);
#ifdef P2P_MULTIVIF
if (priv->if_id == ATBM_WIFI_GENERIC_IF_ID)
return 0;
#endif
/* Disable multicast filtering */
priv->has_multicast_subscription = false;
memset(&priv->multicast_filter, 0x00, sizeof(priv->multicast_filter));
if (netdev_hw_addr_list_count(mc_list) > WSM_MAX_GRP_ADDRTABLE_ENTRIES)
return 0;
/* Enable if requested */
netdev_hw_addr_list_for_each(ha, mc_list) {
sta_printk( "[STA] multicast: %pM\n", ha->addr);
memcpy(&priv->multicast_filter.macAddress[count],
ha->addr, ETH_ALEN);
if (memcmp(ha->addr, broadcast_ipv4, ETH_ALEN) &&
memcmp(ha->addr, broadcast_ipv6, ETH_ALEN))
priv->has_multicast_subscription = true;
count++;
}
if (count) {
priv->multicast_filter.enable = __cpu_to_le32(1);
priv->multicast_filter.numOfAddresses = __cpu_to_le32(count);
}
return netdev_hw_addr_list_count(mc_list);
}
#endif
void atbm_configure_filter(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
if(atbm_bh_is_term(hw_priv)){
*total_flags &= ~(1<<31);
return;
}
#ifdef P2P_MULTIVIF
if (priv->if_id == ATBM_WIFI_GENERIC_IF_ID) {
*total_flags &= ~(1<<31);
return;
}
#endif
*total_flags &= FIF_PROMISC_IN_BSS |
FIF_OTHER_BSS |
FIF_FCSFAIL |
FIF_BCN_PRBRESP_PROMISC |
FIF_PROBE_REQ;
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
priv->rx_filter.promiscuous = (*total_flags & FIF_PROMISC_IN_BSS)
? 1 : 0;
priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS |
FIF_PROBE_REQ)) ? 1 : 0;
priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0;
priv->bf_control.bcn_count = (*total_flags &
(FIF_BCN_PRBRESP_PROMISC |
FIF_PROMISC_IN_BSS |
FIF_PROBE_REQ)) ? 1 : 0;
#if 0
if (priv->listening ^ listening) {
priv->listening = listening;
wsm_lock_tx(hw_priv);
atbm_update_listening(priv, listening);
wsm_unlock_tx(hw_priv);
}
#endif
atbm_update_filtering(priv);
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
}
int atbm_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params)
{
struct atbm_common *hw_priv = dev->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
int ret = 0;
/* To prevent re-applying PM request OID again and again*/
bool old_uapsdFlags;
if(atbm_bh_is_term(hw_priv)){
return 0;
}
if (WARN_ON(!priv))
return -EOPNOTSUPP;
#ifdef P2P_MULTIVIF
if (priv->if_id == ATBM_WIFI_GENERIC_IF_ID)
{
sta_printk("%s:priv->if_id == ATBM_WIFI_GENERIC_IF_ID\n",__func__);
return 0;
}
#endif
mutex_lock(&hw_priv->conf_mutex);
if (queue < dev->queues) {
old_uapsdFlags = priv->uapsd_info.uapsdFlags;
WSM_TX_QUEUE_SET(&priv->tx_queue_params, queue, 0, 0, 0);
ret = wsm_set_tx_queue_params(hw_priv,
&priv->tx_queue_params.params[queue],
queue, priv->if_id);
if (ret) {
sta_printk("%s:wsm_set_tx_queue_params\n",__func__);
ret = -EINVAL;
goto out;
}
WSM_EDCA_SET(&priv->edca, queue, params->aifs,
params->cw_min, params->cw_max, params->txop, 0xc8,
params->uapsd);
ret = wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id);
if (ret) {
sta_printk("%s:wsm_set_edca_params\n",__func__);
ret = -EINVAL;
goto out;
}
if (priv->mode == NL80211_IFTYPE_STATION) {
ret = atbm_set_uapsd_param(priv, &priv->edca);
if (!ret && priv->setbssparams_done &&
(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) &&
(old_uapsdFlags != priv->uapsd_info.uapsdFlags))
atbm_set_pm(priv, &priv->powersave_mode);
}
} else
{
sta_printk("%s:queue(%d),dev->queues(%d)\n",__func__,queue,dev->queues);
ret = -EINVAL;
}
out:
mutex_unlock(&hw_priv->conf_mutex);
return ret;
}
int atbm_get_stats(struct ieee80211_hw *dev,
struct ieee80211_low_level_stats *stats)
{
struct atbm_common *hw_priv = dev->priv;
memcpy(stats, &hw_priv->stats, sizeof(*stats));
return 0;
}
/*
int atbm_get_tx_stats(struct ieee80211_hw *dev,
struct ieee80211_tx_queue_stats *stats)
{
int i;
struct atbm_common *priv = dev->priv;
for (i = 0; i < dev->queues; ++i)
atbm_queue_get_stats(&priv->tx_queue[i], &stats[i]);
return 0;
}
*/
int atbm_set_pm(struct atbm_vif *priv, const struct wsm_set_pm *arg)
{
struct wsm_set_pm pm = *arg;
struct atbm_vif *other_priv=NULL;
if(priv->if_id>=2){
atbm_printk_err("%s %d ,ERROR !!! priv->if_id = %d >=2\n",__func__,__LINE__,priv->if_id);
return -1;
}
other_priv = __ABwifi_hwpriv_to_vifpriv(priv->hw_priv,1-priv->if_id);
/*
*there is only one interface ,so we send ps mode to firmware directly.
*/
if(other_priv == NULL){
sta_printk( "%s,if(%d),there is only one interface\n",__func__,priv->if_id);
goto set_self_ps;
}
/*
*there is no station interface ,so we send ps mode to firmware directly.
*/
if(other_priv->join_status != ATBM_APOLLO_JOIN_STATUS_STA)
{
sta_printk( "atbm_set_pm(1) set_self_ps(%d)\n",priv->if_id);
if(other_priv->join_status == ATBM_APOLLO_JOIN_STATUS_AP)
{
if(pm.pmMode == WSM_PSM_ACTIVE)
{
goto set_self_ps;
}
memcpy(&priv->powersave_mode,&pm,sizeof(struct wsm_set_pm));
return 0;
}
goto set_self_ps;
}
/*
*if there is a station disassociated with ap , we only can send active mode
*to firmware.
*/
if(!(other_priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA &&
other_priv->bss_params.aid &&
other_priv->setbssparams_done))
{
sta_printk( "atbm_set_pm(2) set_self_ps(%d)\n",priv->if_id);
if(pm.pmMode == WSM_PSM_ACTIVE)
{
goto set_self_ps;
}
memcpy(&priv->powersave_mode,&pm,sizeof(struct wsm_set_pm));
return 0;
}
do
{
u8 self_ps_mod = !!pm.pmMode;
u8 other_ps_mod = !!other_priv->powersave_mode.pmMode;
#define CHANGE_FW_PS_MODE(change_priv,ps) \
do \
{ \
if(change_priv->firmware_ps_mode.pmMode != ps) \
{ \
change_priv->firmware_ps_mode.pmMode = ps; \
wsm_set_pm(change_priv->hw_priv,&change_priv->firmware_ps_mode, \
change_priv->if_id); \
sta_printk( "change if_id(%d) to ps mode(%x)\n",change_priv->if_id,ps); \
} \
}while(0)
if(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA)
memcpy(&priv->powersave_mode,&pm,sizeof(struct wsm_set_pm));
sta_printk( "%s:self_%d(%d),other_%d(%d)\n",__func__,priv->if_id,self_ps_mod,
other_priv->if_id,other_ps_mod);
if(self_ps_mod^other_ps_mod)
{
if(!self_ps_mod)
{
/*
*keep other if alive
*/
CHANGE_FW_PS_MODE(other_priv,WSM_PSM_ACTIVE);
}
else
{
/*
*keep self alive
*/
CHANGE_FW_PS_MODE(priv,WSM_PSM_ACTIVE);
sta_printk( "%s:other_if_%d is in ps ,so self_if_%d change into ps\n",
__func__,other_priv->if_id,priv->if_id);
return 0;
}
}
else
{
if(!self_ps_mod)
{
CHANGE_FW_PS_MODE(other_priv,WSM_PSM_ACTIVE);
}
else
{
if(((!(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA&&
priv->bss_params.aid&&priv->setbssparams_done))||(priv->filter4.enable))
&&other_priv->filter4.enable)
CHANGE_FW_PS_MODE(other_priv,other_priv->powersave_mode.pmMode);
else{
sta_printk( "%s:all interface ip is not enable,so all interface keep alive\n",
__func__);
CHANGE_FW_PS_MODE(other_priv,WSM_PSM_ACTIVE);
CHANGE_FW_PS_MODE(priv,WSM_PSM_ACTIVE);
return 0;
}
}
}
}while(0);
set_self_ps:
if((priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA &&
priv->bss_params.aid &&
priv->setbssparams_done)){
sta_printk("%s:set_self_ps,if(%d),pmmode(%x)\n",__func__,
priv->if_id,pm.pmMode);
if (priv->uapsd_info.uapsdFlags != 0)
pm.pmMode &= ~WSM_PSM_FAST_PS_FLAG;
if (memcmp(&pm, &priv->firmware_ps_mode,
sizeof(struct wsm_set_pm))) {
priv->firmware_ps_mode = pm;
return wsm_set_pm(priv->hw_priv, &pm,
priv->if_id);
} else {
return 0;
}
}
else
{
sta_printk( "%s:if_id(%d) is not assco\n",__func__,priv->if_id);
}
return 0;
}
u8 aes_mac_key_index = 0;
int atbm_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
int ret = -EOPNOTSUPP;
struct atbm_common *hw_priv = dev->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
if(atbm_bh_is_term(hw_priv)){
return 0;
}
#ifdef P2P_MULTIVIF
WARN_ON(priv->if_id == ATBM_WIFI_GENERIC_IF_ID);
#endif
mutex_lock(&hw_priv->conf_mutex);
//sta_printk( "%s cmd<%d> cipher<%x> key<%s> keyidx %d pairwise %d \n",__func__,cmd,key->cipher,&key->key[0],key->keyidx,(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
{
int idx = (int)(~0);
struct wsm_add_key *wsm_key = NULL;
if(cmd == SET_KEY)
{
idx = atbm_alloc_key(hw_priv);
priv->cipherType = key->cipher;
}
else if(cmd == DISABLE_KEY)
{
idx = key->hw_key_idx;
}
if (idx < 0) {
ret = -EINVAL;
sta_printk("cmd(%d),index(%x),err\n",cmd,idx);
goto finally;
}
wsm_key = &hw_priv->keys[idx];
if(cmd == SET_KEY)
{
u8 *peer_addr = NULL;
int pairwise = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ?
1 : 0;
key->flags |= IEEE80211_KEY_FLAG_ALLOC_IV;
// BUG_ON(pairwise && !sta);
if(pairwise && !sta){
atbm_printk_err("%s %d ,ERROR !!! pairwise ,sta is NULL\n",__func__,__LINE__);
ret = -EINVAL;
goto finally;
}
if (sta)
peer_addr = sta->addr;
sta_printk(KERN_ERR "SET_KEY:idx(%d),if_id(%d)\n",idx,priv->if_id);
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
if (key->keylen > 16) {
atbm_free_key(hw_priv, idx);
ret = -EINVAL;
goto finally;
}
//sta_printk("%s WEP key<%s> keyidx %d,pairwise %d\n",__func__,&key->key[0],key->keyidx,pairwise);
if (pairwise) {
wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE;
memcpy(wsm_key->wepPairwiseKey.peerAddress,
peer_addr, ETH_ALEN);
memcpy(wsm_key->wepPairwiseKey.keyData,
&key->key[0], key->keylen);
wsm_key->wepPairwiseKey.keyLength = key->keylen;
} else {
wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT;
memcpy(wsm_key->wepGroupKey.keyData,
&key->key[0], key->keylen);
wsm_key->wepGroupKey.keyLength = key->keylen;
wsm_key->wepGroupKey.keyId = key->keyidx;
}
break;
case WLAN_CIPHER_SUITE_TKIP:
if (pairwise) {
wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE;
memcpy(wsm_key->tkipPairwiseKey.peerAddress,
peer_addr, ETH_ALEN);
memcpy(wsm_key->tkipPairwiseKey.tkipKeyData,
&key->key[0], 16);
memcpy(wsm_key->tkipPairwiseKey.txMicKey,
&key->key[16], 8);
memcpy(wsm_key->tkipPairwiseKey.rxMicKey,
&key->key[24], 8);
} else {
size_t mic_offset =
(priv->mode == NL80211_IFTYPE_AP) ?
16 : 24;
wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP;
memcpy(wsm_key->tkipGroupKey.tkipKeyData,
&key->key[0], 16);
memcpy(wsm_key->tkipGroupKey.rxMicKey,
&key->key[mic_offset], 8);
/* TODO: Where can I find TKIP SEQ? */
memset(wsm_key->tkipGroupKey.rxSeqCounter,
0, 8);
wsm_key->tkipGroupKey.keyId = key->keyidx;
}
break;
case WLAN_CIPHER_SUITE_CCMP:
if (pairwise) {
wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE;
memcpy(wsm_key->aesPairwiseKey.peerAddress,
peer_addr, ETH_ALEN);
memcpy(wsm_key->aesPairwiseKey.aesKeyData,
&key->key[0], 16);
} else {
wsm_key->type = WSM_KEY_TYPE_AES_GROUP;
memcpy(wsm_key->aesGroupKey.aesKeyData,
&key->key[0], 16);
/* TODO: Where can I find AES SEQ? */
memset(wsm_key->aesGroupKey.rxSeqCounter,
0, 8);
wsm_key->aesGroupKey.keyId = key->keyidx;
}
break;
case WLAN_CIPHER_SUITE_AES_CMAC: /*add 11W support*/
{
struct wsm_protected_mgmt_policy mgmt_policy;
mgmt_policy.protectedMgmtEnable = 1;
mgmt_policy.unprotectedMgmtFramesAllowed = 1;
mgmt_policy.encryptionForAuthFrame = 1;
wsm_set_protected_mgmt_policy(hw_priv, &mgmt_policy,
priv->if_id);
sta_printk("WLAN_CIPHER_SUITE_AES_CMAC,index(%d)\n",key->keyidx);
wsm_key->type = WSM_KEY_TYPE_IGTK_GROUP;
memcpy(wsm_key->igtkGroupKey.igtKeyData, &key->key[0], 16);
memset(wsm_key->igtkGroupKey.ipn, 0, 8);
wsm_key->igtkGroupKey.keyId = key->keyidx;
aes_mac_key_index = key->keyidx;
}
break;
#ifdef CONFIG_ATBM_APOLLO_WAPI_SUPPORT
case WLAN_CIPHER_SUITE_SMS4:
if (pairwise) {
wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE;
memcpy(wsm_key->wapiPairwiseKey.peerAddress,
peer_addr, ETH_ALEN);
memcpy(wsm_key->wapiPairwiseKey.wapiKeyData,
&key->key[0], 16);
memcpy(wsm_key->wapiPairwiseKey.micKeyData,
&key->key[16], 16);
wsm_key->wapiPairwiseKey.keyId = key->keyidx;
} else {
wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP;
memcpy(wsm_key->wapiGroupKey.wapiKeyData,
&key->key[0], 16);
memcpy(wsm_key->wapiGroupKey.micKeyData,
&key->key[16], 16);
wsm_key->wapiGroupKey.keyId = key->keyidx;
}
break;
#endif /* CONFIG_ATBM_APOLLO_WAPI_SUPPORT */
default:
WARN_ON(1);
atbm_free_key(hw_priv, idx);
ret = -EOPNOTSUPP;
goto finally;
}
ret = WARN_ON(wsm_add_key(hw_priv, wsm_key, priv->if_id));
if (!ret)
key->hw_key_idx = idx;
else
atbm_free_key(hw_priv, idx);
#ifdef CONFIG_ATBM_LMAC_FILTER_IP_FRAME
if (!ret && (pairwise
|| wsm_key->type == WSM_KEY_TYPE_WEP_DEFAULT)
&& (priv->filter4.enable & 0x2))
atbm_set_arpreply(dev, vif);
#ifdef IPV6_FILTERING
if (!ret && (pairwise
|| wsm_key->type == WSM_KEY_TYPE_WEP_DEFAULT)
&& (priv->filter6.enable & 0x2))
atbm_set_na(dev, vif);
#endif /*IPV6_FILTERING*/
#endif
}
else if(cmd == DISABLE_KEY)
{
if (idx > WSM_KEY_MAX_IDX) {
ret = -EINVAL;
goto finally;
}
sta_printk(KERN_ERR "DISABLE_KEY:idx(%d),key_type(%d),if_id(%d)\n",idx,wsm_key->type,priv->if_id);
ret = wsm_remove_key(hw_priv, wsm_key, priv->if_id);
atbm_free_key(hw_priv,idx);
}else {
//BUG_ON("Unsupported command");
atbm_printk_err("%s %d ,ERROR !!! Unsupported command(%x)\n",__func__,__LINE__,cmd);
}
}
finally:
mutex_unlock(&hw_priv->conf_mutex);
return ret;
}
void atbm_wep_key_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif , wep_key_work);
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
u8 queueId = atbm_queue_get_queue_id(hw_priv->pending_frame_id);
struct atbm_queue *queue = &hw_priv->tx_queue[queueId];
__le32 wep_default_key_id = __cpu_to_le32(
priv->wep_default_key_id);
if(atbm_bh_is_term(hw_priv)){
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
if(atbm_queue_remove(hw_priv, queue,hw_priv->pending_frame_id)){
atbm_printk_err("%s %d ,ERROR !!! atbm_queue_remove error\n",__func__,__LINE__);
//return;
}
#else
if(atbm_queue_remove(queue, hw_priv->pending_frame_id)){
atbm_printk_err("%s %d ,ERROR !!! atbm_queue_remove error\n",__func__,__LINE__);
//return;
}
#endif
wsm_unlock_tx(hw_priv);
return;
}
if(queueId >= 4){
atbm_printk_err("%s %d ,ERROR !!! queueId >= 4\n",__func__,__LINE__);
wsm_unlock_tx(hw_priv);
return;
}
sta_printk("[STA] Setting default WEP key: %d\n",
priv->wep_default_key_id);
wsm_flush_tx(hw_priv);
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID,
&wep_default_key_id, sizeof(wep_default_key_id), priv->if_id));
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_requeue(hw_priv, queue,
hw_priv->pending_frame_id, true);
#else
atbm_queue_requeue(queue, hw_priv->pending_frame_id, true);
#endif
wsm_unlock_tx(hw_priv);
}
int atbm_tool_rts_threshold = 0;
int atbm_set_rts_threshold(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u32 value)
{
struct atbm_common *hw_priv = hw->priv;
int ret;
__le32 val32;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
int if_id = priv->if_id;
if(atbm_bh_is_term(hw_priv)){
return 0;
}
#ifdef P2P_MULTIVIF
WARN_ON(priv->if_id == ATBM_WIFI_GENERIC_IF_ID);
#endif
if (value != (u32) -1)
val32 = __cpu_to_le32(value);
else
val32 = 0; /* disabled */
/* mutex_lock(&priv->conf_mutex); */
ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD,
&val32, sizeof(val32), if_id));
/* mutex_unlock(&priv->conf_mutex); */
atbm_tool_rts_threshold = val32;
return ret;
}
#if 0
int atbm_set_tx_rate_retry_cnt(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u8 value1,u8 value2,u8 value3,u8 value4)
{
struct atbm_common *hw_priv = hw->priv;
int ret;
__le32 val32;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
int if_id = priv->if_id;
#ifdef P2P_MULTIVIF
WARN_ON(priv->if_id == ATBM_WIFI_GENERIC_IF_ID);
#endif
WARN_ON((value1 >10)||(value2 >10)||(value3 >10)||(value4 >10));
val32 = value1|
((value1+value2)<<8)|
((value1+value2+value3)<<16)|
((value1+value2+value3+value4)<<24); /* disabled */
/* mutex_lock(&priv->conf_mutex); */
ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_TRANSMIT_RETRY_CNT,
&val32, sizeof(val32), if_id));
/* mutex_unlock(&priv->conf_mutex); */
return ret;
}
#endif
#ifdef ATBM_SDIO_PATCH
int atbm_remove_seqlist(struct atbm_common *hw_priv)
{
struct atbm_seq_bit_map *bitmap=NULL,*tmp=NULL;
spin_lock_bh(&hw_priv->SeqBitMapLock);
list_for_each_entry_safe(bitmap,tmp,&hw_priv->SeqBitMapList,link){
list_del(&bitmap->link);
atbm_kfree(bitmap);
}
spin_unlock_bh(&hw_priv->SeqBitMapLock);
return 0;
}
#endif
/* TODO: COMBO: Flush only a particular interface specific parts */
int __atbm_flush(struct atbm_common *hw_priv, bool drop, int if_id)
{
int i, ret;
struct atbm_vif *priv =
__ABwifi_hwpriv_to_vifpriv(hw_priv, if_id);
if(atbm_bh_is_term(hw_priv)){
sta_printk("<wifi>atbm_bh_is_term just drop txpacket\n");
drop = true;
}
if(priv == NULL){
atbm_printk_err("%s:if_id[%d] is already reset\n",__func__,if_id);
return -1;
}
for (;;) {
/* TODO: correct flush handling is required when dev_stop.
* Temporary workaround: 2s
*/
if (drop) {
for (i = 0; i < 4; ++i)
atbm_queue_clear(&hw_priv->tx_queue[i],
if_id);
#ifdef ATBM_SDIO_PATCH
atbm_remove_seqlist(hw_priv);
#endif
} else {
ret = atbm_wait_event_timeout_stay_awake(hw_priv,
hw_priv->tx_queue_stats.wait_link_id_empty,
atbm_queue_stats_is_empty(
&hw_priv->tx_queue_stats, -1, if_id),
7* HZ,true);
}
if (!drop && unlikely(ret <= 0)) {
wsm_vif_lock_tx(priv);
if(hw_priv->hw_bufs_used == 0){
for (i = 0; i < 4; ++i)
atbm_queue_clear(&hw_priv->tx_queue[i],if_id);
}else {
u8 queueid = 0;
atbm_printk_err( "__atbm_flush: ETIMEDOUT.....hw_priv->hw_bufs_used(%d),tx_lock(%d)\n",hw_priv->hw_bufs_used,
atomic_read(&hw_priv->tx_lock));
for (queueid = 0;queueid<4;queueid++)
atbm_printk_err("%s:queue[%d]-->pending(%d),vif%d_pending(%d),stats->vif_pend(%d)\n",__func__,queueid,
hw_priv->tx_queue[queueid].num_pending,if_id,hw_priv->tx_queue[queueid].num_pending_vif[if_id],
hw_priv->tx_queue_stats.num_queued[if_id]);
mdelay(1000);
ret = -ETIMEDOUT;
wsm_unlock_tx(hw_priv);
break;
}
wsm_unlock_tx(hw_priv);
ret = 0;
} else {
ret = 0;
}
wsm_vif_lock_tx(priv);
if (unlikely(!atbm_queue_stats_is_empty(
&hw_priv->tx_queue_stats, -1, if_id))) {
/* Highly unlekely: WSM requeued frames. */
wsm_unlock_tx(hw_priv);
continue;
}
break;
}
return ret;
}
void atbm_flush(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
bool drop)
{
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
/*TODO:COMBO: reenable this part of code when flush callback
* is implemented per vif */
/*switch (hw_priv->mode) {
case NL80211_IFTYPE_MONITOR:
drop = true;
break;
case NL80211_IFTYPE_AP:
if (!hw_priv->enable_beacon)
drop = true;
break;
}*/
if (!(hw_priv->if_id_slot & BIT(priv->if_id)))
return;
if (!WARN_ON(__atbm_flush(hw_priv, drop, priv->if_id)))
wsm_unlock_tx(hw_priv);
return;
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
int atbm_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
int duration, u64 cookie)
{
int ret;
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
int if_id = priv->if_id;
#ifdef P2P_MULTIVIF
struct atbm_vif *p2p_priv = __ABwifi_hwpriv_to_vifpriv(hw_priv,1);
#endif
if(atbm_bh_is_term(hw_priv)){
return -1;
}
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
hw_priv->roc_if_id = priv->if_id;
hw_priv->roc_start_time = jiffies;
hw_priv->roc_duration = duration+100;
smp_mb();
#ifdef P2P_MULTIVIF
atbm_printk_mgmt("%s:p2p_priv(%x)\n",__func__,(unsigned int)p2p_priv);
if(p2p_priv)
atbm_printk_mgmt( "%s:p2p_priv->join_status(%d)\n",__func__,p2p_priv->join_status);
if((p2p_priv == NULL) || (p2p_priv->join_status <= ATBM_APOLLO_JOIN_STATUS_IBSS))
#else
if((priv->join_status == ATBM_APOLLO_JOIN_STATUS_PASSIVE))
#endif
{
ret = WARN_ON(__atbm_flush(hw_priv, false, if_id));
if(!ret){
wsm_unlock_tx(hw_priv);
atbm_enable_listening(priv, chan);
atbm_printk_mgmt( "%s:remain channel ready,duration(%d),(%llx)\n",__func__,duration,cookie);
}
//hw_priv->roc_not_send = 0;
}
else
{
atbm_printk_err("%s:roc_not_send\n",__func__);
ret = -1;
//ret = 0;
//hw_priv->roc_not_send = 1;
}
if (!ret) {
if(duration>hw->wiphy->max_remain_on_channel_duration){
atbm_printk_err("%s %d ,ERROR !!! duration=%d > max_remain_on_channel_duration = %d\n",
__func__,__LINE__,duration,hw->wiphy->max_remain_on_channel_duration);
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
return -1;
}
atomic_set(&hw_priv->remain_on_channel, 1);
atbm_hw_priv_queue_delayed_work(hw_priv,
&hw_priv->rem_chan_timeout,
(duration+100) * HZ / 1000);
#ifdef P2P_MULTIVIF
priv->join_status = ATBM_APOLLO_JOIN_STATUS_MONITOR;
#endif
ieee80211_ready_on_channel(hw,100);
} else {
hw_priv->roc_if_id = -1;
atomic_set(&hw_priv->remain_on_channel, 0);
atbm_printk_err("atbm_remain_on_channel,err if_id(%d)\n", priv->if_id);
atbm_scan_listenning_restart_delayed(priv);
}
/* set the channel to supplied ieee80211_channel pointer, if it
is not set. This is to remove the crash while sending a probe res
in listen state. Later channel will updated on
IEEE80211_CONF_CHANGE_CHANNEL event*/
if(!hw_priv->channel) {
hw_priv->channel = chan;
}
hw_priv->roc_cookie = cookie;
mutex_unlock(&hw_priv->conf_mutex);
if(ret)
up(&hw_priv->scan.lock);
return ret;
}
int atbm_cancel_remain_on_channel(struct ieee80211_hw *hw)
{
struct atbm_common *hw_priv = hw->priv;
sta_printk( "[STA] Cancel remain on channel\n");
if (atomic_read(&hw_priv->remain_on_channel))
atbm_hw_cancel_delayed_work(&hw_priv->rem_chan_timeout,true);
if (atomic_read(&hw_priv->remain_on_channel))
atbm_rem_chan_timeout(&hw_priv->rem_chan_timeout.work);
return 0;
}
#endif
/* ******************************************************************** */
/* WSM callbacks */
/*
void atbm_channel_switch_cb(struct atbm_common *hw_priv)
{
wsm_unlock_tx(hw_priv);
}
*/
void atbm_free_event_queue(struct atbm_common *hw_priv)
{
LIST_HEAD(list);
spin_lock_bh(&hw_priv->event_queue_lock);
list_splice_init(&hw_priv->event_queue, &list);
spin_unlock_bh(&hw_priv->event_queue_lock);
__atbm_free_event_queue(&list);
}
void atbm_event_handler(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, event_handler);
struct atbm_vif *priv;
struct atbm_wsm_event *event;
LIST_HEAD(list);
spin_lock_bh(&hw_priv->event_queue_lock);
list_splice_init(&hw_priv->event_queue, &list);
spin_unlock_bh(&hw_priv->event_queue_lock);
if(atbm_bh_is_term(hw_priv))
{
goto event_handler_out;
}
mutex_lock(&hw_priv->conf_mutex);
list_for_each_entry(event, &list, link) {
priv = __ABwifi_hwpriv_to_vifpriv(hw_priv, event->if_id);
if (!priv) {
sta_printk( "[CQM] Event for non existing "
"interface, ignoring.\n");
continue;
}
switch (event->evt.eventId) {
case WSM_EVENT_ERROR:
/* I even don't know what is it about.. */
//STUB();
break;
case WSM_EVENT_BSS_LOST:
{
#ifndef CONFIG_TX_NO_CONFIRM
spin_lock_bh(&priv->bss_loss_lock);
if (priv->bss_loss_status > ATBM_APOLLO_BSS_LOSS_NONE) {
spin_unlock_bh(&priv->bss_loss_lock);
break;
}
priv->bss_loss_status = ATBM_APOLLO_BSS_LOSS_CHECKING;
spin_unlock_bh(&priv->bss_loss_lock);
sta_printk("[CQM] BSS lost.");
sta_printk( "[CQM] BSS lost.\n");
atbm_hw_cancel_delayed_work(&priv->bss_loss_work,true);
atbm_hw_cancel_delayed_work(&priv->connection_loss_work,true);
atbm_hw_cancel_delayed_work(&priv->dhcp_retry_work,true);
if (!down_trylock(&hw_priv->scan.lock)) {
up(&hw_priv->scan.lock);
priv->delayed_link_loss = 0;
atbm_hw_priv_queue_delayed_work(hw_priv,
&priv->bss_loss_work, 0);
} else {
/* Scan is in progress. Delay reporting. */
/* Scan complete will trigger bss_loss_work */
priv->delayed_link_loss = 1;
/* Also we're starting watchdog. */
atbm_hw_priv_queue_delayed_work(hw_priv,
&priv->bss_loss_work, 10 * HZ);
}
#else
ieee80211_connection_loss(priv->vif);
#endif
break;
}
#ifndef CONFIG_TX_NO_CONFIRM
case WSM_EVENT_BSS_REGAINED:
{
sta_printk( "[CQM] BSS regained.\n");
priv->delayed_link_loss = 0;
spin_lock_bh(&priv->bss_loss_lock);
priv->bss_loss_status = ATBM_APOLLO_BSS_LOSS_NONE;
spin_unlock_bh(&priv->bss_loss_lock);
atbm_hw_cancel_delayed_work(&priv->bss_loss_work,true);
atbm_hw_cancel_delayed_work(&priv->connection_loss_work,true);
atbm_hw_cancel_delayed_work(&priv->dhcp_retry_work,true);
break;
}
#endif
case WSM_EVENT_RADAR_DETECTED:
//STUB();
break;
case WSM_EVENT_RCPI_RSSI:
{
#ifdef CONFIG_ATBM_SUPPORT_RCPI_RSSI
/* RSSI: signed Q8.0, RCPI: unsigned Q7.1
* RSSI = RCPI / 2 - 110 */
int rcpiRssi = (int)(event->evt.eventData & 0xFF);
int cqm_evt;
#if (PROJ_TYPE>=ARES_A)
if(rcpiRssi > 128)
rcpiRssi = rcpiRssi -256;
else
rcpiRssi = (s8)rcpiRssi;
#else //ATHEBNAB
if (priv->cqm_use_rssi)
rcpiRssi = (s8)rcpiRssi;
else
rcpiRssi = rcpiRssi / 2 - 110;
#endif //(PROJ_TYPE>=ARES_A)
cqm_evt = (rcpiRssi <= priv->cqm_rssi_thold) ?
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW :
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
sta_printk( "[CQM] RSSI event: %d", rcpiRssi);
ieee80211_cqm_rssi_notify(priv->vif, cqm_evt,
GFP_KERNEL);
#endif
break;
}
case WSM_EVENT_BT_INACTIVE:
//STUB();
break;
case WSM_EVENT_BT_ACTIVE:
//STUB();
break;
case WSM_EVENT_INACTIVITY:
{
//int link_id = ffs((u32)(event->evt.eventData)) - 1;
int link_id = 0;
int i = 0;
struct sk_buff *skb;
struct atbm_ieee80211_mgmt *deauth;
struct atbm_link_entry *entry = NULL;
for(i = 0;i<ATBMWIFI_MAX_STA_IN_AP_MODE + 1;i++){
if((BIT(i)&event->evt.eventData) == 0){
continue;
}
if(i == 0){
WARN_ON(1);
continue;
}
link_id = i;
atbm_printk_always("Inactivity entry[%d],[%pM]\n", link_id,priv->link_id_db[link_id-1].mac);
ABwifi_unmap_link(priv, link_id);
skb = atbm_dev_alloc_skb(sizeof(struct atbm_ieee80211_mgmt) + 64);
if(skb == NULL){
atbm_printk_err("Inactivity Event skb NULL\n");
continue;
}
atbm_skb_reserve(skb, 64);
deauth = (struct atbm_ieee80211_mgmt *)atbm_skb_put(skb, sizeof(struct atbm_ieee80211_mgmt));
WARN_ON(!deauth);
entry = &priv->link_id_db[link_id - 1];
deauth->duration = 0;
memcpy(deauth->da, priv->vif->addr, ETH_ALEN);
memcpy(deauth->sa, entry->mac/*priv->link_id_db[i].mac*/, ETH_ALEN);
memcpy(deauth->bssid, priv->vif->addr, ETH_ALEN);
deauth->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_DEAUTH |
IEEE80211_FCTL_TODS);
deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING;
deauth->seq_ctrl = 0;
atbm_ieee80211_rx(hw_priv->hw, skb);
sta_printk(" Inactivity Deauth Frame sent for MAC SA %pM \t and DA %pM\n", deauth->sa, deauth->da);
atbm_hw_priv_queue_work(priv->hw_priv, &priv->set_tim_work);
}
break;
}
case WSM_EVENT_PS_MODE_ERROR:
{
sta_printk("[apollo]:PS_MODE_ERROR");
if (!priv->uapsd_info.uapsdFlags &&
(priv->user_pm_mode != WSM_PSM_PS))
{
struct wsm_set_pm pm = priv->powersave_mode;
int ret = 0;
priv->powersave_mode.pmMode = WSM_PSM_ACTIVE;
ret = atbm_set_pm (priv, &priv->powersave_mode);
if(ret)
priv->powersave_mode = pm;
#ifdef CONFIG_ATBM_STA_DYNAMIC_PS
priv->vif->bss_conf.ps_enabled = false;
#endif
}
break;
}
}
}
mutex_unlock(&hw_priv->conf_mutex);
event_handler_out:
__atbm_free_event_queue(&list);
}
#ifndef CONFIG_TX_NO_CONFIRM
void atbm_bss_loss_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif, bss_loss_work.work);
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
int timeout; /* in beacons */
if(atbm_bh_is_term(hw_priv)){
return;
}
timeout = priv->cqm_link_loss_count -
priv->cqm_beacon_loss_count;
/* Skip the confimration procedure in P2P case */
if (priv->vif->p2p)
goto report;
spin_lock_bh(&priv->bss_loss_lock);
if (priv->bss_loss_status == ATBM_APOLLO_BSS_LOSS_CHECKING) {
// spin_unlock(&priv->bss_loss_lock);
priv->bss_loss_status = ATBM_APOLLO_BSS_LOSS_CONFIRMED;
} else if (priv->bss_loss_status == ATBM_APOLLO_BSS_LOSS_CONFIRMING) {
priv->bss_loss_status = ATBM_APOLLO_BSS_LOSS_NONE;
spin_unlock_bh(&priv->bss_loss_lock);
return;
}
spin_unlock_bh(&priv->bss_loss_lock);
report:
if (priv->cqm_beacon_loss_count) {
sta_printk( "[CQM] Beacon loss.\n");
if (timeout <= 0)
timeout = 0;
// ieee80211_cqm_beacon_miss_notify(priv->vif, GFP_KERNEL);
} else {
timeout = 0;
}
atbm_hw_cancel_delayed_work(&priv->connection_loss_work,true);
atbm_hw_priv_queue_delayed_work(hw_priv,
&priv->connection_loss_work,
timeout * HZ / 10);
spin_lock_bh(&priv->bss_loss_lock);
priv->bss_loss_status = ATBM_APOLLO_BSS_LOSS_NONE;
spin_unlock_bh(&priv->bss_loss_lock);
}
void atbm_connection_loss_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif,
connection_loss_work.work);
sta_printk( "[CQM] Reporting connection loss.\n");
if(atbm_bh_is_term(priv->hw_priv)){
return;
}
ieee80211_connection_loss(priv->vif);
}
void atbm_tx_failure_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif, tx_failure_work);
sta_printk( "[CQM] Reporting TX failure.\n");
if(atbm_bh_is_term(priv->hw_priv)){
return;
}
ieee80211_connection_loss(priv->vif);
// ieee80211_cqm_tx_fail_notify(priv->vif, GFP_KERNEL);
}
#endif
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
/**
* atbm_device_power_calc- Device power calculation
* from values fetch from SDD File.
*
* @priv: the private structure
* @Max_output_power: Power fetch from SDD
* @fe_cor: front-end loss correction
* @band: Either 2GHz or 5GHz
*
*/
void atbm_device_power_calc(struct atbm_common *hw_priv,
s16 max_output_power, s16 fe_cor, u32 band)
{
s16 power_calc;
power_calc = max_output_power - fe_cor;
if ((power_calc % 16) != 0)
power_calc += 16;
hw_priv->txPowerRange[band].max_power_level = power_calc/16;
/*
* 12dBm is control range supported by firmware.
* This means absolute min power is
* max_power_level - 12.
*/
hw_priv->txPowerRange[band].min_power_level =
hw_priv->txPowerRange[band].max_power_level - 12;
hw_priv->txPowerRange[band].stepping = 1;
}
#endif
/* ******************************************************************** */
/* Internal API */
#ifdef CONFIG_SUPPORT_SDD
/*
* This function is called to Parse the SDD file
*to extract listen_interval and PTA related information
*/
static int atbm_parse_SDD_file(struct atbm_common *hw_priv)
{
u8 *sdd_data = (u8 *)hw_priv->sdd->data;
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
s16 max_output_power_2G;
s16 max_output_power_5G;
s16 fe_cor_2G;
s16 fe_cor_5G;
int i;
#endif
struct atbm_sdd {
u8 id ;
u8 length ;
u8 data[] ;
} *pElement;
int parsedLength = 0;
#define SDD_PTA_CFG_ELT_ID 0xEB
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
#define SDD_MAX_OUTPUT_POWER_2G4_ELT_ID 0xE3
#define SDD_MAX_OUTPUT_POWER_5G_ELT_ID 0xE4
#define SDD_FE_COR_2G4_ELT_ID 0x30
#define SDD_FE_COR_5G_ELT_ID 0x31
#define MIN(x, y, z) (x < y ? (x < z ? x : z) : (y < z ? y : z))
#endif
#define FIELD_OFFSET(type, field) ((u8 *)&((type *)0)->field - (u8 *)0)
hw_priv->is_BT_Present = false;
pElement = (struct atbm_sdd *)sdd_data;
pElement = (struct atbm_sdd *)((u8 *)pElement +
FIELD_OFFSET(struct atbm_sdd, data) + pElement->length);
parsedLength += (FIELD_OFFSET(struct atbm_sdd, data) +
pElement->length);
while (parsedLength <= hw_priv->sdd->size) {
switch (pElement->id) {
case SDD_PTA_CFG_ELT_ID:
{
hw_priv->conf_listen_interval =
(*((u16 *)pElement->data+1) >> 7) & 0x1F;
hw_priv->is_BT_Present = true;
sta_printk( "PTA element found.\n");
sta_printk( "Listen Interval %d\n",
hw_priv->conf_listen_interval);
}
break;
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
case SDD_MAX_OUTPUT_POWER_2G4_ELT_ID:
{
max_output_power_2G =
*((s16 *)pElement->data);
}
break;
case SDD_FE_COR_2G4_ELT_ID:
{
fe_cor_2G =
*((s16 *)pElement->data);
}
break;
case SDD_MAX_OUTPUT_POWER_5G_ELT_ID:
{
max_output_power_5G =
*((s16 *)(pElement->data + 4));
}
break;
case SDD_FE_COR_5G_ELT_ID:
{
fe_cor_5G = MIN(
*((s16 *)pElement->data),
*((s16 *)(pElement->data + 2)),
*((s16 *)(pElement->data + 4)));
fe_cor_5G = MIN(
fe_cor_5G,
*((s16 *)(pElement->data + 6)),
*((s16 *)(pElement->data + 8)));
}
break;
#endif
default:
break;
}
pElement = (struct atbm_sdd *)
((u8 *)pElement + FIELD_OFFSET(struct atbm_sdd, data)
+ pElement->length);
parsedLength +=
(FIELD_OFFSET(struct atbm_sdd, data) + pElement->length);
}
if (hw_priv->is_BT_Present == false) {
sta_printk( "PTA element NOT found.\n");
hw_priv->conf_listen_interval = 0;
}
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
/* Max/Min Power Calculation for 2.4G */
atbm_device_power_calc(hw_priv, max_output_power_2G,
fe_cor_2G, IEEE80211_BAND_2GHZ);
/* Max/Min Power Calculation for 5G */
atbm_device_power_calc(hw_priv, max_output_power_5G,
fe_cor_5G, IEEE80211_BAND_5GHZ);
for (i = 0; i < 2; ++i) {
sta_printk( "[STA] Power Values Read from SDD %s:"
"min_power_level[%d]: %d max_power_level[%d]:"
"%d stepping[%d]: %d\n", __func__, i,
hw_priv->txPowerRange[i].min_power_level, i,
hw_priv->txPowerRange[i].max_power_level, i,
hw_priv->txPowerRange[i].stepping);
}
sta_printk( "%s output power before %d\n",__func__,hw_priv->output_power);
/*BUG:TX output power is not set untill config_apollo is called*/
/*This would lead to 0 power set in fw and would effect scan & p2p-find*/
/*Setting to default value here from sdd which would be overwritten when*/
/*we make connection to AP.This value is used only during scan & p2p-ops*/
/*untill AP connection is made*/
if (!hw_priv->output_power)
hw_priv->output_power=hw_priv->txPowerRange[IEEE80211_BAND_2GHZ].max_power_level;
sta_printk( "%s output power after %d\n",__func__,hw_priv->output_power);
#else
sta_printk( "%s output power before %d\n",__func__,hw_priv->output_power);
/*BUG:TX output power: Hardcoding to 20dbm if CCX is not enabled*/
/*TODO: This might change*/
if (!hw_priv->output_power)
hw_priv->output_power=20;
sta_printk( "%s output power after %d\n",__func__,hw_priv->output_power);
#endif
return 0;
#undef SDD_PTA_CFG_ELT_ID
#undef FIELD_OFFSET
}
static char *sdd = SDD_FILE_DEFAULT_PATH;
module_param(sdd, charp, 0644);
MODULE_PARM_DESC(sdd, "Override sdd file");
#endif
int atbm_setup_mac(struct atbm_common *hw_priv)
{
int ret = 0;
#ifdef CONFIG_SUPPORT_SDD
if (0) {
const char *sdd_path = sdd;
struct wsm_configuration cfg = {
.dot11StationId = &hw_priv->mac_addr[0],
};
sta_printk( "setup mac addr start :[ %02x,%02x,%02x,%02x,%02x,%02x ] \n",hw_priv->mac_addr[0],
hw_priv->mac_addr[1],
hw_priv->mac_addr[2],
hw_priv->mac_addr[3],
hw_priv->mac_addr[4],
hw_priv->mac_addr[5]);
ret = request_firmware(&hw_priv->sdd,
sdd_path, hw_priv->pdev);
if (unlikely(ret)) {
atbm_dbg(ATBM_APOLLO_DBG_ERROR,
"%s: can't load sdd file %s.\n",
__func__, sdd_path);
return ret;
}
//#define CONFIG_SUPPORT_SDD
#ifdef CONFIG_SUPPORT_SDD
cfg.dpdData = (u8*)hw_priv->sdd->data;
cfg.dpdData_size = (u32)hw_priv->sdd->size;
#else
cfg.dpdData = NULL;
cfg.dpdData_size = 0;
#endif
sta_printk( "setup SDD file len %ld \n",cfg.dpdData_size);
/* Set low-power mode. */
ret |= WARN_ON(wsm_configuration(hw_priv, &cfg,0));
sta_printk( "setup mac addr end :[ %02x,%02x,%02x,%02x,%02x,%02x ] \n",hw_priv->mac_addr[0],
hw_priv->mac_addr[1],
hw_priv->mac_addr[2],
hw_priv->mac_addr[3],
hw_priv->mac_addr[4],
hw_priv->mac_addr[5]);
/* Parse SDD file for PTA element */
atbm_parse_SDD_file(hw_priv);
}
else
#endif
{
//const char *sdd_path = sdd;
struct wsm_configuration cfg = {
.dot11StationId = &hw_priv->mac_addr[0],
.dot11RtsThreshold = 1000,
};
//#define CONFIG_SUPPORT_SDD
#ifdef CONFIG_SUPPORT_SDD
cfg.dpdData = (u8*)hw_priv->sdd->data;
cfg.dpdData_size = (u32)hw_priv->sdd->size;
#else
cfg.dpdData = NULL;
cfg.dpdData_size = 0;
#endif
sta_printk("atbm_setup_mac:addr(%pm)\n",&hw_priv->mac_addr[0]);
ret |= WARN_ON(wsm_configuration(hw_priv, &cfg,0));
}
if (ret)
return ret;
return 0;
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
void atbm_pending_offchanneltx_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif, pending_offchanneltx_work.work);
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
if(atbm_bh_is_term(hw_priv)){
return;
}
mutex_lock(&hw_priv->conf_mutex);
atbm_disable_listening(priv);
hw_priv->roc_if_id = -1;
up(&hw_priv->scan.lock);
mutex_unlock(&hw_priv->conf_mutex);
}
void atbm_offchannel_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif, offchannel_work);
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
u8 queueId = atbm_queue_get_queue_id(hw_priv->pending_frame_id);
struct atbm_queue *queue = &hw_priv->tx_queue[queueId];
int listening_on = -1;
if(atbm_bh_is_term(hw_priv)){
wsm_unlock_tx(hw_priv);
return;
}
if((queueId >= 4) || (!hw_priv->channel)){
atbm_printk_err("%s %d ,ERROR !!! %s , %s\n",__func__,__LINE__,
queueId >= 4?"queueId >= 4":" ",hw_priv->channel?"hw_priv->channel is NULL":" ");
wsm_unlock_tx(hw_priv);
return;
}
if (unlikely(down_trylock(&hw_priv->scan.lock))) {
int ret;
sta_printk(KERN_ERR "atbm_offchannel_work***** drop frame\n");
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
ret = atbm_queue_remove(hw_priv, queue,
hw_priv->pending_frame_id);
#else
ret = atbm_queue_remove(queue, hw_priv->pending_frame_id);
#endif
if (ret)
sta_printk(KERN_ERR "atbm_offchannel_work: "
"queue_remove failed %d\n", ret);
wsm_unlock_tx(hw_priv);
return;
}
mutex_lock(&hw_priv->conf_mutex);
hw_priv->roc_if_id = priv->if_id;
if (likely(!priv->join_status)) {
wsm_vif_flush_tx(priv);
listening_on = atbm_enable_listening(priv, hw_priv->channel);
/* atbm_update_filtering(priv); */
}
if (unlikely(!priv->join_status)&&(listening_on != 0))
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_remove(hw_priv, queue,
hw_priv->pending_frame_id);
#else
atbm_queue_remove(queue, hw_priv->pending_frame_id);
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
else
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_requeue(hw_priv, queue,
hw_priv->pending_frame_id, false);
#else
atbm_queue_requeue(queue, hw_priv->pending_frame_id, false);
#endif
if(listening_on == 0){
atbm_hw_priv_queue_delayed_work(hw_priv,
&priv->pending_offchanneltx_work,msecs_to_jiffies(5));
}
else{
sta_printk(KERN_ERR "atbm_offchannel_work if_id(%d),cannot in listen state\n",
priv->if_id);
}
mutex_unlock(&hw_priv->conf_mutex);
if(listening_on){
hw_priv->roc_if_id = -1;
up(&hw_priv->scan.lock);
}
wsm_unlock_tx(hw_priv);
}
#endif
void atbm_restart_join_bss(struct atbm_vif *priv,struct cfg80211_bss *bss)
{
const u8 *ssidie;
const u8 *dtimie;
const struct ieee80211_tim_ie *tim = NULL;
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
struct wsm_operational_mode mode = {
.power_mode = wsm_power_mode_quiescent,
.disableMoreFlagUsage = true,
};
struct wsm_template_frame frame = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
};
int ret = 0;
struct wsm_protected_mgmt_policy mgmt_policy;
frame.skb = ieee80211_probereq_get(hw_priv->hw, priv->vif, NULL, 0,
vif_to_sdata(priv->vif)->last_scan_ie, vif_to_sdata(priv->vif)->last_scan_ie_len,NULL);
if (!frame.skb)
return;
#ifdef P2P_MULTIVIF
ret = wsm_set_template_frame(hw_priv, &frame,
priv->if_id ? 1 : 0);
#else
ret = wsm_set_template_frame(hw_priv, &frame,
priv->if_id);
#endif
if(frame.skb){
atbm_dev_kfree_skb(frame.skb);
}
if(ret)
return;
ssidie = ieee80211_bss_get_ie(bss,ATBM_WLAN_EID_SSID);
dtimie = ieee80211_bss_get_ie(bss,ATBM_WLAN_EID_TIM);
if (dtimie)
tim = (struct ieee80211_tim_ie *)&dtimie[2];
if(atomic_read(&priv->enabled) == 1){
struct wsm_join join = {
.mode = (bss->capability & WLAN_CAPABILITY_IBSS) ?
WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS,
.preambleType = WSM_JOIN_PREAMBLE_SHORT,
.probeForJoin = 1,
/* dtimPeriod will be updated after association */
.dtimPeriod = 1,
.beaconInterval = bss->beacon_interval,
};
if (priv->if_id)
join.flags |= WSM_FLAG_MAC_INSTANCE_1;
else
join.flags &= ~WSM_FLAG_MAC_INSTANCE_1;
#ifdef CONFIG_ATBM_BT_COMB
/* BT Coex related changes */
if (hw_priv->is_BT_Present) {
if (((hw_priv->conf_listen_interval * 100) %
bss->beacon_interval) == 0)
priv->listen_interval =
((hw_priv->conf_listen_interval * 100) /
bss->beacon_interval);
else
priv->listen_interval =
((hw_priv->conf_listen_interval * 100) /
bss->beacon_interval + 1);
}
#endif
if (tim && tim->dtim_period > 1) {
join.dtimPeriod = tim->dtim_period;
priv->join_dtim_period = tim->dtim_period;
}
priv->beacon_int = bss->beacon_interval;
sta_printk( "[STA] Join DTIM: %d, interval: %d\n",
join.dtimPeriod, priv->beacon_int);
hw_priv->is_go_thru_go_neg = false;
join.channelNumber = channel_hw_value(hw_priv->channel);
/* basicRateSet will be updated after association.
Currently these values are hardcoded */
if (hw_priv->channel->band == IEEE80211_BAND_5GHZ) {
join.band = WSM_PHY_BAND_5G;
join.basicRateSet = 64; /*6 mbps*/
}else{
join.band = WSM_PHY_BAND_2_4G;
join.basicRateSet = 7; /*1, 2, 5.5 mbps*/
}
memcpy(&join.bssid[0], bss->bssid, sizeof(join.bssid));
memcpy(&priv->join_bssid[0], bss->bssid, sizeof(priv->join_bssid));
if (ssidie) {
join.ssidLength = ssidie[1];
if (WARN_ON(join.ssidLength > sizeof(join.ssid)))
join.ssidLength = sizeof(join.ssid);
memcpy(&join.ssid[0], &ssidie[2], join.ssidLength);
if(strstr(&join.ssid[0],"5.1.4"))
msleep(200);
//#ifdef ROAM_OFFLOAD
if((priv->vif->type == NL80211_IFTYPE_STATION)) {
priv->ssid_length = join.ssidLength;
memcpy(priv->ssid, &join.ssid[0], priv->ssid_length);
}
//#endif /*ROAM_OFFLOAD*/
}
if (priv->vif->p2p) {
join.flags |= WSM_JOIN_FLAGS_P2P_GO;
#ifdef P2P_MULTIVIF
join.flags |= (1 << 6);
#endif
join.basicRateSet =
atbm_rate_mask_to_wsm(hw_priv, 0xFF0);
}
#ifdef ATBM_SUPPORT_WIDTH_40M
if(priv->if_id&&(priv->vif->p2p==true))
{
join.channel_type = (u32)(hw_priv->channel_type>NL80211_CHAN_NO_HT ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
}
else
{
spin_lock_bh(&hw_priv->spinlock_channel_type);
join.channel_type = (u32)hw_priv->channel_type;
spin_unlock_bh(&hw_priv->spinlock_channel_type);
if(start_choff<=NL80211_CHAN_HT40PLUS)
join.channel_type = start_choff;
sta_printk("%s:join.channel_type(%d)\n",__func__,join.channel_type);
}
#endif
memset(&priv->powersave_mode,0,sizeof(struct wsm_set_pm));
atbm_set_pm(priv,&priv->powersave_mode);
//WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id));
WARN_ON(wsm_set_operational_mode(hw_priv, &mode, priv->if_id));
WARN_ON(wsm_set_block_ack_policy(hw_priv,
/*hw_priv->ba_tid_mask*/0, hw_priv->ba_tid_rx_mask, priv->if_id));
#ifdef CONFIG_ATBM_BA_STATUS
spin_lock_bh(&hw_priv->ba_lock);
hw_priv->ba_ena = false;
hw_priv->ba_cnt = 0;
hw_priv->ba_acc = 0;
hw_priv->ba_hist = 0;
hw_priv->ba_cnt_rx = 0;
hw_priv->ba_acc_rx = 0;
spin_unlock_bh(&hw_priv->ba_lock);
#endif
mgmt_policy.protectedMgmtEnable = 0;
mgmt_policy.unprotectedMgmtFramesAllowed = 1;
mgmt_policy.encryptionForAuthFrame = 1;
wsm_set_protected_mgmt_policy(hw_priv, &mgmt_policy,
priv->if_id);
atbm_printk_sta("%s:ch(%d),chtype(%d),if_id(%d)\n",__func__,
join.channelNumber,join.channel_type,priv->if_id);
wsm_join(hw_priv, &join, priv->if_id);
priv->join_status = ATBM_APOLLO_JOIN_STATUS_STA;
/* Due to beacon filtering it is possible that the
* AP's beacon is not known for the mac80211 stack.
* Disable filtering temporary to make sure the stack
* receives at least one */
priv->disable_beacon_filter = true;
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
if(priv->if_id == 0){
atbm_printk_sta("%s:enable combination mode\n",__func__);
atomic_set(&hw_priv->combination,1);
}
#endif
#endif
#ifdef ATBM_WIFI_QUEUE_LOCK_BUG
atbm_set_priv_queue_cap(priv);
#endif
atbm_update_filtering(priv);
#ifdef ATBM_P2P_CHANGE
if(priv->if_id == 1){
atbm_printk_sta("%s:reset p2p go save\n",__func__);
atomic_set(&hw_priv->go_bssid_set,0);
atomic_set(&hw_priv->receive_go_resp,0);
}
#endif
}
}
void atbm_join_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif, join_work);
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
u8 queueId = atbm_queue_get_queue_id(hw_priv->pending_frame_id);
struct atbm_queue *queue = &hw_priv->tx_queue[queueId];
const struct atbm_txpriv *txpriv = NULL;
struct sk_buff *skb = NULL;
const struct wsm_tx *wsm;
const struct ieee80211_hdr *frame;
const u8 *bssid;
struct cfg80211_bss *bss;
const u8 *ssidie;
const u8 *dtimie;
const struct ieee80211_tim_ie *tim = NULL;
struct wsm_protected_mgmt_policy mgmt_policy;
//struct wsm_reset reset = {
// .reset_statistics = true,
//};
struct wsm_operational_mode mode = {
.power_mode = wsm_power_mode_quiescent,
.disableMoreFlagUsage = true,
};
if(queueId >= 4){
atbm_printk_err("%s %d ,ERROR !!! queueId=%d >= 4\n",__func__,__LINE__,queueId);
wsm_unlock_tx(hw_priv);
return;
}
if (atbm_queue_get_skb(queue, hw_priv->pending_frame_id,
&skb, &txpriv)) {
wsm_unlock_tx(hw_priv);
return;
}
if(atbm_bh_is_term(hw_priv)){
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_remove(hw_priv, queue, hw_priv->pending_frame_id);
#else
atbm_queue_remove(queue, hw_priv->pending_frame_id);
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
wsm_unlock_tx(hw_priv);
return;
}
wsm = (struct wsm_tx *)&skb->data[0];
frame = (struct ieee80211_hdr *)&skb->data[txpriv->offset];
bssid = &frame->addr1[0]; /* AP SSID in a 802.11 frame */
if((!wsm) || (!hw_priv->channel)){
atbm_printk_err("%s %d ,ERROR !!! %s , %s\n",__func__,__LINE__,
wsm?" ":"wsm is NULL",hw_priv->channel?" ":"hw_priv->channel is NULL");
wsm_unlock_tx(hw_priv);
return;
}
if (unlikely(priv->join_status)) {
wsm_lock_tx(hw_priv);
sta_printk("[%s] line:%d\n", __func__, __LINE__);
atbm_unjoin_work(&priv->unjoin_work);
}
atbm_hw_cancel_delayed_work(&priv->join_timeout,true);
bss = ieee80211_atbm_get_authen_bss(priv->vif, hw_priv->channel,
bssid, NULL, 0);
if (!bss) {
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_remove(hw_priv, queue, hw_priv->pending_frame_id);
#else
atbm_queue_remove(queue, hw_priv->pending_frame_id);
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
wsm_unlock_tx(hw_priv);
return;
}
ssidie = ieee80211_bss_get_ie(bss,ATBM_WLAN_EID_SSID);
dtimie = ieee80211_bss_get_ie(bss,ATBM_WLAN_EID_TIM);
if (dtimie)
tim = (struct ieee80211_tim_ie *)&dtimie[2];
mutex_lock(&hw_priv->conf_mutex);
if(atomic_read(&priv->enabled) == 1)
{
struct wsm_join join = {
.mode = (bss->capability & WLAN_CAPABILITY_IBSS) ?
WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS,
.preambleType = WSM_JOIN_PREAMBLE_SHORT,
.probeForJoin = 1,
/* dtimPeriod will be updated after association */
.dtimPeriod = 1,
.beaconInterval = bss->beacon_interval,
};
if (priv->if_id)
join.flags |= WSM_FLAG_MAC_INSTANCE_1;
else
join.flags &= ~WSM_FLAG_MAC_INSTANCE_1;
#ifdef CONFIG_ATBM_BT_COMB
/* BT Coex related changes */
if (hw_priv->is_BT_Present) {
if (((hw_priv->conf_listen_interval * 100) %
bss->beacon_interval) == 0)
priv->listen_interval =
((hw_priv->conf_listen_interval * 100) /
bss->beacon_interval);
else
priv->listen_interval =
((hw_priv->conf_listen_interval * 100) /
bss->beacon_interval + 1);
}
#endif
if (tim && tim->dtim_period > 1) {
join.dtimPeriod = tim->dtim_period;
priv->join_dtim_period = tim->dtim_period;
}
priv->beacon_int = bss->beacon_interval;
sta_printk( "[STA] Join DTIM: %d, interval: %d\n",
join.dtimPeriod, priv->beacon_int);
hw_priv->is_go_thru_go_neg = false;
join.channelNumber = channel_hw_value(hw_priv->channel);
/* basicRateSet will be updated after association.
Currently these values are hardcoded */
if (hw_priv->channel->band == IEEE80211_BAND_5GHZ) {
join.band = WSM_PHY_BAND_5G;
join.basicRateSet = 64; /*6 mbps*/
}else{
join.band = WSM_PHY_BAND_2_4G;
join.basicRateSet = 7; /*1, 2, 5.5 mbps*/
}
memcpy(&join.bssid[0], bssid, sizeof(join.bssid));
memcpy(&priv->join_bssid[0], bssid, sizeof(priv->join_bssid));
if (ssidie) {
join.ssidLength = ssidie[1];
if (WARN_ON(join.ssidLength > sizeof(join.ssid)))
join.ssidLength = sizeof(join.ssid);
memcpy(&join.ssid[0], &ssidie[2], join.ssidLength);
if(strstr(&join.ssid[0],"5.1.4"))
msleep(200);
//#ifdef ROAM_OFFLOAD
if((priv->vif->type == NL80211_IFTYPE_STATION)) {
priv->ssid_length = join.ssidLength;
memcpy(priv->ssid, &join.ssid[0], priv->ssid_length);
}
//#endif /*ROAM_OFFLOAD*/
}
if (priv->vif->p2p) {
join.flags |= WSM_JOIN_FLAGS_P2P_GO;
#ifdef P2P_MULTIVIF
join.flags |= (1 << 6);
#endif
join.basicRateSet =
atbm_rate_mask_to_wsm(hw_priv, 0xFF0);
}
#ifdef ATBM_SUPPORT_WIDTH_40M
if(priv->if_id&&(priv->vif->p2p==true))
{
join.channel_type = (u32)(hw_priv->channel_type>NL80211_CHAN_NO_HT ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
}
else
{
spin_lock_bh(&hw_priv->spinlock_channel_type);
join.channel_type = (u32)hw_priv->channel_type;
spin_unlock_bh(&hw_priv->spinlock_channel_type);
if(start_choff<=NL80211_CHAN_HT40PLUS)
join.channel_type = start_choff;
sta_printk("%s:join.channel_type(%d)\n",__func__,join.channel_type);
}
#endif
wsm_flush_tx(hw_priv);
/* Queue unjoin if not associated in 3 sec. */
atbm_hw_priv_queue_delayed_work(hw_priv,
&priv->join_timeout, 3 * HZ);
#ifdef CONFIG_PM
/*Stay Awake for Join Timeout*/
atbm_pm_stay_awake(&hw_priv->pm_state, 3 * HZ);
#endif
#if defined(CONFIG_ATBM_STA_LISTEN) || defined(CONFIG_ATBM_SUPPORT_P2P)
atbm_disable_listening(priv);
#endif
/*
*only try to awake othe interface
*/
memset(&priv->powersave_mode,0,sizeof(struct wsm_set_pm));
atbm_set_pm(priv,&priv->powersave_mode);
//WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id));
WARN_ON(wsm_set_operational_mode(hw_priv, &mode, priv->if_id));
WARN_ON(wsm_set_block_ack_policy(hw_priv,
/*hw_priv->ba_tid_mask*/0, hw_priv->ba_tid_rx_mask, priv->if_id));
#ifdef CONFIG_ATBM_BA_STATUS
spin_lock_bh(&hw_priv->ba_lock);
hw_priv->ba_ena = false;
hw_priv->ba_cnt = 0;
hw_priv->ba_acc = 0;
hw_priv->ba_hist = 0;
hw_priv->ba_cnt_rx = 0;
hw_priv->ba_acc_rx = 0;
spin_unlock_bh(&hw_priv->ba_lock);
#endif
mgmt_policy.protectedMgmtEnable = 0;
mgmt_policy.unprotectedMgmtFramesAllowed = 1;
mgmt_policy.encryptionForAuthFrame = 1;
wsm_set_protected_mgmt_policy(hw_priv, &mgmt_policy,
priv->if_id);
atbm_printk_sta( "%s:ch(%d),chtype(%d),if_id(%d)\n",__func__,
join.channelNumber,join.channel_type,priv->if_id);
if (wsm_join(hw_priv, &join, priv->if_id)) {
memset(&priv->join_bssid[0],
0, sizeof(priv->join_bssid));
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_remove(hw_priv, queue,
hw_priv->pending_frame_id);
#else
atbm_queue_remove(queue, hw_priv->pending_frame_id);
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
atbm_hw_cancel_delayed_work(&priv->join_timeout,true);
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
if(priv->if_id == 0){
atbm_printk_sta( "%s:disable combination mode\n",__func__);
atomic_set(&hw_priv->combination,0);
}
#endif
#endif
} else {
/* Upload keys */
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_requeue(hw_priv, queue,
hw_priv->pending_frame_id, true);
#else
atbm_queue_requeue(queue, hw_priv->pending_frame_id,
true);
#endif
priv->join_status = ATBM_APOLLO_JOIN_STATUS_STA;
/* Due to beacon filtering it is possible that the
* AP's beacon is not known for the mac80211 stack.
* Disable filtering temporary to make sure the stack
* receives at least one */
priv->disable_beacon_filter = true;
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
if(priv->if_id == 0){
atbm_printk_sta("%s:enable combination mode\n",__func__);
atomic_set(&hw_priv->combination,1);
}
#endif
#endif
#ifdef ATBM_WIFI_QUEUE_LOCK_BUG
atbm_set_priv_queue_cap(priv);
#endif
}
atbm_printk_sta("%s:end\n",__func__);
atbm_update_filtering(priv);
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
if(priv->if_id == 1){
atbm_printk_sta( "%s:reset p2p go save\n",__func__);
atomic_set(&hw_priv->go_bssid_set,0);
atomic_set(&hw_priv->receive_go_resp,0);
}
#endif
#endif
}else {
atbm_printk_sta("%s:priv is not enable\n",__func__);
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
atbm_queue_remove(hw_priv, queue, hw_priv->pending_frame_id);
#else
atbm_queue_remove(queue, hw_priv->pending_frame_id);
#endif /*CONFIG_ATBM_APOLLO_TESTMODE*/
}
mutex_unlock(&hw_priv->conf_mutex);
ieee80211_atbm_put_authen_bss(priv->vif,bss);
wsm_unlock_tx(hw_priv);
}
void atbm_join_timeout(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif, join_timeout.work);
if(atbm_bh_is_term(priv->hw_priv)){
return;
}
sta_printk( "[WSM] Issue unjoin command (TMO).\n");
wsm_lock_tx(priv->hw_priv);
sta_printk("[%s] line:%d\n", __func__, __LINE__);
atbm_unjoin_work(&priv->unjoin_work);
}
void atbm_unjoin_work(struct atbm_work_struct *work)
{
struct atbm_vif *priv =
container_of(work, struct atbm_vif, unjoin_work);
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
struct wsm_reset reset = {
.reset_statistics = true,
};
bool is_htcapie = false;
int i;
struct atbm_vif *tmp_priv;
struct wsm_operational_mode mode = {
.power_mode = wsm_power_mode_quiescent,
.disableMoreFlagUsage = true,
};
if(atbm_bh_is_term(hw_priv)){
wsm_unlock_tx(hw_priv);
return;
}
#ifdef CONFIG_ATBM_BA_STATUS
atbm_del_timer_sync(&hw_priv->ba_timer);
#endif
mutex_lock(&hw_priv->conf_mutex);
if (unlikely(atomic_read(&hw_priv->scan.in_progress)
#ifdef CONFIG_ATBM_SUPPORT_P2P
||atomic_read(&hw_priv->remain_on_channel)
#endif
)) {
#if 0
if (priv->delayed_unjoin) {
wiphy_dbg(priv->hw->wiphy,
"%s: Delayed unjoin "
"is already scheduled.\n",
__func__);
wsm_unlock_tx(hw_priv);
sta_printk("%s:priv->delayed_unjoin = true\n",__func__);
} else {
priv->delayed_unjoin = true;
sta_printk("%s:set priv->delayed_unjoin = true\n",__func__);
}
#else
priv->delayed_unjoin = true;
wsm_unlock_tx(hw_priv);
#endif
mutex_unlock(&hw_priv->conf_mutex);
return;
}
if (priv->join_status &&
priv->join_status > ATBM_APOLLO_JOIN_STATUS_STA) {
atbm_printk_err("Unexpected: join status: %d\n",priv->join_status);
// BUG_ON(1);
mutex_unlock(&hw_priv->conf_mutex);
wsm_unlock_tx(hw_priv);
return;
}
if (priv->join_status) {
atbm_printk_sta("%s:join_status(%d),if_id(%d)\n",__func__,
priv->join_status,priv->if_id);
#ifdef CONFIG_ATBM_MAC80211_NO_USE
atbm_hw_cancel_queue_work(&priv->update_filtering_work,true);
#endif
atbm_hw_cancel_queue_work(&priv->set_beacon_wakeup_period_work,true);
memset(&priv->join_bssid[0], 0, sizeof(priv->join_bssid));
priv->join_status = ATBM_APOLLO_JOIN_STATUS_PASSIVE;
#ifdef ATBM_PKG_REORDER
atbm_reorder_func_reset(priv,ATBM_APOLLO_LINK_ID_UNMAPPED-1);
#endif
/* Unjoin is a reset. */
wsm_flush_tx(hw_priv);
#ifdef ATBM_SUPPORT_WIDTH_40M
if(priv->vif->p2p == false)
{
sta_printk(KERN_ERR "atbm_unjoin_work:chantype_change_work+++++\n");
#ifdef CONFIG_ATBM_40M_AUTO_CCA
mutex_unlock(&hw_priv->conf_mutex);
if(atbm_hw_cancel_delayed_work(&priv->chantype_change_work,false))
atbm_channel_type_change_work(&priv->chantype_change_work.work);
if(atbm_work_pending(&hw_priv->get_cca_work))
{
atbm_hw_cancel_queue_work(&hw_priv->get_cca_work,true);
atbm_get_cca_work(&hw_priv->get_cca_work);
}
mutex_lock(&hw_priv->conf_mutex);
#endif
atomic_set(&hw_priv->cca_detect_running,0);
atomic_set(&hw_priv->tx_20M_lock,0);
atomic_set(&hw_priv->phy_chantype,0);
}
#endif
WARN_ON(wsm_keep_alive_period(hw_priv, 0, priv->if_id));
WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id));
WARN_ON(wsm_set_operational_mode(hw_priv, &mode, priv->if_id));
WARN_ON(wsm_set_output_power(hw_priv,
hw_priv->output_power * 10, priv->if_id));
priv->tmpframe_probereq_set = false;
priv->join_dtim_period = 0;
priv->cipherType = 0;
WARN_ON(atbm_setup_mac_pvif(priv));
atbm_free_event_queue(hw_priv);
atbm_hw_cancel_queue_work(&hw_priv->event_handler,true);
#ifndef CONFIG_TX_NO_CONFIRM
atbm_hw_cancel_delayed_work(&priv->connection_loss_work,true);
#endif
WARN_ON(wsm_set_block_ack_policy(hw_priv,
0, hw_priv->ba_tid_rx_mask, priv->if_id));
priv->disable_beacon_filter = false;
atbm_update_filtering(priv);
priv->setbssparams_done = false;
memset(&priv->association_mode, 0,
sizeof(priv->association_mode));
memset(&priv->bss_params, 0, sizeof(priv->bss_params));
memset(&priv->firmware_ps_mode, 0,
sizeof(priv->firmware_ps_mode));
priv->htcap = false;
do
{
/*
*if there is other interface ,try to change the other interface
*to ps mode.
*/
struct wsm_set_pm pm;
pm.pmMode = WSM_PSM_PS;
atbm_set_pm(priv,&pm);
memset(&priv->powersave_mode, 0,
sizeof(priv->powersave_mode));
}while(0);
atbm_for_each_vif(hw_priv, tmp_priv, i) {
#ifdef P2P_MULTIVIF
if ((i == (ATBM_WIFI_MAX_VIFS - 1)) || !tmp_priv)
#else
if (!tmp_priv)
#endif
continue;
if ((tmp_priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) && tmp_priv->htcap)
is_htcapie = true;
}
if (is_htcapie) {
hw_priv->vif0_throttle = ATBM_WIFI_HOST_VIF0_11N_THROTTLE;
hw_priv->vif1_throttle = ATBM_WIFI_HOST_VIF1_11N_THROTTLE;
sta_printk(KERN_ERR "UNJOIN HTCAP 11N %d\n",hw_priv->vif0_throttle);
} else {
hw_priv->vif0_throttle = ATBM_WIFI_HOST_VIF0_11BG_THROTTLE;
hw_priv->vif1_throttle = ATBM_WIFI_HOST_VIF1_11BG_THROTTLE;
sta_printk(KERN_ERR "UNJOIN 11BG %d\n",hw_priv->vif0_throttle);
}
sta_printk( "[STA] Unjoin.\n");
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
if(priv->if_id == 1){
atbm_printk_sta("%s:reset p2p go save\n",__func__);
atomic_set(&hw_priv->go_bssid_set,0);
atomic_set(&hw_priv->receive_go_resp,0);
atomic_set(&hw_priv->p2p_oper_channel,0);
}
else if(priv->if_id == 0){
atbm_printk_sta("%s:disable combination mode\n",__func__);
atomic_set(&hw_priv->combination,0);
}
#endif
#endif
#ifdef ATBM_WIFI_QUEUE_LOCK_BUG
atbm_clear_priv_queue_cap(priv);
#endif
mutex_unlock(&hw_priv->conf_mutex);
wsm_unlock_tx(hw_priv);
}
#if defined(CONFIG_ATBM_STA_LISTEN) || defined(CONFIG_ATBM_SUPPORT_P2P)
int atbm_enable_listening(struct atbm_vif *priv,
struct ieee80211_channel *chan)
{
/* TODO:COMBO: Channel is common to HW currently in mac80211.
Change the code below once channel is made per VIF */
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
struct wsm_start start = {
#ifdef P2P_MULTIVIF
.mode = WSM_START_MODE_P2P_DEV | (priv->if_id ? (1 << 4) : 0),
#else
.mode = WSM_START_MODE_P2P_DEV | (priv->if_id << 4),
#endif
.band = (chan->band == IEEE80211_BAND_5GHZ) ?
WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G,
.channelNumber = channel_hw_value(chan),
.beaconInterval = 100,
.DTIMPeriod = 1,
.probeDelay = 0,
.basicRateSet = 0x0F,
};
if((priv->vif->type == NL80211_IFTYPE_P2P_CLIENT) || (priv->vif->type == NL80211_IFTYPE_P2P_GO)){
start.mode |= BIT(6);
atbm_printk_err("[P2P MODE] SET BIT(6)");
}
#ifdef P2P_MULTIVIF
if(priv->if_id != 2) {
WARN_ON(priv->join_status > ATBM_APOLLO_JOIN_STATUS_MONITOR);
sta_printk(KERN_ERR "%s:if_id(%d),priv->join_status(%d)\n",__func__,priv->if_id,
priv->join_status);
return -1;
}
if (priv->join_status >= ATBM_APOLLO_JOIN_STATUS_MONITOR)
return 0;
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_PASSIVE)
priv->join_status = ATBM_APOLLO_JOIN_STATUS_MONITOR;
WARN_ON(priv->join_status > ATBM_APOLLO_JOIN_STATUS_MONITOR);
#endif //change by wp
#ifdef ATBM_SUPPORT_WIDTH_40M
if(priv->if_id == 0)
start.channel_type = (u32)(hw_priv->channel_type);
else
start.channel_type = NL80211_CHAN_HT20;
#endif
atbm_printk_sta("if(%d):atbm_enable_listening:channelNumber(%d),channel_type(%d)\n",priv->if_id,start.channelNumber,
start.channel_type);
// #ifdef P2P_MULTIVIF
return wsm_start(hw_priv, &start, ATBM_WIFI_GENERIC_IF_ID);
// #else
// return wsm_start(hw_priv, &start, priv->if_id);
// #endif
}
int atbm_disable_listening(struct atbm_vif *priv)
{
int ret;
struct wsm_reset reset = {
.reset_statistics = true,
};
#ifdef P2P_MULTIVIF
if(priv->if_id != 2) {
WARN_ON(priv->join_status > ATBM_APOLLO_JOIN_STATUS_MONITOR);
return 0;
}
#endif //change by wp
priv->join_status = ATBM_APOLLO_JOIN_STATUS_PASSIVE;
WARN_ON(priv->join_status > ATBM_APOLLO_JOIN_STATUS_MONITOR);
if (1
#ifdef CONFIG_ATBM_SUPPORT_P2P
&&(priv->hw_priv->roc_if_id == -1)
#endif
#ifdef CONFIG_ATBM_STA_LISTEN
&&(priv->hw_priv->sta_listen_if == -1)
#endif
)
return 0;
sta_printk( "atbm_disable_listening++++++++\n");
//#ifdef P2P_MULTIVIF
ret = wsm_reset(priv->hw_priv, &reset, ATBM_WIFI_GENERIC_IF_ID);
atbm_printk_sta("%s:atbm_disable_listening(%d)\n",__func__,priv->if_id);
//#else
// ret = wsm_reset(priv->hw_priv, &reset, priv->if_id);
//#endif
return ret;
}
#endif
#ifdef CONFIG_ATBM_STA_LISTEN
static int atbm_sta_enable_listen(struct atbm_vif *priv)
{
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
int ret = 0;
struct ieee80211_channel *chan = NULL;
if((priv->join_status != ATBM_APOLLO_JOIN_STATUS_PASSIVE)&&
(priv->join_status != ATBM_APOLLO_JOIN_STATUS_STA_LISTEN)){
if(hw_priv->sta_listen_if_save == -1)
hw_priv->sta_listen_if_save = priv->if_id;
atbm_printk_err("%s:join status err(%d)\n",__func__,priv->join_status);
return -1;
}
rcu_read_lock();
chan = rcu_dereference(hw_priv->sta_listen_channel);
rcu_read_unlock();
if(chan == NULL){
hw_priv->sta_listen_if_save = -1;
hw_priv->sta_listen_if = -1;
priv->join_status = ATBM_APOLLO_JOIN_STATUS_PASSIVE;
atbm_printk_err("%s:chan is NULL\n",__func__);
return -1;
}
ret = WARN_ON(__atbm_flush(hw_priv, false, priv->if_id));
if(!ret){
wsm_unlock_tx(hw_priv);
atbm_enable_listening(priv, chan);
}
if(ret == 0){
priv->join_status = ATBM_APOLLO_JOIN_STATUS_STA_LISTEN;
hw_priv->sta_listen_if = priv->if_id;
hw_priv->sta_listen_if_save = priv->if_id;
if(hw_priv->channel == NULL)
hw_priv->channel = chan;
atbm_printk_err("%s:vif[%d] in listen\n",__func__,priv->if_id);
}
return ret;
}
static int atbm_sta_disable_listen(struct atbm_vif *priv)
{
struct atbm_common *hw_priv = priv->hw_priv;
int ret = 0;
atbm_printk_err("%s:(%d)(%d)\n",__func__,priv->if_id,priv->join_status);
WARN_ON(priv->join_status != ATBM_APOLLO_JOIN_STATUS_STA_LISTEN);
WARN_ON(priv->if_id != hw_priv->sta_listen_if);
ret = WARN_ON(__atbm_flush(hw_priv, false, priv->if_id));
if(!ret){
wsm_unlock_tx(hw_priv);
}
atbm_disable_listening(priv);
smp_mb();
priv->join_status = ATBM_APOLLO_JOIN_STATUS_PASSIVE;
atbm_printk_err("%s:vif[%d] exit listen\n",__func__,hw_priv->sta_listen_if);
hw_priv->sta_listen_if = -1;
/*make sure all listen pkg processed*/
synchronize_rcu();
return ret;
}
int atbm_sta_triger_listen(struct ieee80211_hw *hw,struct ieee80211_vif *vif,struct ieee80211_channel *chan)
{
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
int ret;
if(atbm_bh_is_term(hw_priv)){
return -EOPNOTSUPP;
}
if(atomic_read(&priv->enabled) == 0){
atbm_printk_err("%s:priv is not enable\n",__func__);
return -EOPNOTSUPP;
}
atbm_flush_workqueue(hw_priv->workqueue);
mutex_lock(&hw_priv->conf_mutex);
rcu_assign_pointer(hw_priv->sta_listen_channel,chan);
synchronize_rcu();
if(hw_priv->sta_listen_if != -1){
struct atbm_vif *listen_priv = __ABwifi_hwpriv_to_vifpriv(hw_priv,hw_priv->sta_listen_if);
if(listen_priv)
atbm_sta_disable_listen(listen_priv);
}
hw_priv->sta_listen_if_save = -1;
hw_priv->sta_listen_if = -1;
smp_mb();
ret = atbm_sta_enable_listen(priv);
mutex_unlock(&hw_priv->conf_mutex);
return ret;
}
int atbm_sta_stop_listen(struct ieee80211_hw *hw,struct ieee80211_vif *vif)
{
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
if(atbm_bh_is_term(hw_priv)){
atbm_printk_err("%s:bh is disable\n",__func__);
return -EOPNOTSUPP;
}
if(atomic_read(&priv->enabled) == 0){
atbm_printk_err("%s:priv is not enable\n",__func__);
return -EOPNOTSUPP;
}
atbm_flush_workqueue(hw_priv->workqueue);
mutex_lock(&hw_priv->conf_mutex);
atbm_sta_disable_listen(priv);
mutex_unlock(&hw_priv->conf_mutex);
return 0;
}
void atbm_sta_listen_int(struct atbm_common *hw_priv)
{
hw_priv->sta_listen_channel = NULL;
hw_priv->sta_listen_if = -1;
hw_priv->sta_listen_if_save = -1;
}
#endif
/* TODO:COMBO:UAPSD will be supported only on one interface */
int atbm_set_uapsd_param(struct atbm_vif *priv,
const struct wsm_edca_params *arg)
{
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
int ret;
u16 uapsdFlags = 0;
/* Here's the mapping AC [queue, bit]
VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0]*/
if (arg->params[0].uapsdEnable)
uapsdFlags |= 1 << 3;
if (arg->params[1].uapsdEnable)
uapsdFlags |= 1 << 2;
if (arg->params[2].uapsdEnable)
uapsdFlags |= 1 << 1;
if (arg->params[3].uapsdEnable)
uapsdFlags |= 1;
/* Currently pseudo U-APSD operation is not supported, so setting
* MinAutoTriggerInterval, MaxAutoTriggerInterval and
* AutoTriggerStep to 0 */
priv->uapsd_info.uapsdFlags = cpu_to_le16(uapsdFlags);
priv->uapsd_info.minAutoTriggerInterval = 0;
priv->uapsd_info.maxAutoTriggerInterval = 0;
priv->uapsd_info.autoTriggerStep = 0;
sta_printk("%s:uapsdFlags(%x)\n",__func__,uapsdFlags);
ret = wsm_set_uapsd_info(hw_priv, &priv->uapsd_info,
priv->if_id);
return ret;
}
#ifdef CONFIG_ATBM_BA_STATUS
void atbm_ba_work(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, ba_work);
//u8 tx_ba_tid_mask;
/* TODO:COMBO: reenable this part of code */
/* if (priv->join_status != ATBM_APOLLO_JOIN_STATUS_STA)
return;
if (!priv->setbssparams_done)
return;*/
sta_printk("BA work****\n");
spin_lock_bh(&hw_priv->ba_lock);
// tx_ba_tid_mask = hw_priv->ba_ena ? hw_priv->ba_tid_mask : 0;
//tx_ba_tid_mask = hw_priv->ba_tid_mask;
spin_unlock_bh(&hw_priv->ba_lock);
wsm_lock_tx(hw_priv);
WARN_ON(wsm_set_block_ack_policy(hw_priv,
hw_priv->ba_tid_tx_mask, hw_priv->ba_tid_rx_mask, -1)); /*TODO:COMBO*/
wsm_unlock_tx(hw_priv);
}
void atbm_ba_timer(unsigned long arg)
{
bool ba_ena;
struct atbm_common *hw_priv =
(struct atbm_common *)arg;
spin_lock_bh(&hw_priv->ba_lock);
atbm_debug_ba(hw_priv, hw_priv->ba_cnt, hw_priv->ba_acc,
hw_priv->ba_cnt_rx, hw_priv->ba_acc_rx);
if (atomic_read(&hw_priv->scan.in_progress)) {
hw_priv->ba_cnt = 0;
hw_priv->ba_acc = 0;
hw_priv->ba_cnt_rx = 0;
hw_priv->ba_acc_rx = 0;
goto skip_statistic_update;
}
if (hw_priv->ba_cnt >= ATBM_APOLLO_BLOCK_ACK_CNT &&
(hw_priv->ba_acc / hw_priv->ba_cnt >= ATBM_APOLLO_BLOCK_ACK_THLD ||
(hw_priv->ba_cnt_rx >= ATBM_APOLLO_BLOCK_ACK_CNT &&
hw_priv->ba_acc_rx / hw_priv->ba_cnt_rx >=
ATBM_APOLLO_BLOCK_ACK_THLD)))
ba_ena = true;
else
ba_ena = false;
hw_priv->ba_cnt = 0;
hw_priv->ba_acc = 0;
hw_priv->ba_cnt_rx = 0;
hw_priv->ba_acc_rx = 0;
if (ba_ena != hw_priv->ba_ena) {
if (ba_ena || ++hw_priv->ba_hist >= ATBM_APOLLO_BLOCK_ACK_HIST) {
hw_priv->ba_ena = ba_ena;
hw_priv->ba_hist = 0;
#if 0
sta_printk( "[STA] %s block ACK:\n",
ba_ena ? "enable" : "disable");
atbm_queue_work(hw_priv->workqueue, &hw_priv->ba_work);
#endif
}
} else if (hw_priv->ba_hist)
--hw_priv->ba_hist;
skip_statistic_update:
spin_unlock_bh(&hw_priv->ba_lock);
}
#endif
void atbm_vif_setup_params(struct atbm_vif *priv)
{
/* Setup per vif workitems and locks */
spin_lock_init(&priv->vif_lock);
ATBM_INIT_WORK(&priv->join_work, atbm_join_work);
ATBM_INIT_DELAYED_WORK(&priv->join_timeout, atbm_join_timeout);
ATBM_INIT_WORK(&priv->unjoin_work, atbm_unjoin_work);
ATBM_INIT_WORK(&priv->wep_key_work, atbm_wep_key_work);
#ifdef CONFIG_ATBM_SUPPORT_P2P
ATBM_INIT_WORK(&priv->offchannel_work, atbm_offchannel_work);
ATBM_INIT_DELAYED_WORK(&priv->pending_offchanneltx_work,
atbm_pending_offchanneltx_work);
#endif
#ifndef CONFIG_TX_NO_CONFIRM
ATBM_INIT_DELAYED_WORK(&priv->bss_loss_work, atbm_bss_loss_work);
ATBM_INIT_DELAYED_WORK(&priv->connection_loss_work,
atbm_connection_loss_work);
spin_lock_init(&priv->bss_loss_lock);
ATBM_INIT_WORK(&priv->tx_failure_work, atbm_tx_failure_work);
#endif
spin_lock_init(&priv->ps_state_lock);
// ATBM_INIT_DELAYED_WORK(&priv->set_cts_work, atbm_set_cts_work);
ATBM_INIT_WORK(&priv->set_tim_work, atbm_set_tim_work);
ATBM_INIT_WORK(&priv->multicast_start_work, atbm_multicast_start_work);
ATBM_INIT_WORK(&priv->multicast_stop_work, atbm_multicast_stop_work);
ATBM_INIT_WORK(&priv->link_id_work, atbm_link_id_work);
ATBM_INIT_DELAYED_WORK(&priv->link_id_gc_work, atbm_link_id_gc_work);
#if 0
ATBM_INIT_WORK(&priv->linkid_reset_work, atbm_link_id_reset);
#endif
#ifdef CONFIG_ATBM_MAC80211_NO_USE
ATBM_INIT_WORK(&priv->update_filtering_work, atbm_update_filtering_work);
#endif
ATBM_INIT_WORK(&priv->set_beacon_wakeup_period_work,
atbm_set_beacon_wakeup_period_work);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0))
ATBM_INIT_WORK(&priv->ht_info_update_work, atbm_ht_info_update_work);
#endif
#ifdef ATBM_SUPPORT_WIDTH_40M
#ifdef CONFIG_ATBM_40M_AUTO_CCA
ATBM_INIT_DELAYED_WORK(&priv->chantype_change_work, atbm_channel_type_change_work);
#endif
#endif
atbm_init_timer(&priv->mcast_timeout);
//DHCP
spin_lock_init(&priv->dhcp_retry_spinlock);
ATBM_INIT_DELAYED_WORK(&priv->dhcp_retry_work, atbm_dhcp_retry_work);
spin_lock_bh(&priv->dhcp_retry_spinlock);
priv->dhcp_retry_skb=NULL;
spin_unlock_bh(&priv->dhcp_retry_spinlock);
priv->mcast_timeout.data = (unsigned long)priv;
priv->mcast_timeout.function = atbm_mcast_timeout;
priv->setbssparams_done = false;
priv->power_set_true = 0;
priv->user_power_set_true = 0;
priv->user_pm_mode = 0;
/* Initialising the broadcast filter */
memset(priv->broadcast_filter.MacAddr, 0xFF, ETH_ALEN);
priv->broadcast_filter.nummacaddr = 1;
priv->broadcast_filter.address_mode = 1;
priv->broadcast_filter.filter_mode = 1;
priv->htcap = false;
#ifdef ATBM_SUPPORT_WIDTH_40M
priv->join_status = ATBM_APOLLO_JOIN_STATUS_PASSIVE;
#endif
sta_printk(KERN_ERR " !!! %s: enabling priv\n", __func__);
atomic_set(&priv->enabled, 1);
}
int atbm_vif_setup(struct atbm_vif *priv)
{
struct atbm_common *hw_priv = priv->hw_priv;
int ret = 0;
#ifdef P2P_MULTIVIF
if (priv->if_id < 2) {
#endif
/* default EDCA */
WSM_EDCA_SET(&priv->edca, 0, 0x0002, 0x0003, 0x0007,
47, 0xc8, false);
WSM_EDCA_SET(&priv->edca, 1, 0x0002, 0x0007, 0x000f,
94, 0xc8, false);
WSM_EDCA_SET(&priv->edca, 2, 0x0003, 0x000f, 0x03ff,
0, 0xc8, false);
WSM_EDCA_SET(&priv->edca, 3, 0x0007, 0x000f, 0x03ff,
0, 0xc8, false);
ret = wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id);
if (WARN_ON(ret))
goto out;
ret = atbm_set_uapsd_param(priv, &priv->edca);
if (WARN_ON(ret))
goto out;
memset(priv->bssid, ~0, ETH_ALEN);
priv->wep_default_key_id = -1;
priv->cipherType = 0;
priv->cqm_link_loss_count = 40;
priv->cqm_beacon_loss_count = 20;
/* Temporary configuration - beacon filter table */
__atbm_bf_configure(priv);
#ifdef P2P_MULTIVIF
}
#endif
out:
return ret;
}
int atbm_setup_mac_pvif(struct atbm_vif *priv)
{
int ret = 0;
/* NOTE: There is a bug in FW: it reports signal
* as RSSI if RSSI subscription is enabled.
* It's not enough to set WSM_RCPI_RSSI_USE_RSSI. */
/* NOTE2: RSSI based reports have been switched to RCPI, since
* FW has a bug and RSSI reported values are not stable,
* what can leads to signal level oscilations in user-end applications */
struct wsm_rcpi_rssi_threshold threshold = {
.rssiRcpiMode = WSM_RCPI_RSSI_THRESHOLD_ENABLE |
WSM_RCPI_RSSI_DONT_USE_UPPER |
WSM_RCPI_RSSI_DONT_USE_LOWER,
.rollingAverageCount = 16,
};
/* Remember the decission here to make sure, we will handle
* the RCPI/RSSI value correctly on WSM_EVENT_RCPI_RSS */
if (threshold.rssiRcpiMode & WSM_RCPI_RSSI_USE_RSSI)
priv->cqm_use_rssi = true;
/* Configure RSSI/SCPI reporting as RSSI. */
#ifdef P2P_MULTIVIF
ret = wsm_set_rcpi_rssi_threshold(priv->hw_priv, &threshold,
priv->if_id ? 1 : 0);
#else
ret = wsm_set_rcpi_rssi_threshold(priv->hw_priv, &threshold,
priv->if_id);
#endif
#ifdef IPC_AP_USED_11G_NO_RTS
if (priv->mode != NL80211_IFTYPE_STATION)
{
wsm_set_rts_threshold(priv->hw_priv,priv->if_id);
}
#endif
return ret;
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
void atbm_rem_chan_timeout(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, rem_chan_timeout.work);
int ret, if_id;
struct atbm_vif *priv;
if (atomic_read(&hw_priv->remain_on_channel) == 0) {
return;
}
atbm_printk_mgmt("%s:roc_cookie(%llx)\n",__func__,hw_priv->roc_cookie);
ieee80211_remain_on_channel_expired(hw_priv->hw, hw_priv->roc_cookie);
mutex_lock(&hw_priv->conf_mutex);
if_id = hw_priv->roc_if_id;
priv = __ABwifi_hwpriv_to_vifpriv(hw_priv, if_id);
if(atbm_bh_is_term(hw_priv))
{
goto chan_timeout_exit;
}
// if(hw_priv->roc_not_send == 0)
{
ret = WARN_ON(__atbm_flush(hw_priv, false, if_id));
if (!ret) {
wsm_unlock_tx(hw_priv);
atbm_disable_listening(priv);
}
}
chan_timeout_exit:
atomic_set(&hw_priv->remain_on_channel, 0);
hw_priv->roc_if_id = -1;
atbm_scan_listenning_restart_delayed(priv);
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
}
#endif
const u8 *atbm_get_ie(u8 *start, size_t len, u8 ie)
{
u8 *end, *pos;
pos = start;
if (pos == NULL)
return NULL;
end = pos + len;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == ie)
return pos;
pos += 2 + pos[1];
}
return NULL;
}
#ifdef ATBM_SUPPORT_WOW
/**
* atbm_set_macaddrfilter -called when tesmode command
* is for setting mac address filter
*
* @hw: the hardware
* @data: incoming data
*
* Returns: 0 on success or non zero value on failure
*/
int atbm_set_macaddrfilter(struct atbm_common *hw_priv, struct atbm_vif *priv, u8 *data)
{
struct wsm_mac_addr_filter *mac_addr_filter = NULL;
struct wsm_mac_addr_info *addr_info = NULL;
u8 action_mode = 0, no_of_mac_addr = 0, i = 0;
int ret = 0;
u16 macaddrfiltersize = 0;
/* Retrieving Action Mode */
action_mode = data[0];
/* Retrieving number of address entries */
no_of_mac_addr = data[1];
addr_info = (struct wsm_mac_addr_info *)&data[2];
/* Computing sizeof Mac addr filter */
macaddrfiltersize = sizeof(*mac_addr_filter) + \
(no_of_mac_addr * sizeof(struct wsm_mac_addr_info));
mac_addr_filter = atbm_kzalloc(macaddrfiltersize, GFP_KERNEL);
if (!mac_addr_filter) {
ret = -ENOMEM;
goto exit_p;
}
mac_addr_filter->action_mode = action_mode;
mac_addr_filter->numfilter = no_of_mac_addr;
for (i = 0; i < no_of_mac_addr; i++) {
mac_addr_filter->macaddrfilter[i].address_mode = \
addr_info[i].address_mode;
memcpy(mac_addr_filter->macaddrfilter[i].MacAddr, \
addr_info[i].MacAddr , ETH_ALEN);
mac_addr_filter->macaddrfilter[i].filter_mode = \
addr_info[i].filter_mode;
}
ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_MAC_ADDR_FILTER, \
mac_addr_filter, macaddrfiltersize, priv->if_id));
atbm_kfree(mac_addr_filter);
exit_p:
return ret;
}
#endif
#if 0
/**
* atbm_set_multicastaddrfilter -called when tesmode command
* is for setting the ipv4 address filter
*
* @hw: the hardware
* @data: incoming data
*
* Returns: 0 on success or non zero value on failure
*/
static int atbm_set_multicastfilter(struct atbm_common *hw_priv, struct atbm_vif *priv, u8 *data)
{
u8 i = 0;
int ret = 0;
memset(&priv->multicast_filter, 0, sizeof(priv->multicast_filter));
priv->multicast_filter.enable = (u32)data[0];
priv->multicast_filter.numOfAddresses = (u32)data[1];
for (i = 0; i < priv->multicast_filter.numOfAddresses; i++) {
memcpy(&priv->multicast_filter.macAddress[i], \
&data[2+(i*ETH_ALEN)], ETH_ALEN);
}
/* Configure the multicast mib in case of drop all multicast */
if (priv->multicast_filter.enable != 2)
return ret;
ret = wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE, \
&priv->multicast_filter, sizeof(priv->multicast_filter), priv->if_id);
return ret;
}
#endif
#ifdef CONFIG_ATBM_LMAC_FILTER_IP_FRAME
#ifdef IPV6_FILTERING
/**
* atbm_set_ipv6addrfilter -called when tesmode command
* is for setting the ipv6 address filter
*
* @hw: the hardware
* @data: incoming data
* @if_id: interface id
*
* Returns: 0 on success or non zero value on failure
*/
static int atbm_set_ipv6addrfilter(struct ieee80211_hw *hw,
u8 *data, int if_id)
{
struct atbm_common *hw_priv = (struct atbm_common *) hw->priv;
struct wsm_ipv6_filter *ipv6_filter = NULL;
struct ipv6_addr_info *ipv6_info = NULL;
u8 action_mode = 0, no_of_ip_addr = 0, i = 0, ret = 0;
u16 ipaddrfiltersize = 0;
/* Retrieving Action Mode */
action_mode = data[0];
/* Retrieving number of ipv4 address entries */
no_of_ip_addr = data[1];
ipv6_info = (struct ipv6_addr_info *)&data[2];
/* Computing sizeof Mac addr filter */
ipaddrfiltersize = sizeof(*ipv6_filter) + \
(no_of_ip_addr * sizeof(struct wsm_ip6_addr_info));
ipv6_filter = atbm_kzalloc(ipaddrfiltersize, GFP_KERNEL);
if (!ipv6_filter) {
ret = -ENOMEM;
goto exit_p;
}
ipv6_filter->action_mode = action_mode;
ipv6_filter->numfilter = no_of_ip_addr;
for (i = 0; i < no_of_ip_addr; i++) {
ipv6_filter->ipv6filter[i].address_mode = \
ipv6_info[i].address_mode;
ipv6_filter->ipv6filter[i].filter_mode = \
ipv6_info[i].filter_mode;
memcpy(ipv6_filter->ipv6filter[i].ipv6, \
(u8 *)(ipv6_info[i].ipv6), 16);
}
ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_IP_IPV6_ADDR_FILTER, \
ipv6_filter, ipaddrfiltersize, \
if_id));
atbm_kfree(ipv6_filter);
exit_p:
return ret;
}
#endif /*IPV6_FILTERING*/
/**
* atbm_set_data_filter -configure data filter in device
*
* @hw: the hardware
* @vif: vif
* @data: incoming data
* @len: incoming data length
*
*/
void atbm_set_data_filter(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
void *data, int len)
{
int ret = 0;
int filter_id;
if (!data) {
ret = -EINVAL;
goto exit_p;
}
filter_id=*((enum atbm_data_filterid*)data);
switch (filter_id) {
#ifdef IPV6_FILTERING
case IPV6ADDR_FILTER_ID:
ret = atbm_set_ipv6addrfilter(hw, \
&((u8 *)data)[4], priv->if_id);
break;
#endif /*IPV6_FILTERING*/
default:
ret = -EINVAL;
break;
}
exit_p:
ret = ret;
return ;
}
/**
* atbm_set_arpreply -called for creating and
* configuring arp response template frame
*
* @hw: the hardware
*
* Returns: 0 on success or non zero value on failure
*/
int atbm_set_arpreply(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
struct atbm_common *hw_priv = (struct atbm_common *)hw->priv;
u32 framehdrlen, encrypthdr, encrypttailsize, framebdylen = 0;
bool encrypt = false;
int ret = 0;
u8 *template_frame = NULL;
struct ieee80211_hdr_3addr *dot11hdr = NULL;
struct ieee80211_snap_hdr *snaphdr = NULL;
struct arphdr *arp_hdr = NULL;
template_frame = atbm_kzalloc(MAX_ARP_REPLY_TEMPLATE_SIZE, GFP_ATOMIC);
if (!template_frame) {
sta_printk( "[STA] Template frame memory failed\n");
ret = -ENOMEM;
goto exit_p;
}
dot11hdr = (struct ieee80211_hdr_3addr *)&template_frame[4];
framehdrlen = sizeof(*dot11hdr);
if ((priv->vif->type == NL80211_IFTYPE_AP) && priv->vif->p2p)
priv->cipherType = WLAN_CIPHER_SUITE_CCMP;
switch (priv->cipherType) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
sta_printk( "[STA] WEP\n");
encrypthdr = WEP_ENCRYPT_HDR_SIZE;
encrypttailsize = WEP_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
case WLAN_CIPHER_SUITE_TKIP:
sta_printk( "[STA] WPA\n");
encrypthdr = WPA_ENCRYPT_HDR_SIZE;
encrypttailsize = WPA_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
case WLAN_CIPHER_SUITE_CCMP:
sta_printk( "[STA] WPA2\n");
encrypthdr = WPA2_ENCRYPT_HDR_SIZE;
encrypttailsize = WPA2_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
sta_printk( "[STA] WPA2\n");
encrypthdr = WPA2_ENCRYPT_HDR_SIZE;
encrypttailsize = WPA2_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
#ifdef CONFIG_WAPI_SUPPORT
case WLAN_CIPHER_SUITE_SMS4:
sta_printk( "[STA] WAPI\n");
encrypthdr = WAPI_ENCRYPT_HDR_SIZE;
encrypttailsize = WAPI_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
#endif
default:
encrypthdr = 0;
encrypttailsize = 0;
encrypt = 0;
break;
}
framehdrlen += encrypthdr;
/* Filling the 802.11 Hdr */
dot11hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
if (priv->vif->type == NL80211_IFTYPE_STATION)
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS);
else
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
if (encrypt)
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_WEP);
if (priv->vif->bss_conf.qos) {
sta_printk( "[STA] QOS Enabled\n");
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_QOS_DATAGRP);
*(u16 *)(dot11hdr + 1) = 0x0;
framehdrlen += 2;
} else {
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_STYPE_DATA);
}
memcpy(dot11hdr->addr1, priv->vif->bss_conf.bssid, ETH_ALEN);
memcpy(dot11hdr->addr2, priv->vif->addr, ETH_ALEN);
memcpy(dot11hdr->addr3, priv->vif->bss_conf.bssid, ETH_ALEN);
/* Filling the LLC/SNAP Hdr */
snaphdr = (struct ieee80211_snap_hdr *)((u8 *)dot11hdr + framehdrlen);
memcpy(snaphdr, (struct ieee80211_snap_hdr *)rfc1042_header, \
sizeof(*snaphdr));
*(u16 *)(++snaphdr) = cpu_to_be16(ETH_P_ARP);
/* Updating the framebdylen with snaphdr and LLC hdr size */
framebdylen = sizeof(*snaphdr) + 2;
/* Filling the ARP Reply Payload */
arp_hdr = (struct arphdr *)((u8 *)dot11hdr + framehdrlen + framebdylen);
arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
arp_hdr->ar_hln = ETH_ALEN;
arp_hdr->ar_pln = 4;
arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
/* Updating the frmbdylen with Arp Reply Hdr and Arp payload size(20) */
framebdylen += sizeof(*arp_hdr) + 20;
/* Updating the framebdylen with Encryption Tail Size */
framebdylen += encrypttailsize;
/* Filling the Template Frame Hdr */
template_frame[0] = WSM_FRAME_TYPE_ARP_REPLY; /* Template frame type */
template_frame[1] = 0xFF; /* Rate to be fixed */
((u16 *)&template_frame[2])[0] = framehdrlen + framebdylen;
ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_TEMPLATE_FRAME, \
template_frame, (framehdrlen+framebdylen+4), priv->if_id));
atbm_kfree(template_frame);
exit_p:
return ret;
}
#endif
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
/**
* atbm_testmode_event -send asynchronous event
* to userspace
*
* @wiphy: the wiphy
* @msg_id: STE msg ID
* @data: data to be sent
* @len: data length
* @gfp: allocation flag
*
* Returns: 0 on success or non zero value on failure
*/
int atbm_testmode_event(struct wiphy *wiphy, const u32 msg_id,
const void *data, int len, gfp_t gfp)
{
struct sk_buff *skb = cfg80211_testmode_alloc_event_skb(wiphy,
nla_total_size(len+sizeof(msg_id)), gfp);
if (!skb)
return -ENOMEM;
cfg80211_testmode_event(skb, gfp);
return 0;
}
#endif /*ROAM_OFFLOAD*/
#endif
#ifdef CONFIG_ATBM_LMAC_FILTER_IP_FRAME
#ifdef IPV6_FILTERING
/**
* atbm_set_na -called for creating and
* configuring NDP Neighbor Advertisement (NA) template frame
*
* @hw: the hardware
* @vif: vif
*
* Returns: 0 on success or non zero value on failure
*/
int atbm_set_na(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
struct atbm_common *hw_priv = (struct atbm_common *)hw->priv;
u32 framehdrlen, encrypthdr, encrypttailsize, framebdylen = 0;
bool encrypt = false;
int ret = 0;
u8 *template_frame = NULL;
struct ieee80211_hdr_3addr *dot11hdr = NULL;
struct ieee80211_snap_hdr *snaphdr = NULL;
struct ipv6hdr *ipv6_hdr = NULL;
struct icmp6hdr *icmp6_hdr = NULL;
struct nd_msg *na = NULL;
struct nd_opt_hdr *opt_hdr = NULL;
template_frame = atbm_kzalloc(MAX_NEIGHBOR_ADVERTISEMENT_TEMPLATE_SIZE, GFP_ATOMIC);
if (!template_frame) {
sta_printk( "[STA] Template frame memory failed\n");
ret = -ENOMEM;
goto exit_p;
}
dot11hdr = (struct ieee80211_hdr_3addr *)&template_frame[4];
framehdrlen = sizeof(*dot11hdr);
if ((priv->vif->type == NL80211_IFTYPE_AP) && priv->vif->p2p)
priv->cipherType = WLAN_CIPHER_SUITE_CCMP;
switch (priv->cipherType) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
sta_printk( "[STA] WEP\n");
encrypthdr = WEP_ENCRYPT_HDR_SIZE;
encrypttailsize = WEP_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
case WLAN_CIPHER_SUITE_TKIP:
sta_printk( "[STA] WPA\n");
encrypthdr = WPA_ENCRYPT_HDR_SIZE;
encrypttailsize = WPA_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
case WLAN_CIPHER_SUITE_CCMP:
sta_printk( "[STA] WPA2\n");
encrypthdr = WPA2_ENCRYPT_HDR_SIZE;
encrypttailsize = WPA2_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
#ifdef CONFIG_WAPI_SUPPORT
case WLAN_CIPHER_SUITE_SMS4:
sta_printk( "[STA] WAPI\n");
encrypthdr = WAPI_ENCRYPT_HDR_SIZE;
encrypttailsize = WAPI_ENCRYPT_TAIL_SIZE;
encrypt = 1;
break;
#endif
default:
encrypthdr = 0;
encrypttailsize = 0;
encrypt = 0;
break;
}
framehdrlen += encrypthdr;
/* Filling the 802.11 Hdr */
dot11hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
if (priv->vif->type == NL80211_IFTYPE_STATION)
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS);
else
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
if (encrypt)
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_WEP);
if (priv->vif->bss_conf.qos) {
sta_printk( "[STA] QOS Enabled\n");
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_QOS_DATAGRP);
/* Filling QOS Control Field */
*(u16 *)(dot11hdr + 1) = 0x0;
framehdrlen += 2;
} else {
dot11hdr->frame_control |= cpu_to_le16(IEEE80211_STYPE_DATA);
}
memcpy(dot11hdr->addr1, priv->vif->bss_conf.bssid, ETH_ALEN);
memcpy(dot11hdr->addr2, priv->vif->addr, ETH_ALEN);
memcpy(dot11hdr->addr3, priv->vif->bss_conf.bssid, ETH_ALEN);
/* Filling the LLC/SNAP Hdr */
snaphdr = (struct ieee80211_snap_hdr *)((u8 *)dot11hdr + framehdrlen);
memcpy(snaphdr, (struct ieee80211_snap_hdr *)rfc1042_header, \
sizeof(*snaphdr));
*(u16 *)(++snaphdr) = cpu_to_be16(ETH_P_IPV6);
/* Updating the framebdylen with snaphdr and LLC hdr size */
framebdylen = sizeof(*snaphdr) + 2;
/* Filling the ipv6 header */
ipv6_hdr = (struct ipv6hdr *)((u8 *)dot11hdr + framehdrlen + framebdylen);
ipv6_hdr->version = 6;
ipv6_hdr->priority = 0;
ipv6_hdr->payload_len = cpu_to_be16(32); /* ??? check the be or le ??? whether to use cpu_to_be16(32)*/
ipv6_hdr->nexthdr = 58;
ipv6_hdr->hop_limit = 255;
/* Updating the framebdylen with ipv6 Hdr */
framebdylen += sizeof(*ipv6_hdr);
/* Filling the Neighbor Advertisement */
na = (struct nd_msg *)((u8 *)dot11hdr + framehdrlen + framebdylen);
icmp6_hdr = (struct icmp6hdr *)(&na->icmph);
icmp6_hdr->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
icmp6_hdr->icmp6_code = 0;
/* checksum (2 bytes), RSO fields (4 bytes) and target IP address (16 bytes) shall be filled by firmware */
/* Filling the target link layer address in the optional field */
opt_hdr = (struct nd_opt_hdr *)(&na->opt[0]);
opt_hdr->nd_opt_type = 2;
opt_hdr->nd_opt_len = 1;
/* optional target link layer address (6 bytes) shall be filled by firmware */
/* Updating the framebdylen with the ipv6 payload length */
framebdylen += 32;
/* Updating the framebdylen with Encryption Tail Size */
framebdylen += encrypttailsize;
/* Filling the Template Frame Hdr */
template_frame[0] = WSM_FRAME_TYPE_NA; /* Template frame type */
template_frame[1] = 0xFF; /* Rate to be fixed */
((u16 *)&template_frame[2])[0] = framehdrlen + framebdylen;
ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_TEMPLATE_FRAME, \
template_frame, (framehdrlen+framebdylen+4), \
priv->if_id));
atbm_kfree(template_frame);
exit_p:
return ret;
}
#endif /*IPV6_FILTERING*/
#endif
int atbm_tool_shortGi = 0;
int atbm_tool_use_short_slot = 0;
int atbm_tool_use_short_preamble = 0;
int atbm_tool_use_cts_prot = 0;
#if defined(CONFIG_NL80211_TESTMODE) && defined(CONFIG_ATBM_TEST_TOOL)
/**
* atbm_tesmode_reply -called inside a testmode command
* handler to send a response to user space
*
* @wiphy: the wiphy
* @data: data to be send to user space
* @len: data length
*
* Returns: 0 on success or non zero value on failure
*/
int atbm_tesmode_reply(struct wiphy *wiphy,
const void *data, int len)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
int ret = 0;
if(local->hw.vendcmd_nl80211 == 0)
{
#if defined(CONFIG_NL80211_TESTMODE)
struct sk_buff *skb = cfg80211_testmode_alloc_reply_skb(wiphy,
nla_total_size(len));
if (!skb){
return -ENOMEM;
}
ret = nla_put(skb, ATBM_TM_MSG_DATA, len, data);
if (ret) {
atbm_kfree_skb(skb);
return ret;
}
return cfg80211_testmode_reply(skb);
#endif
}
else
{
if(len >0)
{
local->hw.vendreturn.len = len;
memcpy((u8*)local->hw.vendreturn.respbuff,(u8*)data,len);
}
ret = len;
}
return ret;
}
/**
* atbm_start_stop_tsm - starts/stops collecting TSM
*
* @hw: the hardware
* @data: data frame
*
* Returns: 0 on success or non zero value on failure
*/
int atbm_start_stop_tsm(struct ieee80211_hw *hw, void *data)
{
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
struct atbm_msg_start_stop_tsm *start_stop_tsm =
(struct atbm_msg_start_stop_tsm *) data;
struct atbm_common *hw_priv = hw->priv;
hw_priv->start_stop_tsm.start = start_stop_tsm->start;
hw_priv->start_stop_tsm.up = start_stop_tsm->up;
//hw_priv->start_stop_tsm.packetization_delay =
// start_stop_tsm->packetization_delay;
sta_printk("[STA] %s: start : %u: up : %u",
__func__, hw_priv->start_stop_tsm.start,
hw_priv->start_stop_tsm.up);
hw_priv->tsm_info.ac = atbm_1d_to_ac[start_stop_tsm->up];
if (!hw_priv->start_stop_tsm.start) {
spin_lock_bh(&hw_priv->tsm_lock);
memset(&hw_priv->tsm_stats, 0, sizeof(hw_priv->tsm_stats));
memset(&hw_priv->tsm_info, 0, sizeof(hw_priv->tsm_info));
spin_unlock_bh(&hw_priv->tsm_lock);
}
#endif
return 0;
}
/**
* atbm_get_tsm_params - Retrieves TSM parameters
*
* @hw: the hardware
*
* Returns: TSM parameters collected
*/
int atbm_get_tsm_params(struct ieee80211_hw *hw)
{
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
struct atbm_common *hw_priv = hw->priv;
struct atbm_tsm_stats tsm_stats;
u32 pkt_count;
spin_lock_bh(&hw_priv->tsm_lock);
pkt_count = hw_priv->tsm_stats.txed_msdu_count;
sta_printk( "[STA] : pkt_count : %u discarded:%u",
hw_priv->tsm_stats.txed_msdu_count ,
hw_priv->tsm_stats.msdu_discarded_count);
if (pkt_count) {
hw_priv->tsm_stats.avg_q_delay =
hw_priv->tsm_info.sum_pkt_q_delay/pkt_count;
hw_priv->tsm_stats.avg_transmit_delay =
hw_priv->tsm_info.sum_media_delay/pkt_count;
} else {
hw_priv->tsm_stats.avg_q_delay = 0;
hw_priv->tsm_stats.avg_transmit_delay = 0;
}
sta_printk( "[STA] : Txed MSDU count : %u\n",
hw_priv->tsm_stats.txed_msdu_count);
sta_printk( "[STA] : Average queue delay : %u\n",
hw_priv->tsm_stats.avg_q_delay);
sta_printk( "[STA] : Average transmit delay : %u\n",
hw_priv->tsm_stats.avg_transmit_delay);
sta_printk( "\n [STA] : "
" Txed MSDU count 0~500us: %u,\n"
" Txed MSDU count 500~1ms: %u,\n"
" Txed MSDU count 1~2ms: %u,\n"
" Txed MSDU count 2~4ms: %u,\n"
" Txed MSDU count 4~6ms: %u,\n"
" Txed MSDU count 6~8ms: %u,\n"
" Txed MSDU count 8~10ms: %u,\n"
" Txed MSDU count 10~20ms: %u,\n, "
" Txed MSDU count 20~40ms: %u,\n, "
" Txed MSDU count 40~xxms: %u,\n,",
hw_priv->tsm_stats.bin00,
hw_priv->tsm_stats.bin01,
hw_priv->tsm_stats.bin02,
hw_priv->tsm_stats.bin03,
hw_priv->tsm_stats.bin04,
hw_priv->tsm_stats.bin05,
hw_priv->tsm_stats.bin0,
hw_priv->tsm_stats.bin1,
hw_priv->tsm_stats.bin2,
hw_priv->tsm_stats.bin3);
memcpy(&tsm_stats, &hw_priv->tsm_stats, sizeof(hw_priv->tsm_stats));
/* Reset the TSM statistics */
memset(&hw_priv->tsm_stats, 0, sizeof(hw_priv->tsm_stats));
hw_priv->tsm_info.sum_pkt_q_delay = 0;
hw_priv->tsm_info.sum_media_delay = 0;
spin_unlock_bh(&hw_priv->tsm_lock);
return atbm_tesmode_reply(hw->wiphy, &tsm_stats,
sizeof(hw_priv->tsm_stats));
#else
return -1;
#endif
}
/**
* atbm_get_roam_delay - Retrieves roam delay
*
* @hw: the hardware
*
* Returns: Returns the last measured roam delay
*/
int atbm_get_roam_delay(struct ieee80211_hw *hw)
{
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
struct atbm_common *hw_priv = hw->priv;
u16 roam_delay = hw_priv->tsm_info.roam_delay / 1000;
sta_printk( "[STA] %s: Roam delay : %u",
__func__, roam_delay);
spin_lock_bh(&hw_priv->tsm_lock);
hw_priv->tsm_info.roam_delay = 0;
hw_priv->tsm_info.use_rx_roaming = 0;
spin_unlock_bh(&hw_priv->tsm_lock);
return atbm_tesmode_reply(hw->wiphy, &roam_delay, sizeof(u16));
#else
return -1;
#endif
}
static int atbm_set_tx_power_level(struct ieee80211_hw *hw, int power)
{
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif * vif = NULL;
int i = 0;
hw_priv->output_power = power;
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
wsm_set_output_power(hw_priv,
hw_priv->output_power * 10,
vif->if_id);
}
}
sta_printk( "[STA] %s: Power set on Device : %d",
__func__, power);
return 0;
}
static int atbm_set_wme_uapsd(struct ieee80211_hw *hw, int apsd)
{
int if_id = 0;
struct atbm_common *hw_priv = (struct atbm_common *) hw->priv;
struct atbm_vif *priv;
int ret = 0, i;
struct wsm_edca_params arg;
priv = ABwifi_hwpriv_to_vifpriv(hw_priv, if_id);
if (unlikely(!priv)) {
sta_printk(KERN_ERR "[STA] %s: Warning Priv is Null\n",
__func__);
return 0;
}
atbm_priv_vif_list_read_unlock(&priv->vif_lock);
mutex_lock(&hw_priv->conf_mutex);
for (i = 0; i < 4; i++)
{
arg.params[i].uapsdEnable = !!apsd;
}
ret = atbm_set_uapsd_param(priv, &arg);
ret = ret;
mutex_unlock(&hw_priv->conf_mutex);
return 0;
}
static int atbm_set_power_save_mode(struct ieee80211_hw *hw,
u8 *data, int len)
{
int ps_elems = 0;
struct atbm_common *hw_priv = (struct atbm_common *) hw->priv;
struct atbm_vif *priv;
int if_id = 0;
/* Interface ID is hard coded here, as interface is not
* passed in testmode command.
* Also it is assumed here that STA will be on interface
* 0 always.
*/
priv = ABwifi_hwpriv_to_vifpriv(hw_priv, if_id);
if (unlikely(!priv)) {
sta_printk(KERN_ERR "[STA] %s: Warning Priv is Null\n",
__func__);
return 0;
}
atbm_priv_vif_list_read_unlock(&priv->vif_lock);
mutex_lock(&hw_priv->conf_mutex);
ps_elems = *(int*)data;
if (ps_elems == 0)
priv->user_pm_mode = WSM_PSM_ACTIVE;
else if (ps_elems == 1)
priv->user_pm_mode = WSM_PSM_PS;
else if (ps_elems == 2)
priv->user_pm_mode = WSM_PSM_FAST_PS;
else
return 0;
sta_printk( "[STA] Aid: %d, Joined: %s, Powersave: %s\n",
priv->bss_params.aid,
priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA ? "yes" : "no",
priv->user_pm_mode == WSM_PSM_ACTIVE ? "WSM_PSM_ACTIVE" :
priv->user_pm_mode == WSM_PSM_PS ? "WSM_PSM_PS" :
priv->user_pm_mode == WSM_PSM_FAST_PS ? "WSM_PSM_FAST_PS" :
"UNKNOWN");
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA &&
priv->bss_params.aid ) {
priv->powersave_mode.pmMode = priv->user_pm_mode;
sta_printk("atbm_set_pm %d\n",priv->powersave_mode.pmMode);
atbm_set_pm(priv, &priv->powersave_mode);
}
else
priv->user_power_set_true = ps_elems;
mutex_unlock(&hw_priv->conf_mutex);
return 0;
}
#if 0
extern int wsm_test_cmd(struct atbm_common *hw_priv,u8 *buffer,int size);
#endif
#ifdef USB_BUS
extern int atbm_device_txrx_test_init(struct atbm_common *hw_priv,int caseNum );
int atbm_device_wakeup_test(struct atbm_common *hw_priv, int enable)
{
//atbm_device_txrx_test_init(hw_priv,enable);
return 0;
}
#else
int atbm_device_wakeup_test(struct atbm_common *hw_priv, int enable)
{
return 0;
}
#endif
enum altm_atbm_msg{
ALTM_SET_BLOCK_ACK_RX = 7,
ALTM_GET_BLOCK_ACK_RX = 8,
ALTM_SET_BLOCK_ACK_TX = 9,
ALTM_GET_BLOCK_ACK_TX = 10,
ALTM_GET_TSM_STATS = 11,
ALTM_CLEAR_TSM_STATS = 12,
ALTM_GET_PREAMBLE = 17,
ALTM_GET_CTSPROT = 18,
ALTM_GET_STATUS_COMMON = 19,
ALTM_GET_STATUS_COUNTERS = 20,
ALTM_GET_STATUS_PRIV = 21,
ALTM_GET_RSSI = 22,
ALTM_SET_PS_MODE = 23,
ALTM_SET_TX_POWER = 24,
ALTM_SET_WME_APSD = 25,
ALTM_GET_REVINFO = 28,
ALTM_GET_SHMEM = 29,
ALTM_SET_SHMEM = 30,
ALTM_GET_PACKETCNT = 37,
ALTM_SET_DBG_PRINT_TO_HOST = 38,
ALTM_SET_ZERO_COUNTERS_TABLE = 39,
ALTM_GET_DBG_PRINT_TO_HOST = 40,
ALTM_SET_FWCMD = 42,
ALTM_SET_WAKEUP = 43,
ALTM_SET_SHORT_GI = 44,
ALTM_SET_40M = 45,
ALTM_GET_EDCA_PARAM = 46,
ALTM_SET_TXQUEUE_PARAM = 47,
ALTM_GET_RTSTHRESHOLD = 13,
ALTM_SET_RTSTHRESHOLD = 14,
ALTM_SET_CTSPROT = 15,
ALTM_SET_PREAMBLE = 16,
ALTM_GET_SHORTSLOT = 27,
ALTM_SET_SHORTSLOT = 26,
ALTM_SET_SRL = 48,
ALTM_SET_LRL = 49,
ALTM_SHOW_EVENT_CMD = 50,
ALTM_CLEAR_EVENT_CMD = 51,
ALTM_SET_CCA = 100,
ATBM_MSG_GET_TSM_PARAMS = 102,
ATBM_MSG_START_STOP_TSM = 103,
ATBM_MSG_GET_ROAM_DELAY = 104,
ATBM_START_SMARTCONFIG = 107,
ATBM_SET_START_TX = 108,
ATBM_SET_STOP_TX = 109,
ATBM_SET_START_RX = 110,
ATBM_SET_STOP_RX = 111,
ATBM_WRITE_REG = 112,
ATBM_READ_REG = 113,
};
struct altbeam_tsm_stats {
//u64 actual_msrmt_start_time;
u16 msrmt_duration;
//u8 peer_sta_addr[6];
u8 tid;
u8 reporting_reason;
u32 txed_msdu_count;
u32 msdu_discarded_count;
u32 msdu_failed_count;
u32 multi_retry_count;
u32 qos_cfpolls_lost_count;
u32 avg_q_delay;
u32 avg_transmit_delay;
};
struct altm_msg_shmem{
u8 type;
u32 address;
u32 buff;
u32 size;
};
struct altbm_tx_queue_params {
u16 txop;
u16 cw_min;
u16 cw_max;
u8 aifs;
u8 queue;
};
extern void atbm_set_shortGI(u32 shortgi);
#ifdef CONFIG_ATBM_40M_AUTO_CCA
extern void atbm_set_40M(struct atbm_common *hw_priv,u32 is40M);
extern void atbm_set_cca(struct atbm_common *hw_priv,u8 *buff);
#endif
#define BUFFER_SIZE 1024
static char buff[BUFFER_SIZE];
extern int wsm_start_tx(struct atbm_common *hw_priv, struct ieee80211_vif *vif);
int wsm_stop_tx(struct atbm_common *hw_priv);
int atbm_altmtest_cmd(struct ieee80211_hw *hw, void *data, int len)
{
struct altm_msg{
u8 type;
u32 value;
};
struct altm_msg_txrx{
u32 type;
u32 value;
u32 externData[20];
};
int ret = 0;
struct altbeam_tsm_stats altbeam_tsm_stat[4];
int i = 0;
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif * vif = NULL;
struct atbm_debug_param seq;
u8 ucDbgPrintOpenFlag = 0;
u8 ucZeroCounterTable = 0;
char *pFwCmd = NULL;
char *str = NULL;
int queue;
int length;
//int registerValue;
struct altm_msg *msg =0;
struct altm_msg_txrx *msg_txrx =0;
u32 value = 0;
struct altm_msg_shmem *altm_shmem;
char * const fw_types[] = {
"ETF",
"WFM",
"WSM",
"HI test",
"Platform test"
};
if(hw->vendcmd_nl80211 == 0)
{
struct nlattr *data_p = nla_find(data, len, ATBM_TM_MSG_DATA);
if (!data_p)
return ret;
msg = (struct altm_msg *)nla_data(data_p);
}
else
msg = (struct altm_msg *)data;
sta_printk(KERN_ERR "[STA] %s: type: %i\n", __func__, msg->type);
switch (msg->type)
{
#ifdef CONFIG_ATBM_40M_AUTO_CCA
case ALTM_SET_CCA:
{
atbm_set_cca(hw_priv,(u8*)(&msg->value));
break;
}
#endif
#ifndef CONFIG_RATE_HW_CONTROL
case ALTM_SET_SRL:
sta_printk(KERN_ERR "Retry limits: %d (short).\n", msg->value);
spin_lock_bh(&hw_priv->tx_policy_cache.lock);
hw_priv->short_frame_max_tx_count =
( msg->value < 0x0F) ?
msg->value : 0x0F;
hw_priv->hw->max_rate_tries = hw_priv->short_frame_max_tx_count;
spin_unlock_bh(&hw_priv->tx_policy_cache.lock);
break;
case ALTM_SET_LRL:
sta_printk(KERN_ERR "Retry limits: %d (long).\n", msg->value);
spin_lock_bh(&hw_priv->tx_policy_cache.lock);
hw_priv->long_frame_max_tx_count = msg->value;
spin_unlock_bh(&hw_priv->tx_policy_cache.lock);
break;
#endif
case ALTM_GET_SHORTSLOT:
sta_printk(KERN_ERR "use_short_slot is %d\n", atbm_tool_use_short_slot);
break;
case ALTM_SET_SHORTSLOT:
atbm_for_each_vif(hw_priv,vif,i){
if(vif != NULL)
{
__le32 slot_time = (!!msg->value) ?
__cpu_to_le32(9) : __cpu_to_le32(20);
//add by wp fix PHICOMM AP4 long slot bug
if(vif->htcap){
slot_time = __cpu_to_le32(9);
}
sta_printk(KERN_ERR "[STA] Slot time :%d us.\n",__le32_to_cpu(slot_time));
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_SLOT_TIME,
&slot_time, sizeof(slot_time), vif->if_id));
atbm_tool_use_short_slot = (slot_time == __cpu_to_le32(9))? 1:0;
break;
}
}
break;
case ALTM_GET_PREAMBLE:
sta_printk(KERN_ERR "use_short_preamble is %d\n", atbm_tool_use_short_preamble);
break;
case ALTM_SET_PREAMBLE:
sta_printk(KERN_ERR "set_preamble is %d\n", msg->value);
atbm_for_each_vif(hw_priv,vif,i){
if(vif != NULL)
{
vif->association_mode.preambleType = msg->value ? WSM_JOIN_PREAMBLE_SHORT :
WSM_JOIN_PREAMBLE_LONG;
wsm_set_association_mode(hw_priv,
&vif->association_mode, vif->if_id);
atbm_tool_use_short_preamble = vif->association_mode.preambleType;
break;
}
}
break;
case ALTM_GET_CTSPROT:
sta_printk(KERN_ERR "use_cts_prot is %d\n", atbm_tool_use_cts_prot);
break;
case ALTM_SET_CTSPROT:
{
__le32 use_cts_prot = 0;
value = msg->value? 1:0;
use_cts_prot = __cpu_to_le32(value);
sta_printk(KERN_ERR "set_cts_prot is %d\n", use_cts_prot);
atbm_for_each_vif(hw_priv,vif,i){
if(vif != NULL)
{
wsm_write_mib(hw_priv, WSM_MIB_ID_NON_ERP_PROTECTION,
&use_cts_prot, sizeof(use_cts_prot),vif->if_id);
atbm_tool_use_cts_prot = value;
break;
}
}
}
break;
case ALTM_SET_RTSTHRESHOLD:
sta_printk(KERN_ERR "set_rtsthr is %d\n", msg->value);
atbm_for_each_vif(hw_priv,vif,i){
if(vif != NULL)
{
__le32 val32;
value = msg->value;
if (value != (u32) -1)
val32 = __cpu_to_le32(value);
else
val32 = 0; /* disabled */
/* mutex_lock(&priv->conf_mutex); */
ret = (wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD,
&val32, sizeof(val32), vif->if_id));
atbm_tool_rts_threshold = val32;
break;
}
}
break;
case ALTM_GET_RTSTHRESHOLD:
sta_printk(KERN_ERR "get_rts_threshold = %d\n", atbm_tool_rts_threshold);
break;
case ALTM_SET_TXQUEUE_PARAM:
{
struct altbm_tx_queue_params *altbm_param;
struct ieee80211_tx_queue_params params;
altbm_param = (struct altbm_tx_queue_params *)&msg->value;
params.aifs = altbm_param->aifs;
params.txop = altbm_param->txop;
params.cw_min = altbm_param->cw_min;
params.cw_max = altbm_param->cw_max;
params.uapsd = false;
sta_printk(KERN_ERR "set_tx_queue:aifs(%d),txop(%d),cw_min(%d),cw_max(%d)\n",
params.aifs,params.txop,params.cw_min,params.cw_max);
atbm_for_each_vif(hw_priv,vif,i){
if((vif != NULL) && (vif->vif != NULL)){
atbm_conf_tx(hw, vif->vif, altbm_param->queue, &params);
break;
}
}
}
break;
#ifdef CONFIG_ATBM_40M_AUTO_CCA
case ALTM_SET_40M:
atbm_set_40M(hw_priv,msg->value);
break;
#endif
case ALTM_GET_EDCA_PARAM:
atbm_for_each_vif(hw_priv,vif,i){
if((vif != NULL)){
for (queue = 0;queue < 4; queue++)
sta_printk(KERN_ERR "vif[%d],queue[%d]: txOpLimit=%d,aifns=%d,cwMin=%d,cwMax=%d;\n", i, queue,vif->edca.params[queue].txOpLimit, vif->edca.params[queue].aifns, vif->edca.params[queue].cwMin, vif->edca.params[queue].cwMax);
}
}
break;
case ALTM_SET_WAKEUP:
/*
if( msg->value == 1){
hw_priv->etf_channel = 1;
hw_priv->etf_channel_type = NL80211_CHAN_HT20;
hw_priv->etf_rate = WSM_TRANSMIT_RATE_6;
hw_priv->etf_len = 200;
atbm_for_each_vif(hw_priv,vif,i) {
if((vif != NULL)){
wsm_start_tx(hw_priv, vif->vif);
break;
}
}
}
else */if( msg->value == 1){
hw_priv->etf_channel = 6;
hw_priv->etf_channel_type = NL80211_CHAN_HT40PLUS;
hw_priv->etf_rate = WSM_TRANSMIT_RATE_HT_65;
hw_priv->etf_len = 1000;
atbm_for_each_vif(hw_priv,vif,i) {
if((vif != NULL)){
wsm_start_tx(hw_priv, vif->vif);
break;
}
}
}
else {
wsm_stop_tx(hw_priv);
}
//ret = atbm_device_wakeup_test(hw_priv, msg->value);
sta_printk(KERN_ERR "device wakeup set:%d, ret:%d\n", msg->value, ret);
break;
case ALTM_GET_REVINFO:
ret = sprintf(buff,
" Input buffers: %d x %d bytes\n"
" Hardware: %d.%d\n"
" %s firmware, ver: %d, build: %d,"
" api: %d, cap: 0x%.4X\n",
hw_priv->wsm_caps.numInpChBufs,
hw_priv->wsm_caps.sizeInpChBuf,
hw_priv->wsm_caps.hardwareId,
hw_priv->wsm_caps.hardwareSubId,
fw_types[hw_priv->wsm_caps.firmwareType],
hw_priv->wsm_caps.firmwareVersion,
hw_priv->wsm_caps.firmwareBuildNumber,
hw_priv->wsm_caps.firmwareApiVer,
hw_priv->wsm_caps.firmwareCap);
if (ret > 0)
{
ret = atbm_tesmode_reply(hw->wiphy, (void *)buff, ret);
}
break;
case ALTM_GET_SHMEM:
altm_shmem = (struct altm_msg_shmem *)msg;
if (altm_shmem->size <= 4)
{
sta_printk(KERN_ERR "size:0x%x, buff:%#x\n", altm_shmem->size, altm_shmem->buff);
ret = wsm_read_shmem(hw_priv, altm_shmem->address, &altm_shmem->buff, altm_shmem->size);
//atbm_direct_read_reg_32(hw_priv,altm_shmem->address,&altm_shmem->buff);
if (ret == 0)
{
sta_printk(KERN_ERR "size:0x%x, buff:%x\n", altm_shmem->size, altm_shmem->buff);
ret = atbm_tesmode_reply(hw->wiphy, &altm_shmem->buff, altm_shmem->size);
}
}else
{
sta_printk(KERN_ERR "proccess error, size range 1~4\n");
}
break;
case ALTM_SET_SHMEM:
altm_shmem = (struct altm_msg_shmem *)msg;
if (altm_shmem->size <= 4)
{
sta_printk(KERN_ERR "size:0x%x, buff:%#x\n", altm_shmem->size, altm_shmem->buff);
//atbm_direct_write_reg_32(hw_priv, altm_shmem->address,altm_shmem->buff);
ret = wsm_write_shmem(hw_priv, altm_shmem->address, altm_shmem->size, &altm_shmem->buff);
}else
{
sta_printk(KERN_ERR "proccess error, size range 1~4\n");
}
break;
case ALTM_SET_WME_APSD:
sta_printk(KERN_ERR "set wme_apsd(%d)\n",msg->value);
ret = atbm_set_wme_uapsd(hw, msg->value);
break;
case ALTM_SET_BLOCK_ACK_RX:
sta_printk(KERN_ERR "block_ack_rx(%x)\n",msg->value);
hw_priv->ba_tid_rx_mask = (u8)msg->value;
break;
case ALTM_GET_BLOCK_ACK_RX:
value = (u32)hw_priv->ba_tid_rx_mask;
ret = atbm_tesmode_reply(hw->wiphy, &value, sizeof(value));
break;
case ALTM_SET_BLOCK_ACK_TX:
sta_printk(KERN_ERR "block_ack_tx(%x)\n",msg->value);
hw_priv->ba_tid_tx_mask = (u8)msg->value;
break;
case ALTM_GET_BLOCK_ACK_TX:
value = (u32)hw_priv->ba_tid_tx_mask;
ret = atbm_tesmode_reply(hw->wiphy, &value, sizeof(value));
break;
case ALTM_CLEAR_TSM_STATS:
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
spin_lock_bh(&hw_priv->tsm_lock);
memset(&hw_priv->tsm_stats, 0, sizeof(struct atbm_tsm_stats));
memset(hw_priv->atbm_tsm_stats, 0, 4 * sizeof(struct atbm_tsm_stats));
memset(&hw_priv->tsm_info, 0, sizeof(struct atbm_tsm_info));
spin_unlock_bh(&hw_priv->tsm_lock);
#endif
break;
case ALTM_GET_TSM_STATS:
memset(&altbeam_tsm_stat[0], 0, sizeof(altbeam_tsm_stat));
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
for (; i < 4; i++)
{
altbeam_tsm_stat[i].msrmt_duration = hw_priv->atbm_tsm_stats[i].msrmt_duration;
altbeam_tsm_stat[i].tid = hw_priv->atbm_tsm_stats[i].tid;
altbeam_tsm_stat[i].reporting_reason = hw_priv->atbm_tsm_stats[i].reporting_reason;
altbeam_tsm_stat[i].txed_msdu_count = hw_priv->atbm_tsm_stats[i].txed_msdu_count;
altbeam_tsm_stat[i].msdu_discarded_count = hw_priv->atbm_tsm_stats[i].msdu_discarded_count;
altbeam_tsm_stat[i].msdu_failed_count = hw_priv->atbm_tsm_stats[i].msdu_failed_count;
altbeam_tsm_stat[i].multi_retry_count = hw_priv->atbm_tsm_stats[i].multi_retry_count;
altbeam_tsm_stat[i].qos_cfpolls_lost_count = hw_priv->atbm_tsm_stats[i].qos_cfpolls_lost_count;
altbeam_tsm_stat[i].avg_q_delay = hw_priv->atbm_tsm_stats[i].avg_q_delay;
altbeam_tsm_stat[i].avg_transmit_delay = hw_priv->atbm_tsm_stats[i].avg_transmit_delay;
}
#endif
ret = atbm_tesmode_reply(hw->wiphy, &altbeam_tsm_stat[0], sizeof(altbeam_tsm_stat));
break;
case ATBM_MSG_GET_TSM_PARAMS:
ret = atbm_get_tsm_params(hw);
break;
case ATBM_MSG_START_STOP_TSM:
ret = atbm_start_stop_tsm(hw, (u8*)(&msg->value));
break;
case ATBM_MSG_GET_ROAM_DELAY:
ret = atbm_get_roam_delay(hw);
break;
case ALTM_GET_STATUS_COMMON:
seq.buff = buff;
seq.private = (void *)hw_priv;
seq.size = BUFFER_SIZE;
seq.cout = 0;
atbm_status_show_common((void *)&seq, NULL);
ret = atbm_tesmode_reply(hw->wiphy, buff, seq.cout);
break;
case ALTM_GET_STATUS_COUNTERS:
seq.buff = buff;
seq.private = (void *)hw_priv;
seq.size = BUFFER_SIZE;
seq.cout = 0;
atbm_counters_show((void *)&seq, NULL);
ret = atbm_tesmode_reply(hw->wiphy, buff, seq.cout);
break;
case ALTM_GET_PACKETCNT:
seq.buff = buff;
seq.private = (void *)hw_priv;
seq.size = BUFFER_SIZE;
seq.cout = 0;
ret = atbm_pkt_show((void *)&seq, NULL);
ret |= atbm_tesmode_reply(hw->wiphy, buff, seq.cout);
break;
case ALTM_GET_STATUS_PRIV:
seq.buff = buff;
seq.private = (void *)hw_priv;
seq.size = BUFFER_SIZE;
seq.cout = 0;
sta_printk(KERN_ERR "hw_bufs_used: %d\n",hw_priv->hw_bufs_used);
atbm_for_each_vif(hw_priv,vif,i){
if(vif != NULL){
seq.private = (void *)vif;
seq.cout += snprintf(seq.buff + seq.cout, seq.size - seq.cout,
"0===========atbm_status_show_priv====%s=====:\n",vif_to_sdata(vif->vif)->name);
atbm_status_show_priv((void *)&seq, NULL);
}
}
seq.cout += snprintf(seq.buff + seq.cout, seq.size - seq.cout,
"=================End==================:\n");
ret = atbm_tesmode_reply(hw->wiphy, buff, seq.cout);
break;
case ALTM_GET_RSSI:
sta_printk(KERN_ERR "xxxxxxxxxxxxxxx\n");
seq.buff = buff;
seq.private = (void *)hw_priv;
seq.size = BUFFER_SIZE;
seq.cout = 0;
ret = atbm_statistics_show((void *)&seq, NULL);
ret |= atbm_tesmode_reply(hw->wiphy, buff, seq.cout);
break;
case ALTM_SET_PS_MODE:
sta_printk(KERN_ERR "set ps mode(%d)\n",msg->value);
ret = atbm_set_power_save_mode(hw, (u8 *)&msg->value, sizeof(msg->value));
break;
case ALTM_SET_TX_POWER:
sta_printk(KERN_ERR "set_tx_power(%d)\n",msg->value);
ret = atbm_set_tx_power_level(hw, msg->value);
break;
case ALTM_SET_DBG_PRINT_TO_HOST:
ucDbgPrintOpenFlag = !!msg->value;
sta_printk(KERN_ERR "%s dbgflag:%d\n", __func__, ucDbgPrintOpenFlag);
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DBG_PRINT_TO_HOST,
&ucDbgPrintOpenFlag, sizeof(ucDbgPrintOpenFlag), vif->if_id));
break;
}
}
break;
case ALTM_SET_ZERO_COUNTERS_TABLE:
sta_printk(KERN_ERR "set_zero_counters_table\n");
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_ZERO_COUNTERS_TABLE,
&ucZeroCounterTable, sizeof(ucZeroCounterTable), vif->if_id));
break;
}
}
break;
case ALTM_GET_DBG_PRINT_TO_HOST:
sta_printk(KERN_ERR "ALTM_GET_DBG_PRINT_TO_HOST\n");
WARN_ON(wsm_read_mib(hw_priv, WSM_MIB_ID_DBG_PRINT_TO_HOST,
&ucDbgPrintOpenFlag, sizeof(ucDbgPrintOpenFlag),-1));
ret = atbm_tesmode_reply(hw->wiphy, &ucDbgPrintOpenFlag, sizeof(ucDbgPrintOpenFlag));
break;
case ALTM_SET_FWCMD:
pFwCmd = (char *)&msg[1];
length = msg->value;
atbm_printk_sta("enter atbm_set_fwcmd msg[1]:%s\n", (char *)&msg[1]);
atbm_printk_sta("set fwcmd(%s)\n",pFwCmd);
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD,
pFwCmd, length, vif->if_id));
break;
}
}
break;
case ALTM_SET_SHORT_GI:
sta_printk(KERN_ERR "set_short_gi(%d)\n",msg->value);
atbm_set_shortGI(msg->value);
atbm_tool_shortGi = msg->value;
break;
case ALTM_SHOW_EVENT_CMD:
EELOG_Show();
break;
case ALTM_CLEAR_EVENT_CMD:
EELOG_Clear();
break;
#ifdef ATBM_SUPPORT_SMARTCONFIG
case ATBM_START_SMARTCONFIG:
atbm_smartconfig_start(hw_priv,msg->value);
break;
#endif
case ATBM_SET_START_TX:
//mutex_lock(&hw_priv->conf_mutex);
//wsm_stop_tx(hw_priv);
//mutex_unlock(&hw_priv->conf_mutex);
atbm_printk_sta("enter atbm_set_start_tx:value:%d\n", msg->value);
if(ETF_bStart_Tx || ETF_bStart_Rx){
atbm_printk_err("Error!:already start_tx,please stop_tx first!!\n");
return 0;
}
//mutex_lock(&hw_priv->conf_mutex);
// wsm_stop_tx(hw_priv);
// mutex_unlock(&hw_priv->conf_mutex);
if(hw->vendcmd_nl80211 == 0)
{
struct nlattr *data_p = nla_find(data, len, ATBM_TM_MSG_DATA);
if (!data_p)
return ret;
msg_txrx = (struct altm_msg_txrx *)nla_data(data_p);
}
else{
msg_txrx = (struct altm_msg_txrx *)data;
}
hw_priv->etf_channel = msg_txrx->externData[0];
hw_priv->etf_rate = msg_txrx->externData[1];
hw_priv->etf_len = msg_txrx->externData[2];
hw_priv->etf_channel_type = msg_txrx->externData[3];
hw_priv->etf_greedfiled = msg_txrx->externData[4];
atbm_for_each_vif(hw_priv,vif,i){
if(vif != NULL){
atbm_printk_sta("*******\n");
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
ETF_bStart_Tx = 1;
wsm_start_tx(hw_priv, vif->vif);
mutex_unlock(&hw_priv->conf_mutex);
break;
}
}
break;
case ATBM_SET_STOP_TX:
if(ETF_bStart_Tx == 0){
atbm_printk_sta("please start_tx first, then stop_tx");
return -EINVAL;
}
mutex_lock(&hw_priv->conf_mutex);
wsm_stop_tx(hw_priv);
ETF_bStart_Tx = 0;
mutex_unlock(&hw_priv->conf_mutex);
break;
case ATBM_SET_START_RX:
if(ETF_bStart_Rx || ETF_bStart_Tx){
atbm_printk_sta("Error!already ETF_bStartTx/ETF_bStartRx,please stop_rx first!!!\n");
return -EINVAL;
}
str = (char *)&msg[1];
memset(str+msg->value, 0, strlen(str)-msg->value);
memcpy(ch_and_type, str+10, msg->value-10);
atbm_for_each_vif(hw_priv, vif, i){
if(vif != NULL){
ETF_bStart_Rx = 1;
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD,
str, msg->value, vif->if_id));
}
break;
}
atbm_printk_sta("fwcmd:%s\n", str);
break;
case ATBM_SET_STOP_RX:
if((0 == ETF_bStart_Rx) || (0 == ch_and_type[0])){
atbm_printk_sta("please start_rx first,then stop_rx!!!\n");
return -EINVAL;
}
str = (char *)&msg[1];
memset(str+10, 0, 20);
memcpy(str+10, ch_and_type, strlen(ch_and_type));
atbm_for_each_vif(hw_priv, vif, i){
if(vif != NULL){
ETF_bStart_Rx = 0;
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD,
str, strlen(str), vif->if_id));
}
break;
}
case ATBM_WRITE_REG:
altm_shmem = (struct altm_msg_shmem *)msg;
if (altm_shmem->size <= 4){
atbm_printk_sta("Write Register %x=%x\n",altm_shmem->address,altm_shmem->buff);
atbm_direct_write_reg_32(hw_priv,altm_shmem->address,altm_shmem->buff);
}else{
atbm_printk_sta("proccess error, size range 1~4\n");
}
break;
case ATBM_READ_REG:
altm_shmem = (struct altm_msg_shmem *)msg;
if (altm_shmem->size <= 4){
atbm_direct_read_reg_32(hw_priv,altm_shmem->address,&altm_shmem->buff);
atbm_printk_sta("Read Register %x=%x\n",altm_shmem->address,altm_shmem->buff);
}else{
atbm_printk_sta("proccess error, size range 1~4\n");
}
break;
default:
break;
}
return ret;
}
#endif /* CONFIG_ATBM_APOLLO_TESTMODE */