6599 lines
186 KiB
C
Executable File
6599 lines
186 KiB
C
Executable File
/*
|
|
* Copyright (c) 2004-2011 Atheros Communications Inc.
|
|
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifdef __KERNEL__
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <asm/uaccess.h>
|
|
#include <linux/unistd.h>
|
|
#include <linux/file.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/delay.h>
|
|
#endif
|
|
|
|
#include "./8192cd_cfg.h"
|
|
|
|
#ifdef RTK_NL80211
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <net/cfg80211.h>
|
|
#include <net/mac80211.h>
|
|
#include <net/ieee80211_radiotap.h>
|
|
#include <linux/wireless.h>
|
|
#include <linux/device.h>
|
|
#include <linux/if_ether.h>
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
#include <uapi/linux/nl80211.h>
|
|
#else
|
|
#include <linux/nl80211.h>
|
|
#endif
|
|
#include <linux/ieee80211.h>
|
|
|
|
|
|
|
|
//#include "./nl80211_copy.h"
|
|
|
|
#ifdef __LINUX_2_6__
|
|
#include <linux/initrd.h>
|
|
#include <linux/syscalls.h>
|
|
#endif
|
|
|
|
#include "./8192cd.h"
|
|
#include "./8192cd_debug.h"
|
|
#include "./8192cd_cfg80211.h"
|
|
#include "./8192cd_headers.h"
|
|
#include "./8192cd_p2p.h"
|
|
|
|
#include "net80211/ieee80211.h"
|
|
#include "net80211/ieee80211_crypto.h"
|
|
#include "net80211/ieee80211_ioctl.h"
|
|
#include "./8192cd_net80211.h"
|
|
|
|
//#define DEBUG_NL80211
|
|
#ifdef DEBUG_NL80211
|
|
//#define NLENTER {}
|
|
//#define NLEXIT {}
|
|
#define NLENTER printk("[RTKNL][%s][%s] +++ \n", priv->dev->name, (char *)__FUNCTION__)
|
|
#define NLEXIT printk("[RTKNL][%s][%s] --- \n\n", priv->dev->name, (char *)__FUNCTION__)
|
|
#define NLINFO(fmt, args...) printk("[RTKNL][%s %d]"fmt, __FUNCTION__,__LINE__, ## args)
|
|
#define NLNOT printk("[RTKNL][%s %d] !!! NOT implement YET !!!\n", (char *)__FUNCTION__,__LINE__)
|
|
#else
|
|
#define NLENTER
|
|
#define NLEXIT
|
|
#define NLINFO(fmt, args...)
|
|
#define NLNOT
|
|
#endif
|
|
|
|
void void_printk_nl80211(const char *fmt, ...)
|
|
{
|
|
;
|
|
}
|
|
|
|
static void rtk_destroy_dev(struct rtknl *rtk);
|
|
|
|
#ifdef DEBUG_NL80211
|
|
#define NLMSG panic_printk
|
|
#else
|
|
#define NLMSG void_printk_nl80211
|
|
#endif
|
|
|
|
//#define SIGNAL_TYPE_UNSPEC
|
|
|
|
extern unsigned char WFA_OUI_PLUS_TYPE[];
|
|
|
|
#define RTK_MAX_WIFI_PHY 2
|
|
static int rtk_phy_idx=0;
|
|
struct rtknl *rtk_phy[RTK_MAX_WIFI_PHY];
|
|
static dev_t rtk_wifi_dev[RTK_MAX_WIFI_PHY];
|
|
static char *rtk_dev_name[RTK_MAX_WIFI_PHY]={"RTKWiFi0","RTKWiFi1"};
|
|
|
|
char rtk_fake_addr[6]={0x00,0xe0,0x4c,0xcc,0xdd,0x01}; //mark_dual , FIXME if wlan_mac readable
|
|
|
|
#define MAX_5G_DIFF_NUM 14
|
|
#define PIN_LEN 8
|
|
#define SIGNATURE_LEN 4
|
|
#if 0
|
|
#ifdef CONFIG_RTL_HW_SETTING_OFFSET
|
|
#define HW_SETTING_OFFSET CONFIG_RTL_HW_SETTING_OFFSET
|
|
#else
|
|
#define HW_SETTING_OFFSET 0x6000
|
|
#endif
|
|
#endif
|
|
extern unsigned int HW_SETTING_OFFSET; //mark_hw,from rtl819x_flash.c
|
|
#define HW_WLAN_SETTING_OFFSET 13
|
|
|
|
__PACK struct hw_wlan_setting {
|
|
unsigned char macAddr[6] ;
|
|
unsigned char macAddr1[6] ;
|
|
unsigned char macAddr2[6] ;
|
|
unsigned char macAddr3[6] ;
|
|
unsigned char macAddr4[6] ;
|
|
unsigned char macAddr5[6] ;
|
|
unsigned char macAddr6[6] ;
|
|
unsigned char macAddr7[6] ;
|
|
unsigned char pwrlevelCCK_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrlevelCCK_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrlevelHT40_1S_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrlevelHT40_1S_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiffHT40_2S[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiffHT20[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiffOFDM[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char regDomain ;
|
|
unsigned char rfType ;
|
|
unsigned char ledType ; // LED type, see LED_TYPE_T for definition
|
|
unsigned char xCap ;
|
|
unsigned char TSSI1 ;
|
|
unsigned char TSSI2 ;
|
|
unsigned char Ther ;
|
|
unsigned char Reserved1 ;
|
|
unsigned char Reserved2 ;
|
|
unsigned char Reserved3 ;
|
|
unsigned char Reserved4 ;
|
|
unsigned char Reserved5 ;
|
|
unsigned char Reserved6 ;
|
|
unsigned char Reserved7 ;
|
|
unsigned char Reserved8 ;
|
|
unsigned char Reserved9 ;
|
|
unsigned char Reserved10 ;
|
|
unsigned char pwrlevel5GHT40_1S_A[MAX_5G_CHANNEL_NUM] ;
|
|
unsigned char pwrlevel5GHT40_1S_B[MAX_5G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff5GHT40_2S[MAX_5G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff5GHT20[MAX_5G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff5GOFDM[MAX_5G_CHANNEL_NUM] ;
|
|
|
|
|
|
unsigned char wscPin[PIN_LEN+1] ;
|
|
|
|
#ifdef RTK_AC_SUPPORT
|
|
unsigned char pwrdiff_20BW1S_OFDM1T_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_40BW2S_20BW2S_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_OFDM2T_CCK2T_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_40BW3S_20BW3S_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_4OFDM3T_CCK3T_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_40BW4S_20BW4S_A[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_OFDM4T_CCK4T_A[MAX_2G_CHANNEL_NUM] ;
|
|
|
|
unsigned char pwrdiff_5G_20BW1S_OFDM1T_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_40BW2S_20BW2S_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_40BW3S_20BW3S_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_40BW4S_20BW4S_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_RSVD_OFDM4T_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW1S_160BW1S_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW2S_160BW2S_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW3S_160BW3S_A[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW4S_160BW4S_A[MAX_5G_DIFF_NUM] ;
|
|
|
|
|
|
unsigned char pwrdiff_20BW1S_OFDM1T_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_40BW2S_20BW2S_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_OFDM2T_CCK2T_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_40BW3S_20BW3S_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_OFDM3T_CCK3T_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_40BW4S_20BW4S_B[MAX_2G_CHANNEL_NUM] ;
|
|
unsigned char pwrdiff_OFDM4T_CCK4T_B[MAX_2G_CHANNEL_NUM] ;
|
|
|
|
unsigned char pwrdiff_5G_20BW1S_OFDM1T_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_40BW2S_20BW2S_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_40BW3S_20BW3S_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_40BW4S_20BW4S_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_RSVD_OFDM4T_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW1S_160BW1S_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW2S_160BW2S_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW3S_160BW3S_B[MAX_5G_DIFF_NUM] ;
|
|
unsigned char pwrdiff_5G_80BW4S_160BW4S_B[MAX_5G_DIFF_NUM] ;
|
|
|
|
unsigned char pwrdiff_20BW1S_OFDM1T_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_40BW2S_20BW2S_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_OFDM2T_CCK2T_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_40BW3S_20BW3S_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_4OFDM3T_CCK3T_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_40BW4S_20BW4S_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_OFDM4T_CCK4T_C[MAX_2G_CHANNEL_NUM];
|
|
|
|
unsigned char pwrdiff_5G_20BW1S_OFDM1T_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_40BW2S_20BW2S_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_40BW3S_20BW3S_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_40BW4S_20BW4S_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_RSVD_OFDM4T_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW1S_160BW1S_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW2S_160BW2S_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW3S_160BW3S_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW4S_160BW4S_C[MAX_5G_CHANNEL_NUM];
|
|
|
|
unsigned char pwrdiff_20BW1S_OFDM1T_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_40BW2S_20BW2S_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_OFDM2T_CCK2T_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_40BW3S_20BW3S_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_4OFDM3T_CCK3T_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_40BW4S_20BW4S_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_OFDM4T_CCK4T_D[MAX_2G_CHANNEL_NUM];
|
|
|
|
unsigned char pwrdiff_5G_20BW1S_OFDM1T_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_40BW2S_20BW2S_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_40BW3S_20BW3S_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_40BW4S_20BW4S_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_RSVD_OFDM4T_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW1S_160BW1S_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW2S_160BW2S_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW3S_160BW3S_D[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrdiff_5G_80BW4S_160BW4S_D[MAX_5G_CHANNEL_NUM];
|
|
|
|
unsigned char pwrlevelCCK_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrlevelCCK_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrlevelHT40_1S_C[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrlevelHT40_1S_D[MAX_2G_CHANNEL_NUM];
|
|
unsigned char pwrlevel5GHT40_1S_C[MAX_5G_CHANNEL_NUM];
|
|
unsigned char pwrlevel5GHT40_1S_D[MAX_5G_CHANNEL_NUM];
|
|
#endif
|
|
}__WLAN_ATTRIB_PACK__;
|
|
|
|
__PACK struct param_header {
|
|
unsigned char signature[SIGNATURE_LEN]; // Tag + version
|
|
unsigned short len ;
|
|
} __WLAN_ATTRIB_PACK__;
|
|
|
|
unsigned char is_WRT_scan_iface(const char* if_name)
|
|
{
|
|
#ifdef CONFIG_OPENWRT_SDK
|
|
if((strcmp(if_name, "tmp.wlan0")==0) || (strcmp(if_name, "tmp.wlan1")==0))
|
|
return 1;
|
|
else
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int is_zero_mac(const unsigned char *mac)
|
|
{
|
|
return !(mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5]| mac[6]| mac[7]);
|
|
}
|
|
|
|
void dump_mac(struct rtl8192cd_priv *priv, unsigned char *mac)
|
|
{
|
|
if(mac && !is_zero_mac(mac)){
|
|
NDEBUG(" %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
|
|
}
|
|
}
|
|
|
|
#if defined(P2P_SUPPORT) || defined(HS_WPA_CLI)
|
|
// function declaration
|
|
int realtek_remain_on_channel(struct wiphy *wiphy,
|
|
struct wireless_dev *wdev,
|
|
struct ieee80211_channel *channel,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
enum nl80211_channel_type channel_type,
|
|
#endif
|
|
unsigned int duration,
|
|
u64 *cookie);
|
|
|
|
static int realtek_cancel_remain_on_channel(struct wiphy *wiphy,
|
|
struct wireless_dev *wdev, u64 cookie);
|
|
|
|
#endif //CONFIG_P2P
|
|
|
|
#if defined(VAP_MAC_DRV_READ_FLASH)
|
|
int read_flash_hw_mac_vap(unsigned char *mac, int vap_idx)
|
|
{
|
|
unsigned int offset;
|
|
|
|
//NLENTER;
|
|
|
|
if(!mac)
|
|
return -1;
|
|
|
|
vap_idx +=1;
|
|
|
|
if(vap_idx > 7)
|
|
return -1;
|
|
|
|
offset = HW_SETTING_OFFSET+ sizeof(struct param_header)+ HW_WLAN_SETTING_OFFSET + sizeof(struct hw_wlan_setting) * (rtk_phy_idx-1);
|
|
offset += (vap_idx*ETH_ALEN);
|
|
offset |= 0xbd000000;
|
|
memcpy(mac,(unsigned char *)offset,ETH_ALEN);
|
|
|
|
if(is_zero_mac(mac))
|
|
return -1;
|
|
|
|
DEBUG_INFO("VAP[%d][%d]=%02x:%02x:%02x:%02x:%02x:%02x\n", (rtk_phy_idx-1), vap_idx, mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
//brian, get MAC address from utility, rtk_tx_calr
|
|
#if 0
|
|
void read_flash_hw_mac( unsigned char *mac,int idx)
|
|
{
|
|
unsigned int offset;
|
|
if(!mac)
|
|
return;
|
|
offset = HW_SETTING_OFFSET+ sizeof(struct param_header)+ HW_WLAN_SETTING_OFFSET + sizeof(struct hw_wlan_setting) * idx;
|
|
offset |= 0xbd000000;
|
|
memcpy(mac,(unsigned char *)offset,ETH_ALEN);
|
|
}
|
|
#endif
|
|
//#define CPTCFG_CFG80211_MODULE 1 // mark_com
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
|
|
void chan_type_to_name(enum nl80211_channel_type type, char *type_name)
|
|
{
|
|
switch (type) {
|
|
case NL80211_CHAN_NO_HT:
|
|
strcpy(type_name, "RTK_NL80211_CHAN_NO_HT");
|
|
break;
|
|
case NL80211_CHAN_HT20:
|
|
strcpy(type_name, "RTK_NL80211_CHAN_HT20");
|
|
break;
|
|
case NL80211_CHAN_HT40MINUS:
|
|
strcpy(type_name, "RTK_NL80211_CHAN_HT40MINUS");
|
|
break;
|
|
case NL80211_CHAN_HT40PLUS:
|
|
strcpy(type_name, "RTK_NL80211_CHAN_HT40PLUS");
|
|
break;
|
|
default:
|
|
strcpy(type_name, "NOT SUPPORT TYPE");
|
|
}
|
|
}
|
|
|
|
enum nl80211_chan_width convert_chan_type2width(enum nl80211_channel_type channel_type)
|
|
{
|
|
unsigned char type_name[32];
|
|
enum nl80211_chan_width width;
|
|
|
|
chan_type_to_name(channel_type, type_name);
|
|
|
|
printk("channel_type:%x %s\n", channel_type, type_name);
|
|
|
|
switch (channel_type) {
|
|
case NL80211_CHAN_NO_HT:
|
|
width = NL80211_CHAN_WIDTH_20_NOHT;
|
|
break;
|
|
case NL80211_CHAN_HT20:
|
|
width = NL80211_CHAN_WIDTH_20;
|
|
break;
|
|
case NL80211_CHAN_HT40MINUS:
|
|
case NL80211_CHAN_HT40PLUS:
|
|
width = NL80211_CHAN_WIDTH_40;
|
|
break;
|
|
default:
|
|
width = NL80211_CHAN_WIDTH_20_NOHT;
|
|
break;
|
|
}
|
|
|
|
return width;
|
|
}
|
|
#endif
|
|
|
|
#if 1 //_eric_nl event
|
|
|
|
struct rtl8192cd_priv* realtek_get_priv(struct wiphy *wiphy, struct net_device *dev)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
|
|
return (dev) ? (GET_DEV_PRIV(dev)) : (rtk->priv);
|
|
}
|
|
|
|
struct ieee80211_channel *rtk_get_iee80211_channel(struct wiphy *wiphy, unsigned int channel)
|
|
{
|
|
unsigned int freq = 0;
|
|
|
|
if(channel >= 34)
|
|
freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
|
|
else
|
|
freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
|
|
|
|
return ieee80211_get_channel(wiphy, freq);
|
|
|
|
}
|
|
|
|
int translate_ss_result_rssi(int rssi)
|
|
{
|
|
#if !defined(SIGNAL_TYPE_UNSPEC)
|
|
//reference libiwinfo/iwinfo_nl80211.c - scan_cb
|
|
return ((rssi-100+0x100)*100);
|
|
#else
|
|
return rssi;
|
|
#endif
|
|
}
|
|
|
|
void realtek_cfg80211_inform_bss(struct rtl8192cd_priv *priv)
|
|
{
|
|
struct wiphy *wiphy = priv->rtk->wiphy;
|
|
struct ieee80211_channel *channel = NULL;
|
|
struct cfg80211_bss *bss = NULL;
|
|
char tmpbuf[33];
|
|
UINT8 *mac = NULL;
|
|
u64 timestamp = 0;
|
|
unsigned char ie[MAX_IE_LEN];
|
|
unsigned char ie_len = 0;
|
|
unsigned char wpa_ie_len = 0;
|
|
unsigned char rsn_ie_len = 0;
|
|
unsigned int freq = 0;
|
|
|
|
mac = priv->pmib->dot11Bss.bssid;
|
|
wpa_ie_len = priv->rtk->clnt_info.wpa_ie.wpa_ie_len;
|
|
rsn_ie_len = priv->rtk->clnt_info.rsn_ie.rsn_ie_len;
|
|
|
|
channel = rtk_get_iee80211_channel(wiphy, priv->pmib->dot11Bss.channel);
|
|
|
|
if(channel == NULL)
|
|
{
|
|
printk("Null channel!!\n");
|
|
return;
|
|
}
|
|
|
|
timestamp = priv->pmib->dot11Bss.timestamp;
|
|
|
|
ie[0]= _SSID_IE_;
|
|
ie[1]= priv->pmib->dot11Bss.ssidlen;
|
|
memcpy(ie+2, priv->pmib->dot11Bss.ssid, priv->pmib->dot11Bss.ssidlen);
|
|
ie_len += (priv->pmib->dot11Bss.ssidlen + 2);
|
|
|
|
if((ie_len + wpa_ie_len + rsn_ie_len) < MAX_IE_LEN)
|
|
{
|
|
if(wpa_ie_len)
|
|
{
|
|
memcpy(ie+ie_len, priv->rtk->clnt_info.wpa_ie.data, wpa_ie_len);
|
|
ie_len += wpa_ie_len;
|
|
}
|
|
|
|
if(rsn_ie_len)
|
|
{
|
|
memcpy(ie+ie_len, priv->rtk->clnt_info.rsn_ie.data, rsn_ie_len);
|
|
ie_len += rsn_ie_len;
|
|
}
|
|
}
|
|
else
|
|
printk("ie_len too long !!!\n");
|
|
#if 1
|
|
NDEBUG2("bss[%s],hw_value[%03d],timestamp[0x%llx]",
|
|
priv->pmib->dot11Bss.ssid,
|
|
channel->hw_value,
|
|
timestamp);
|
|
|
|
NDEBUG2("capa[0x%02x],beacon_prd[%d],ie_len[%d],rssi[%d]\n",
|
|
priv->pmib->dot11Bss.capability,
|
|
priv->pmib->dot11Bss.beacon_prd,
|
|
ie_len,
|
|
priv->pmib->dot11Bss.rssi);
|
|
#endif
|
|
|
|
bss = cfg80211_inform_bss(wiphy, channel,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
|
|
CFG80211_BSS_FTYPE_UNKNOWN,
|
|
#endif
|
|
mac, timestamp,
|
|
priv->pmib->dot11Bss.capability,
|
|
priv->pmib->dot11Bss.beacon_prd,
|
|
ie, ie_len, translate_ss_result_rssi(priv->pmib->dot11Bss.rssi), GFP_ATOMIC);
|
|
|
|
if(bss) {
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
cfg80211_put_bss(wiphy, bss);
|
|
#else
|
|
cfg80211_put_bss(bss);
|
|
#endif
|
|
} else {
|
|
printk("%s bss = null\n",__func__);
|
|
}
|
|
}
|
|
|
|
void realtek_cfg80211_inform_bss_ies(unsigned char *ie_buf, unsigned int *total_ie_len,
|
|
unsigned char ie_id, unsigned char *ie, unsigned char ie_len)
|
|
{
|
|
ie_buf[*total_ie_len] = ie_id;
|
|
ie_buf[*total_ie_len+1] = ie_len;
|
|
*total_ie_len += 2;
|
|
memcpy(ie_buf+*total_ie_len,ie,ie_len);
|
|
*total_ie_len += ie_len;
|
|
}
|
|
|
|
#ifdef NOT_RTK_BSP
|
|
extern void vxd_copy_ss_result_from_root(struct rtl8192cd_priv *priv);
|
|
#endif
|
|
|
|
void realtek_cfg80211_inform_ss_result(struct rtl8192cd_priv *priv)
|
|
{
|
|
int i;
|
|
struct wiphy *wiphy = NULL;
|
|
struct ieee80211_channel *channel = NULL;
|
|
struct cfg80211_bss *bss = NULL;
|
|
|
|
if ( priv->rtk == NULL)
|
|
{
|
|
printk("inform_ss_result: rtk null\n");
|
|
return;
|
|
}
|
|
|
|
wiphy = priv->rtk->wiphy;
|
|
NLMSG("SiteSurvey Count=%d dev:%s\n", priv->site_survey->count, priv->dev->name);
|
|
//printk("SSID BSSID ch prd cap bsc oper ss sq bd 40m\n");
|
|
|
|
if (!priv->scan_req)
|
|
{
|
|
NLMSG("[%s][%s] No scan_req, No report to NL80211!!\n", priv->dev->name, __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
for(i=0; i<priv->site_survey->count; i++)
|
|
{
|
|
char tmpbuf[33];
|
|
UINT8 *mac = priv->site_survey->bss[i].bssid;
|
|
u64 timestamp = 0;
|
|
unsigned char report_ie[MAX_IE_LEN];
|
|
unsigned int report_ie_len = 0;
|
|
unsigned char wpa_ie_len = priv->site_survey->bss[i].wpa_ie_len;
|
|
unsigned char rsn_ie_len = priv->site_survey->bss[i].rsn_ie_len;
|
|
#ifdef WIFI_SIMPLE_CONFIG
|
|
unsigned char wps_ie_len = priv->site_survey->wscie[i].wps_ie_len; //wrt-wps-clnt
|
|
#endif
|
|
unsigned char rtk_p2p_ie_len = priv->site_survey->rtk_p2p_ie[i].p2p_ie_len; //wrt-wps-clnt
|
|
|
|
#ifdef NOT_RTK_BSP
|
|
unsigned int all_ie_len = priv->site_survey->bss[i].all_ie_len;
|
|
#endif
|
|
unsigned int total_len = 0;
|
|
unsigned int freq = 0;
|
|
|
|
channel = rtk_get_iee80211_channel(wiphy, priv->site_survey->bss[i].channel);
|
|
|
|
if(channel == NULL)
|
|
{
|
|
NDEBUG("Null channel!!\n");
|
|
continue;
|
|
}
|
|
|
|
timestamp = priv->site_survey->bss[i].timestamp;
|
|
|
|
#ifdef NOT_RTK_BSP
|
|
memcpy(report_ie + report_ie_len, priv->site_survey->bss[i].all_ie, all_ie_len);
|
|
report_ie_len += all_ie_len;
|
|
#else
|
|
report_ie[0]= _SSID_IE_;
|
|
report_ie[1]= priv->site_survey->bss[i].ssidlen;
|
|
memcpy(report_ie+2, priv->site_survey->bss[i].ssid, priv->site_survey->bss[i].ssidlen);
|
|
report_ie_len += (priv->site_survey->bss[i].ssidlen + 2);
|
|
|
|
if((report_ie_len + wpa_ie_len + rsn_ie_len + wps_ie_len + rtk_p2p_ie_len) < MAX_IE_LEN)
|
|
{
|
|
//NDEBUG("\n");
|
|
if(wpa_ie_len)
|
|
{
|
|
|
|
memcpy(report_ie+report_ie_len, priv->site_survey->bss[i].wpa_ie, wpa_ie_len);
|
|
report_ie_len += wpa_ie_len;
|
|
//NDEBUG("\n");
|
|
}
|
|
|
|
if(rsn_ie_len)
|
|
{
|
|
|
|
memcpy(report_ie+report_ie_len, priv->site_survey->bss[i].rsn_ie, rsn_ie_len);
|
|
report_ie_len += rsn_ie_len;
|
|
//NDEBUG("\n");
|
|
}
|
|
|
|
if(wps_ie_len)
|
|
{
|
|
memcpy(report_ie+report_ie_len, priv->site_survey->bss[i].wscie, wps_ie_len);
|
|
report_ie_len += wps_ie_len;
|
|
NDEBUG2("bss include wps ie[%d]\n",wps_ie_len);
|
|
}
|
|
|
|
if(rtk_p2p_ie_len)
|
|
{
|
|
memcpy(report_ie+report_ie_len, priv->site_survey->bss[i].p2p_ie, rtk_p2p_ie_len);
|
|
report_ie_len += rtk_p2p_ie_len;
|
|
NDEBUG2("scan include p2p ie[%d]\n",rtk_p2p_ie_len);
|
|
}
|
|
//for DSSET IE
|
|
realtek_cfg80211_inform_bss_ies(report_ie,&report_ie_len,_DSSET_IE_,&priv->site_survey->bss[i].channel,DSSET_IE_LEN);
|
|
//for ht cap
|
|
realtek_cfg80211_inform_bss_ies(report_ie,&report_ie_len,_HT_CAP_,&priv->site_survey->bss[i].ht_cap,HTCAP_IE_LEN);
|
|
//for ht oper
|
|
realtek_cfg80211_inform_bss_ies(report_ie,&report_ie_len,_HT_IE_,&priv->site_survey->bss[i].ht_info,HTINFO_IE_LEN);
|
|
}
|
|
else{
|
|
NDEBUG("report_ie_len too long !!!\n");
|
|
}
|
|
|
|
#if 0
|
|
printk("[%d=%s] %03d 0x%08x 0x%02x %d %d %d\n", i, priv->site_survey->bss[i].ssid,
|
|
channel->hw_value, timestamp,
|
|
priv->site_survey->bss[i].capability,
|
|
priv->site_survey->bss[i].beacon_prd, report_ie_len,
|
|
priv->site_survey->bss[i].rssi);
|
|
#endif
|
|
#endif
|
|
|
|
bss = cfg80211_inform_bss(wiphy, channel,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
|
|
CFG80211_BSS_FTYPE_UNKNOWN,
|
|
#endif
|
|
mac, timestamp,
|
|
priv->site_survey->bss[i].capability,
|
|
priv->site_survey->bss[i].beacon_prd,
|
|
report_ie, report_ie_len, translate_ss_result_rssi(priv->site_survey->bss[i].rssi), GFP_ATOMIC);
|
|
|
|
if(bss) {
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
cfg80211_put_bss(wiphy, bss);
|
|
#else
|
|
cfg80211_put_bss(bss);
|
|
#endif
|
|
} else {
|
|
//printk("%s bss = null\n",__func__);
|
|
}
|
|
}
|
|
}
|
|
|
|
// static void realtek_cfg80211_sscan_disable(struct rtl8192cd_priv *priv) rename to easy understand name rtk_abort_scan
|
|
static void rtk_abort_scan(struct rtl8192cd_priv *priv, enum scan_abort_case abort_case)
|
|
{
|
|
struct rtl8192cd_priv *priv_root = GET_ROOT(priv);
|
|
struct cfg80211_scan_request *scan_req = priv_root->scan_req;
|
|
|
|
NLMSG("[%s] rtk_abort_scan [%p]+++ \n", priv->dev->name, scan_req);
|
|
|
|
if(priv_root->scan_req)
|
|
{
|
|
priv_root->ss_req_ongoing = 0;
|
|
priv_root->scan_req = NULL;
|
|
}
|
|
|
|
if(priv->scan_req) //VXD can also do scan
|
|
{
|
|
priv->ss_req_ongoing = 0;
|
|
priv->scan_req = NULL;
|
|
}
|
|
|
|
//event_indicate_cfg80211(priv, NULL, CFG80211_SCAN_ABORDED, NULL);
|
|
//cfg80211_sched_scan_stopped(wiphy);
|
|
}
|
|
|
|
|
|
|
|
#define HAPD_READY_RX_EVENT 5
|
|
|
|
void event_to_name(int event, char *event_name)
|
|
{
|
|
|
|
switch (event) {
|
|
case CFG80211_CONNECT_RESULT:
|
|
strcpy(event_name, "CFG80211_CONNECT_RESULT");
|
|
break;
|
|
case CFG80211_ROAMED:
|
|
strcpy(event_name, "CFG80211_ROAMED");
|
|
break;
|
|
case CFG80211_DISCONNECTED:
|
|
strcpy(event_name, "CFG80211_DISCONNECTED");
|
|
break;
|
|
case CFG80211_IBSS_JOINED:
|
|
strcpy(event_name, "CFG80211_IBSS_JOINED");
|
|
break;
|
|
case CFG80211_NEW_STA:
|
|
strcpy(event_name, "CFG80211_NEW_STA");
|
|
break;
|
|
case CFG80211_SCAN_DONE:
|
|
strcpy(event_name, "CFG80211_SCAN_DONE");
|
|
break;
|
|
case CFG80211_SCAN_ABORTED:
|
|
strcpy(event_name, "CFG80211_SCAN_ABORTED");
|
|
break;
|
|
case CFG80211_DEL_STA:
|
|
strcpy(event_name, "CFG80211_DEL_STA");
|
|
break;
|
|
case CFG80211_RADAR_CAC_FINISHED:
|
|
strcpy(event_name, "CFG80211_RADAR_CAC_FINISHED");
|
|
break;
|
|
case CFG80211_RADAR_DETECTED:
|
|
strcpy(event_name, "CFG80211_RADAR_DETECTED");
|
|
break;
|
|
case CFG80211_RADAR_CAC_ABORTED:
|
|
strcpy(event_name, "CFG80211_RADAR_CAC_ABORTED");
|
|
break;
|
|
default:
|
|
strcpy(event_name, "UNKNOWN EVENT");
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
int event_indicate_cfg80211(struct rtl8192cd_priv *priv, unsigned char *mac, int event, void *extra)
|
|
{
|
|
struct net_device *dev = (struct net_device *)priv->dev;
|
|
struct stat_info *pstat = NULL;
|
|
struct station_info sinfo;
|
|
struct wiphy *wiphy = priv->rtk->wiphy;
|
|
|
|
u8 assoc_req_ies_buf[256*3];
|
|
u8* ie_pos=assoc_req_ies_buf;
|
|
unsigned long flags;
|
|
//NLENTER;
|
|
|
|
|
|
{
|
|
char event_name[32];
|
|
event_to_name(event, event_name);
|
|
NLMSG("EVENT [%s][%s=%d]\n", priv->dev->name, event_name, event);
|
|
}
|
|
|
|
/*cfg p2p 2014-0330 , report CFG80211_NEW_STA , ASAP*/
|
|
if( (event != CFG80211_SCAN_DONE) && (event != CFG80211_NEW_STA) && (event != CFG80211_DEL_STA) && (event != CFG80211_RADAR_CAC_FINISHED) ) { //eric-bb
|
|
if( (OPMODE & WIFI_AP_STATE) && (priv->up_time <= HAPD_READY_RX_EVENT) )
|
|
{
|
|
NLMSG("ignore cfg event,up_time[%ld],event[%d]\n", priv->up_time,event);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
printk("event_indicate_cfg80211 ++++++ \n");
|
|
|
|
if(mac)
|
|
pstat = get_stainfo(priv, mac);
|
|
|
|
SMP_LOCK_CFG80211(flags);
|
|
|
|
switch(event) {
|
|
case CFG80211_CONNECT_RESULT:
|
|
{
|
|
struct cfg80211_bss *bss = NULL;
|
|
NDEBUG3("[%s][CFG80211_CONNECT_RESULT][%d]\n", priv->dev->name, event);
|
|
|
|
if(priv->receive_connect_cmd == 0)
|
|
{
|
|
NDEBUG3("Not received connect cmd yet !! No report CFG80211_CONNECT_RESULT\n");
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
bss = cfg80211_get_bss(wiphy,
|
|
priv->pmib->dot11Bss.channel, priv->pmib->dot11Bss.bssid,
|
|
priv->pmib->dot11Bss.ssid, priv->pmib->dot11Bss.ssidlen,
|
|
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
|
|
|
if(bss==NULL)
|
|
{
|
|
NDEBUG2("report this bss\n");
|
|
realtek_cfg80211_inform_bss(priv);
|
|
}
|
|
#endif
|
|
|
|
cfg80211_connect_result(priv->dev, BSSID,
|
|
priv->rtk->clnt_info.assoc_req, priv->rtk->clnt_info.assoc_req_len,
|
|
priv->rtk->clnt_info.assoc_rsp, priv->rtk->clnt_info.assoc_rsp_len,
|
|
WLAN_STATUS_SUCCESS, GFP_KERNEL);
|
|
}
|
|
break;
|
|
case CFG80211_ROAMED:
|
|
{
|
|
NDEBUG3("[%s][CFG80211_ROAMED][%d]\n", priv->dev->name, event);
|
|
break;
|
|
}
|
|
break;
|
|
case CFG80211_DISCONNECTED:
|
|
{
|
|
//_eric_nl ?? disconnect event no mac, for station mode only ??
|
|
NDEBUG3("[%s][CFG80211_DISCONNECTED][%d]\n", priv->dev->name, event);
|
|
cfg80211_disconnected(priv->dev, 0, NULL, 0,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0)
|
|
1,
|
|
#endif
|
|
GFP_KERNEL);
|
|
break;
|
|
}
|
|
break;
|
|
case CFG80211_IBSS_JOINED:
|
|
{
|
|
struct cfg80211_bss *bss = NULL;
|
|
struct ieee80211_channel *channel = NULL;
|
|
|
|
bss = cfg80211_get_bss(wiphy,
|
|
channel, priv->pmib->dot11Bss.bssid,
|
|
priv->pmib->dot11Bss.ssid, priv->pmib->dot11Bss.ssidlen,
|
|
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
|
|
|
if(bss==NULL)
|
|
{
|
|
printk("report this bss\n");
|
|
realtek_cfg80211_inform_bss(priv);
|
|
}
|
|
|
|
channel = rtk_get_iee80211_channel(wiphy, priv->pmib->dot11Bss.channel);
|
|
|
|
cfg80211_ibss_joined(priv->dev, BSSID,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0)
|
|
channel,
|
|
#endif
|
|
GFP_KERNEL);
|
|
}
|
|
break;
|
|
case CFG80211_NEW_STA:
|
|
{
|
|
NDEBUG3("[%s][CFG80211_NEW_STA][%d]\n", priv->dev->name, event);
|
|
/* send event to application */
|
|
memset(&sinfo, 0, sizeof(struct station_info));
|
|
memset(assoc_req_ies_buf, 0, sizeof(256*3));
|
|
sinfo.assoc_req_ies = assoc_req_ies_buf;
|
|
|
|
if(pstat == NULL)
|
|
{
|
|
NDEBUG3("!!PSTA = NULL, MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
|
|
if(extra == NULL){
|
|
NDEBUG3("NO PSTA for CFG80211_NEW_STA\n");
|
|
break;
|
|
} else
|
|
pstat = extra;
|
|
}
|
|
|
|
/* TODO: sinfo.generation ???*/
|
|
if(pstat->wpa_ie[1] > 0){
|
|
sinfo.assoc_req_ies_len += pstat->wpa_ie[1]+2;
|
|
memcpy(ie_pos,pstat->wpa_ie, pstat->wpa_ie[1]+2);
|
|
ie_pos+=pstat->wpa_ie[1]+2;
|
|
}
|
|
|
|
|
|
if(pstat->wps_ie[1] > 0) // for wrt-wps
|
|
{
|
|
sinfo.assoc_req_ies_len += pstat->wps_ie[1]+2;
|
|
memcpy(ie_pos,pstat->wps_ie, pstat->wps_ie[1]+2);
|
|
ie_pos+=pstat->wps_ie[1]+2;
|
|
}
|
|
|
|
#if defined(P2P_SUPPORT)
|
|
/*p2p support , cfg p2p , 2014 0330 , report p2p_ie included in assoc_req*/
|
|
if(pstat->p2p_ie[1] > 0)
|
|
{
|
|
sinfo.assoc_req_ies_len += pstat->p2p_ie[1]+2;
|
|
memcpy(ie_pos,pstat->p2p_ie, pstat->p2p_ie[1]+2);
|
|
ie_pos += (pstat->p2p_ie[1]+2);
|
|
}
|
|
/*p2p support , cfg p2p , 2014 0330 , report p2p_ie included in assoc_req*/
|
|
#endif
|
|
|
|
if(sinfo.assoc_req_ies_len)
|
|
sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
|
|
|
|
SMP_UNLOCK_CFG80211(flags);
|
|
NDEBUG2("cfg80211_new_sta assoc req,[idx=%d] Rx assoc_req_ies_len = %d\n", priv->dev->ifindex, sinfo.assoc_req_ies_len);
|
|
cfg80211_new_sta(priv->dev, mac, &sinfo, GFP_KERNEL);
|
|
NDEBUG3("cfg80211_new_sta ,STA[%02x%02x%02x:%02x%02x%02x]\n",mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
|
|
netif_wake_queue(priv->dev); //wrt-vap
|
|
SMP_LOCK_CFG80211(flags);
|
|
|
|
}
|
|
break;
|
|
case CFG80211_SCAN_ABORTED:
|
|
{
|
|
//NDEBUG2("[%s][CFG80211_SCAN_ABORTED][%d]\n", priv->dev->name, event);
|
|
priv->ss_req_ongoing = 0;
|
|
#ifdef USE_OUT_SRC
|
|
priv->pshare->bScanInProcess = FALSE;
|
|
#endif
|
|
|
|
if (priv->scan_req)
|
|
{
|
|
struct cfg80211_scan_request *scan_req = priv->scan_req;
|
|
|
|
priv->scan_req = NULL;
|
|
|
|
cfg80211_scan_done(scan_req, true);
|
|
}
|
|
}
|
|
break;
|
|
case CFG80211_SCAN_DONE:
|
|
{
|
|
//NDEBUG2("[%s][CFG80211_SCAN_DONE][%d]\n", priv->dev->name, event);
|
|
priv->ss_req_ongoing = 0;
|
|
priv->site_survey->count_backup = priv->site_survey->count;
|
|
memcpy(priv->site_survey->bss_backup, priv->site_survey->bss, sizeof(struct bss_desc)*priv->site_survey->count);
|
|
#if defined(P2P_SUPPORT)
|
|
if(rtk_p2p_is_enabled(priv)==CFG80211_P2P){
|
|
rtk_p2p_set_role(priv,priv->p2pPtr->pre_p2p_role);
|
|
rtk_p2p_set_state(priv,priv->p2pPtr->pre_p2p_state);
|
|
|
|
NDEBUG2("role[%d]\n",rtk_p2p_get_role(priv));
|
|
NDEBUG2("state[%d]\n",rtk_p2p_get_state(priv));
|
|
}
|
|
#endif
|
|
|
|
if (priv->scan_req)
|
|
{
|
|
struct cfg80211_scan_request *scan_req = priv->scan_req;
|
|
priv->scan_req = NULL;
|
|
cfg80211_scan_done(scan_req, false);
|
|
}
|
|
}
|
|
break;
|
|
case CFG80211_DEL_STA:
|
|
NDEBUG("[%s][CFG80211_DEL_STA][%d]\n", priv->dev->name, event);
|
|
cfg80211_del_sta(priv->dev, mac, GFP_KERNEL);
|
|
break;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
case CFG80211_RADAR_CAC_FINISHED:
|
|
if (priv->pshare->dfs_chan_def && priv->wdev.cac_started) {
|
|
NDEBUG("[%s][CFG80211_RADAR_CAC_FINISHED][%d]\n", priv->dev->name, event);
|
|
cfg80211_cac_event(priv->dev,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
|
priv->pshare->dfs_chan_def,
|
|
#endif
|
|
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
|
|
}
|
|
break;
|
|
case CFG80211_RADAR_DETECTED:
|
|
if (priv->pshare->dfs_chan_def && priv->wdev.cac_started) {
|
|
NDEBUG("[%s][CFG80211_RADAR_DETECTED][%d]\n", priv->dev->name, event);
|
|
cfg80211_radar_event(wiphy, priv->pshare->dfs_chan_def, GFP_KERNEL);
|
|
}
|
|
break;
|
|
case CFG80211_RADAR_CAC_ABORTED:
|
|
if (priv->pshare->dfs_chan_def) {
|
|
NDEBUG("[%s][CFG80211_RADAR_CAC_ABORTED][%d]\n", priv->dev->name, event);
|
|
cfg80211_cac_event(priv->dev,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
|
priv->pshare->dfs_chan_def,
|
|
#endif
|
|
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
|
|
}
|
|
break;
|
|
#endif
|
|
case CFG80211_REMAIN_CHANNEL:
|
|
{
|
|
struct wireless_dev *wdev = &priv->wdev;
|
|
cfg80211_remain_on_channel_expired(
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
wdev,
|
|
#else
|
|
priv->dev,
|
|
#endif
|
|
priv->nl_ctx.remain_on_ch_cookie,
|
|
&priv->nl_ctx.remain_on_ch_channel,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
priv->nl_ctx.remain_on_ch_type,
|
|
#endif
|
|
GFP_KERNEL);
|
|
}
|
|
break;
|
|
case CFG80211_MIC_FAILURE:
|
|
NDEBUG("[%s][CFG80211_MIC_FAILURE][%d]\n", priv->dev->name, event);
|
|
//cfg80211_michael_mic_failure(priv->dev,GFP_KERNEL);
|
|
default:
|
|
NDEBUG("[%s][Unknown Event !!][%d]\n", priv->dev->name, event);
|
|
}
|
|
|
|
SMP_UNLOCK_CFG80211(flags);
|
|
|
|
printk("event_indicate_cfg80211 -----\n");
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
void realtek_ap_calibration(struct rtl8192cd_priv *priv)
|
|
{
|
|
NLENTER;
|
|
|
|
#if 0
|
|
unsigned char CCK_A[3] = {0x2a,0x2a,0x28};
|
|
unsigned char CCK_B[3] = {0x2a,0x2a,0x28};
|
|
unsigned char HT40_A[3] = {0x2b,0x2b,0x29};
|
|
unsigned char HT40_B[3] = {0x2b,0x2b,0x29};
|
|
unsigned char DIFF_HT40_2S[3] = {0x0,0x0,0x0};
|
|
unsigned char DIFF_20[3] = {0x02,0x02,0x02};
|
|
unsigned char DIFF_OFDM[3] = {0x04,0x04,0x04};
|
|
unsigned int thermal = 0x19;
|
|
unsigned int crystal = 32;
|
|
#else
|
|
unsigned char CCK_A[3] = {0x2b,0x2a,0x29};
|
|
unsigned char CCK_B[3] = {0x2b,0x2a,0x29};
|
|
unsigned char HT40_A[3] = {0x2c,0x2b,0x2a};
|
|
unsigned char HT40_B[3] = {0x2c,0x2b,0x2a};
|
|
unsigned char DIFF_HT40_2S[3] = {0x0,0x0,0x0};
|
|
unsigned char DIFF_20[3] = {0x02,0x02,0x02};
|
|
unsigned char DIFF_OFDM[3] = {0x04,0x04,0x04};
|
|
unsigned int thermal = 0x16;
|
|
unsigned int crystal = 32;
|
|
#endif
|
|
|
|
int tmp = 0;
|
|
int tmp2 = 0;
|
|
|
|
for(tmp = 0; tmp <=13; tmp ++)
|
|
{
|
|
if(tmp < 3)
|
|
tmp2 = 0;
|
|
else if(tmp < 9)
|
|
tmp2 = 1;
|
|
else
|
|
tmp2 = 2;
|
|
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_A[tmp] = CCK_A[tmp2];
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_B[tmp] = CCK_B[tmp2];
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[tmp] = HT40_A[tmp2];
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[tmp] = HT40_B[tmp2];
|
|
priv->pmib->dot11RFEntry.pwrdiffHT40_2S[tmp] = DIFF_HT40_2S[tmp2];
|
|
priv->pmib->dot11RFEntry.pwrdiffHT20[tmp] = DIFF_20[tmp2];
|
|
priv->pmib->dot11RFEntry.pwrdiffOFDM[tmp] = DIFF_OFDM[tmp2];
|
|
}
|
|
|
|
priv->pmib->dot11RFEntry.ther = thermal;
|
|
priv->pmib->dot11RFEntry.xcap = crystal;
|
|
|
|
NLEXIT;
|
|
}
|
|
#endif
|
|
|
|
|
|
//mark_swc
|
|
static void rtk_set_phy_channel(struct rtl8192cd_priv *priv,unsigned int channel,unsigned int bandwidth,unsigned int chan_offset)
|
|
{
|
|
NDEBUG3("ch[%d]bw[%d]offset[%d]\n",channel,bandwidth,chan_offset);
|
|
//priv , share part
|
|
priv->pshare->CurrentChannelBW = bandwidth;
|
|
priv->pshare->offset_2nd_chan =chan_offset ;
|
|
|
|
// wifi chanel hw settting API
|
|
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
|
|
SwChnl(priv, channel, priv->pshare->offset_2nd_chan);
|
|
//printk("rtk_set_phy_channel end !!!\n chan=%d \n",channel );
|
|
|
|
}
|
|
|
|
static void rtk_get_band_capa(struct rtl8192cd_priv *priv,BOOLEAN *band_2gig ,BOOLEAN *band_5gig)
|
|
{
|
|
//default register as 2.4GHz
|
|
*band_2gig = true;
|
|
*band_5gig = false;
|
|
|
|
if ((GET_CHIP_VER(priv) == VERSION_8812E)
|
|
#if defined(CONFIG_WLAN_HAL_8814AE)
|
|
|| (GET_CHIP_VER(priv) == VERSION_8814A)
|
|
#endif
|
|
)
|
|
{
|
|
#if defined(CONFIG_WLAN_HAL_8814AE)
|
|
if(priv->pshare->is5g)
|
|
#endif
|
|
{
|
|
*band_2gig = false;
|
|
*band_5gig = true;
|
|
}
|
|
}
|
|
else if (GET_CHIP_VER(priv) == VERSION_8192D)
|
|
{
|
|
*band_2gig = false;
|
|
*band_5gig = true;
|
|
}
|
|
else if (GET_CHIP_VER(priv) == VERSION_8881A)
|
|
{
|
|
#if defined(CONFIG_RTL_8881A_SELECTIVE)
|
|
//8881A selective mode
|
|
*band_2gig = true;
|
|
*band_5gig = true;
|
|
#else
|
|
//use pcie slot 0 for 2.4G 88E/92E, 8881A is 5G now
|
|
*band_2gig = false;
|
|
*band_5gig = true;
|
|
#endif
|
|
}
|
|
//mark_sel
|
|
//if 881a , then it is possible to *band_2gig = true ,*band_5gig = true in selective mode(FLAG?)
|
|
//FIXME
|
|
}
|
|
|
|
void realtek_ap_default_config(struct rtl8192cd_priv *priv)
|
|
{
|
|
//short GI default
|
|
priv->pmib->dot11nConfigEntry.dot11nShortGIfor20M = 1;
|
|
priv->pmib->dot11nConfigEntry.dot11nShortGIfor40M = 1;
|
|
priv->pmib->dot11nConfigEntry.dot11nShortGIfor80M = 1;
|
|
//APMDU
|
|
priv->pmib->dot11nConfigEntry.dot11nAMPDU = 1;
|
|
|
|
#ifdef MBSSID
|
|
if(IS_ROOT_INTERFACE(priv))
|
|
{
|
|
priv->pmib->miscEntry.vap_enable = 1; //eric-vap //eric-brsc
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
if(IS_VAP_INTERFACE(priv))
|
|
{
|
|
struct rtl8192cd_priv *priv_root = GET_ROOT(priv);
|
|
struct rtl8192cd_priv *priv_vxd = GET_VXD_PRIV(priv_root);
|
|
unsigned char is_vxd_running = 0;
|
|
|
|
if(priv_vxd)
|
|
is_vxd_running = netif_running(priv_vxd->dev);
|
|
|
|
if(priv_root->pmib->miscEntry.vap_enable == 0)
|
|
{
|
|
priv_root->pmib->miscEntry.vap_enable = 1;
|
|
|
|
if(is_vxd_running)
|
|
rtl8192cd_close(priv_vxd->dev);
|
|
|
|
rtl8192cd_close(priv_root->dev);
|
|
rtl8192cd_open(priv_root->dev);
|
|
|
|
if(is_vxd_running)
|
|
rtl8192cd_open(priv_vxd->dev);
|
|
|
|
}
|
|
}
|
|
#endif
|
|
//vif copy settings from root
|
|
priv->pmib->dot11BssType.net_work_type = GET_ROOT(priv)->pmib->dot11BssType.net_work_type;
|
|
priv->pmib->dot11RFEntry.phyBandSelect = GET_ROOT(priv)->pmib->dot11RFEntry.phyBandSelect;
|
|
priv->pmib->dot11RFEntry.dot11channel = GET_ROOT(priv)->pmib->dot11RFEntry.dot11channel;
|
|
priv->pmib->dot11nConfigEntry.dot11nUse40M = GET_ROOT(priv)->pmib->dot11nConfigEntry.dot11nUse40M;
|
|
priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = GET_ROOT(priv)->pmib->dot11nConfigEntry.dot11n2ndChOffset;
|
|
|
|
priv->pmib->dot11OperationEntry.dot11FragmentationThreshold = GET_ROOT(priv)->pmib->dot11OperationEntry.dot11FragmentationThreshold;
|
|
priv->pmib->dot11OperationEntry.dot11RTSThreshold = GET_ROOT(priv)->pmib->dot11OperationEntry.dot11RTSThreshold;
|
|
priv->pmib->dot11OperationEntry.dot11ShortRetryLimit = GET_ROOT(priv)->pmib->dot11OperationEntry.dot11ShortRetryLimit;
|
|
priv->pmib->dot11OperationEntry.dot11LongRetryLimit = GET_ROOT(priv)->pmib->dot11OperationEntry.dot11LongRetryLimit;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
//mark_priv
|
|
#define RTK_PRIV_BW_5M 1
|
|
#define RTK_PRIV_BW_10M 2
|
|
#define RTK_PRIV_BW_80M_MINUS 3
|
|
#define RTK_PRIV_BW_80M_PLUS 4
|
|
|
|
static inline int is_hw_vht_support(struct rtl8192cd_priv *priv)
|
|
{
|
|
int support=0;
|
|
|
|
if (GET_CHIP_VER(priv) == VERSION_8812E)
|
|
support=1;
|
|
else if (GET_CHIP_VER(priv) == VERSION_8881A)
|
|
support=1;
|
|
|
|
return support;
|
|
}
|
|
//priv low bandwidth
|
|
static inline int is_hw_lbw_support(struct rtl8192cd_priv *priv)
|
|
{
|
|
int support=0;
|
|
|
|
if (GET_CHIP_VER(priv) == VERSION_8812E)
|
|
support=1;
|
|
#if defined(CONFIG_WLAN_HAL_8192EE)
|
|
if ((GET_CHIP_VER(priv) == VERSION_8192E) && (_GET_HAL_DATA(priv)->cutVersion == ODM_CUT_C))
|
|
support=1;
|
|
#endif
|
|
if(!support)
|
|
printk("This IC NOT support 5M10M !! \n");
|
|
|
|
return support;
|
|
}
|
|
|
|
static inline int convert_privBW(char *str_bw) //mark_priv
|
|
{
|
|
int priv_bw=0;
|
|
|
|
if(!strcmp(str_bw,"5M"))
|
|
priv_bw = RTK_PRIV_BW_5M;
|
|
else if(!strcmp(str_bw,"10M"))
|
|
priv_bw = RTK_PRIV_BW_10M;
|
|
//future 160M
|
|
|
|
return priv_bw;
|
|
}
|
|
|
|
int check_5M10M_config(struct rtl8192cd_priv *priv)
|
|
{
|
|
|
|
int priv_bw=0;
|
|
int ret = 0;
|
|
|
|
priv_bw = convert_privBW(priv->pshare->rf_ft_var.rtk_uci_PrivBandwidth);
|
|
//printk("rtk_set_channel_mode , priv_band= %s , val=%d \n", priv->pshare->rf_ft_var.rtk_uci_PrivBandwidth, priv_bw);
|
|
|
|
//first check if priv_band is set
|
|
if(priv_bw)
|
|
{
|
|
//check 5/10M
|
|
if( (priv_bw == RTK_PRIV_BW_10M) && is_hw_lbw_support(priv))
|
|
{
|
|
priv->pmib->dot11nConfigEntry.dot11nUse40M = HT_CHANNEL_WIDTH_10;
|
|
priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_DONTCARE;
|
|
ret = 1;
|
|
NDEBUG("Force config bandwidth=10M\n");
|
|
}
|
|
else if( (priv_bw == RTK_PRIV_BW_5M) && is_hw_lbw_support(priv))
|
|
{
|
|
priv->pmib->dot11nConfigEntry.dot11nUse40M = HT_CHANNEL_WIDTH_5;
|
|
priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_DONTCARE;
|
|
ret = 1;
|
|
NDEBUG("Force config bandwidth=5M\n");
|
|
}
|
|
else
|
|
NDEBUG("No such priv channel type !!!\n");
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int is_support_ac(struct rtl8192cd_priv *priv)
|
|
{
|
|
int ret=0;
|
|
|
|
switch(GET_CHIP_VER(priv)) {
|
|
case VERSION_8812E:
|
|
case VERSION_8881A:
|
|
ret=1;
|
|
break;
|
|
#if defined(CONFIG_WLAN_HAL_8814AE)
|
|
case VERSION_8814A:
|
|
if(priv->pshare->is5g)
|
|
ret=1;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
static void rtk_set_band_mode(struct rtl8192cd_priv *priv, enum ieee80211_band band ,enum nl80211_chan_width channel_width)
|
|
#else
|
|
static void rtk_set_band_mode(struct rtl8192cd_priv *priv, int band, int channel_width)
|
|
#endif
|
|
{
|
|
NDEBUG2("\n");
|
|
|
|
if(band == IEEE80211_BAND_2GHZ)
|
|
{
|
|
priv->pmib->dot11BssType.net_work_type = WIRELESS_11B|WIRELESS_11G;
|
|
priv->pmib->dot11RFEntry.phyBandSelect = PHY_BAND_2G;
|
|
}
|
|
else if(band == IEEE80211_BAND_5GHZ)
|
|
{
|
|
priv->pmib->dot11BssType.net_work_type = WIRELESS_11A;
|
|
priv->pmib->dot11RFEntry.phyBandSelect = PHY_BAND_5G;
|
|
}
|
|
|
|
if(channel_width != NL80211_CHAN_WIDTH_20_NOHT) {
|
|
priv->pmib->dot11BssType.net_work_type |= WIRELESS_11N;
|
|
} else {
|
|
if((OPMODE & WIFI_AP_STATE)
|
|
#ifdef UNIVERSAL_REPEATER
|
|
&& !under_apmode_repeater(priv)
|
|
#endif
|
|
)
|
|
priv->rtk->keep_legacy = 1;
|
|
}
|
|
|
|
if(channel_width == NL80211_CHAN_WIDTH_80 || is_support_ac(priv)) {
|
|
priv->pmib->dot11BssType.net_work_type |= WIRELESS_11AC;
|
|
}
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if(IS_ROOT_INTERFACE(priv) && priv->pvxd_priv)
|
|
{
|
|
priv->pvxd_priv->pmib->dot11BssType.net_work_type = priv->pmib->dot11BssType.net_work_type;
|
|
priv->pvxd_priv->pmib->dot11RFEntry.phyBandSelect = priv->pmib->dot11RFEntry.phyBandSelect;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
static void rtk_set_channel_mode(struct rtl8192cd_priv *priv, struct cfg80211_chan_def *chandef)
|
|
#else
|
|
static void rtk_set_channel_mode(struct rtl8192cd_priv *priv, int channel, enum nl80211_channel_type channel_type)
|
|
#endif
|
|
{
|
|
int config_BW5m10m=0;
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
int upper_ch = chandef->center_freq1 > chandef->chan->center_freq;
|
|
enum nl80211_chan_width width = chandef->width;
|
|
#else
|
|
int upper_ch = (channel_type == NL80211_CHAN_HT40PLUS);
|
|
enum nl80211_chan_width width = convert_chan_type2width(channel_type);
|
|
#endif
|
|
|
|
config_BW5m10m = check_5M10M_config(priv);
|
|
|
|
//printk("[%s]rtk_set_channel_mode , priv_band= %s , val=%d \n", priv->dev->name, priv->pshare->rf_ft_var.rtk_uci_PrivBandwidth, priv_bw);
|
|
|
|
//first check if priv_band is set
|
|
if(!config_BW5m10m)
|
|
{
|
|
//normal channel setup path from cfg80211
|
|
if(width == NL80211_CHAN_WIDTH_40) {
|
|
priv->pmib->dot11nConfigEntry.dot11nUse40M = HT_CHANNEL_WIDTH_20_40;
|
|
if ( upper_ch ) {
|
|
priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_ABOVE; //above
|
|
} else {
|
|
priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_BELOW; //below
|
|
}
|
|
} else if(width == NL80211_CHAN_WIDTH_80) {
|
|
//printk("NL80211_CHAN_WIDTH_80\n");
|
|
priv->pmib->dot11nConfigEntry.dot11nUse40M = HT_CHANNEL_WIDTH_80;
|
|
priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_DONTCARE; //dontcare
|
|
} else {
|
|
#if 0
|
|
if(chandef->width == NL80211_CHAN_WIDTH_20 || chandef->width == NL80211_CHAN_WIDTH_20_NOHT)
|
|
printk("NL80211_CHAN_WIDTH_20\/NL80211_CHAN_WIDTH_20_NOHT\n");
|
|
else
|
|
printk("Unknown bandwidth: %d, use 20Mhz be default\n", chandef->width);
|
|
#endif
|
|
priv->pmib->dot11nConfigEntry.dot11nUse40M = HT_CHANNEL_WIDTH_20;
|
|
priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_DONTCARE;
|
|
}
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if(IS_ROOT_INTERFACE(priv) && priv->pvxd_priv)
|
|
{
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11nUse40M = priv->pmib->dot11nConfigEntry.dot11nUse40M;
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11n2ndChOffset = priv->pmib->dot11nConfigEntry.dot11n2ndChOffset;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
void realtek_ap_config_apply(struct rtl8192cd_priv *priv)
|
|
{
|
|
#if 0 //def P2P_SUPPORT
|
|
int keep_go_state=0;
|
|
|
|
if(priv->pmib->p2p_mib.p2p_enabled==CFG80211_P2P){
|
|
keep_go_state=1;
|
|
}
|
|
#endif
|
|
|
|
NLENTER;
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if(under_apmode_repeater(priv) && (GET_VXD_PRIV(priv)->pmib->dot11OperationEntry.opmode & WIFI_ASOC_STATE)) {
|
|
NLINFO("Repeater! STA is alive, skip down-up\n");
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
NLINFO("[%s][down up]\n",priv->dev->name);
|
|
|
|
rtl8192cd_close(priv->dev);
|
|
#ifndef NOT_RTK_BSP
|
|
priv->dev->flags &= ~IFF_UP;
|
|
#endif
|
|
#if 0 //def P2P_SUPPORT
|
|
if(keep_go_state){
|
|
NDEBUG3("[P2P GO mode]\n");
|
|
priv->pmib->p2p_mib.p2p_enabled=CFG80211_P2P;
|
|
}
|
|
#endif
|
|
rtl8192cd_open(priv->dev);
|
|
}
|
|
|
|
}
|
|
|
|
int realtek_cfg80211_ready(struct rtl8192cd_priv *priv)
|
|
{
|
|
|
|
if (netif_running(priv->dev))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void realtek_reset_security(struct rtl8192cd_priv *priv)
|
|
{
|
|
NLENTER;
|
|
priv->pmib->dot1180211AuthEntry.dot11AuthAlgrthm = 0;
|
|
priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm = 0;
|
|
priv->pmib->dot1180211AuthEntry.dot11EnablePSK = 0;
|
|
priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm = 0;
|
|
priv->pmib->dot1180211AuthEntry.dot11WPACipher = 0;
|
|
priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher = 0;
|
|
priv->pmib->dot11GroupKeysTable.dot11Privacy = 0;
|
|
priv->pmib->dot11RsnIE.rsnielen = 0; // reset RSN IE length
|
|
#ifdef CONFIG_IEEE80211W
|
|
priv->pmib->dot1180211AuthEntry.dot11IEEE80211W = 0;
|
|
priv->pmib->dot1180211AuthEntry.dot11EnableSHA256 = 0;
|
|
#endif
|
|
}
|
|
|
|
void realtek_auth_wep(struct rtl8192cd_priv *priv, int cipher)
|
|
{
|
|
//_eric_nl ?? wep auto/shared/open ??
|
|
NLENTER;
|
|
priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm = cipher;
|
|
priv->pmib->dot1180211AuthEntry.dot11EnablePSK = 0;
|
|
priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm = 0;
|
|
priv->pmib->dot1180211AuthEntry.dot11WPACipher = 0;
|
|
priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher = 0;
|
|
NLEXIT;
|
|
}
|
|
|
|
void realtek_auth_wpa(struct rtl8192cd_priv *priv, int wpa, int psk, int cipher)
|
|
{
|
|
int wpa_cipher = 0;
|
|
|
|
if(cipher & BIT(_TKIP_PRIVACY_))
|
|
wpa_cipher |= BIT(1);
|
|
if(cipher & BIT(_CCMP_PRIVACY_))
|
|
wpa_cipher |= BIT(3);
|
|
|
|
NLENTER;
|
|
NDEBUG3("%s wpa[%d] psk[%d] cipher[0x%x] wpa_cipher[0x%x]\n",priv->dev->name ,wpa ,psk ,cipher ,wpa_cipher);
|
|
priv->pmib->dot1180211AuthEntry.dot11AuthAlgrthm = 2;
|
|
priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm = 2;
|
|
|
|
if(psk)
|
|
priv->pmib->dot1180211AuthEntry.dot11EnablePSK = wpa;
|
|
|
|
priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm = 1;
|
|
|
|
if(wpa & PSK_WPA)
|
|
priv->pmib->dot1180211AuthEntry.dot11WPACipher = wpa_cipher;
|
|
if(wpa & PSK_WPA2)
|
|
priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher = wpa_cipher;
|
|
NLEXIT;
|
|
}
|
|
|
|
void realtek_get_security(struct rtknl *rtk, struct cfg80211_crypto_settings crypto)
|
|
{
|
|
int i = 0;
|
|
|
|
rtk->cipher = rtk->wpa = rtk->psk = rtk->sha256 = 0;
|
|
|
|
NDEBUG2("n_akm_suites=[%d], n_ciphers_pairwise=[%d]\n", crypto.n_akm_suites, crypto.n_ciphers_pairwise);
|
|
|
|
for (i = 0; i < crypto.n_akm_suites; i++) {
|
|
switch (crypto.akm_suites[i]) {
|
|
case WLAN_AKM_SUITE_8021X:
|
|
if (crypto.wpa_versions & NL80211_WPA_VERSION_1)
|
|
rtk->wpa |= PSK_WPA;
|
|
if (crypto.wpa_versions & NL80211_WPA_VERSION_2)
|
|
rtk->wpa |= PSK_WPA2;
|
|
break;
|
|
case WLAN_AKM_SUITE_PSK:
|
|
rtk->psk = 1;
|
|
if (crypto.wpa_versions & NL80211_WPA_VERSION_1)
|
|
rtk->wpa |= PSK_WPA;
|
|
if (crypto.wpa_versions & NL80211_WPA_VERSION_2)
|
|
rtk->wpa |= PSK_WPA2;
|
|
break;
|
|
case WLAN_AKM_SUITE_PSK_SHA256:
|
|
rtk->psk = 1;
|
|
rtk->sha256 = 1;
|
|
if (crypto.wpa_versions & NL80211_WPA_VERSION_1)
|
|
rtk->wpa |= PSK_WPA;
|
|
if (crypto.wpa_versions & NL80211_WPA_VERSION_2)
|
|
rtk->wpa |= PSK_WPA2;
|
|
break;
|
|
default:
|
|
NDEBUG2("[akm_suites]=0x%08x not support\n", crypto.akm_suites[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//_eric_nl ?? multiple ciphers ??
|
|
for (i = 0; i < crypto.n_ciphers_pairwise; i++) {
|
|
switch (crypto.ciphers_pairwise[i]) {
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
rtk->cipher = BIT(_WEP_40_PRIVACY_);
|
|
NDEBUG3("WEP40[%d]\n", i);
|
|
break;
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
rtk->cipher = BIT(_WEP_104_PRIVACY_);
|
|
NDEBUG3("WEP104[%d]\n", i);
|
|
break;
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
rtk->cipher |= BIT(_TKIP_PRIVACY_);
|
|
NDEBUG3("TKIP[%d]\n", i);
|
|
break;
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
rtk->cipher |= BIT(_CCMP_PRIVACY_);
|
|
NDEBUG3("CCMP[%d]\n", i);
|
|
break;
|
|
default:
|
|
NDEBUG3("[ciphers_pairwise]=0x%08x not support\n", crypto.ciphers_pairwise[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (crypto.cipher_group) {
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
rtk->cipher = BIT(_WEP_40_PRIVACY_);
|
|
NDEBUG3("WEP GROUP\n");
|
|
break;
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
rtk->cipher = BIT(_WEP_104_PRIVACY_);
|
|
NDEBUG3("WEP GROUP\n");
|
|
break;
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
NDEBUG3("TKIP GROUP\n");
|
|
break;
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
NDEBUG3("CCMP GROUP\n");
|
|
break;
|
|
case WLAN_CIPHER_SUITE_SMS4:
|
|
NDEBUG3("WAPI GROUP\n");
|
|
break;
|
|
default:
|
|
NDEBUG3("NONE GROUP\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void realtek_set_security(struct rtl8192cd_priv *priv, struct rtknl *rtk)
|
|
{
|
|
if (rtk->wpa)
|
|
realtek_auth_wpa(priv, rtk->wpa, rtk->psk, rtk->cipher);
|
|
else {
|
|
if (rtk->cipher & BIT(_WEP_40_PRIVACY_))
|
|
realtek_auth_wep(priv, _WEP_40_PRIVACY_);
|
|
else if (rtk->cipher & BIT(_WEP_104_PRIVACY_))
|
|
realtek_auth_wep(priv, _WEP_104_PRIVACY_);
|
|
}
|
|
}
|
|
|
|
void realtek_set_security_ap(struct rtl8192cd_priv *priv, struct rtknl *rtk, struct cfg80211_crypto_settings crypto)
|
|
{
|
|
realtek_get_security(rtk, crypto);
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
/*
|
|
* hostapd don't set 11w in akm_suites, workaround here
|
|
* check dot11IEEE80211W @realtek_set_band
|
|
*/
|
|
if (priv->pmib->dot1180211AuthEntry.dot11IEEE80211W != NO_MGMT_FRAME_PROTECTION) {
|
|
rtk->psk = 1;
|
|
rtk->wpa = PSK_WPA2;
|
|
}
|
|
#endif /* CONFIG_IEEE80211W */
|
|
|
|
realtek_set_security(priv, rtk);
|
|
}
|
|
|
|
void realtek_set_security_cli(struct rtl8192cd_priv *priv, struct rtknl *rtk, struct cfg80211_connect_params *sme)
|
|
{
|
|
realtek_get_security(rtk, sme->crypto);
|
|
|
|
#ifdef CONFIG_IEEE80211W_CLI
|
|
if (sme->mfp == NL80211_MFP_REQUIRED)
|
|
{
|
|
if (rtk->sha256 == true)
|
|
priv->pmib->dot1180211AuthEntry.dot11EnableSHA256 = 1;
|
|
else
|
|
priv->pmib->dot1180211AuthEntry.dot11EnableSHA256 = 0;
|
|
|
|
priv->pmib->dot1180211AuthEntry.dot11IEEE80211W = MGMT_FRAME_PROTECTION_OPTIONAL;
|
|
}
|
|
#endif /* CONFIG_IEEE80211W_CLI */
|
|
|
|
realtek_set_security(priv, rtk);
|
|
}
|
|
|
|
void realtek_get_key_from_sta(struct rtl8192cd_priv *priv, struct stat_info *pstat, struct key_params *params, u8 key_index)
|
|
{
|
|
unsigned int cipher = 0;
|
|
struct Dot11EncryptKey *pEncryptKey;
|
|
|
|
//_eric_cfg ?? key len data seq for get_key ??
|
|
if(pstat == NULL)
|
|
{
|
|
if (key_index == priv->default_mgmt_key_idx)
|
|
{
|
|
NDEBUG("get default mgnt key\n");
|
|
cipher = priv->pmib->dot11IGTKTable.dot11Privacy;
|
|
pEncryptKey = &priv->pmib->dot11IGTKTable.dot11EncryptKey;
|
|
}
|
|
else
|
|
{
|
|
cipher = priv->pmib->dot11GroupKeysTable.dot11Privacy;
|
|
pEncryptKey = &priv->pmib->dot11GroupKeysTable.dot11EncryptKey;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cipher = pstat->dot11KeyMapping.dot11Privacy;
|
|
pEncryptKey = &pstat->dot11KeyMapping.dot11EncryptKey;
|
|
}
|
|
|
|
switch (cipher) {
|
|
case DOT11_ENC_WEP40:
|
|
params->cipher = WLAN_CIPHER_SUITE_WEP40;
|
|
params->key_len = 5;
|
|
memcpy(params->key, pEncryptKey->dot11TTKey.skey, pEncryptKey->dot11TTKeyLen);
|
|
break;
|
|
case DOT11_ENC_WEP104:
|
|
params->cipher = WLAN_CIPHER_SUITE_WEP104;
|
|
params->key_len = 10;
|
|
memcpy(params->key, pEncryptKey->dot11TTKey.skey, pEncryptKey->dot11TTKeyLen);
|
|
break;
|
|
case DOT11_ENC_CCMP:
|
|
params->cipher = WLAN_CIPHER_SUITE_CCMP;/*eric refine*/
|
|
params->key_len = 32;
|
|
memcpy(params->key, pEncryptKey->dot11TTKey.skey, pEncryptKey->dot11TTKeyLen);
|
|
memcpy(params->key+16, pEncryptKey->dot11TMicKey1.skey, pEncryptKey->dot11TMicKeyLen);
|
|
break;
|
|
case DOT11_ENC_TKIP:
|
|
params->cipher = WLAN_CIPHER_SUITE_TKIP;/*eric refine*/
|
|
params->key_len = 32;
|
|
memcpy(params->key, pEncryptKey->dot11TTKey.skey, pEncryptKey->dot11TTKeyLen);
|
|
memcpy(params->key+16, pEncryptKey->dot11TMicKey1.skey, pEncryptKey->dot11TMicKeyLen);
|
|
memcpy(params->key+24, pEncryptKey->dot11TMicKey2.skey, pEncryptKey->dot11TMicKeyLen);
|
|
break;
|
|
case DOT11_ENC_BIP:
|
|
params->cipher = WLAN_CIPHER_SUITE_AES_CMAC;
|
|
params->key_len = 32;
|
|
memcpy(params->key, pEncryptKey->dot11TTKey.skey, pEncryptKey->dot11TTKeyLen);
|
|
memcpy(params->key+16, pEncryptKey->dot11TMicKey1.skey, pEncryptKey->dot11TMicKeyLen);
|
|
break;
|
|
default:
|
|
NDEBUG("cipher(%d) not support!!\n", cipher);
|
|
}
|
|
}
|
|
|
|
void clear_wps_ies(struct rtl8192cd_priv *priv)
|
|
{
|
|
priv->pmib->wscEntry.wsc_enable = 0;
|
|
|
|
priv->pmib->wscEntry.beacon_ielen = 0;
|
|
priv->pmib->wscEntry.probe_rsp_ielen = 0;
|
|
priv->pmib->wscEntry.probe_req_ielen = 0;
|
|
priv->pmib->wscEntry.assoc_ielen = 0;
|
|
}
|
|
|
|
|
|
/*void copy_wps_ie(struct rtl8192cd_priv *priv, unsigned char *wps_ie, unsigned char mgmt_type) move to 8192cd_util.c*/
|
|
/*the function can be replaced by rtk_cfg80211_set_wps_p2p_ie*/
|
|
//void rtk_set_ie(struct rtl8192cd_priv *priv, unsigned char *pies, unsigned int ies_len, unsigned char mgmt_type)
|
|
|
|
|
|
//static int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtl8192cd_priv *priv, char *buf, int len)
|
|
int rtk_cfg80211_set_wps_p2p_ie(struct rtl8192cd_priv *priv, const char *buf, int len, int mgmt_type)
|
|
{
|
|
int ret = 0;
|
|
int wps_ielen = 0;
|
|
u8 *wps_ie;
|
|
u32 p2p_ielen = 0;
|
|
u8 *p2p_ie;
|
|
//u32 wfd_ielen = 0;
|
|
//u8 *wfd_ie;
|
|
u8* p2p_ie_listen_tag_ptr=NULL;
|
|
int p2p_ie_listen_tag;
|
|
|
|
if(len<=0)
|
|
return -1;
|
|
|
|
NDEBUG2("mgmt_type=[%d]\n",mgmt_type);
|
|
|
|
/*set WPS IE*/
|
|
if((wps_ie = rtk_get_wps_ie(buf, len, NULL, &wps_ielen)))
|
|
{
|
|
copy_wps_ie(priv,wps_ie,mgmt_type);
|
|
}
|
|
|
|
#if defined(P2P_SUPPORT)
|
|
/*set P2P IE*/
|
|
if((p2p_ie = rtk_get_p2p_ie(buf, len, NULL, &p2p_ielen)))
|
|
{
|
|
copy_p2p_ie(priv,p2p_ie,mgmt_type);
|
|
|
|
if(mgmt_type == MGMT_PROBEREQ){
|
|
/*check if listen channel from cfg80211 equl my keep*/
|
|
p2p_ie_listen_tag_ptr = p2p_search_tag(p2p_ie, p2p_ielen ,TAG_LISTEN_CHANNEL, &p2p_ie_listen_tag);
|
|
if(p2p_ie_listen_tag_ptr && p2p_ie_listen_tag==5){
|
|
if( priv->pmib->p2p_mib.p2p_listen_channel != p2p_ie_listen_tag_ptr[4]){
|
|
NDEBUG("listen ch no equl\n");
|
|
priv->pmib->p2p_mib.p2p_listen_channel = p2p_ie_listen_tag_ptr[4];
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
/*set WFD IE to do */
|
|
|
|
return 0;
|
|
}
|
|
|
|
void dump_ies(struct rtl8192cd_priv *priv,
|
|
unsigned char *pies, unsigned int ies_len, unsigned char mgmt_type)
|
|
{
|
|
unsigned char *pie = pies;
|
|
unsigned int len, total_len = 0;
|
|
int i = 0;
|
|
|
|
while(1)
|
|
{
|
|
len = pie[1];
|
|
|
|
total_len += (len+2);
|
|
if(total_len > ies_len)
|
|
{
|
|
printk("Exceed !!\n");
|
|
break;
|
|
}
|
|
|
|
if(pie[0] == _WPS_IE_)
|
|
copy_wps_ie(priv, pie, mgmt_type);
|
|
|
|
//printk("[Tag=0x%02x Len=%d(0x%x)]\n", pie[0], len, len);
|
|
pie+=2;
|
|
|
|
#if 0
|
|
for(i=0; i<len; i++)
|
|
{
|
|
if((i%10) == 9)
|
|
printk("\n");
|
|
|
|
printk("%02x ", pie[i]);
|
|
}
|
|
|
|
printk("\n");
|
|
#endif
|
|
|
|
pie+=len;
|
|
|
|
if(total_len == ies_len)
|
|
{
|
|
//printk("Done \n");
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void realtek_set_ies_apmode(struct rtl8192cd_priv *priv, struct cfg80211_beacon_data *info)
|
|
{
|
|
NLENTER;
|
|
clear_wps_ies(priv);
|
|
|
|
if(info->beacon_ies)
|
|
{
|
|
NDEBUG2("beacon_ies_len[%d]\n", info->beacon_ies_len);
|
|
rtk_cfg80211_set_wps_p2p_ie(priv, info->beacon_ies, info->beacon_ies_len, MGMT_BEACON);
|
|
}
|
|
|
|
if(info->proberesp_ies)
|
|
{
|
|
NDEBUG2("proberesp_ies_len[%d]\n", info->proberesp_ies_len);
|
|
rtk_cfg80211_set_wps_p2p_ie(priv, info->proberesp_ies, info->proberesp_ies_len, MGMT_PROBERSP);
|
|
}
|
|
|
|
if(info->assocresp_ies)
|
|
{
|
|
NDEBUG2("assocresp_ies_len[%d]\n", info->assocresp_ies_len);
|
|
rtk_cfg80211_set_wps_p2p_ie(priv, info->assocresp_ies, info->assocresp_ies_len, MGMT_ASSOCRSP);
|
|
}
|
|
}
|
|
|
|
static int realtek_set_bss(struct rtl8192cd_priv *priv, struct cfg80211_ap_settings *info)
|
|
{
|
|
NDEBUG3("SSID[%s]\n", info->ssid);
|
|
memcpy(SSID, info->ssid, info->ssid_len);
|
|
SSID_LEN = info->ssid_len;
|
|
|
|
switch(info->hidden_ssid)
|
|
{
|
|
case NL80211_HIDDEN_SSID_NOT_IN_USE:
|
|
HIDDEN_AP=0;
|
|
break;
|
|
case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
|
|
HIDDEN_AP=1;
|
|
break;
|
|
case NL80211_HIDDEN_SSID_ZERO_LEN:
|
|
HIDDEN_AP=2;
|
|
break;
|
|
default:
|
|
NDEBUG("fail, unknown hidden SSID option[%d]\n", info->hidden_ssid);
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
priv->pmib->dot11StationConfigEntry.dot11BeaconPeriod = info->beacon_interval;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_set_auth_type(struct rtl8192cd_priv *priv, enum nl80211_auth_type auth_type)
|
|
{
|
|
//NDEBUG3("auth_type[0x%02X]\n", auth_type);
|
|
|
|
switch (auth_type) {
|
|
case NL80211_AUTHTYPE_OPEN_SYSTEM:
|
|
NDEBUG3("NL80211_AUTHTYPE_OPEN_SYSTEM\n");
|
|
break;
|
|
case NL80211_AUTHTYPE_SHARED_KEY:
|
|
NDEBUG3("NL80211_AUTHTYPE_SHARED_KEY\n");
|
|
priv->pmib->dot1180211AuthEntry.dot11AuthAlgrthm = 1;
|
|
break;
|
|
case NL80211_AUTHTYPE_NETWORK_EAP:
|
|
NDEBUG3("NL80211_AUTHTYPE_NETWORK_EAP\n");
|
|
break;
|
|
case NL80211_AUTHTYPE_AUTOMATIC:
|
|
NDEBUG3("NL80211_AUTHTYPE_AUTOMATIC\n");
|
|
priv->pmib->dot1180211AuthEntry.dot11AuthAlgrthm = 2;
|
|
break;
|
|
|
|
default:
|
|
NDEBUG("no support auth type[0x%02x]\n",auth_type);
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void config_ssid_from_beacon(struct rtl8192cd_priv *priv, struct cfg80211_beacon_data *beacon)
|
|
{
|
|
u8 *p, *skip_hdr, *ssid;
|
|
s32 len, remain_len;
|
|
|
|
skip_hdr = beacon->head + (WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_);
|
|
remain_len = beacon->head_len - (WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_);
|
|
|
|
p = get_ie(skip_hdr, _SSID_IE_, &len, remain_len);
|
|
|
|
if (p)
|
|
{
|
|
ssid = p + 2;
|
|
|
|
/* ssid changed */
|
|
if ((len != SSID_LEN) || memcmp(ssid, SSID, len))
|
|
{
|
|
memset(SSID, 0, sizeof(SSID));
|
|
memcpy(SSID, ssid, len);
|
|
SSID_LEN = len;
|
|
init_beacon(priv);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void config_security_from_beacon(struct rtl8192cd_priv *priv,
|
|
struct cfg80211_beacon_data *beacon)
|
|
{
|
|
u8 *p;
|
|
s32 len;
|
|
u16 cap_info;
|
|
bool privacy_enable = false;
|
|
|
|
u8 dot11EnablePSK = 0, dot11WPACipher = 0, dot11WPA2Cipher = 0, dot11PrivacyAlgrthm = 0, dot118021xAlgrthm = 0;
|
|
#ifdef CONFIG_IEEE80211W
|
|
u8 dot11IEEE80211W = 0;
|
|
bool dot11EnableSHA256 = false;
|
|
#endif
|
|
|
|
u16 count, i;
|
|
|
|
DOT11_RSN_IE_HEADER *pDot11RSNIEHeader;
|
|
DOT11_RSN_IE_SUITE *pDot11RSNIESuite;
|
|
DOT11_RSN_IE_COUNT_SUITE *pDot11RSNIECountSuite;
|
|
DOT11_RSN_CAPABILITY *pDot11RSNCapability;
|
|
|
|
if (beacon->head)
|
|
{
|
|
/* get capability info */
|
|
p = beacon->head + _BEACON_CAP_OFFSET_;
|
|
cap_info = le16_to_cpu(*((u16 *)p));
|
|
privacy_enable = (cap_info & BIT4) ? true : false;
|
|
}
|
|
|
|
if (privacy_enable && beacon->tail_len)
|
|
{
|
|
/* parse wpa2 */
|
|
p = get_ie(beacon->tail, _RSN_IE_2_, &len, beacon->tail_len);
|
|
if (p)
|
|
{
|
|
/* header */
|
|
p += sizeof(DOT11_WPA2_IE_HEADER);
|
|
|
|
/* group chipher */
|
|
pDot11RSNIESuite = (DOT11_RSN_IE_SUITE *)p;
|
|
p += sizeof(DOT11_RSN_IE_SUITE);
|
|
|
|
/* pairwise chiper */
|
|
pDot11RSNIECountSuite = (DOT11_RSN_IE_COUNT_SUITE *)p;
|
|
count = le16_to_cpu(pDot11RSNIECountSuite->SuiteCount);
|
|
|
|
for (i = 0 ; i < count ; ++i)
|
|
{
|
|
if (pDot11RSNIECountSuite->dot11RSNIESuite[i].Type == DOT11_ENC_TKIP)
|
|
dot11WPA2Cipher |= BIT1;
|
|
else if (pDot11RSNIECountSuite->dot11RSNIESuite[i].Type == DOT11_ENC_CCMP)
|
|
dot11WPA2Cipher |= BIT3;
|
|
}
|
|
|
|
p += (2 + count * sizeof(DOT11_RSN_IE_SUITE));
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
/* check akm */
|
|
pDot11RSNIECountSuite = (DOT11_RSN_IE_COUNT_SUITE *)p;
|
|
count = le16_to_cpu(pDot11RSNIECountSuite->SuiteCount);
|
|
for (i = 0 ; i < count ; ++i)
|
|
if (pDot11RSNIECountSuite->dot11RSNIESuite[i].Type == DOT11_ENC_BIP)
|
|
dot11EnableSHA256 = true;
|
|
p += (2 + count * sizeof(DOT11_RSN_IE_SUITE));
|
|
|
|
/* rsn cap */
|
|
pDot11RSNCapability = (DOT11_RSN_CAPABILITY *)p;
|
|
if (pDot11RSNCapability->field.MFPC && pDot11RSNCapability->field.MFPR)
|
|
dot11IEEE80211W = MGMT_FRAME_PROTECTION_REQUIRED;
|
|
else if (pDot11RSNCapability->field.MFPC)
|
|
dot11IEEE80211W = MGMT_FRAME_PROTECTION_OPTIONAL;
|
|
else
|
|
dot11IEEE80211W = NO_MGMT_FRAME_PROTECTION;
|
|
#endif
|
|
}
|
|
|
|
/* parse wpa */
|
|
u8 wpa_oui[] = {0x00, 0x50, 0xf2, 0x01};
|
|
size_t offset = 0;
|
|
|
|
do
|
|
{
|
|
p = get_ie(beacon->tail + offset, _RSN_IE_1_, &len, beacon->tail_len - offset);
|
|
if (!p) break;
|
|
|
|
offset = (p - beacon->tail) + 2 + len;
|
|
pDot11RSNIEHeader = (DOT11_RSN_IE_HEADER *)p;
|
|
|
|
if (memcmp(pDot11RSNIEHeader->OUI, wpa_oui, sizeof(wpa_oui)))
|
|
continue;
|
|
|
|
p += sizeof(DOT11_RSN_IE_HEADER);
|
|
|
|
/* group cipher */
|
|
p += sizeof(DOT11_RSN_IE_SUITE);
|
|
|
|
/* unicast cipher */
|
|
pDot11RSNIECountSuite = (DOT11_RSN_IE_COUNT_SUITE *)p;
|
|
count = le16_to_cpu(pDot11RSNIECountSuite->SuiteCount);
|
|
for (i = 0 ; i != count ; ++i)
|
|
{
|
|
if (pDot11RSNIECountSuite->dot11RSNIESuite[i].Type == DOT11_ENC_TKIP)
|
|
dot11WPACipher |= BIT1;
|
|
else if (pDot11RSNIECountSuite->dot11RSNIESuite[i].Type == DOT11_ENC_CCMP)
|
|
dot11WPACipher |= BIT3;
|
|
}
|
|
} while (p);
|
|
|
|
if (dot11WPACipher) dot11EnablePSK |= PSK_WPA;
|
|
if (dot11WPA2Cipher) dot11EnablePSK |= PSK_WPA2;
|
|
|
|
if (dot11EnablePSK)
|
|
{
|
|
if ((dot11WPACipher & BIT3) || (dot11WPA2Cipher & BIT3))
|
|
dot11PrivacyAlgrthm = _CCMP_PRIVACY_;
|
|
else
|
|
dot11PrivacyAlgrthm = _TKIP_PRIVACY_;
|
|
|
|
dot118021xAlgrthm = 1;
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
if (!(dot11EnablePSK == PSK_WPA2) || !(dot11WPA2Cipher & BIT3))
|
|
{
|
|
dot11IEEE80211W = 0;
|
|
dot11EnableSHA256 = 0;
|
|
}
|
|
#endif
|
|
}
|
|
else if (privacy_enable) /* wep encryption */
|
|
{
|
|
NDEBUG("wep encryption, need to check dot11PrivacyAlgrthm\n");
|
|
}
|
|
|
|
NDEBUG("dot11PrivacyAlgrthm=%d, dot11EnablePSK=%d, dot11WPACipher=%d, dot11WPA2Cipher=%d, dot118021xAlgrthm=%d\n",
|
|
dot11PrivacyAlgrthm, dot11EnablePSK, dot11WPACipher, dot11WPA2Cipher, dot118021xAlgrthm);
|
|
#ifdef CONFIG_IEEE80211W
|
|
NDEBUG("dot11IEEE80211W=%d, dot11EnableSHA256=%d\n", dot11IEEE80211W, dot11EnableSHA256);
|
|
#endif
|
|
|
|
/* apply setting */
|
|
priv->pmib->dot1180211AuthEntry.dot11AuthAlgrthm = 2;
|
|
priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm = dot11PrivacyAlgrthm;
|
|
priv->pmib->dot1180211AuthEntry.dot11EnablePSK = dot11EnablePSK;
|
|
priv->pmib->dot1180211AuthEntry.dot11WPACipher = dot11WPACipher;
|
|
priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher = dot11WPA2Cipher;
|
|
priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm = dot118021xAlgrthm;
|
|
#ifdef CONFIG_IEEE80211W
|
|
priv->pmib->dot1180211AuthEntry.dot11IEEE80211W = dot11IEEE80211W;
|
|
priv->pmib->dot1180211AuthEntry.dot11EnableSHA256 = dot11EnableSHA256;
|
|
#endif
|
|
|
|
if (dot11EnablePSK)
|
|
nl80211_psk_init(priv);
|
|
}
|
|
}
|
|
|
|
static int realtek_change_beacon(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_beacon_data *beacon)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
|
|
if (!realtek_cfg80211_ready(priv))
|
|
return -EIO;
|
|
|
|
if ((OPMODE & WIFI_AP_STATE) == 0)
|
|
return -EOPNOTSUPP;
|
|
|
|
realtek_set_ies_apmode(priv, beacon);/*cfg p2p*/
|
|
|
|
config_ssid_from_beacon(priv, beacon);
|
|
realtek_reset_security(priv);
|
|
config_security_from_beacon(priv, beacon);
|
|
|
|
NLEXIT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
|
|
if(priv->pmib->p2p_mib.p2p_enabled){
|
|
OPMODE = WIFI_STATION_STATE;
|
|
priv->pmib->p2p_mib.p2p_enabled=0;
|
|
}
|
|
|
|
if ((OPMODE & WIFI_AP_STATE) == 0)
|
|
return -EOPNOTSUPP;
|
|
|
|
rtl8192cd_close(priv->dev);
|
|
#ifndef NOT_RTK_BSP
|
|
priv->dev->flags &= ~IFF_UP;
|
|
#endif
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int realtek_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
int ret = 0;
|
|
|
|
NLENTER;
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if(under_apmode_repeater(priv)) {
|
|
NLINFO("Repeater! Do nothing\n");
|
|
} else
|
|
#endif
|
|
{
|
|
ret = realtek_cfg80211_del_beacon(wiphy, dev);
|
|
}
|
|
|
|
NLEXIT;
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
static int realtek_cfg80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
|
|
struct beacon_parameters *info)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
|
|
realtek_ap_beacon(wiphy, dev, info, true);
|
|
realtek_ap_config_apply(priv);
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
//_eric_nl ?? what's the diff between st & add beacon??
|
|
static int realtek_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
|
|
struct beacon_parameters *info)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
|
|
realtek_ap_beacon(wiphy, dev, info, false);
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
|
|
}
|
|
|
|
//_eric_nl ?? what's the purpose of del_beacon ??
|
|
static int realtek_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
|
|
if (OPMODE & WIFI_AP_STATE == 0)
|
|
return -EOPNOTSUPP;
|
|
if (priv->assoc_num == 0)
|
|
return -ENOTCONN;
|
|
|
|
rtl8192cd_close(priv->dev);
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
static int realtek_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_chan_def *chandef)
|
|
#else
|
|
static int realtek_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
|
|
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
|
|
#endif
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
int channel = 0;
|
|
enum nl80211_band band;
|
|
enum nl80211_chan_width width;
|
|
|
|
NLENTER;
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
|
|
|
|
NDEBUG3("[%s]center_freq=[%u] channel=[%d] hw_value=[%u] bandwidth=[%d]\n", priv->dev->name,
|
|
chandef->chan->center_freq, channel, chandef->chan->hw_value, chandef->width);
|
|
#else
|
|
channel = ieee80211_frequency_to_channel(chan->center_freq);
|
|
NDEBUG3("[%s]center_freq=[%u] channel=[%d] hw_value=[%u] bandwidth=[%d] ch_type=[%d]\n", priv->dev->name,
|
|
chan->center_freq, channel, chan->hw_value, chan->flags,channel_type);
|
|
#endif
|
|
|
|
priv->pmib->dot11RFEntry.dot11channel = channel;
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
band = chandef->chan->band;
|
|
width = chandef->width;
|
|
rtk_set_band_mode(priv, band, width);
|
|
rtk_set_channel_mode(priv, chandef);
|
|
#else
|
|
band = chan->band;
|
|
width = convert_chan_type2width(channel_type);
|
|
rtk_set_band_mode(priv, band, width);
|
|
rtk_set_channel_mode(priv, channel, channel_type);
|
|
#endif
|
|
|
|
// realtek_ap_default_config(priv);
|
|
// realtek_ap_config_apply(priv);
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//Not in ath6k
|
|
static int realtek_cfg80211_change_bss(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
struct bss_parameters *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
unsigned char dot11_rate_table[]={2,4,11,22,12,18,24,36,48,72,96,108,0};
|
|
|
|
NLENTER;
|
|
|
|
#if 0
|
|
if (params->use_cts_prot >= 0) {
|
|
sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
|
|
changed |= BSS_CHANGED_ERP_CTS_PROT;
|
|
}
|
|
#endif
|
|
|
|
priv->pmib->dot11RFEntry.shortpreamble = params->use_short_preamble;
|
|
changePreamble(priv, params->use_short_preamble);
|
|
#if 0
|
|
if (params->use_short_slot_time >= 0) {
|
|
sdata->vif.bss_conf.use_short_slot =
|
|
params->use_short_slot_time;
|
|
changed |= BSS_CHANGED_ERP_SLOT;
|
|
}
|
|
#endif
|
|
|
|
if (params->basic_rates) {
|
|
int i, j;
|
|
u32 rates = 0;
|
|
|
|
//printk("rate = ");
|
|
for (i = 0; i < params->basic_rates_len; i++) {
|
|
int rate = params->basic_rates[i];
|
|
//printk("%d ", rate);
|
|
|
|
for (j = 0; j < 13; j++) {
|
|
if ((dot11_rate_table[j]) == rate)
|
|
{
|
|
//printk("BIT(%d) ", j);
|
|
rates |= BIT(j);
|
|
}
|
|
|
|
}
|
|
}
|
|
//printk("\n");
|
|
priv->pmib->dot11StationConfigEntry.dot11BasicRates = rates;
|
|
}
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static int realtek_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 key_idx, const u8 *mac_addr,
|
|
struct key_params *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = rtk->priv;
|
|
|
|
NLENTER;
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
static int realtek_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 key_idx, const u8 *mac_addr)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = rtk->priv;
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 key_idx, const u8 *mac_addr, void *cookie,
|
|
void (*callback)(void *cookie,
|
|
struct key_params *params))
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = rtk->priv;
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
void set_pairwise_key_for_ibss(struct rtl8192cd_priv *priv, union iwreq_data *wrqu)
|
|
{
|
|
int i = 0;
|
|
struct stat_info *pstat = NULL;
|
|
struct ieee80211req_key *wk = (struct ieee80211req_key *)wrqu->data.pointer;
|
|
|
|
printk("set_pairwise_key_for_ibss +++ \n");
|
|
|
|
for(i=0; i<NUM_STAT; i++)
|
|
{
|
|
if(priv->pshare->aidarray[i] && (priv->pshare->aidarray[i]->used == TRUE))
|
|
{
|
|
pstat = get_stainfo(priv, priv->pshare->aidarray[i]->station.hwaddr);
|
|
|
|
if(pstat)
|
|
{
|
|
memcpy(wk->ik_macaddr, priv->pshare->aidarray[i]->station.hwaddr, ETH_ALEN);
|
|
rtl_net80211_setkey(priv->dev, NULL, wrqu, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//#define TOTAL_CAM_ENTRY (priv->pshare->total_cam_entry)
|
|
|
|
static int realtek_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 key_index, bool pairwise,
|
|
const u8 *mac_addr,
|
|
struct key_params *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
union iwreq_data wrqu;
|
|
struct ieee80211req_key wk;
|
|
|
|
NLENTER;
|
|
|
|
if (!realtek_cfg80211_ready(priv))
|
|
return -EIO;
|
|
|
|
NDEBUG("cipher=0x%x key_len=%d seq_len=%d key_index=%d pairwise=%d for %pM\n",
|
|
params->cipher, params->key_len, params->seq_len,
|
|
key_index, pairwise, mac_addr);
|
|
|
|
#if 0
|
|
if (key_index > TOTAL_CAM_ENTRY) {
|
|
NDEBUG("key index [%d] out of bounds\n", key_index);
|
|
return -ENOENT;
|
|
}
|
|
|
|
if(mac_addr == NULL) {
|
|
printk("NO MAC Address !!\n");
|
|
return -ENOENT;;
|
|
}
|
|
#endif
|
|
|
|
memset(&wk, 0, sizeof(struct ieee80211req_key));
|
|
|
|
wk.ik_keyix = key_index;
|
|
|
|
if(mac_addr != NULL)
|
|
memcpy(wk.ik_macaddr, mac_addr, ETH_ALEN);
|
|
else
|
|
memset(wk.ik_macaddr, 0, ETH_ALEN);
|
|
|
|
#if 1
|
|
if (!pairwise) //in rtl_net80211_setkey(), group identification is by mac address
|
|
{
|
|
unsigned char MULTICAST_ADD[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
|
|
|
memcpy(wk.ik_macaddr, MULTICAST_ADD, ETH_ALEN);
|
|
}
|
|
#endif
|
|
|
|
switch (params->cipher) {
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
wk.ik_type = IEEE80211_CIPHER_WEP;
|
|
//printk("WEP !!\n");
|
|
break;
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
wk.ik_type = IEEE80211_CIPHER_TKIP;
|
|
//printk("TKIP !!\n");
|
|
break;
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
wk.ik_type = IEEE80211_CIPHER_AES_CCM;
|
|
//printk("AES !!\n");
|
|
break;
|
|
#ifdef CONFIG_IEEE80211W
|
|
case WLAN_CIPHER_SUITE_AES_CMAC:
|
|
wk.ik_type = IEEE80211_CIPHER_AES_CMAC;
|
|
break;
|
|
#endif
|
|
default:
|
|
NDEBUG("cipher(0x%08x) not support\n", params->cipher);
|
|
return -EINVAL;
|
|
}
|
|
|
|
#if 0
|
|
switch (rtk->cipher) { //_eric_cfg ?? mixed mode ??
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
wk.ik_type = IEEE80211_CIPHER_WEP;
|
|
break;
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
wk.ik_type = IEEE80211_CIPHER_TKIP;
|
|
break;
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
wk.ik_type = IEEE80211_CIPHER_AES_CCM;
|
|
break;
|
|
default:
|
|
return -ENOTSUPP;
|
|
}
|
|
#endif
|
|
wk.ik_keylen = params->key_len;
|
|
memcpy(wk.ik_keydata, params->key, params->key_len);
|
|
|
|
#if 0
|
|
{
|
|
int tmp = 0;
|
|
printk("keylen = %d: ", wk.ik_keylen);
|
|
for(tmp = 0; tmp < wk.ik_keylen; tmp ++)
|
|
printk("%02x ", wk.ik_keydata[tmp]);
|
|
printk("\n");
|
|
}
|
|
|
|
//_eric_cfg ?? key seq is not used ??
|
|
|
|
printk("[%s] add keyid = %d, mac = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
|
priv->dev->name , wk.ik_keyix, wk.ik_macaddr[0], wk.ik_macaddr[1], wk.ik_macaddr[2],
|
|
wk.ik_macaddr[3], wk.ik_macaddr[4], wk.ik_macaddr[5]);
|
|
printk("type = 0x%x, flags = 0x%x, keylen = 0x%x \n"
|
|
, wk.ik_type, wk.ik_flags, wk.ik_keylen);
|
|
#endif
|
|
|
|
|
|
wrqu.data.pointer = &wk;
|
|
|
|
rtl_net80211_setkey(priv->dev, NULL, &wrqu, NULL);
|
|
|
|
#if 1 //wrt-adhoc
|
|
if(OPMODE & WIFI_ADHOC_STATE)
|
|
{
|
|
if(!pairwise)
|
|
set_pairwise_key_for_ibss(priv, &wrqu); //or need to apply set_default_key
|
|
}
|
|
#endif
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int realtek_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 key_index, bool pairwise,
|
|
const u8 *mac_addr)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
union iwreq_data wrqu;
|
|
struct ieee80211req_del_key wk;
|
|
int ret=0;
|
|
|
|
NLENTER;
|
|
|
|
if(!pairwise)
|
|
{
|
|
// NDEBUG2("No need to delete Groupe key !!\n");
|
|
goto realtek_cfg80211_del_key_end;
|
|
}
|
|
|
|
|
|
if (!realtek_cfg80211_ready(priv)){
|
|
NDEBUG("No realtek_cfg80211_ready !!\n");
|
|
ret = -EIO;
|
|
goto realtek_cfg80211_del_key_end;
|
|
}
|
|
|
|
#if 0
|
|
if (key_index > TOTAL_CAM_ENTRY) {
|
|
NDEBUG("key index %d out of bounds\n" ,key_index);
|
|
return -ENOENT;
|
|
}
|
|
#endif
|
|
|
|
memset(&wk, 0, sizeof(struct ieee80211req_del_key));
|
|
|
|
wk.idk_keyix = key_index;
|
|
|
|
if(mac_addr != NULL)
|
|
memcpy(wk.idk_macaddr, mac_addr, ETH_ALEN);
|
|
else
|
|
memset(wk.idk_macaddr, 0, ETH_ALEN);
|
|
|
|
#if 0
|
|
if (!pairwise) //in rtl_net80211_delkey(), group identification is by mac address
|
|
{
|
|
unsigned char MULTICAST_ADD[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
|
unsigned char GROUP_ADD[6]={0x0,0x0,0x0,0x0,0x0,0x0};
|
|
|
|
if(OPMODE & WIFI_AP_STATE)
|
|
memcpy(wk->idk_macaddr, GROUP_ADD, ETH_ALEN);
|
|
}
|
|
|
|
printk("keyid = %d, mac = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n"
|
|
, wk.idk_keyix, wk.idk_macaddr[0], wk.idk_macaddr[1], wk.idk_macaddr[2],
|
|
wk.idk_macaddr[3], wk.idk_macaddr[4], wk.idk_macaddr[5]);
|
|
#endif
|
|
|
|
|
|
wrqu.data.pointer = &wk;
|
|
|
|
rtl_net80211_delkey(priv->dev, NULL, &wrqu, NULL);
|
|
|
|
realtek_cfg80211_del_key_end:
|
|
NLEXIT;
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int realtek_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 key_index, bool pairwise,
|
|
const u8 *mac_addr, void *cookie,
|
|
void (*callback) (void *cookie, struct key_params *))
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
struct key_params params;
|
|
struct stat_info *pstat = NULL;
|
|
unsigned int cipher = 0;
|
|
|
|
NLENTER;
|
|
|
|
if(mac_addr)
|
|
pstat = get_stainfo(priv, mac_addr);
|
|
|
|
NDEBUG2("key_index [%d]\n", key_index);
|
|
|
|
if (!realtek_cfg80211_ready(priv))
|
|
return -EIO;
|
|
|
|
#if 0
|
|
if (key_index > TOTAL_CAM_ENTRY) {
|
|
NDEBUG("key index [%d] out of bounds\n" , key_index);
|
|
return -ENOENT;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
if(pairwise)
|
|
{
|
|
pstat = get_stainfo(priv, mac_addr);
|
|
if (pstat == NULL)
|
|
return -ENOENT;
|
|
}
|
|
#endif
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
|
|
#ifdef NOT_RTK_BSP
|
|
params.key = rtw_zmalloc(64);
|
|
params.seq = rtw_zmalloc(64);
|
|
#endif
|
|
|
|
realtek_get_key_from_sta(priv, pstat, ¶ms, key_index);
|
|
|
|
//_eric_cfg ?? key seq is not used ??
|
|
#if 0
|
|
params.seq_len = key->seq_len;
|
|
params.seq = key->seq;
|
|
#endif
|
|
|
|
callback(cookie, ¶ms);
|
|
|
|
NLEXIT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_set_default_key(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
u8 key_index, bool unicast,
|
|
bool multicast)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
NDEBUG2("defaukt key_index[%d] unicast[%d] multicast[%d] \n", key_index, unicast, multicast);
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_set_default_mgmt_key(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
u8 key_idx)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
NDEBUG2(" key_index[%d]\n", key_idx);
|
|
priv->default_mgmt_key_idx = key_idx;
|
|
return 0;
|
|
}
|
|
|
|
//not in ath6k
|
|
static int realtek_cfg80211_auth(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_auth_request *req)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_assoc(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_assoc_request *req)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_deauth_request *req,
|
|
void *cookie)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_disassoc_request *req,
|
|
void *cookie)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
//Not in ath6k
|
|
static int realtek_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 *mac, struct station_parameters *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void realtek_del_station(struct rtl8192cd_priv *priv, struct stat_info *pstat)
|
|
{
|
|
unsigned long flags;
|
|
NDEBUG3("\n");
|
|
if(pstat->state & WIFI_ASOC_STATE){
|
|
// if we even received dis_assoc from this STA don't send dis_assoc to it again
|
|
NDEBUG3("\n");
|
|
issue_disassoc(priv, pstat->hwaddr, _RSON_AUTH_NO_LONGER_VALID_);
|
|
}
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
|
|
if (!SWCRYPTO && pstat->dot11KeyMapping.keyInCam) {
|
|
if (CamDeleteOneEntry(priv, pstat->hwaddr, 0, 0)) {
|
|
pstat->dot11KeyMapping.keyInCam = FALSE;
|
|
pstat->tmp_rmv_key = TRUE;
|
|
priv->pshare->CamEntryOccupied--;
|
|
}
|
|
}
|
|
|
|
if (asoc_list_del(priv, pstat))
|
|
{
|
|
if (pstat->expire_to > 0)
|
|
{
|
|
cnt_assoc_num(priv, pstat, DECREASE, (char *)__FUNCTION__);
|
|
check_sta_characteristic(priv, pstat, DECREASE);
|
|
LOG_MSG("A STA is rejected by nl80211 - %02X:%02X:%02X:%02X:%02X:%02X\n",
|
|
pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5]);
|
|
}
|
|
}
|
|
free_stainfo(priv, pstat);
|
|
RESTORE_INT(flags);
|
|
|
|
}
|
|
|
|
//eric ?? can apply to disconnect ??
|
|
static int realtek_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0)
|
|
struct station_del_parameters *params
|
|
#else
|
|
u8 *mac
|
|
#endif
|
|
)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
struct stat_info *pstat;
|
|
int ret=0;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0)
|
|
const u8 *mac = params->mac;
|
|
#endif
|
|
|
|
NLENTER;
|
|
|
|
if(!IS_DRV_OPEN(priv)) {
|
|
NLMSG("[%s]%s is not open\n", __func__, priv->dev->name);
|
|
goto realtek_cfg80211_del_station_end;
|
|
}
|
|
|
|
pstat = get_stainfo(priv, mac);
|
|
|
|
if (pstat == NULL) {
|
|
goto realtek_cfg80211_del_station_end;
|
|
}
|
|
|
|
NDEBUG("try disassoc sta[%02X%02X%02X%02X%02X%02X]\n",
|
|
mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
|
|
|
|
realtek_del_station(priv, pstat);
|
|
|
|
realtek_cfg80211_del_station_end:
|
|
NLEXIT;
|
|
return ret;
|
|
}
|
|
|
|
static int realtek_cfg80211_change_station(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
u8 *mac,
|
|
struct station_parameters *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
struct stat_info *pstat = NULL;
|
|
union iwreq_data wrqu;
|
|
struct ieee80211req_mlme mlme;
|
|
int err = 0;
|
|
|
|
NLENTER;
|
|
|
|
if (! (dev->flags & IFF_UP) )
|
|
return 0;
|
|
|
|
if(mac)
|
|
{
|
|
//dump_mac(priv, mac);
|
|
pstat = get_stainfo(priv, mac);
|
|
}
|
|
|
|
if(pstat == NULL)
|
|
goto realtek_cfg80211_change_station_end;
|
|
|
|
#if 0
|
|
if ((OPMODE & WIFI_AP_STATE) == 0)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
#endif
|
|
|
|
memcpy(mlme.im_macaddr, mac, ETH_ALEN);
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
|
|
err = cfg80211_check_station_change(wiphy, params,
|
|
CFG80211_STA_AP_MLME_CLIENT);
|
|
|
|
if (err)
|
|
{
|
|
NDEBUG(" error(%d)!!\n", err);
|
|
goto realtek_cfg80211_change_station_end;
|
|
}
|
|
#else
|
|
/* Use this only for authorizing/unauthorizing a station */
|
|
if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
|
|
return -EOPNOTSUPP;
|
|
#endif
|
|
|
|
if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
|
|
mlme.im_op = IEEE80211_MLME_AUTHORIZE;
|
|
else
|
|
mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
|
|
|
|
wrqu.data.pointer = &mlme;
|
|
|
|
#if 0
|
|
printk("NO SET PORT !!\n");
|
|
#else
|
|
|
|
if(mlme.im_op == IEEE80211_MLME_AUTHORIZE){
|
|
NDEBUG3("IEEE80211_MLME_AUTHORIZE(4-way success!)\n");
|
|
#ifdef CONFIG_IEEE80211W
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
NDEBUG3("[mgmt_frame_prot]=%d\n", pstat->wpa_sta_info->mgmt_frame_prot);
|
|
pstat->isPMF = (pstat->wpa_sta_info->mgmt_frame_prot) ? 1 : 0;
|
|
}
|
|
#ifdef CONFIG_IEEE80211W_CLI
|
|
else if (OPMODE & WIFI_STATION_STATE) {
|
|
pstat->isPMF = (priv->support_pmf) ? 1 : 0;
|
|
}
|
|
#endif
|
|
#endif
|
|
}else{
|
|
NDEBUG3("IEEE80211_MLME_UNAUTHORIZE(clean port)\n");
|
|
}
|
|
|
|
if(priv->pmib->dot1180211AuthEntry.dot11EnablePSK || priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm)//OPENWRT_RADIUS
|
|
rtl_net80211_setmlme(priv->dev, NULL, &wrqu, NULL);
|
|
#endif
|
|
|
|
realtek_cfg80211_change_station_end:
|
|
NLEXIT;
|
|
return err;
|
|
}
|
|
|
|
static void realtek_cfg80211_set_rate_info(struct rate_info *r_info, unsigned int rate, unsigned char bw, unsigned char isSgi)
|
|
{
|
|
r_info->flags = 0;
|
|
|
|
#if defined(RTK_AC_SUPPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0))
|
|
if (is_VHT_rate(rate))
|
|
{
|
|
r_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
|
|
r_info->mcs = (rate - VHT_RATE_ID) % 10;
|
|
r_info->nss = (rate - VHT_RATE_ID) / 10 + 1;
|
|
}
|
|
else
|
|
#endif
|
|
if (is_MCS_rate(rate))
|
|
{
|
|
r_info->flags |= RATE_INFO_FLAGS_MCS;
|
|
r_info->mcs = (rate - HT_RATE_ID);
|
|
}
|
|
else
|
|
r_info->legacy = (rate&0x7f) * 5;
|
|
|
|
if(isSgi)
|
|
r_info->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
|
|
|
switch(bw) {
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
|
|
case HT_CHANNEL_WIDTH_160:
|
|
r_info->bw = RATE_INFO_BW_160;
|
|
break;
|
|
case HT_CHANNEL_WIDTH_80:
|
|
r_info->bw = RATE_INFO_BW_80;
|
|
break;
|
|
case HT_CHANNEL_WIDTH_20_40:
|
|
r_info->bw = RATE_INFO_BW_40;
|
|
break;
|
|
case HT_CHANNEL_WIDTH_20:
|
|
r_info->bw = RATE_INFO_BW_20;
|
|
break;
|
|
case HT_CHANNEL_WIDTH_10:
|
|
r_info->bw = RATE_INFO_BW_10;
|
|
break;
|
|
case HT_CHANNEL_WIDTH_5:
|
|
r_info->bw = RATE_INFO_BW_5;
|
|
break;
|
|
default:
|
|
NDEBUG2("Unknown bw(=%d)\n", bw);
|
|
r_info->bw = RATE_INFO_BW_20;
|
|
break;
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
case HT_CHANNEL_WIDTH_160:
|
|
r_info->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
|
|
break;
|
|
case HT_CHANNEL_WIDTH_80:
|
|
r_info->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
|
|
break;
|
|
#else
|
|
case HT_CHANNEL_WIDTH_20_40:
|
|
r_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
static int realtek_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 *mac, struct station_info *sinfo)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
struct stat_info *pstat = NULL;
|
|
|
|
unsigned int tx_rate, rx_rate;
|
|
unsigned char tx_bw, rx_bw, tx_sgi, rx_sgi;
|
|
|
|
if(mac)
|
|
pstat = get_stainfo(priv, mac);
|
|
|
|
if(pstat==NULL)
|
|
return -ENOENT;
|
|
|
|
tx_rate = pstat->current_tx_rate;
|
|
rx_rate = pstat->rx_rate;
|
|
tx_bw = pstat->tx_bw;
|
|
rx_bw = pstat->rx_bw;
|
|
tx_sgi = (pstat->ht_current_tx_info&BIT(1))?TRUE:FALSE;
|
|
rx_sgi = (pstat->rx_splcp)?TRUE:FALSE;
|
|
|
|
|
|
sinfo->filled = 0;
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
|
|
sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME) |
|
|
BIT(NL80211_STA_INFO_CONNECTED_TIME)|
|
|
BIT(NL80211_STA_INFO_RX_BYTES64) |
|
|
BIT(NL80211_STA_INFO_RX_PACKETS) |
|
|
BIT(NL80211_STA_INFO_TX_BYTES64) |
|
|
BIT(NL80211_STA_INFO_TX_PACKETS) |
|
|
BIT(NL80211_STA_INFO_SIGNAL) |
|
|
BIT(NL80211_STA_INFO_TX_BITRATE) |
|
|
BIT(NL80211_STA_INFO_RX_BITRATE) |
|
|
0;
|
|
#else
|
|
sinfo->filled = STATION_INFO_INACTIVE_TIME |
|
|
STATION_INFO_CONNECTED_TIME |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
|
|
STATION_INFO_RX_BYTES |
|
|
STATION_INFO_TX_BYTES |
|
|
#else
|
|
STATION_INFO_RX_BYTES64 |
|
|
STATION_INFO_TX_BYTES64 |
|
|
#endif
|
|
STATION_INFO_RX_PACKETS |
|
|
STATION_INFO_TX_PACKETS |
|
|
STATION_INFO_SIGNAL |
|
|
STATION_INFO_TX_BITRATE |
|
|
STATION_INFO_RX_BITRATE |
|
|
0;
|
|
#endif
|
|
|
|
sinfo->inactive_time = pstat->idle_count*1000;
|
|
sinfo->connected_time = pstat->link_time;
|
|
sinfo->rx_bytes = pstat->rx_bytes;
|
|
sinfo->rx_packets = pstat->rx_pkts;
|
|
sinfo->tx_bytes = pstat->tx_bytes;
|
|
sinfo->tx_packets = pstat->tx_pkts;
|
|
#if defined(SIGNAL_TYPE_UNSPEC)
|
|
sinfo->signal = pstat->rssi;
|
|
#else
|
|
if(pstat->rssi > 100)
|
|
sinfo->signal = -20;
|
|
else
|
|
sinfo->signal = pstat->rssi-100;
|
|
#endif
|
|
|
|
realtek_cfg80211_set_rate_info(&sinfo->txrate, tx_rate, tx_bw, tx_sgi);
|
|
realtek_cfg80211_set_rate_info(&sinfo->rxrate, rx_rate, rx_bw, rx_sgi);
|
|
|
|
#if 0 //_eric_nl ?? sinfo->bss_param ??
|
|
if(OPMODE & WIFI_STATION_STATE)
|
|
{
|
|
sinfo->filled |= STATION_INFO_BSS_PARAM;
|
|
sinfo->bss_param.flags = 0;
|
|
sinfo->bss_param.dtim_period = priv->pmib->dot11Bss.dtim_prd;
|
|
sinfo->bss_param.beacon_interval = priv->pmib->dot11StationConfigEntry.dot11BeaconPeriod;
|
|
}
|
|
#endif
|
|
|
|
//NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int realtek_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
|
|
int idx, u8 *mac, struct station_info *sinfo)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
int num = 0;
|
|
struct list_head *phead, *plist;
|
|
struct stat_info *pstat;
|
|
int ret = -ENOENT;
|
|
#ifdef SMP_SYNC
|
|
unsigned long flags = 0;
|
|
#endif
|
|
|
|
//NDEBUG2("\n");
|
|
//printk("try dump sta[%d]\n", idx);
|
|
|
|
if(idx >= priv->assoc_num)
|
|
return -ENOENT;
|
|
|
|
phead = &priv->asoc_list;
|
|
if (!(priv->drv_state & DRV_STATE_OPEN) || list_empty(phead)) {
|
|
return -ENOENT;
|
|
}
|
|
|
|
SMP_LOCK_ASOC_LIST(flags);
|
|
|
|
plist = phead->next;
|
|
while (plist != phead) {
|
|
if (num == idx) {
|
|
pstat = list_entry(plist, struct stat_info, asoc_list);
|
|
if(mac)
|
|
memcpy(mac, pstat->hwaddr, ETH_ALEN);
|
|
else
|
|
mac = pstat->hwaddr;
|
|
|
|
ret = realtek_cfg80211_get_station(wiphy, dev, pstat->hwaddr, sinfo);
|
|
break;
|
|
}
|
|
num++;
|
|
plist = plist->next;
|
|
}
|
|
|
|
SMP_UNLOCK_ASOC_LIST(flags);
|
|
|
|
//NLEXIT;
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
//not in ath6k
|
|
static int realtek_cfg80211_set_txq_params(struct wiphy *wiphy,
|
|
struct ieee80211_txq_params *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
|
|
NLENTER;
|
|
NLNOT;
|
|
|
|
printk("queue = %d\n", params->queue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
#endif
|
|
|
|
static int realtek_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
|
|
NLENTER;
|
|
|
|
if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
|
|
priv->pmib->dot11OperationEntry.dot11FragmentationThreshold = wiphy->frag_threshold;
|
|
if (changed & WIPHY_PARAM_RTS_THRESHOLD)
|
|
priv->pmib->dot11OperationEntry.dot11RTSThreshold = wiphy->rts_threshold;
|
|
if (changed & WIPHY_PARAM_RETRY_SHORT)
|
|
priv->pmib->dot11OperationEntry.dot11ShortRetryLimit = wiphy->retry_short;
|
|
if (changed & WIPHY_PARAM_RETRY_LONG)
|
|
priv->pmib->dot11OperationEntry.dot11LongRetryLimit = wiphy->retry_long;
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if(under_apmode_repeater(priv)) {
|
|
priv = GET_VXD_PRIV(priv);
|
|
|
|
if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
|
|
priv->pmib->dot11OperationEntry.dot11FragmentationThreshold = wiphy->frag_threshold;
|
|
if (changed & WIPHY_PARAM_RTS_THRESHOLD)
|
|
priv->pmib->dot11OperationEntry.dot11RTSThreshold = wiphy->rts_threshold;
|
|
if (changed & WIPHY_PARAM_RETRY_SHORT)
|
|
priv->pmib->dot11OperationEntry.dot11ShortRetryLimit = wiphy->retry_short;
|
|
if (changed & WIPHY_PARAM_RETRY_LONG)
|
|
priv->pmib->dot11OperationEntry.dot11LongRetryLimit = wiphy->retry_long;
|
|
|
|
NLMSG("Apply advanced settings to VXD(%s)\n",priv->dev->name);
|
|
}
|
|
#endif
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
|
|
static int realtek_cfg80211_set_ap_chanwidth(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
struct cfg80211_chan_def *chandef)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
|
|
NLENTER;
|
|
return realtek_cfg80211_set_channel(wiphy, dev, chandef);
|
|
}
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
static int realtek_cfg80211_set_monitor_channel(struct wiphy *wiphy,
|
|
struct cfg80211_chan_def *chandef)
|
|
#else
|
|
static int realtek_cfg80211_set_monitor_channel(struct wiphy *wiphy,
|
|
struct ieee80211_channel *chan,
|
|
enum nl80211_channel_type channel_type)
|
|
#endif
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
|
|
NLENTER;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
return realtek_cfg80211_set_channel(wiphy, priv->dev, chandef);
|
|
#else
|
|
return realtek_cfg80211_set_channel(wiphy, priv->dev, chan, channel_type);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#define MAX_2G_CHANNEL_NUM_MIB 14
|
|
#define MAX_5G_CHANNEL_NUM_MIB 196
|
|
|
|
#define MAX_2G_POWER_dBm 20 //defined by OpenWrt Webpage
|
|
#define MAX_5G_POWER_dBm 20 //defined by OpenWrt Webpage
|
|
|
|
|
|
unsigned int get_max_power(struct rtl8192cd_priv *priv)
|
|
{
|
|
int max_power = 0;
|
|
|
|
#ifdef TXPWR_LMT
|
|
if(!priv->pshare->rf_ft_var.disable_txpwrlmt) {
|
|
if((priv->pshare->txpwr_lmt_HT1S)
|
|
&& (priv->pshare->txpwr_lmt_HT1S <= priv->pshare->tgpwr_HT1S_new[RF_PATH_A]))
|
|
max_power = priv->pshare->txpwr_lmt_HT1S;
|
|
else
|
|
max_power = priv->pshare->tgpwr_HT1S_new[RF_PATH_A];
|
|
}
|
|
else
|
|
max_power = priv->pshare->tgpwr_HT1S_new[RF_PATH_A];
|
|
#else
|
|
max_power = priv->pshare->tgpwr_HT1S_new[RF_PATH_A];
|
|
#endif
|
|
|
|
max_power = (max_power/2);
|
|
|
|
//panic_printk("[%s][%s][%d] max_power=%d dBm \n", priv->dev->name, __FUNCTION__, __LINE__, max_power);
|
|
|
|
return max_power;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
static int realtek_cfg80211_set_tx_power(struct wiphy *wiphy,
|
|
struct wireless_dev *wdev,
|
|
enum nl80211_tx_power_setting type, int mbm)
|
|
#else
|
|
static int realtek_cfg80211_set_tx_power(struct wiphy *wiphy,
|
|
enum nl80211_tx_power_setting type, int mbm)
|
|
#endif
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
int dbm = MBM_TO_DBM(mbm);
|
|
int max_pwr=0, rfuoput=0, new_rfuoput=0, i;
|
|
|
|
NLENTER;
|
|
|
|
max_pwr = get_max_power(priv);
|
|
|
|
if(max_pwr == 0) {
|
|
if(priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G)
|
|
max_pwr=MAX_5G_POWER_dBm;
|
|
else
|
|
max_pwr=MAX_2G_POWER_dBm;
|
|
}
|
|
|
|
//panic_printk("### max_pwr=%d dbm=%d(mbm=%d) \n", max_pwr, dbm, mbm);
|
|
|
|
rtk->pwr_set_dbm = dbm;
|
|
|
|
if(dbm >= max_pwr)
|
|
{
|
|
rfuoput = 0;
|
|
rtk->pwr_rate = 100;
|
|
}
|
|
#if defined(DEC_PWR_BY_PERCENTAGE)
|
|
else if(dbm >= ((max_pwr*70)/100))
|
|
{
|
|
rfuoput = 1;
|
|
rtk->pwr_rate = 70;
|
|
}
|
|
else if(dbm >= ((max_pwr*50)/100))
|
|
{
|
|
rfuoput = 2;
|
|
rtk->pwr_rate = 50;
|
|
}
|
|
else if(dbm >= ((max_pwr*35)/100))
|
|
{
|
|
rfuoput = 3;
|
|
rtk->pwr_rate = 35;
|
|
}
|
|
else
|
|
{
|
|
rfuoput = 4;
|
|
rtk->pwr_rate = 15;
|
|
}
|
|
//panic_printk("### rfuoput idx=%d rtk->pwr_rate=%d(percent) \n", rfuoput, rtk->pwr_rate);
|
|
|
|
if(rfuoput == 1)
|
|
rfuoput = -3;
|
|
else if(rfuoput == 2)
|
|
rfuoput = -6;
|
|
else if(rfuoput == 3)
|
|
rfuoput = -9;
|
|
else if(rfuoput == 4)
|
|
rfuoput = -17;
|
|
#else
|
|
else{
|
|
rfuoput = (dbm-max_pwr)*2;
|
|
}
|
|
#endif
|
|
new_rfuoput = rfuoput;
|
|
|
|
//panic_printk("### from cur_pwr=%d to rfuoput=%d \n",rtk->pwr_cur, rfuoput);
|
|
|
|
rfuoput = rfuoput - rtk->pwr_cur;
|
|
rtk->pwr_cur = new_rfuoput;
|
|
|
|
//panic_printk("### adjust power=%d\n", rfuoput);
|
|
|
|
if(priv->pmib->dot11RFEntry.phyBandSelect & PHY_BAND_2G) {
|
|
for (i=0; i<MAX_2G_CHANNEL_NUM_MIB; i++) {
|
|
if(priv->pmib->dot11RFEntry.pwrlevelCCK_A[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelCCK_A[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_A[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_A[i] = 1;
|
|
}
|
|
if(priv->pmib->dot11RFEntry.pwrlevelCCK_B[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelCCK_B[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_B[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_B[i] = 1;
|
|
}
|
|
#if 0
|
|
if(priv->pmib->dot11RFEntry.pwrlevelCCK_C[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelCCK_C[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_C[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_C[i] = 1;
|
|
}
|
|
if(priv->pmib->dot11RFEntry.pwrlevelCCK_D[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelCCK_D[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_D[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelCCK_D[i] = 1;
|
|
}
|
|
#endif
|
|
|
|
if(priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_A[i] = 1;
|
|
}
|
|
if(priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_B[i] = 1;
|
|
}
|
|
#if 0
|
|
if(priv->pmib->dot11RFEntry.pwrlevelHT40_1S_C[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelHT40_1S_C[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_C[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_C[i] = 1;
|
|
}
|
|
if(priv->pmib->dot11RFEntry.pwrlevelHT40_1S_D[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevelHT40_1S_D[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_D[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevelHT40_1S_D[i] = 1;
|
|
}
|
|
#endif
|
|
}
|
|
} else {
|
|
for (i=0; i<MAX_5G_CHANNEL_NUM_MIB; i++) {
|
|
if(priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_A[i] = 1;
|
|
}
|
|
if(priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_B[i] = 1;
|
|
}
|
|
#if 0
|
|
if(priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_C[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_C[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_C[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_C[i] = 1;
|
|
}
|
|
if(priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_D[i] != 0){
|
|
if ((priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_D[i] + rfuoput) >= 1)
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_D[i] += rfuoput;
|
|
else
|
|
priv->pmib->dot11RFEntry.pwrlevel5GHT40_1S_D[i] = 1;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//Apply config immediately for AP mode
|
|
if(OPMODE & WIFI_AP_STATE)
|
|
{
|
|
if(priv->pmib->dot11RFEntry.dot11channel)
|
|
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pmib->dot11nConfigEntry.dot11n2ndChOffset);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct rtl8192cd_priv* get_priv_from_wdev(struct rtknl *rtk, struct wireless_dev *wdev)
|
|
{
|
|
struct rtl8192cd_priv *priv = NULL;
|
|
int tmp = 0;
|
|
|
|
for(tmp = 0; tmp<(IF_NUM); tmp++)
|
|
{
|
|
if(rtk->rtk_iface[tmp].priv)
|
|
if(wdev == &(rtk->rtk_iface[tmp].priv->wdev))
|
|
{
|
|
priv = rtk->rtk_iface[tmp].priv;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//printk("wdev = 0x%x priv = 0x%x \n", wdev, priv);
|
|
|
|
return priv;
|
|
}
|
|
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
static int realtek_cfg80211_get_tx_power(struct wiphy *wiphy,
|
|
struct wireless_dev *wdev, int *dbm)
|
|
#else
|
|
static int realtek_cfg80211_get_tx_power(struct wiphy *wiphy, int *dbm)
|
|
#endif
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#endif
|
|
|
|
//NLENTER;
|
|
|
|
if(rtk->pwr_set_dbm)
|
|
*dbm = rtk->pwr_set_dbm;
|
|
else
|
|
*dbm = 13;
|
|
|
|
//NLEXIT;
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
#if 1
|
|
//_eric_nl ?? suspend/resume use open/close ??
|
|
static int realtek_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
|
|
NLENTER;
|
|
NLNOT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_resume(struct wiphy *wiphy)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
|
|
NLENTER;
|
|
NLNOT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*cfg p2p*/
|
|
void realtek_cfg80211_fill_available_channel(struct rtl8192cd_priv *priv,
|
|
struct cfg80211_scan_request *request)
|
|
{
|
|
int idx=0;
|
|
//NDEBUG("\n");
|
|
if (request->n_channels > 0) {
|
|
//request should scan only one band, apply band here cliW
|
|
rtk_set_band_mode(priv, request->channels[0]->band, NL80211_CHAN_WIDTH_20_NOHT);
|
|
// rtk_set_band_mode(priv, request->channels[0]->band, request->scan_width);
|
|
|
|
if(IS_HAL_CHIP(priv) && request->channels[0]->band == IEEE80211_BAND_5GHZ && !(RTL_R8(0x454) & BIT(7))) {
|
|
//To prevent treated as 2.4GHz at CheckBand88XX_AC(), Hal88XXPhyCfg.c
|
|
//0x454 is configured at rtl8192cd_init_hw_PCI(), rtl8192cd_hw.c
|
|
RTL_W8(0x454, RTL_R8(0x454) | BIT(7));
|
|
}
|
|
|
|
if(request->n_channels == 3 &&
|
|
request->channels[0]->hw_value == 1 &&
|
|
request->channels[1]->hw_value == 6 &&
|
|
request->channels[2]->hw_value == 11
|
|
){
|
|
NDEBUG2("social_channel from cfg80211\n");
|
|
}
|
|
|
|
priv->available_chnl_num = request->n_channels;
|
|
//NDEBUG2("n_channels[%d]\n",n_channels);
|
|
if (request->n_channels==1) {
|
|
NDEBUG2("n_channels[%d],ch[%d]\n", request->n_channels,ieee80211_frequency_to_channel(request->channels[0]->center_freq));
|
|
}
|
|
for (idx = 0; idx < request->n_channels; idx++){
|
|
priv->available_chnl[idx] = ieee80211_frequency_to_channel(request->channels[idx]->center_freq);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*cfg p2p*/
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
static int realtek_cfg80211_scan(struct wiphy *wiphy,
|
|
struct cfg80211_scan_request *request)
|
|
#else
|
|
static int realtek_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_scan_request *request)
|
|
#endif
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv;
|
|
struct cfg80211_ssid *ssids = request->ssids;
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
priv = get_priv_from_wdev(rtk, request->wdev);
|
|
NLMSG("request->flags = 0x%x \n", request->flags);
|
|
#else
|
|
// priv = rtk->priv;
|
|
priv = get_priv_from_wdev(rtk, &rtk->priv->wdev);
|
|
#endif
|
|
|
|
NLENTER;
|
|
|
|
if(is_WRT_scan_iface(priv->dev->name))
|
|
priv = GET_ROOT(priv);
|
|
|
|
if ( request->wiphy == NULL )
|
|
request->wiphy = wiphy;
|
|
|
|
if (TRUE == priv->pshare->bScanInProcess) {
|
|
NLMSG("scan disable (bScanInProcess %s)\n", priv->dev->name);
|
|
rtk_abort_scan(priv, SCAN_ABORT_START_AP);
|
|
return -EBUSY;
|
|
}
|
|
|
|
if (!netif_running(priv->dev)){
|
|
NLMSG("scan disable (!netif_running %s)\n", priv->dev->name);
|
|
return -ENETDOWN;
|
|
}
|
|
|
|
if (priv->ss_req_ongoing ){
|
|
NLMSG("scan disable (ss_req_ongoing %s)\n", priv->dev->name);
|
|
return -EBUSY;
|
|
}
|
|
|
|
if (priv->scan_req){
|
|
NLMSG("scan disable (scan_req %s)\n", priv->dev->name);
|
|
return -EBUSY;
|
|
}
|
|
|
|
#if defined(DFS)
|
|
if (timer_pending(&GET_ROOT(priv)->ch_avail_chk_timer)) {
|
|
NLMSG("%s ch_avail_chk_timer pending\n", priv->dev->name);
|
|
return -EBUSY;
|
|
}
|
|
#endif
|
|
|
|
if (request->n_channels == 0) {
|
|
NDEBUG("start_scan\n");
|
|
goto start_scan;
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
unsigned char idx;
|
|
if(ssids->ssid != NULL ){
|
|
NDEBUG("p2pssid=[%s]\n",ssids->ssid);
|
|
}
|
|
|
|
if (request->ie) {
|
|
printk("request->ie = ");
|
|
for(idx=0; idx<request->ie_len; idx++)
|
|
{
|
|
printk(" %02x", request->ie);
|
|
}
|
|
printk("\n");
|
|
}
|
|
|
|
printk("\n");
|
|
|
|
if (request->n_channels > 0) {
|
|
unsigned char n_channels = 0;
|
|
n_channels = request->n_channels;
|
|
for (idx = 0; idx < n_channels; idx++){
|
|
NDEBUG("channel[%d]=%d\n", idx, ieee80211_frequency_to_channel(request->channels[idx]->center_freq));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//rtk_abort_scan(priv);
|
|
|
|
priv->ss_ssidlen = 0;
|
|
memset(priv->ss_ssid, 0, 32);
|
|
|
|
#if defined(P2P_SUPPORT)
|
|
if(ssids->ssid != NULL
|
|
&& !memcmp(ssids->ssid, "DIRECT-", 7)
|
|
&& rtk_get_p2p_ie((u8 *)request->ie, request->ie_len, NULL, NULL))
|
|
{
|
|
NDEBUG("Ssid=[%s],len[%d]...\n",ssids->ssid,ssids->ssid_len);
|
|
|
|
priv->ss_ssidlen = ssids->ssid_len;
|
|
memcpy(priv->ss_ssid,ssids->ssid,ssids->ssid_len);
|
|
|
|
if(!rtk_p2p_is_enabled(priv)){
|
|
NDEBUG3("==>rtk_p2p_enable(CFG80211_P2P)\n");
|
|
rtk_p2p_enable(priv , P2P_DEVICE , CFG80211_P2P);
|
|
}
|
|
|
|
priv->p2pPtr->pre_p2p_role=rtk_p2p_get_role(priv);
|
|
priv->p2pPtr->pre_p2p_state=rtk_p2p_get_state(priv);
|
|
|
|
rtk_p2p_set_role(priv,P2P_DEVICE);
|
|
rtk_p2p_set_state(priv, P2P_S_SEARCH);
|
|
//GET_ROOT(priv)->site_survey_times = SS_COUNT-2; // pre-channel just scan twice
|
|
} else
|
|
#endif
|
|
if(ssids->ssid != NULL) {
|
|
NDEBUG3("Ssid=[%s],len[%d]...\n", ssids->ssid, ssids->ssid_len);
|
|
priv->ss_ssidlen = ssids->ssid_len;
|
|
memcpy(priv->ss_ssid, ssids->ssid, ssids->ssid_len);
|
|
priv->site_survey->hidden_ap_found = HIDE_AP_FOUND_DO_ACTIVE_SSAN;
|
|
|
|
SSID2SCAN_LEN = (ssids->ssid_len > 32) ? 32 : ssids->ssid_len;
|
|
memcpy(SSID2SCAN, ssids->ssid, SSID2SCAN_LEN);
|
|
} else
|
|
priv->site_survey->hidden_ap_found = 0;
|
|
|
|
#if defined(P2P_SUPPORT)
|
|
/*set WPS P2P IE to probe_req*/
|
|
if(request->ie && request->ie_len>0)
|
|
{
|
|
rtk_cfg80211_set_wps_p2p_ie(priv, (u8 *)request->ie, request->ie_len ,MGMT_PROBEREQ );
|
|
}
|
|
#endif
|
|
#ifdef CUSTOMIZE_SCAN_HIDDEN_AP
|
|
//scan for HiddenAP
|
|
if(request->n_ssids && request->ssids[0].ssid_len)
|
|
{
|
|
priv->ss_ssidlen = request->ssids[0].ssid_len;
|
|
memcpy(priv->ss_ssid, request->ssids[0].ssid, request->ssids[0].ssid_len);
|
|
}
|
|
#endif
|
|
|
|
#if 0//def WIFI_SIMPLE_CONFIG
|
|
if (len == 2)
|
|
priv->ss_req_ongoing = 2; // WiFi-Simple-Config scan-req
|
|
else
|
|
#endif
|
|
|
|
start_scan:
|
|
if(IS_VXD_INTERFACE(priv))
|
|
priv->ss_req_ongoing = SSFROM_REPEATER_VXD;
|
|
else
|
|
priv->ss_req_ongoing = SSFROM_WEB;
|
|
|
|
priv->scan_req = request;
|
|
if(request->n_channels > 0) {
|
|
/*use channels from cfg80211 parameter*/
|
|
realtek_cfg80211_fill_available_channel(priv,request);
|
|
} else {
|
|
/*use rtk default available channels*/
|
|
get_available_channel(priv);
|
|
}
|
|
|
|
NDEBUG("start_clnt_ss\n");
|
|
start_clnt_ss(priv);
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
static void realtek_set_band(struct rtl8192cd_priv *priv, struct cfg80211_beacon_data *beacon)
|
|
{
|
|
#ifdef CONFIG_IEEE80211W
|
|
enum mfp_options dot11IEEE80211W = NO_MGMT_FRAME_PROTECTION;
|
|
bool dot11EnableSHA256 = false;
|
|
#endif
|
|
bool is_b_only = true, is_ht_enable = false, is_vht_enable = false;
|
|
bool dot11nShortGIfor20M = false, dot11nShortGIfor40M = false, dot11nShortGIfor80M = false, dot11nAMPDU = false;
|
|
u8 net_work_type = WIRELESS_11B;
|
|
u8 phyBandSelect;
|
|
|
|
NLENTER;
|
|
|
|
if (beacon->tail_len)
|
|
{
|
|
unsigned char *p;
|
|
unsigned int len;
|
|
|
|
/* after TIM IE */
|
|
// mem_dump("beacon tail", beacon->tail, beacon->tail_len);
|
|
|
|
p = get_ie(beacon->tail, _EXT_SUPPORTEDRATES_IE_, &len, beacon->tail_len);
|
|
if (p)
|
|
is_b_only = false;
|
|
|
|
p = get_ie(beacon->tail, _HT_CAP_, &len, beacon->tail_len);
|
|
if (p)
|
|
{
|
|
struct ht_cap_elmt *ht_cap = (p + 2);
|
|
|
|
is_ht_enable = true;
|
|
dot11nAMPDU = true;
|
|
|
|
if (ht_cap->ht_cap_info & HT_CAP_INFO_SHORT_GI20MHZ)
|
|
dot11nShortGIfor20M = true;
|
|
|
|
if (ht_cap->ht_cap_info & HT_CAP_INFO_SHORT_GI40MHZ)
|
|
dot11nShortGIfor40M = true;
|
|
}
|
|
|
|
#ifdef RTK_AC_SUPPORT
|
|
p = get_ie(beacon->tail, EID_VHTCapability, &len, beacon->tail_len);
|
|
if (p)
|
|
{
|
|
struct vht_cap_elmt *vht_cap = (p + 2);
|
|
|
|
is_vht_enable = true;
|
|
|
|
if (vht_cap->vht_cap_info & VHT_CAP_SHORT_GI_80)
|
|
dot11nShortGIfor80M = true;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
/* check 11w configuration */
|
|
p = get_ie(beacon->tail, _RSN_IE_2_, &len, beacon->tail_len);
|
|
if (p)
|
|
{
|
|
unsigned short count, i;
|
|
signed short valid_len = len + 2;
|
|
DOT11_RSN_IE_COUNT_SUITE *pDot11RSNIECountSuite;
|
|
DOT11_RSN_CAPABILITY *pDot11RSNCapability;
|
|
unsigned char oui[4] = {0x00, 0x0f, 0xac, 0x06};
|
|
|
|
/* skip hdr and group chipher */
|
|
p += sizeof(DOT11_WPA2_IE_HEADER) + sizeof(DOT11_RSN_IE_SUITE);
|
|
valid_len -= sizeof(DOT11_WPA2_IE_HEADER) + sizeof(DOT11_RSN_IE_SUITE);
|
|
if (valid_len < 0) goto check_end;
|
|
|
|
/* skip pairwise chiper */
|
|
pDot11RSNIECountSuite = (DOT11_RSN_IE_COUNT_SUITE *)p;
|
|
count = le16_to_cpu(pDot11RSNIECountSuite->SuiteCount);
|
|
p += (2 + count * sizeof(DOT11_RSN_IE_SUITE));
|
|
valid_len -= (2 + count * sizeof(DOT11_RSN_IE_SUITE));
|
|
if (valid_len < 0) goto check_end;
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
/* check akm */
|
|
pDot11RSNIECountSuite = (DOT11_RSN_IE_COUNT_SUITE *)p;
|
|
count = le16_to_cpu(pDot11RSNIECountSuite->SuiteCount);
|
|
for (i = 0 ; i < count ; ++i)
|
|
if (!memcmp(&pDot11RSNIECountSuite->dot11RSNIESuite[i], oui, sizeof(DOT11_RSN_IE_SUITE)))
|
|
dot11EnableSHA256 = true;
|
|
p += (2 + count * sizeof(DOT11_RSN_IE_SUITE));
|
|
valid_len -= (2 + count * sizeof(DOT11_RSN_IE_SUITE));
|
|
if (valid_len < 0) goto check_end;
|
|
|
|
/* rsn cap */
|
|
pDot11RSNCapability = (DOT11_RSN_CAPABILITY *)p;
|
|
if (pDot11RSNCapability->field.MFPC && pDot11RSNCapability->field.MFPR)
|
|
dot11IEEE80211W = MGMT_FRAME_PROTECTION_REQUIRED;
|
|
else if (pDot11RSNCapability->field.MFPC)
|
|
dot11IEEE80211W = MGMT_FRAME_PROTECTION_OPTIONAL;
|
|
else
|
|
dot11IEEE80211W = NO_MGMT_FRAME_PROTECTION;
|
|
#endif //CONFIG_IEEE80211W
|
|
}
|
|
check_end:
|
|
;
|
|
#endif
|
|
}
|
|
|
|
NDEBUG(" sgi 20(%d), 40(%d), 80(%d)\n", dot11nShortGIfor20M, dot11nShortGIfor40M, dot11nShortGIfor80M);
|
|
#ifdef CONFIG_IEEE80211W
|
|
NDEBUG(" 11w(%d), sha256(%d)\n", dot11IEEE80211W, dot11EnableSHA256);
|
|
#endif
|
|
|
|
/* apply setting */
|
|
priv->pmib->dot11nConfigEntry.dot11nShortGIfor20M = dot11nShortGIfor20M;
|
|
priv->pmib->dot11nConfigEntry.dot11nShortGIfor40M = dot11nShortGIfor40M;
|
|
priv->pmib->dot11nConfigEntry.dot11nShortGIfor80M = dot11nShortGIfor80M;
|
|
priv->pmib->dot11nConfigEntry.dot11nAMPDU = dot11nAMPDU;
|
|
#ifdef CONFIG_IEEE80211W
|
|
priv->pmib->dot1180211AuthEntry.dot11IEEE80211W = dot11IEEE80211W;
|
|
priv->pmib->dot1180211AuthEntry.dot11EnableSHA256 = dot11EnableSHA256;
|
|
#endif
|
|
|
|
#ifdef CONFIG_WLAN_HAL_8814AE
|
|
if(GET_CHIP_VER(priv) == VERSION_8814A)
|
|
priv->pmib->dot11nConfigEntry.dot11nAMSDU = 2;
|
|
#endif
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if(IS_ROOT_INTERFACE(priv) && priv->pvxd_priv)
|
|
{
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11nAMPDU = priv->pmib->dot11nConfigEntry.dot11nAMPDU;
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11nSTBC = priv->pmib->dot11nConfigEntry.dot11nSTBC;
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11nShortGIfor20M = priv->pmib->dot11nConfigEntry.dot11nShortGIfor20M;
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11nShortGIfor40M = priv->pmib->dot11nConfigEntry.dot11nShortGIfor40M;
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11nShortGIfor80M = priv->pmib->dot11nConfigEntry.dot11nShortGIfor80M;
|
|
#ifdef CONFIG_WLAN_HAL_8814AE
|
|
if(GET_CHIP_VER(priv) == VERSION_8814A)
|
|
priv->pvxd_priv->pmib->dot11nConfigEntry.dot11nAMSDU = priv->pmib->dot11nConfigEntry.dot11nAMSDU;
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int realtek_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_ap_settings *info)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
struct cfg80211_scan_request *scan_req_pending = NULL;
|
|
int ret = 0;
|
|
|
|
NLENTER;
|
|
|
|
if (!realtek_cfg80211_ready(priv))
|
|
return -EIO;
|
|
|
|
if ((OPMODE & (WIFI_AP_STATE | WIFI_ADHOC_STATE)) == 0) //wrt-adhoc
|
|
return -EOPNOTSUPP;
|
|
|
|
if (info->ssid == NULL)
|
|
return -EINVAL;
|
|
|
|
scan_req_pending = priv->scan_req;
|
|
|
|
if(IS_ROOT_INTERFACE(priv))
|
|
rtk_abort_scan(priv, SCAN_ABORT_START_AP);
|
|
|
|
/*fixme, should not enable carrier here.
|
|
Under mac80211 architecture will be invoked by compatible-wireless */
|
|
netif_carrier_on(priv->dev);
|
|
|
|
realtek_reset_security(priv);
|
|
|
|
realtek_set_band(priv, &info->beacon);
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
realtek_cfg80211_set_channel(wiphy, dev, &info->chandef);
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
realtek_cfg80211_set_channel(wiphy, dev, info->channel, info->channel_type);
|
|
#endif
|
|
realtek_set_ies_apmode(priv, &info->beacon);
|
|
|
|
ret = realtek_set_bss(priv, info);
|
|
|
|
ret = realtek_set_auth_type(priv, info->auth_type);
|
|
|
|
realtek_set_security_ap(priv, rtk, info->crypto);
|
|
|
|
realtek_ap_default_config(priv);
|
|
|
|
realtek_ap_config_apply(priv);
|
|
|
|
//start sending beacon, blocked while init_beacon()
|
|
priv->pmib->miscEntry.func_off = 0;
|
|
|
|
NDEBUG("start ap band=%d channel=%d\n",
|
|
priv->pmib->dot11BssType.net_work_type, priv->pmib->dot11RFEntry.dot11channel);
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
|
|
#if defined(DFS)
|
|
if((OPMODE&WIFI_AP_STATE) && info->chandef.chan->dfs_state == NL80211_DFS_AVAILABLE) {
|
|
printk("*** [%s]Under DFS channel, radar detection is active ***\n",priv->dev->name);
|
|
/* DFS activated after 1 sec; prevent switching channel due to DFS false alarm */
|
|
init_timer(&priv->DFS_timer);
|
|
priv->DFS_timer.data = (unsigned long) priv;
|
|
priv->DFS_timer.function = rtl8192cd_DFS_timer;
|
|
mod_timer(&priv->DFS_timer, jiffies + RTL_SECONDS_TO_JIFFIES(1));
|
|
|
|
init_timer(&priv->dfs_det_chk_timer);
|
|
priv->dfs_det_chk_timer.data = (unsigned long) priv;
|
|
priv->dfs_det_chk_timer.function = rtl8192cd_dfs_det_chk_timer;
|
|
mod_timer(&priv->dfs_det_chk_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(priv->pshare->rf_ft_var.dfs_det_period*10));
|
|
|
|
DFS_SetReg(priv);
|
|
RTL_W8(TXPAUSE, 0x00);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
if(scan_req_pending) {
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
realtek_cfg80211_scan(wiphy, scan_req_pending);
|
|
#else
|
|
realtek_cfg80211_scan(wiphy, dev, scan_req_pending);
|
|
#endif
|
|
}
|
|
|
|
if(ret){
|
|
NDEBUG("fail[%d]\n",ret);
|
|
}
|
|
|
|
NLEXIT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int realtek_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_ibss_params *ibss_param)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
|
|
if (!realtek_cfg80211_ready(priv))
|
|
return -EIO;
|
|
|
|
if ((OPMODE & WIFI_ADHOC_STATE) == 0)
|
|
return -EOPNOTSUPP;
|
|
|
|
//printk("Ad-Hoc join [%s] \n", ibss_param->ssid);
|
|
|
|
memcpy(SSID, ibss_param->ssid, ibss_param->ssid_len);
|
|
SSID_LEN = ibss_param->ssid_len;
|
|
|
|
realtek_reset_security(priv);
|
|
|
|
if (ibss_param->privacy)
|
|
{
|
|
realtek_auth_wep(priv, _WEP_40_PRIVACY_);
|
|
}
|
|
|
|
#if 0
|
|
if (ibss_param->chandef.chan)
|
|
{
|
|
realtek_cfg80211_set_channel(wiphy, dev, ibss_param->chandef.chan, ibss_param->channel_type);
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
|
|
if (ibss_param->channel_fixed) {
|
|
/*
|
|
* TODO: channel_fixed: The channel should be fixed, do not
|
|
* search for IBSSs to join on other channels. Target
|
|
* firmware does not support this feature, needs to be
|
|
* updated.
|
|
*/
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
|
|
if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
|
|
memcpy(vif->req_bssid, ibss_param->bssid,
|
|
sizeof(vif->req_bssid));
|
|
#endif
|
|
|
|
#if defined(CLIENT_MODE) && !defined(NON_NL80211_WPAS)
|
|
if(IS_VXD_INTERFACE(priv))
|
|
{
|
|
//printk("launch vxd_ibss_beacon timer !!\n");
|
|
construct_ibss_beacon(priv);
|
|
issue_beacon_ibss_vxd((unsigned long)priv);
|
|
}
|
|
|
|
priv->join_res = STATE_Sta_No_Bss;
|
|
start_clnt_lookup(priv, 1);
|
|
#endif
|
|
|
|
NLEXIT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int realtek_cfg80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
|
u8 *addr)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
static void realtek_cfg80211_rfkill_poll(struct wiphy *wiphy)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
|
|
NLENTER;
|
|
}
|
|
|
|
|
|
static int realtek_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
|
BOOLEAN enabled, int timeout)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
|
|
//not in ath6k
|
|
static int realtek_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
const u8 *addr,
|
|
const struct cfg80211_bitrate_mask *mask)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
NLNOT;
|
|
|
|
//printk("fixed=%d, maxrate=%d\n", mask->fixed, mask->maxrate); //mark_com
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int apply_acl_rules(struct rtl8192cd_priv *priv)
|
|
{
|
|
unsigned int i=0;
|
|
|
|
for (i=0; i<priv->pmib->dot11StationConfigEntry.dot11AclNum; i++)
|
|
{
|
|
struct list_head *pnewlist;
|
|
struct wlan_acl_node *paclnode;
|
|
|
|
pnewlist = priv->wlan_aclpolllist.next;
|
|
list_del_init(pnewlist);
|
|
|
|
paclnode = list_entry(pnewlist, struct wlan_acl_node, list);
|
|
memcpy((void *)paclnode->addr, priv->pmib->dot11StationConfigEntry.dot11AclAddr[i], MACADDRLEN);
|
|
paclnode->mode = (unsigned char)priv->pmib->dot11StationConfigEntry.dot11AclMode;
|
|
NDEBUG("[Drv]Sync MAC ACL entry[%d]: %02x:%02x:%02x:%02x:%02x:%02x,%s from MIB\n",i,
|
|
paclnode->addr[0],paclnode->addr[1],paclnode->addr[2],
|
|
paclnode->addr[3],paclnode->addr[4],paclnode->addr[5],
|
|
(paclnode->mode&1U)? "Allowed":"Denied");
|
|
list_add_tail(pnewlist, &priv->wlan_acl_list);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_reset_mac_acl(struct rtl8192cd_priv *priv)
|
|
{
|
|
int i, cnt = 0;
|
|
struct list_head *phead, *plist;
|
|
struct wlan_acl_node *paclnode;
|
|
#ifdef SMP_SYNC
|
|
unsigned long flags = 0;
|
|
#endif
|
|
|
|
for(i=0;i<priv->pmib->dot11StationConfigEntry.dot11AclNum;i++) {
|
|
NDEBUG("Reset MAC ACL entry[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",i,
|
|
priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][0],priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][1],
|
|
priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][2],priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][3],
|
|
priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][4],priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][5]);
|
|
memset(priv->pmib->dot11StationConfigEntry.dot11AclAddr[i],0,MACADDRLEN);
|
|
}
|
|
|
|
// clear list
|
|
phead = &priv->wlan_acl_list;
|
|
|
|
if (list_empty(phead)) // nothing to remove
|
|
goto exit;
|
|
|
|
SMP_LOCK_ACL(flags);
|
|
|
|
plist = phead->next;
|
|
|
|
while(plist != phead)
|
|
{
|
|
paclnode = list_entry(plist, struct wlan_acl_node, list);
|
|
plist = plist->next;
|
|
list_del_init(&paclnode->list);
|
|
list_add_tail(&paclnode->list, &priv->wlan_aclpolllist);
|
|
++cnt;
|
|
}
|
|
|
|
SMP_UNLOCK_ACL(flags);
|
|
|
|
exit:
|
|
priv->pmib->dot11StationConfigEntry.dot11AclNum = 0;
|
|
priv->pmib->dot11StationConfigEntry.dot11AclMode = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
static int realtek_set_mac_acl(struct wiphy *wiphy, struct net_device *dev,
|
|
const struct cfg80211_acl_data *params)
|
|
{
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
int i;
|
|
|
|
NLENTER;
|
|
|
|
realtek_reset_mac_acl(priv);
|
|
|
|
NDEBUG("MAC ACL mode:%s configured\n",(params->acl_policy&NL80211_ACL_POLICY_DENY_UNLESS_LISTED)? "Allow":"Deny");
|
|
priv->pmib->dot11StationConfigEntry.dot11AclMode = (params->acl_policy&NL80211_ACL_POLICY_DENY_UNLESS_LISTED)? 1:2;
|
|
|
|
for(i=0;i<params->n_acl_entries;i++) {
|
|
priv->pmib->dot11StationConfigEntry.dot11AclNum++;
|
|
memcpy(priv->pmib->dot11StationConfigEntry.dot11AclAddr[i],params->mac_addrs[i].addr,MACADDRLEN);
|
|
NDEBUG("Append MAC ACL entry[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",i,
|
|
priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][0],priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][1],
|
|
priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][2],priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][3],
|
|
priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][4],priv->pmib->dot11StationConfigEntry.dot11AclAddr[i][5]);
|
|
}
|
|
NDEBUG("MAC ACL total entry number:%d\n",priv->pmib->dot11StationConfigEntry.dot11AclNum);
|
|
|
|
apply_acl_rules(priv);
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
#if defined(DFS)
|
|
static int realtek_start_radar_detection (struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
struct cfg80211_chan_def *chandef,
|
|
u32 cac_time_ms)
|
|
{
|
|
int ret=0;
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, NULL);
|
|
int channel = 0;
|
|
|
|
NLENTER;
|
|
|
|
/*fixme, should not enable carrier here.
|
|
Under mac80211 architecture will be invoked by compatible-wireless */
|
|
netif_carrier_on(priv->dev);
|
|
|
|
if(priv->pshare->dfs_chan_def) {
|
|
if(priv->pshare->dfs_chan_def->chan)
|
|
kfree(priv->pshare->dfs_chan_def->chan);
|
|
|
|
kfree(priv->pshare->dfs_chan_def);
|
|
}
|
|
|
|
priv->pshare->dfs_chan_def = (struct cfg80211_chan_def *)kmalloc(sizeof(*chandef), GFP_KERNEL);
|
|
if(priv->pshare->dfs_chan_def)
|
|
memset(priv->pshare->dfs_chan_def, 0, sizeof(*chandef));
|
|
else
|
|
return -1;
|
|
|
|
priv->pshare->dfs_chan_def->chan = (struct ieee80211_channel *)kmalloc(sizeof(struct ieee80211_channel), GFP_KERNEL);
|
|
if(priv->pshare->dfs_chan_def->chan)
|
|
memset(priv->pshare->dfs_chan_def->chan, 0, sizeof(struct ieee80211_channel));
|
|
else
|
|
return -1;
|
|
|
|
//backup chandef for DFS report
|
|
memcpy(priv->pshare->dfs_chan_def,chandef,sizeof(*chandef));
|
|
memcpy(priv->pshare->dfs_chan_def->chan,chandef->chan,sizeof(struct ieee80211_channel));
|
|
|
|
channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
|
|
|
|
NDEBUG3("center_freq=[%u] channel=[%d] hw_value=[%u] bandwidth=[%d]\n",
|
|
chandef->chan->center_freq, channel, chandef->chan->hw_value, chandef->width);
|
|
|
|
priv->pmib->dot11RFEntry.dot11channel = channel;
|
|
|
|
rtk_set_band_mode(priv,chandef->chan->band , chandef->width);
|
|
rtk_set_channel_mode(priv,chandef);
|
|
SwChnl(priv, channel, priv->pmib->dot11nConfigEntry.dot11n2ndChOffset);
|
|
|
|
init_timer(&priv->ch_avail_chk_timer);
|
|
priv->ch_avail_chk_timer.data = (unsigned long) priv;
|
|
priv->ch_avail_chk_timer.function = rtl8192cd_ch_avail_chk_timer;
|
|
mod_timer(&priv->ch_avail_chk_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(cac_time_ms));
|
|
printk("*** [%s]Activate DFS-CAC for %d miliseconds ***\n",priv->dev->name,cac_time_ms);
|
|
|
|
init_timer(&priv->DFS_timer);
|
|
priv->DFS_timer.data = (unsigned long) priv;
|
|
priv->DFS_timer.function = rtl8192cd_DFS_timer;
|
|
|
|
init_timer(&priv->DFS_TXPAUSE_timer);
|
|
priv->DFS_TXPAUSE_timer.data = (unsigned long) priv;
|
|
priv->DFS_TXPAUSE_timer.function = rtl8192cd_DFS_TXPAUSE_timer;
|
|
|
|
/* DFS activated after 5 sec; prevent switching channel due to DFS false alarm */
|
|
mod_timer(&priv->DFS_timer, jiffies + RTL_SECONDS_TO_JIFFIES(5));
|
|
|
|
init_timer(&priv->dfs_det_chk_timer);
|
|
priv->dfs_det_chk_timer.data = (unsigned long) priv;
|
|
priv->dfs_det_chk_timer.function = rtl8192cd_dfs_det_chk_timer;
|
|
mod_timer(&priv->dfs_det_chk_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(priv->pshare->rf_ft_var.dfs_det_period*10));
|
|
|
|
DFS_SetReg(priv);
|
|
|
|
if (!priv->pmib->dot11DFSEntry.CAC_enable) {
|
|
del_timer_sync(&priv->ch_avail_chk_timer);
|
|
mod_timer(&priv->ch_avail_chk_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(200));
|
|
}
|
|
|
|
priv->pmib->dot11DFSEntry.disable_tx = 1;
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void copy_bss_ie(struct rtl8192cd_priv *priv, int ix)
|
|
{
|
|
int wpa_ie_len = priv->site_survey->bss[ix].wpa_ie_len;
|
|
int rsn_ie_len = priv->site_survey->bss[ix].rsn_ie_len;
|
|
|
|
priv->rtk->clnt_info.wpa_ie.wpa_ie_len = wpa_ie_len;
|
|
memcpy(priv->rtk->clnt_info.wpa_ie.data, priv->site_survey->bss[ix].wpa_ie, wpa_ie_len);
|
|
|
|
priv->rtk->clnt_info.rsn_ie.rsn_ie_len = rsn_ie_len;
|
|
memcpy(priv->rtk->clnt_info.rsn_ie.data, priv->site_survey->bss[ix].rsn_ie, rsn_ie_len);
|
|
}
|
|
|
|
int get_bss_by_bssid(struct rtl8192cd_priv *priv, unsigned char* bssid, unsigned int bssdb_count, struct bss_desc *bssdb)
|
|
{
|
|
int ix = 0, found = 0;
|
|
|
|
STADEBUG("count = %d %02x:%02x:%02x:%02x:%02x:%02x\n", bssdb_count, bssid[0],bssid[1],bssid[2],bssid[3],bssid[4],bssid[5]);
|
|
//dump_mac(priv, bssid);
|
|
|
|
for(ix = 0 ; ix < bssdb_count ; ix++) //_Eric ?? will bss_backup be cleaned?? -> Not found in codes
|
|
{
|
|
STADEBUG("[%d]Match %02x:%02x:%02x:%02x:%02x:%02x with %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
ix,bssdb[ix].bssid[0],bssdb[ix].bssid[1],
|
|
bssdb[ix].bssid[2],bssdb[ix].bssid[3],
|
|
bssdb[ix].bssid[4],bssdb[ix].bssid[5],
|
|
bssid[0],bssid[1],bssid[2],bssid[3],bssid[4],bssid[5]);
|
|
|
|
if(!memcmp(bssdb[ix].bssid , bssid, 6))
|
|
{
|
|
found = 1;
|
|
copy_bss_ie(priv, ix);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(found == 0)
|
|
{
|
|
STADEBUG("%s BSSID NOT Found !!\n",__func__);
|
|
return -EINVAL;
|
|
}
|
|
else
|
|
return ix;
|
|
|
|
}
|
|
|
|
|
|
int get_bss_by_ssid(struct rtl8192cd_priv *priv, const char* ssid, int ssid_len, unsigned int bssdb_count, struct bss_desc *bssdb)
|
|
{
|
|
int ix = 0, found = 0;
|
|
|
|
STADEBUG("count[%d] ssid[%s]\n", bssdb_count, ssid);
|
|
|
|
for(ix = 0 ; ix < bssdb_count ; ix++) //_Eric ?? will bss_backup be cleaned?? -> Not found in codes
|
|
{
|
|
STADEBUG("[%d]Match %s to %s\n", ix, bssdb[ix].ssid, ssid);
|
|
if( ! memcmp(bssdb[ix].ssid , ssid, ssid_len) )
|
|
{
|
|
found = 1;
|
|
copy_bss_ie(priv, ix);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(found == 0)
|
|
{
|
|
STADEBUG("SSID NOT Found !!\n");
|
|
return -EINVAL;
|
|
}
|
|
else
|
|
return ix;
|
|
|
|
}
|
|
|
|
void vxd_copy_ss_result_from_root(struct rtl8192cd_priv *priv)
|
|
{
|
|
struct rtl8192cd_priv *priv_root = GET_ROOT(priv);
|
|
|
|
priv->site_survey->count_backup = priv_root->site_survey->count_backup;
|
|
memcpy(priv->site_survey->bss_backup, priv_root->site_survey->bss_backup,
|
|
sizeof(struct bss_desc)*priv_root->site_survey->count_backup);
|
|
}
|
|
|
|
void vxd_copy_ss_result_to_target(struct rtl8192cd_priv *priv)
|
|
{
|
|
priv->site_survey->count_target = priv->site_survey->count_backup;
|
|
|
|
memcpy(priv->site_survey->bss_target, priv->site_survey->bss_backup,
|
|
sizeof(struct bss_desc)*priv->site_survey->count_backup);
|
|
}
|
|
|
|
static int realtek_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
|
struct cfg80211_connect_params *sme)
|
|
{
|
|
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
unsigned int bssdb_count=0;
|
|
struct bss_desc *bssdb=NULL;
|
|
int bss_num = -1;
|
|
int ret = 0;
|
|
|
|
NLENTER;
|
|
|
|
if(dev){
|
|
//dump_mac(priv, GET_MY_HWADDR);
|
|
}
|
|
#ifdef UNIVERSAL_REPEATER //wrt-vxd
|
|
if((!IS_ROOT_INTERFACE(priv)) && (!IS_VXD_INTERFACE(priv)))
|
|
#else
|
|
if(!IS_ROOT_INTERFACE(priv))
|
|
#endif
|
|
{
|
|
NDEBUG("vap can not connect, switch to root\n");
|
|
priv = GET_ROOT(priv);
|
|
}
|
|
|
|
if (!realtek_cfg80211_ready(priv)){
|
|
NDEBUG3("return!\n");
|
|
return -EIO;
|
|
}
|
|
|
|
#if 1 //wrt_clnt
|
|
if((OPMODE & WIFI_STATION_STATE) == 0)
|
|
{
|
|
printk("NOT in Client Mode, can NOT Associate !!!\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
//rtk_abort_scan(priv);
|
|
|
|
priv->receive_connect_cmd = 1;
|
|
|
|
#if 1 //wrt-wps-clnt
|
|
priv->pmib->wscEntry.assoc_ielen = 0;
|
|
priv->pmib->wscEntry.wsc_enable = 0;
|
|
|
|
if (sme->ie && (sme->ie_len > 0)) {
|
|
NDEBUG("ie from cfg,len=[%d]\n", sme->ie_len);
|
|
/*set WPS P2P IE to Assoc_Req*/
|
|
rtk_cfg80211_set_wps_p2p_ie(priv, sme->ie, sme->ie_len, MGMT_ASSOCREQ);
|
|
}
|
|
|
|
if(priv->pmib->wscEntry.wsc_enable)
|
|
priv->wps_issue_join_req = 1;
|
|
#endif
|
|
|
|
//=== check parameters
|
|
if((sme->bssid == NULL) && (sme->ssid == NULL))
|
|
{
|
|
NDEBUG("No bssid&ssid from request !!!\n");
|
|
return -1;
|
|
}
|
|
|
|
if(OPMODE & WIFI_STATION_STATE) {
|
|
bssdb_count = priv->site_survey->count_target;
|
|
bssdb = priv->site_survey->bss_target;
|
|
} else {
|
|
bssdb_count = priv->site_survey->count_backup;
|
|
bssdb = priv->site_survey->bss_backup;
|
|
}
|
|
|
|
if(sme->bssid) {
|
|
bss_num = get_bss_by_bssid(priv, sme->bssid, bssdb_count, bssdb);
|
|
} else if(sme->ssid) { //?? channel parameter check ??
|
|
bss_num = get_bss_by_ssid(priv, sme->ssid, sme->ssid_len, bssdb_count, bssdb);
|
|
} else {
|
|
NDEBUG("Unknown rule to search BSS!!\n");
|
|
return -1;
|
|
}
|
|
|
|
if(bss_num < 0)
|
|
{
|
|
NDEBUG("Can not found this bss from SiteSurvey result!!\n");
|
|
return -1;
|
|
}
|
|
|
|
priv->ss_req_ongoing = 0; //found bss, no need to scan ...
|
|
|
|
//=== set security
|
|
realtek_reset_security(priv);
|
|
|
|
realtek_set_security_cli(priv, rtk, sme);
|
|
|
|
if(priv->pmib->dot1180211AuthEntry.dot11EnablePSK) {
|
|
nl80211_psk_init(priv); // rsn_init(priv);
|
|
}
|
|
|
|
//=== set key (for wep only)
|
|
if(sme->key_len &&
|
|
(rtk->cipher & (BIT(_WEP_40_PRIVACY_) | BIT(_WEP_104_PRIVACY_))))
|
|
{
|
|
NDEBUG2("Set wep key to connect ! \n");
|
|
|
|
if(rtk->cipher & BIT(_WEP_40_PRIVACY_))
|
|
{
|
|
priv->pmib->dot11GroupKeysTable.dot11Privacy = DOT11_ENC_WEP40;
|
|
|
|
}
|
|
else if(rtk->cipher & BIT(_WEP_104_PRIVACY_))
|
|
{
|
|
priv->pmib->dot11GroupKeysTable.dot11Privacy = DOT11_ENC_WEP104;
|
|
|
|
}
|
|
|
|
memcpy(&priv->pmib->dot11DefaultKeysTable.keytype[sme->key_idx].skey[0], sme->key, sme->key_len);
|
|
|
|
priv->pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKeyLen = sme->key_len;
|
|
memcpy(&priv->pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKey.skey[0], sme->key, sme->key_len);
|
|
|
|
if(sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
|
|
priv->pmib->dot1180211AuthEntry.dot11AuthAlgrthm = 1;
|
|
}
|
|
|
|
syncMulticastCipher(priv, &bssdb[bss_num]); /*eric refine 23277*/
|
|
|
|
if((OPMODE&(WIFI_AUTH_SUCCESS|WIFI_ASOC_STATE))==(WIFI_AUTH_SUCCESS|WIFI_ASOC_STATE)) {
|
|
NDEBUG3("try issue deauth to...\n");
|
|
if(memcmp(priv->pmib->dot11StationConfigEntry.dot11Bssid , bssdb[bss_num].bssid , 6)==0) {
|
|
NDEBUG3("issue deauth to...\n");
|
|
//dump_mac(priv,priv->site_survey->bss_target[bss_num].bssid);
|
|
issue_deauth(priv,priv->site_survey->bss_target[bss_num].bssid,_RSON_DEAUTH_STA_LEAVING_);
|
|
OPMODE &= (~(WIFI_AUTH_SUCCESS|WIFI_ASOC_STATE)) ;
|
|
}
|
|
}
|
|
|
|
#ifdef CLIENT_MODE
|
|
//=== connect
|
|
ret = rtl_wpas_join(priv, bss_num);
|
|
#endif
|
|
|
|
NLEXIT;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int realtek_cfg80211_disconnect(struct wiphy *wiphy,
|
|
struct net_device *dev, u16 reason_code)
|
|
{
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
//rtk_abort_scan(priv);
|
|
|
|
event_indicate_cfg80211(priv, NULL, CFG80211_DISCONNECTED, NULL);
|
|
|
|
if(IS_VXD_INTERFACE(priv))
|
|
rtl8192cd_close(priv->dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0)
|
|
static int realtek_cfg80211_channel_switch(struct wiphy *wiphy,
|
|
struct net_device *dev, struct cfg80211_csa_settings *params)
|
|
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = realtek_get_priv(wiphy, dev);
|
|
|
|
NLENTER;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static void realtek_mgmt_frame_register(struct wiphy *wiphy,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct wireless_dev *wdev,
|
|
#else
|
|
struct net_device *wdev,
|
|
#endif
|
|
u16 frame_type, bool reg)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#else
|
|
struct rtl8192cd_priv *priv = GET_DEV_PRIV(wdev);
|
|
#endif
|
|
if ((frame_type == IEEE80211_STYPE_PROBE_REQ) && (OPMODE & WIFI_AP_STATE))
|
|
priv->probe_req_report = reg;
|
|
}
|
|
|
|
static struct device_type wiphy_type = {
|
|
.name = "wlan",
|
|
};
|
|
|
|
|
|
int register_netdevice_name_rtk(struct net_device *dev)
|
|
{
|
|
int err;
|
|
|
|
if (strchr(dev->name, '%')) {
|
|
err = dev_alloc_name(dev, dev->name);
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
|
|
return register_netdevice(dev);
|
|
}
|
|
|
|
#if 1 //wrt-vap
|
|
|
|
static int realtek_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
|
|
{
|
|
switch (type) {
|
|
case NL80211_IFTYPE_STATION:
|
|
//case NL80211_IFTYPE_P2P_CLIENT:
|
|
*nw_type = INFRA_NETWORK;
|
|
break;
|
|
case NL80211_IFTYPE_ADHOC:
|
|
*nw_type = ADHOC_NETWORK;
|
|
break;
|
|
case NL80211_IFTYPE_AP:
|
|
//case NL80211_IFTYPE_P2P_GO:
|
|
*nw_type = AP_NETWORK;
|
|
break;
|
|
default:
|
|
printk("invalid interface type %u\n", type);
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool realtek_is_valid_iftype(struct rtknl *rtk, enum nl80211_iftype type,
|
|
u8 *if_idx, u8 *nw_type)
|
|
{
|
|
if (realtek_nliftype_to_drv_iftype(type, nw_type))
|
|
return false;
|
|
|
|
if ( type == NL80211_IFTYPE_AP
|
|
|| type == NL80211_IFTYPE_STATION
|
|
|| type == NL80211_IFTYPE_ADHOC
|
|
#if defined(P2P_SUPPORT)
|
|
|| type == NL80211_IFTYPE_P2P_CLIENT
|
|
|| type == NL80211_IFTYPE_P2P_GO
|
|
|| type == NL80211_IFTYPE_P2P_DEVICE
|
|
#endif
|
|
) //wrt-adhoc
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
char check_vif_existed(struct rtl8192cd_priv *priv, struct rtknl *rtk, unsigned char *name)
|
|
{
|
|
int tmp = 0;
|
|
|
|
for(tmp =0; tmp < VIF_NUM; tmp++)
|
|
{
|
|
if(!strcmp(name, rtk->ndev_name[tmp]))
|
|
{
|
|
printk("%s = %s, existed in vif[%d]\n", name, rtk->ndev_name[tmp], tmp);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned char check_vif_type_match(struct rtl8192cd_priv *priv, unsigned char is_vxd)
|
|
{
|
|
unsigned char ret = 0;
|
|
|
|
NDEBUG3("priv[%p],(root=%d vxd=%d vap=%d)\n", priv, IS_ROOT_INTERFACE(priv), IS_VXD_INTERFACE(priv), IS_VAP_INTERFACE(priv));
|
|
#ifdef MBSSID
|
|
NDEBUG3("proot_priv[%p],vap_id[%d]\n", priv->proot_priv, priv->vap_id);
|
|
#endif
|
|
|
|
if(is_vxd && IS_VXD_INTERFACE(priv))
|
|
ret = 1;
|
|
|
|
if((!is_vxd) && IS_VAP_INTERFACE(priv))
|
|
ret = 1;
|
|
|
|
if(ret){
|
|
NDEBUG2("is_vxd[%d],type OK \n", is_vxd);
|
|
}else{
|
|
NDEBUG2("is_vxd[%d],type NOT match \n", is_vxd);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void rtk_change_netdev_name(struct rtl8192cd_priv *priv, unsigned char *name)
|
|
{
|
|
#if 1
|
|
printk("rtk_change_netdev_name for priv = %p (root=%d vxd=%d vap=%d) +++ \n",
|
|
priv, IS_ROOT_INTERFACE(priv), IS_VXD_INTERFACE(priv), IS_VAP_INTERFACE(priv));
|
|
printk("from %s to %s \n", priv->dev->name, name);
|
|
#else
|
|
dev_change_name(priv->dev, name); //Need to modify kernel code to export this API
|
|
#endif
|
|
}
|
|
|
|
struct rtl8192cd_priv* get_priv_vxd_from_rtk(struct rtknl *rtk)
|
|
{
|
|
struct rtl8192cd_priv *priv = NULL;
|
|
int tmp = 0;
|
|
|
|
for(tmp = 0; tmp<(IF_NUM); tmp++)
|
|
{
|
|
if(rtk->rtk_iface[tmp].priv)
|
|
if(IS_VXD_INTERFACE(rtk->rtk_iface[tmp].priv))
|
|
{
|
|
priv = rtk->rtk_iface[tmp].priv;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//printk("name = %s priv_vxd = 0x%x \n", priv->dev->name, priv);
|
|
|
|
return priv;
|
|
}
|
|
|
|
struct rtl8192cd_priv* get_priv_from_rtk(struct rtknl *rtk, const char *name)
|
|
{
|
|
struct rtl8192cd_priv *priv = NULL;
|
|
int tmp = 0;
|
|
|
|
for(tmp = 0; tmp<(IF_NUM); tmp++)
|
|
{
|
|
if(rtk->rtk_iface[tmp].priv)
|
|
if(!strcmp(rtk->rtk_iface[tmp].priv->dev->name, name))
|
|
{
|
|
priv = rtk->rtk_iface[tmp].priv;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if(priv) //rtk_vap
|
|
printk("get_priv_from_rtk name = %s priv = 0x%x %s\n", name, priv, priv->dev->name);
|
|
else
|
|
printk("get_priv_from_rtk = NULL !!\n");
|
|
#endif
|
|
|
|
return priv;
|
|
}
|
|
|
|
|
|
struct rtl8192cd_priv* get_priv_from_ndev(struct rtknl *rtk, struct net_device *ndev)
|
|
{
|
|
struct rtl8192cd_priv *priv = NULL;
|
|
int tmp = 0;
|
|
|
|
for(tmp = 0; tmp<(IF_NUM); tmp++)
|
|
{
|
|
if(rtk->rtk_iface[tmp].priv)
|
|
if(ndev == rtk->rtk_iface[tmp].priv->dev)
|
|
{
|
|
priv = rtk->rtk_iface[tmp].priv;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//printk("ndev = 0x%x priv = 0x%x \n", ndev, priv);
|
|
|
|
return priv;
|
|
}
|
|
|
|
void rtk_add_priv(struct rtl8192cd_priv *priv_add, struct rtknl *rtk)
|
|
{
|
|
int tmp = 0;
|
|
|
|
for(tmp = 0; tmp<(IF_NUM); tmp++)
|
|
{
|
|
if(rtk->rtk_iface[tmp].priv == NULL)
|
|
{
|
|
rtk->rtk_iface[tmp].priv = priv_add;
|
|
strcpy(rtk->rtk_iface[tmp].ndev_name, priv_add->dev->name); /*eric refine 23390*/
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void rtk_del_priv(struct rtl8192cd_priv *priv_del, struct rtknl *rtk)
|
|
{
|
|
int tmp = 0;
|
|
|
|
for(tmp = 0; tmp<(IF_NUM); tmp++)
|
|
{
|
|
if(rtk->rtk_iface[tmp].priv == priv_del)
|
|
{
|
|
rtk->rtk_iface[tmp].priv = NULL;
|
|
memset(rtk->rtk_iface[tmp].ndev_name, 0, 32);/*eric refine 23390*/
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned char find_ava_vif_idx(struct rtknl *rtk)
|
|
{
|
|
unsigned char idx = 0;
|
|
|
|
for(idx = 0; idx < VIF_NUM; idx ++)
|
|
{
|
|
if(rtk->ndev_name[idx][0] == 0)
|
|
return idx;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
unsigned char get_vif_idx(struct rtknl *rtk, unsigned char *name)
|
|
{
|
|
unsigned char idx = 0;
|
|
|
|
for(idx = 0; idx < VIF_NUM; idx ++)
|
|
{
|
|
if(rtk->ndev_name[idx][0] != 0)
|
|
if(strcmp(name, rtk->ndev_name[idx])==0)
|
|
return idx;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
void realtek_create_vap_iface(struct rtknl *rtk, unsigned char *name)
|
|
{
|
|
struct rtl8192cd_priv *priv = rtk->priv;
|
|
|
|
if(check_vif_existed(priv, rtk, name))
|
|
{
|
|
printk("vif interface already existed !! \n");
|
|
return;
|
|
}
|
|
|
|
if (rtk->num_vif == VIF_NUM)
|
|
{
|
|
printk("Reached maximum number of supported vif\n");
|
|
return;
|
|
}
|
|
|
|
rtk->idx_vif = find_ava_vif_idx(rtk);
|
|
|
|
printk("rtk->idx_vif = %d\n", rtk->idx_vif);
|
|
|
|
if(rtk->idx_vif < 0)
|
|
{
|
|
printk("rtk->idx_vif < 0 \n");
|
|
return;
|
|
}
|
|
|
|
if(name){
|
|
if(dev_valid_name(name))
|
|
strcpy(rtk->ndev_name[rtk->idx_vif], name);
|
|
}
|
|
else
|
|
{
|
|
printk("No interface name !!\n");
|
|
return;
|
|
}
|
|
|
|
rtl8192cd_init_one_cfg80211(rtk);
|
|
rtk->num_vif++;
|
|
}
|
|
|
|
#endif
|
|
|
|
int realtek_interface_add(struct rtl8192cd_priv *priv,
|
|
struct rtknl *rtk, const char *name,
|
|
enum nl80211_iftype type,
|
|
u8 fw_vif_idx, u8 nw_type)
|
|
{
|
|
struct net_device *ndev;
|
|
|
|
NLENTER;
|
|
|
|
NDEBUG("type[%d]\n", type);
|
|
|
|
ndev = priv->dev;
|
|
|
|
//dump_mac(priv, ndev->dev_addr);
|
|
|
|
if (!ndev)
|
|
{
|
|
NDEBUG("ndev = NULL !!\n");
|
|
free_netdev(ndev);
|
|
return -1;
|
|
}
|
|
|
|
strcpy(ndev->name, name);
|
|
realtek_change_iftype(priv, type);
|
|
|
|
dev_net_set(ndev, wiphy_net(rtk->wiphy));
|
|
|
|
priv->wdev.wiphy = rtk->wiphy;
|
|
|
|
ndev->ieee80211_ptr = &priv->wdev;
|
|
|
|
SET_NETDEV_DEV(ndev, wiphy_dev(rtk->wiphy));
|
|
|
|
priv->wdev.netdev = ndev;
|
|
priv->wdev.iftype = type;
|
|
|
|
SET_NETDEV_DEVTYPE(ndev, &wiphy_type);
|
|
|
|
priv->cfg80211_interface_add = FALSE;
|
|
priv->is_cfg80211_iface = 1;
|
|
|
|
register_netdev(ndev);
|
|
|
|
#if 0
|
|
if(IS_ROOT_INTERFACE(priv))
|
|
register_netdev(ndev);
|
|
#ifdef UNIVERSAL_REPEATER //wrt-vxd
|
|
else if(IS_VXD_INTERFACE(priv))
|
|
register_netdev(ndev);
|
|
#endif
|
|
else
|
|
register_netdevice_name_rtk(ndev);
|
|
#endif
|
|
|
|
rtk->ndev_add = ndev;
|
|
|
|
NDEBUG2(" priv=[%p] wdev=[%p] ndev=[%p] rtk=[%p]\n", priv, &priv->wdev, ndev, rtk);
|
|
rtk_add_priv(priv, rtk);
|
|
|
|
NLEXIT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int realtek_interface_del(struct rtl8192cd_priv *priv, struct rtknl *rtk, struct net_device *ndev)
|
|
{
|
|
NDEBUG2(" priv=[%p] wdev=[%p] ndev=[%p] rtk=[%p]\n", priv, &priv->wdev, ndev, rtk);
|
|
|
|
unregister_netdev(ndev);
|
|
|
|
//SET_NETDEV_DEVTYPE(ndev, NULL);
|
|
|
|
dev_net_set(ndev, NULL);
|
|
|
|
rtk_del_priv(priv, rtk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef SUPPORT_MONITOR
|
|
void rtk_enable_monitor_mode(struct rtl8192cd_priv *priv)
|
|
{
|
|
//if(priv->pmib->miscEntry.scan_enable)
|
|
priv->chan_num = 0;
|
|
|
|
priv->is_monitor_mode = TRUE;
|
|
RTL_W32(RCR, RCR_APP_FCS | RCR_APP_MIC | RCR_APP_ICV | RCR_APP_PHYSTS | RCR_HTC_LOC_CTRL
|
|
| RCR_AMF | RCR_ADF | RCR_AICV | RCR_ACRC32 | RCR_CBSSID_ADHOC | RCR_AB | RCR_AM | RCR_APM | RCR_AAP);
|
|
|
|
init_timer(&priv->chan_switch_timer);
|
|
priv->chan_switch_timer.data = (unsigned long) priv;
|
|
priv->chan_switch_timer.function = rtl8192cd_chan_switch_timer;
|
|
mod_timer(&priv->chan_switch_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(priv->pmib->miscEntry.chan_switch_time));
|
|
}
|
|
|
|
void rtk_disable_monitor_mode(struct rtl8192cd_priv *priv)
|
|
{
|
|
priv->is_monitor_mode = FALSE;
|
|
if (timer_pending(&priv->chan_switch_timer))
|
|
del_timer(&priv->chan_switch_timer);
|
|
}
|
|
#endif
|
|
|
|
void realtek_change_iftype(struct rtl8192cd_priv *priv ,enum nl80211_iftype type)
|
|
{
|
|
//OPMODE &= ~(WIFI_STATION_STATE|WIFI_ADHOC_STATE|WIFI_AP_STATE);
|
|
#if defined(P2P_SUPPORT)
|
|
if(IS_ROOT_INTERFACE(priv) && IS_DRV_OPEN(priv)) {
|
|
if(type != NL80211_IFTYPE_P2P_CLIENT)
|
|
rtl8192cd_close(priv->dev);
|
|
}
|
|
#endif
|
|
switch (type) {
|
|
case NL80211_IFTYPE_STATION:
|
|
OPMODE = WIFI_STATION_STATE;
|
|
priv->pmib->p2p_mib.p2p_enabled=0;
|
|
priv->wdev.iftype = type;
|
|
_NDEBUG("switch to [NL80211_IFTYPE_STATION]\n");
|
|
break;
|
|
case NL80211_IFTYPE_ADHOC:
|
|
OPMODE = WIFI_ADHOC_STATE;
|
|
priv->wdev.iftype = type;
|
|
priv->pmib->p2p_mib.p2p_enabled=0;
|
|
_NDEBUG("switch to [NL80211_IFTYPE_ADHOC]\n");
|
|
break;
|
|
case NL80211_IFTYPE_AP:
|
|
OPMODE = WIFI_AP_STATE;
|
|
priv->wdev.beacon_interval = 0;
|
|
priv->pmib->miscEntry.func_off = 1;
|
|
priv->pmib->p2p_mib.p2p_enabled=0;
|
|
priv->wdev.iftype = type;
|
|
#ifdef SUPPORT_MONITOR
|
|
rtk_disable_monitor_mode(priv);
|
|
#endif
|
|
#if defined(DFS)
|
|
/*fixme, should not disable carrier here.
|
|
Under mac80211 architecture will be invoked by compatible-wireless */
|
|
netif_carrier_off(priv->dev);
|
|
#endif
|
|
_NDEBUG("switch to [NL80211_IFTYPE_AP]\n");
|
|
break;
|
|
#if defined(P2P_SUPPORT)
|
|
case NL80211_IFTYPE_P2P_CLIENT:
|
|
OPMODE = (WIFI_STATION_STATE );
|
|
rtk_p2p_set_role(priv,P2P_DEVICE);
|
|
priv->pmib->p2p_mib.p2p_enabled=CFG80211_P2P;
|
|
priv->wdev.iftype = type;
|
|
_NDEBUG("switch to [NL80211_IFTYPE_P2P_CLIENT]\n");
|
|
break;
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
OPMODE = (WIFI_AP_STATE );
|
|
rtk_p2p_set_role(priv,P2P_TMP_GO);
|
|
priv->pmib->p2p_mib.p2p_enabled=CFG80211_P2P;
|
|
priv->wdev.iftype = type;
|
|
_NDEBUG("switch to [NL80211_IFTYPE_P2P_GO]\n");
|
|
break;
|
|
|
|
case NL80211_IFTYPE_P2P_DEVICE:
|
|
OPMODE = (WIFI_STATION_STATE);
|
|
rtk_p2p_set_role(priv,P2P_DEVICE);
|
|
priv->pmib->p2p_mib.p2p_enabled=CFG80211_P2P;
|
|
priv->wdev.iftype = type;
|
|
_NDEBUG("switch to [NL80211_IFTYPE_P2P_DEVICE]\n");
|
|
break;
|
|
#endif
|
|
#ifdef SUPPORT_MONITOR
|
|
case NL80211_IFTYPE_MONITOR:
|
|
OPMODE = (WIFI_SITE_MONITOR);
|
|
priv->wdev.iftype = type;
|
|
priv->pmib->p2p_mib.p2p_enabled=0;
|
|
rtk_enable_monitor_mode(priv);
|
|
_NDEBUG("switch to [NL80211_IFTYPE_MONITOR]\n");
|
|
break;
|
|
#endif
|
|
default:
|
|
NDEBUG("invalid interface type [%d]\n", type);
|
|
OPMODE = WIFI_AP_STATE;
|
|
}
|
|
}
|
|
|
|
void type_to_name(enum nl80211_iftype type, unsigned char* type_name)
|
|
{
|
|
switch (type) {
|
|
case NL80211_IFTYPE_STATION:
|
|
strcpy(type_name, "NL80211_IFTYPE_STATION");
|
|
break;
|
|
case NL80211_IFTYPE_ADHOC:
|
|
strcpy(type_name, "NL80211_IFTYPE_ADHOC");
|
|
break;
|
|
case NL80211_IFTYPE_AP:
|
|
strcpy(type_name, "NL80211_IFTYPE_AP");
|
|
break;
|
|
case NL80211_IFTYPE_P2P_CLIENT:
|
|
strcpy(type_name, "NL80211_IFTYPE_P2P_CLIENT");
|
|
break;
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
strcpy(type_name, "NL80211_IFTYPE_P2P_GO");
|
|
break;
|
|
case NL80211_IFTYPE_MONITOR:
|
|
strcpy(type_name, "NL80211_IFTYPE_MONITOR");
|
|
break;
|
|
default:
|
|
strcpy(type_name, "NOT SUPPORT TYPE");
|
|
}
|
|
}
|
|
|
|
static struct wireless_dev *realtek_cfg80211_add_iface(struct wiphy *wiphy,
|
|
const char *name,
|
|
enum nl80211_iftype type,
|
|
u32 *flags,
|
|
struct vif_params *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy); //return &wiphy->priv;
|
|
struct rtl8192cd_priv *priv = rtk->priv;
|
|
struct rtl8192cd_priv *priv_add = NULL;
|
|
unsigned char type_name[32];
|
|
|
|
NLENTER;
|
|
|
|
type_to_name(type, type_name);
|
|
NLMSG("ADD [%s][%s=%d]\n", name, type_name, type);
|
|
|
|
#if 0//def WDS
|
|
if(params)
|
|
{
|
|
printk("use_4addr = %d \n", params->use_4addr);
|
|
}
|
|
#endif
|
|
|
|
if((strcmp(name, "wlan0")==0) || (strcmp(name, "wlan1")==0))
|
|
{
|
|
NLMSG("Root interface, just change type: %d\n", type);
|
|
priv->cfg80211_interface_add = TRUE;
|
|
realtek_change_iftype(priv, type);
|
|
return &rtk->priv->wdev;
|
|
}
|
|
|
|
priv_add = get_priv_from_rtk(rtk, name);
|
|
|
|
if(priv_add)
|
|
{
|
|
unsigned char type_match = 0;
|
|
unsigned char is_vxd = 0;
|
|
|
|
if(is_WRT_scan_iface(name))
|
|
{
|
|
printk("Add Scan interface, do nothing\n");
|
|
return &priv_add->wdev;
|
|
}
|
|
|
|
if(type == NL80211_IFTYPE_AP)
|
|
{
|
|
is_vxd = 0;
|
|
rtk->num_vap ++ ;
|
|
}
|
|
else
|
|
{
|
|
is_vxd = 1;
|
|
rtk->num_vxd = 1;
|
|
}
|
|
|
|
type_match = check_vif_type_match(priv_add, is_vxd);
|
|
|
|
if(!type_match)
|
|
{
|
|
unsigned char name_vxd[32];
|
|
unsigned char name_vap[32];
|
|
unsigned char name_tmp[32];
|
|
struct rtl8192cd_priv *priv_vxd = NULL;
|
|
struct rtl8192cd_priv *priv_vap = NULL;
|
|
struct rtl8192cd_priv *priv_tmp = NULL;
|
|
|
|
printk("Type NOT Match !!! need to change name\n");
|
|
|
|
if(is_vxd)
|
|
{
|
|
priv_vap = priv_add;
|
|
priv_vxd = get_priv_vxd_from_rtk(rtk);
|
|
}
|
|
else
|
|
{
|
|
sprintf(name_vap, "%s-%d", rtk->priv->dev->name, (RTL8192CD_NUM_VWLAN));
|
|
priv_vap = get_priv_from_rtk(rtk, name_vap);
|
|
priv_vxd = priv_add;
|
|
}
|
|
|
|
sprintf(name_tmp, "%s-%d", rtk->priv->dev->name, (RTL8192CD_NUM_VWLAN+10));
|
|
|
|
strcpy(name_vap, priv_vap->dev->name);
|
|
strcpy(name_vxd, priv_vxd->dev->name);
|
|
|
|
#if 0
|
|
printk(" [BEFORE] +++ \n");
|
|
printk("VAP = 0x%x(0x%x) name=%s \n", priv_vap, priv_vap->dev, priv_vap->dev->name);
|
|
printk("VXD = 0x%x(0x%x) name=%s \n", priv_vxd, priv_vxd->dev, priv_vxd->dev->name);
|
|
#endif
|
|
|
|
rtk_change_netdev_name(priv_vap, name_tmp);
|
|
rtk_change_netdev_name(priv_vxd, name_vap);
|
|
rtk_change_netdev_name(priv_vap, name_vxd);
|
|
|
|
#if 0
|
|
printk(" [AFTER] --- \n");
|
|
printk("VAP = 0x%x(0x%x) name=%s \n", priv_vap, priv_vap->dev, priv_vap->dev->name);
|
|
printk("VXD = 0x%x(0x%x) name=%s \n", priv_vxd, priv_vxd->dev, priv_vxd->dev->name);
|
|
#endif
|
|
|
|
|
|
if(is_vxd)
|
|
{
|
|
#if 1 //wrt-adhoc
|
|
{
|
|
NDEBUG("\n\nVXD change type to %d \n\n", type);
|
|
realtek_change_iftype(priv_vxd, type);
|
|
}
|
|
#endif
|
|
priv_vxd->cfg80211_interface_add = TRUE;
|
|
return &priv_vxd->wdev;
|
|
}
|
|
else {
|
|
priv_vap->cfg80211_interface_add = TRUE;
|
|
return &priv_vap->wdev;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
printk("Type OK, do nothing\n");
|
|
|
|
#if 1 //wrt-adhoc
|
|
if(is_vxd)
|
|
{
|
|
NDEBUG("\n\nVXD change type to %d \n\n", type);
|
|
realtek_change_iftype(priv_add, type);
|
|
}
|
|
#endif
|
|
priv_add->cfg80211_interface_add = TRUE;
|
|
return &priv_add->wdev;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
printk("Can not find correspinding priv for %s !!\n", name);
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
|
|
NLEXIT;
|
|
|
|
return &rtk->priv->wdev;
|
|
|
|
}
|
|
|
|
|
|
void close_vxd_vap(struct rtl8192cd_priv *priv_root)
|
|
{
|
|
int i = 0;
|
|
|
|
//#ifdef UNIVERSAL_REPEATER
|
|
#if 0 //prevent drop vxd connection
|
|
if(IS_DRV_OPEN(priv_root->pvxd_priv))
|
|
rtl8192cd_close(priv_root->pvxd_priv->dev);
|
|
#endif
|
|
|
|
#ifdef MBSSID
|
|
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
|
|
if(IS_DRV_OPEN(priv_root->pvap_priv[i]))
|
|
rtl8192cd_close(priv_root->pvap_priv[i]->dev);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
static int realtek_cfg80211_del_iface(struct wiphy *wiphy,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct wireless_dev *wdev
|
|
#else
|
|
struct net_device *wdev
|
|
#endif
|
|
)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#else
|
|
struct rtl8192cd_priv *priv = GET_DEV_PRIV(wdev);
|
|
#endif
|
|
unsigned char *name = NULL;
|
|
|
|
NLENTER;
|
|
|
|
if(priv)
|
|
{
|
|
name = priv->dev->name;
|
|
NDEBUG3("del_iface:name[%s] priv[%p] wdev[%p]\n", name, priv, wdev);
|
|
}
|
|
else
|
|
{
|
|
NDEBUG3("Can NOT find priv from wdev[%p]", wdev);
|
|
return -1;
|
|
}
|
|
|
|
netif_stop_queue(priv->dev);
|
|
|
|
if(priv->cfg80211_interface_add == FALSE) {
|
|
NDEBUG3("del_iface:name[%s] is already closed\n", name);
|
|
return 0;
|
|
}
|
|
#ifdef MBSSID
|
|
if(IS_ROOT_INTERFACE(priv))
|
|
{
|
|
close_vxd_vap(priv);
|
|
}
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if(IS_VXD_INTERFACE(priv))
|
|
rtk->num_vxd = 0;
|
|
#endif
|
|
|
|
if(IS_VAP_INTERFACE(priv))
|
|
rtk->num_vap --;
|
|
#endif
|
|
priv->cfg80211_interface_add = FALSE;
|
|
|
|
priv->receive_connect_cmd = 0;
|
|
|
|
rtk_abort_scan(priv, SCAN_ABORT_DEL_IFACE);
|
|
|
|
if(IS_ROOT_INTERFACE(priv))
|
|
rtl8192cd_close(priv->dev);
|
|
else
|
|
dev_change_flags(priv->dev, (priv->dev->flags&~IFF_UP) ); //disable virtual interface.
|
|
|
|
NLEXIT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//survey_dump
|
|
static int realtek_dump_survey(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
int idx,
|
|
struct survey_info *survey)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = rtk->priv;
|
|
struct ieee80211_supported_band *sband=NULL;
|
|
int freq, band=0;
|
|
|
|
//NLENTER;
|
|
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
|
sband = wiphy->bands[band];
|
|
|
|
if (sband)
|
|
break;;
|
|
}
|
|
|
|
if(!sband) {
|
|
NDEBUG("%s under unknown band!!\n",dev->name);
|
|
return -1;
|
|
} else {
|
|
//this ops will be invoked several times, until statistic of all channels reported
|
|
if(idx > sband->n_channels-1)
|
|
{
|
|
NDEBUG2("Exceed maximum:%d, statistic of all channels were reported \n", sband->n_channels-1);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if(sband->band == IEEE80211_BAND_2GHZ)
|
|
freq = ieee80211_channel_to_frequency(priv->rtk->survey_info[idx].channel, IEEE80211_BAND_2GHZ);
|
|
else
|
|
freq = ieee80211_channel_to_frequency(priv->rtk->survey_info[idx].channel, IEEE80211_BAND_5GHZ);
|
|
|
|
survey->channel = ieee80211_get_channel(wiphy, freq);
|
|
survey->noise = priv->rtk->survey_info[idx].noise;
|
|
survey->channel_time = 1000;
|
|
survey->channel_time_busy = priv->rtk->survey_info[idx].chbusytime;
|
|
survey->channel_time_rx = priv->rtk->survey_info[idx].rx_time;
|
|
survey->channel_time_tx = priv->rtk->survey_info[idx].tx_time;
|
|
survey->filled = SURVEY_INFO_NOISE_DBM|SURVEY_INFO_CHANNEL_TIME|SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX|SURVEY_INFO_CHANNEL_TIME_TX;
|
|
#if 0
|
|
if(priv->rtk->survey_info[idx].chbusytime > priv->rtk->survey_info[idx].rx_time)
|
|
{
|
|
survey->channel_time_busy = priv->rtk->survey_info[idx].chbusytime + priv->rtk->survey_info[idx].tx_time;
|
|
survey->channel_time_rx = priv->rtk->survey_info[idx].rx_time;
|
|
}
|
|
else
|
|
{
|
|
survey->channel_time_busy = priv->rtk->survey_info[idx].rx_time + priv->rtk->survey_info[idx].tx_time;
|
|
survey->channel_time_rx = priv->rtk->survey_info[idx].rx_time - priv->rtk->survey_info[idx].chbusytime;
|
|
}
|
|
survey->channel_time_tx = priv->rtk->tx_time;
|
|
#endif
|
|
|
|
//NLEXIT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int realtek_cfg80211_change_iface(struct wiphy *wiphy,
|
|
struct net_device *ndev,
|
|
enum nl80211_iftype type, u32 *flags,
|
|
struct vif_params *params)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = get_priv_from_ndev(rtk, ndev); //rtk->priv;
|
|
unsigned char type_name[32];
|
|
|
|
NLENTER;
|
|
|
|
type_to_name(type, type_name);
|
|
NLMSG("CHANGE [%s][%s=%d]\n", priv->dev->name, type_name, type);
|
|
realtek_change_iftype(priv, type);
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
static int realtek_cfg80211_sscan_start(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
struct cfg80211_sched_scan_request *request)
|
|
{
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_sscan_stop(struct wiphy *wiphy,
|
|
struct net_device *dev)
|
|
{
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_set_bitrate(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
const u8 *addr,
|
|
const struct cfg80211_bitrate_mask *mask)
|
|
{
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cfg80211_set_txe_config(struct wiphy *wiphy,
|
|
struct net_device *dev,
|
|
u32 rate, u32 pkts, u32 intvl)
|
|
{
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void rtk_cfg80211_rx_mgmt(struct rtl8192cd_priv *priv , struct rx_frinfo *pfrinfo, unsigned char channel)
|
|
{
|
|
int freq;
|
|
NDEBUG3("\n");
|
|
|
|
printk("cliw: rx mgmt to nl80211\n");
|
|
|
|
if (channel <= MAX_2G_CHANNEL_NUM)
|
|
freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
|
|
else
|
|
freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
|
|
|
|
// rtk_set_scan_deny(priv,2000);
|
|
cfg80211_rx_mgmt(
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
&priv->wdev,
|
|
#else
|
|
priv->dev,
|
|
#endif
|
|
freq, 0, get_pframe(pfrinfo), pfrinfo->pktlen
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0)
|
|
,0
|
|
#endif
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
|
|
,GFP_KERNEL
|
|
#endif
|
|
);
|
|
}
|
|
|
|
#if defined(NOT_RTK_BSP) && defined(RTK_NL80211_HS_CLI)
|
|
|
|
enum rtk_nl80211_rxmgmt_flags {
|
|
RTK_NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0,
|
|
};
|
|
|
|
int realtek_remain_on_channel(
|
|
struct wiphy *wiphy,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct wireless_dev *wdev,
|
|
#else
|
|
struct net_device *wdev,
|
|
#endif
|
|
struct ieee80211_channel *channel,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
enum nl80211_channel_type channel_type,
|
|
#endif
|
|
unsigned int duration,
|
|
u64 *cookie)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#else
|
|
struct rtl8192cd_priv *priv = GET_DEV_PRIV(wdev);
|
|
#endif
|
|
// struct wireless_dev *wdev = (&priv->wdev);
|
|
|
|
u8 remain_ch = (u8) ieee80211_frequency_to_channel(channel->center_freq);
|
|
|
|
NLENTER;
|
|
|
|
printk("realtek_remain_on_channel : %d\n", remain_ch);
|
|
|
|
if (timer_pending(&priv->nl_ctx.remain_on_ch_timer))
|
|
del_timer(&priv->nl_ctx.remain_on_ch_timer);
|
|
|
|
memcpy(&priv->nl_ctx.remain_on_ch_channel, channel, sizeof(struct ieee80211_channel));
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
priv->nl_ctx.remain_on_ch_type = channel_type;
|
|
#endif
|
|
priv->nl_ctx.remain_on_ch_cookie = *cookie;
|
|
priv->nl_ctx.restore_channel = GET_ROOT(priv)->pmib->dot11RFEntry.dot11channel; /*restore orignal channel*/
|
|
|
|
priv->nl_ctx.p2p_listen_channel = remain_ch; /*set listen channel to remain channel */
|
|
|
|
priv->pshare->rtk_remain_on_channel = 1; // for lock channel switch and indicate now under remain channel mode
|
|
|
|
/* siwtch to */
|
|
priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_20;
|
|
|
|
if(priv->pmib->dot11RFEntry.dot11channel != priv->nl_ctx.p2p_listen_channel)
|
|
priv->pmib->dot11RFEntry.dot11channel = priv->nl_ctx.p2p_listen_channel;
|
|
|
|
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
|
|
SwChnl(priv, priv->nl_ctx.p2p_listen_channel, priv->pshare->offset_2nd_chan);
|
|
|
|
cfg80211_ready_on_channel(wdev, *cookie, channel,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
channel_type,
|
|
#endif
|
|
duration, GFP_KERNEL);
|
|
|
|
mod_timer(&priv->nl_ctx.remain_on_ch_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(duration));
|
|
//NDEBUG("ch[%d],for[%d]ms\n",remain_ch,duration);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int realtek_cancel_remain_on_channel (
|
|
struct wiphy *wiphy,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct wireless_dev *wdev,
|
|
#else
|
|
struct net_device *wdev,
|
|
#endif
|
|
u64 cookie )
|
|
{
|
|
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#else
|
|
struct rtl8192cd_priv *priv = GET_DEV_PRIV(wdev);
|
|
#endif
|
|
NLENTER;
|
|
|
|
printk("realtek_cancel_remain_on_channel \n");
|
|
if(timer_pending(&priv->nl_ctx.remain_on_ch_timer)){
|
|
del_timer(&priv->nl_ctx.remain_on_ch_timer);
|
|
}
|
|
NDEBUG("\n");
|
|
|
|
priv->pmib->dot11RFEntry.dot11channel = priv->nl_ctx.restore_channel;
|
|
|
|
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
|
|
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan);
|
|
|
|
priv->pshare->rtk_remain_on_channel = 0; // for unlock channel switch
|
|
}
|
|
|
|
void realtek_cfg80211_RemainOnChExpire( unsigned long task_priv )
|
|
{
|
|
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
|
|
struct wireless_dev *wdev = &priv->wdev;
|
|
|
|
printk("realtek_cfg80211_RemainOnChExpire \n");
|
|
priv->pshare->rtk_remain_on_channel = 0; // for unlock channel switch
|
|
//NDEBUG2("\n");
|
|
|
|
notify_cfg_evt(priv, NULL, CFG80211_REMAIN_CHANNEL, NULL);
|
|
/*
|
|
cfg80211_remain_on_channel_expired(wdev, priv->nl_ctx.remain_on_ch_cookie,
|
|
&priv->nl_ctx.remain_on_ch_channel, GFP_KERNEL);
|
|
*/
|
|
return;
|
|
}
|
|
|
|
#define WLAN_ACT_CAT_CODE_GAS 4
|
|
|
|
int rtk_cfg80211_mgmt_tx(struct rtl8192cd_priv *priv, int tx_ch, const u8 *mgmt_buf_from_cfg, int mgmt_buf_from_cfg_len)
|
|
{
|
|
unsigned char *pbuf;
|
|
unsigned char *frame_after_wlan_hrd=NULL;
|
|
int frame_after_wlan_hrd_len = 0;
|
|
int sizeof_mgmt_wlan_hrd = 0;
|
|
struct ieee80211_mgmt *mgmt;
|
|
int idx=0;
|
|
u8 category,action;
|
|
u8 OUI_Subtype;
|
|
u8 dialogToken;
|
|
unsigned char P2P_OUI[] = {0x50,0x6F,0x9A,0x09};
|
|
u8* p2p_ie_start;
|
|
int p2p_ie_len;
|
|
int my_p2p_role;
|
|
unsigned char* p2p_capa;
|
|
// struct ieee80211_mgmt_hrd mgmt_hrd;
|
|
|
|
DECLARE_TXINSN(txinsn);
|
|
|
|
printk("rtk_cfg80211_mgmt_tx ++ \n");
|
|
#if 0
|
|
if(priv->pshare->working_channel2 != tx_ch){
|
|
NDEBUG(" chk , our working ch != assigned by cfg\n\n");
|
|
priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_20;
|
|
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
|
|
SwChnl(priv, tx_ch, priv->pshare->offset_2nd_chan);
|
|
}
|
|
#endif
|
|
|
|
// rtk_set_scan_deny(priv,300); // deny channel switch for 300 ms
|
|
pbuf = txinsn.pframe = get_mgtbuf_from_poll(priv);
|
|
if (pbuf == NULL)
|
|
goto fail;
|
|
|
|
txinsn.phdr = get_wlanhdr_from_poll(priv);
|
|
|
|
if (txinsn.phdr == NULL)
|
|
goto fail;
|
|
|
|
txinsn.q_num = MANAGE_QUE_NUM;
|
|
txinsn.fr_type = _PRE_ALLOCMEM_;
|
|
txinsn.tx_rate = _6M_RATE_;
|
|
#ifndef TX_LOWESTRATE
|
|
txinsn.lowest_tx_rate = txinsn.tx_rate;
|
|
#endif
|
|
txinsn.fixed_rate = true;
|
|
txinsn.need_ack = true;
|
|
txinsn.retry = true;
|
|
|
|
sizeof_mgmt_wlan_hrd = sizeof(struct ieee80211_mgmt_hrd);
|
|
frame_after_wlan_hrd = mgmt_buf_from_cfg + sizeof_mgmt_wlan_hrd;
|
|
frame_after_wlan_hrd_len = mgmt_buf_from_cfg_len - sizeof_mgmt_wlan_hrd;
|
|
|
|
|
|
/*-------------parse p2p_ie and do some handling----------------*/
|
|
category = frame_after_wlan_hrd[0];
|
|
if(category == WLAN_CATEGORY_PUBLIC) // 0x4 p2p public action frame
|
|
{
|
|
|
|
}
|
|
else if(category == WLAN_CATEGORY_VENDOR_SPECIFIC) // 0x7F action frame
|
|
{
|
|
|
|
}
|
|
else if( category == WLAN_ACT_CAT_CODE_GAS ) // 0x7F action frame
|
|
{
|
|
action = frame_after_wlan_hrd[1];
|
|
printk("GAS: action code:%d\n", action);
|
|
}
|
|
else
|
|
{
|
|
NDEBUG("unknown action frame\n");
|
|
}
|
|
|
|
/*fill wlan head*/
|
|
memset((void *)(txinsn.phdr), 0, sizeof(struct wlan_hdr));
|
|
memcpy((void *)(txinsn.phdr) , mgmt_buf_from_cfg , sizeof(struct ieee80211_mgmt_hrd));
|
|
|
|
/*fill frame content after wlan head*/
|
|
memcpy((void *)pbuf , frame_after_wlan_hrd , frame_after_wlan_hrd_len);
|
|
|
|
txinsn.fr_len += frame_after_wlan_hrd_len;
|
|
|
|
if ((rtl8192cd_firetx(priv, &txinsn)) == SUCCESS) {
|
|
printk("rtk_cfg80211_mgmt_tx: ok --\n");
|
|
return SUCCESS;
|
|
} else {
|
|
P2P_DEBUG("TX action fail\n");
|
|
}
|
|
|
|
fail:
|
|
NDEBUG("fail !!!\n");
|
|
printk("rtk_cfg80211_mgmt_tx: ng--\n");
|
|
|
|
if (txinsn.phdr)
|
|
release_wlanhdr_to_poll(priv, txinsn.phdr);
|
|
if (txinsn.pframe)
|
|
release_mgtbuf_to_poll(priv, txinsn.pframe);
|
|
return FAIL;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
|
|
static int realtek_mgmt_tx (
|
|
struct wiphy *wiphy,
|
|
struct wireless_dev *wdev,
|
|
struct cfg80211_mgmt_tx_params *params,
|
|
u64 *cookie )
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
int tx_ch = ieee80211_frequency_to_channel(params->chan->center_freq);
|
|
|
|
int ret = 0;
|
|
u32 cookie_id;
|
|
const struct ieee80211_mgmt *mgmt;
|
|
NLENTER;
|
|
|
|
*cookie = 0;
|
|
|
|
priv->nl_ctx.send_action_id++;
|
|
if( priv->nl_ctx.send_action_id == 0 )
|
|
priv->nl_ctx.send_action_id++;
|
|
|
|
*cookie = priv->nl_ctx.send_action_id;
|
|
|
|
mgmt = (const struct ieee80211_mgmt *)params->buf;
|
|
|
|
if (ieee80211_is_mgmt(mgmt->frame_control)) {
|
|
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
|
s32 ie_offset = WLAN_HDR_A3_LEN + _PROBERSP_IE_OFFSET_;
|
|
s32 ie_len = params->len - ie_offset;
|
|
NDEBUG("!!!set probe rsp from cfg80211\n");
|
|
rtk_cfg80211_set_wps_p2p_ie(priv,params->buf+ie_offset,ie_len,MGMT_PROBERSP);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, params->buf, params->len, TRUE, GFP_KERNEL); //GFP_ATOMIC
|
|
return 0;
|
|
} else if (ieee80211_is_disassoc(mgmt->frame_control) ||
|
|
ieee80211_is_deauth(mgmt->frame_control)) {
|
|
NDEBUG("Disconnect STA[%02X%02X%02X:%02X%02X%02X] reason[%d]\n",
|
|
mgmt->da[0],mgmt->da[1],mgmt->da[2],
|
|
mgmt->da[3],mgmt->da[4],mgmt->da[5],mgmt->u.disassoc.reason_code);
|
|
|
|
issue_deauth(priv,mgmt->da, mgmt->u.disassoc.reason_code);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, params->buf, params->len, TRUE, GFP_KERNEL); //GFP_ATOMIC
|
|
return 0;
|
|
} else if (ieee80211_is_action(mgmt->frame_control)) {
|
|
|
|
/* indicate ack before issue frame to avoid racing with rsp frame */
|
|
|
|
// rtk_abort_scan(priv); // abort on going scan
|
|
rtk_cfg80211_mgmt_tx(priv, tx_ch, params->buf, params->len);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, params->buf, params->len, TRUE, GFP_KERNEL); //GFP_ATOMIC
|
|
// NDEBUG("cookie_id[%02X]\n",priv->p2pPtr->send_action_id);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#else // LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
|
|
static int realtek_mgmt_tx(
|
|
struct wiphy *wiphy,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct wireless_dev *wdev,
|
|
#else
|
|
struct net_device *wdev,
|
|
#endif
|
|
struct ieee80211_channel *chan, bool offchan,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
enum nl80211_channel_type channel_type,
|
|
bool channel_type_valid,
|
|
#endif
|
|
unsigned int wait, const u8 *buf, size_t len,
|
|
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#else
|
|
struct rtl8192cd_priv *priv = GET_DEV_PRIV(wdev);
|
|
#endif
|
|
|
|
int tx_ch = ieee80211_frequency_to_channel(chan->center_freq);
|
|
NDEBUG3("[%s]center_freq=[%u] channel=[%d] hw_value=[%u] bandwidth=[%d] \n",
|
|
priv->dev->name, chan->center_freq, tx_ch, chan->hw_value, chan->flags);
|
|
printk("realtek_mgmt_tx:[%s] center_freq=[%u] channel=[%d] hw_value=[%u]\n",
|
|
priv->dev->name, chan->center_freq, tx_ch, chan->hw_value);
|
|
|
|
int ret = 0;
|
|
u32 cookie_id;
|
|
const struct ieee80211_mgmt *mgmt;
|
|
NLENTER;
|
|
|
|
*cookie = 0;
|
|
|
|
priv->nl_ctx.send_action_id++;
|
|
if( priv->nl_ctx.send_action_id == 0 )
|
|
priv->nl_ctx.send_action_id++;
|
|
|
|
*cookie = priv->nl_ctx.send_action_id;
|
|
|
|
mgmt = (const struct ieee80211_mgmt *)buf;
|
|
|
|
printk("realtek_mgmt_tx:mgmt->frame_control:%x\n", mgmt->frame_control);
|
|
|
|
if (ieee80211_is_mgmt(mgmt->frame_control)) {
|
|
printk(" is ieee80211_is_mgmt \n");
|
|
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
|
s32 ie_offset = WLAN_HDR_A3_LEN + _PROBERSP_IE_OFFSET_;
|
|
s32 ie_len = len - ie_offset;
|
|
NDEBUG("!!!set probe rsp from cfg80211\n");
|
|
printk("!!!set probe rsp from cfg80211\n");
|
|
rtk_cfg80211_set_wps_p2p_ie(priv, buf + ie_offset, ie_len, MGMT_PROBERSP);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, TRUE, GFP_KERNEL); //GFP_ATOMIC
|
|
return 0;
|
|
} else if (ieee80211_is_disassoc(mgmt->frame_control) ||
|
|
ieee80211_is_deauth(mgmt->frame_control)) {
|
|
NDEBUG("Disconnect STA[%02X%02X%02X:%02X%02X%02X] reason[%d]\n",
|
|
mgmt->da[0],mgmt->da[1],mgmt->da[2],
|
|
mgmt->da[3],mgmt->da[4],mgmt->da[5],mgmt->u.disassoc.reason_code);
|
|
|
|
printk("Disconnect STA[%02X%02X%02X:%02X%02X%02X] reason[%d]\n",
|
|
mgmt->da[0],mgmt->da[1],mgmt->da[2],
|
|
mgmt->da[3],mgmt->da[4],mgmt->da[5],mgmt->u.disassoc.reason_code);
|
|
|
|
issue_deauth(priv, mgmt->da, mgmt->u.disassoc.reason_code);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, TRUE, GFP_KERNEL);//GFP_ATOMIC
|
|
return 0;
|
|
} else if (ieee80211_is_action(mgmt->frame_control)) {
|
|
printk(" is_action \n");
|
|
/* indicate ack before issue frame to avoid racing with rsp frame */
|
|
//rtk_abort_scan(priv); // abort on going scan
|
|
rtk_cfg80211_mgmt_tx(priv, tx_ch, buf, len);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, TRUE, GFP_KERNEL);//GFP_ATOMIC
|
|
//NDEBUG("cookie_id[%02X]\n",priv->p2pPtr->send_action_id);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#elif defined(P2P_SUPPORT)
|
|
int realtek_remain_on_channel(struct wiphy *wiphy,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct wireless_dev *wdev,
|
|
#else
|
|
struct net_device *wdev,
|
|
#endif
|
|
struct ieee80211_channel *channel,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
enum nl80211_channel_type channel_type,
|
|
#endif
|
|
unsigned int duration,
|
|
u64 *cookie)
|
|
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#else
|
|
struct rtl8192cd_priv *priv = GET_DEV_PRIV(wdev);
|
|
#endif
|
|
// struct wireless_dev *wdev = (&priv->wdev);
|
|
u8 remain_ch = (u8) ieee80211_frequency_to_channel(channel->center_freq);
|
|
|
|
NLENTER;
|
|
|
|
if (timer_pending(&priv->p2pPtr->remain_on_ch_timer))
|
|
del_timer(&priv->p2pPtr->remain_on_ch_timer);
|
|
|
|
//rtk_abort_scan(priv); // abort on going scan
|
|
memcpy(&priv->p2pPtr->remain_on_ch_channel, channel, sizeof(struct ieee80211_channel));
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
priv->p2pPtr->remain_on_ch_type = channel_type;
|
|
#endif
|
|
priv->p2pPtr->remain_on_ch_cookie= *cookie;
|
|
priv->p2pPtr->restore_channel=GET_ROOT(priv)->pmib->dot11RFEntry.dot11channel; /*restore orignal channel*/
|
|
|
|
priv->pmib->p2p_mib.p2p_listen_channel=remain_ch; /*set listen channel to remain channel */
|
|
|
|
priv->p2pPtr->pre_p2p_role=rtk_p2p_get_role(priv);
|
|
priv->p2pPtr->pre_p2p_state=rtk_p2p_get_state(priv);
|
|
|
|
//priv->p2pPtr->pre_opmode = OPMODE;
|
|
#if 0 //before 0326 1450
|
|
if(rtk_p2p_is_enabled(priv)==CFG80211_P2P){ // rdy under p2p mode
|
|
if(!rtk_p2p_chk_role(priv,P2P_DEVICE)){
|
|
NDEBUG("change mode to p2p-device\n");
|
|
rtk_p2p_set_role(priv,P2P_DEVICE);
|
|
}
|
|
}else{
|
|
NDEBUG("rtk_p2p_enable\n");
|
|
rtk_p2p_enable(priv,P2P_DEVICE, CFG80211_P2P);
|
|
}
|
|
#else
|
|
if(!rtk_p2p_is_enabled(priv)){
|
|
NDEBUG3("==>rtk_p2p_enable(CFG80211_P2P)\n");
|
|
rtk_p2p_enable(priv,P2P_DEVICE, CFG80211_P2P);
|
|
}
|
|
#endif
|
|
|
|
rtk_p2p_set_role(priv,P2P_DEVICE); // role to device
|
|
P2P_listen(priv,NULL); //state to listen
|
|
|
|
|
|
NDEBUG3("role[%d]\n",rtk_p2p_get_role(priv));
|
|
NDEBUG3("state[%d]\n",rtk_p2p_get_state(priv));
|
|
priv->pshare->rtk_remain_on_channel=1; // for lock channel switch and indicate now under remain channel mode
|
|
|
|
cfg80211_ready_on_channel(wdev, *cookie, channel,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
channel_type,
|
|
#endif
|
|
duration, GFP_KERNEL);
|
|
|
|
if(duration < 400)
|
|
duration = duration*3;//extend from exper. unit ms
|
|
|
|
mod_timer(&priv->p2pPtr->remain_on_ch_timer,jiffies + RTL_MILISECONDS_TO_JIFFIES(duration));
|
|
//NDEBUG("ch[%d],for[%d]ms\n",remain_ch,duration);
|
|
return 0;
|
|
|
|
}
|
|
static int realtek_cancel_remain_on_channel(struct wiphy *wiphy,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct wireless_dev *wdev,
|
|
#else
|
|
struct net_device *wdev,
|
|
#endif
|
|
u64 cookie)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
#else
|
|
struct rtl8192cd_priv *priv = GET_DEV_PRIV(wdev);
|
|
#endif
|
|
NLENTER;
|
|
|
|
if(timer_pending(&priv->p2pPtr->remain_on_ch_timer)){
|
|
del_timer(&priv->p2pPtr->remain_on_ch_timer);
|
|
}
|
|
NDEBUG("\n");
|
|
|
|
priv->pshare->rtk_remain_on_channel=0; // for unlock channel switch
|
|
rtk_p2p_set_role(priv,priv->p2pPtr->pre_p2p_role);
|
|
rtk_p2p_set_state(priv,priv->p2pPtr->pre_p2p_state);
|
|
return 0;
|
|
}
|
|
|
|
void realtek_cfg80211_RemainOnChExpire(unsigned long task_priv)
|
|
{
|
|
|
|
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
|
|
struct wireless_dev *wdev = &priv->wdev;
|
|
|
|
priv->pshare->rtk_remain_on_channel=0; // for unlock channel switch
|
|
rtk_p2p_set_role(priv,priv->p2pPtr->pre_p2p_role);
|
|
rtk_p2p_set_state(priv,priv->p2pPtr->pre_p2p_state);
|
|
//NDEBUG2("\n");
|
|
cfg80211_remain_on_channel_expired(
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
wdev,
|
|
#else
|
|
priv->dev,
|
|
#endif
|
|
priv->p2pPtr->remain_on_ch_cookie,
|
|
&priv->p2pPtr->remain_on_ch_channel,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
|
priv->p2pPtr->remain_on_ch_type,
|
|
#endif
|
|
GFP_KERNEL);
|
|
return;
|
|
}
|
|
|
|
int rtk_cfg80211_mgmt_tx(struct rtl8192cd_priv *priv,int tx_ch,const u8 *mgmt_buf_from_cfg, int mgmt_buf_from_cfg_len)
|
|
{
|
|
unsigned char *pbuf;
|
|
unsigned char *frame_after_wlan_hrd=NULL;
|
|
int frame_after_wlan_hrd_len = 0;
|
|
int sizeof_mgmt_wlan_hrd = 0;
|
|
struct ieee80211_mgmt *mgmt;
|
|
int idx=0;
|
|
u8 category,action;
|
|
u8 OUI_Subtype;
|
|
u8 dialogToken;
|
|
unsigned char P2P_OUI[] = {0x50,0x6F,0x9A,0x09};
|
|
u8* p2p_ie_start;
|
|
int p2p_ie_len;
|
|
int my_p2p_role;
|
|
unsigned char* p2p_capa;
|
|
//struct ieee80211_mgmt_hrd mgmt_hrd;
|
|
|
|
DECLARE_TXINSN(txinsn);
|
|
|
|
if(priv->pshare->working_channel2 != tx_ch){
|
|
NDEBUG(" chk , our working ch != assigned by cfg\n\n");
|
|
priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_20;
|
|
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
|
|
SwChnl(priv, tx_ch, priv->pshare->offset_2nd_chan);
|
|
}
|
|
//rtk_set_scan_deny(priv,300); // deny channel switch for 300 ms
|
|
pbuf = txinsn.pframe = get_mgtbuf_from_poll(priv);
|
|
if (pbuf == NULL)
|
|
goto fail;
|
|
|
|
txinsn.phdr = get_wlanhdr_from_poll(priv);
|
|
|
|
if (txinsn.phdr == NULL)
|
|
goto fail;
|
|
|
|
|
|
txinsn.q_num = MANAGE_QUE_NUM;
|
|
txinsn.fr_type = _PRE_ALLOCMEM_;
|
|
txinsn.tx_rate = _6M_RATE_;
|
|
#ifndef TX_LOWESTRATE
|
|
txinsn.lowest_tx_rate = txinsn.tx_rate;
|
|
#endif
|
|
txinsn.fixed_rate = true;
|
|
txinsn.need_ack = true;
|
|
txinsn.retry = true;
|
|
|
|
sizeof_mgmt_wlan_hrd = sizeof(struct ieee80211_mgmt_hrd);
|
|
frame_after_wlan_hrd = mgmt_buf_from_cfg + sizeof_mgmt_wlan_hrd;
|
|
frame_after_wlan_hrd_len = mgmt_buf_from_cfg_len-sizeof_mgmt_wlan_hrd;
|
|
|
|
|
|
/*-------------parse p2p_ie and do some handling----------------*/
|
|
category = frame_after_wlan_hrd[0];
|
|
if(category == WLAN_CATEGORY_PUBLIC) // 0x4 p2p public action frame
|
|
{
|
|
action = frame_after_wlan_hrd[1];
|
|
if (action == _P2P_PUBLIC_ACTION_FIELD_ && !memcmp(frame_after_wlan_hrd+2, WFA_OUI_PLUS_TYPE, 4))
|
|
{
|
|
OUI_Subtype = frame_after_wlan_hrd[6];
|
|
dialogToken = frame_after_wlan_hrd[7];
|
|
switch(OUI_Subtype){
|
|
case P2P_GO_NEG_REQ:
|
|
NDEBUG("P2P_GO_NEG_REQ ,dialog[%d]\n",dialogToken);
|
|
break;
|
|
case P2P_GO_NEG_RESP:
|
|
NDEBUG("P2P_GO_NEG_RESP \n");
|
|
|
|
break;
|
|
case P2P_GO_NEG_CONF:
|
|
NDEBUG("P2P_GO_NEG_CONF\n");
|
|
|
|
break;
|
|
case P2P_INVITATION_REQ:
|
|
NDEBUG("P2P_INVITATION_REQ,dialog[%d]\n",dialogToken);
|
|
break;
|
|
case P2P_INVITATION_RESP:
|
|
NDEBUG("P2P_INVITATION_RESP,dialog[%d]\n",dialogToken);
|
|
break;
|
|
case P2P_DEV_DISC_REQ:
|
|
NDEBUG("P2P_INVITATION_RESP,dialog[%d]\n",dialogToken);
|
|
rtk_p2p_set_state(priv,P2P_S_IDLE);
|
|
break;
|
|
case P2P_DEV_DISC_RESP:
|
|
NDEBUG("P2P_DEV_DISC_RESP,dialog[%d]\n",dialogToken);
|
|
rtk_p2p_set_state(priv,P2P_S_IDLE);
|
|
break;
|
|
case P2P_PROV_DISC_REQ:
|
|
NDEBUG("P2P_PROV_DISC_REQ,dialog[%d]\n",dialogToken);
|
|
break;
|
|
case P2P_PROV_DISC_RSP:
|
|
NDEBUG("P2P_PROV_DISC_RSP,dialog[%d]\n",dialogToken);
|
|
break;
|
|
default:
|
|
NDEBUG("unknown [%d]\n",dialogToken);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
else if(category == WLAN_CATEGORY_VENDOR_SPECIFIC) // 0x7F action frame
|
|
{
|
|
OUI_Subtype = frame_after_wlan_hrd[5];
|
|
dialogToken = frame_after_wlan_hrd[6];
|
|
switch(OUI_Subtype)
|
|
{
|
|
case P2P_NOA:
|
|
NDEBUG("P2P_NOA,dialog[%d]\n",dialogToken);
|
|
break;
|
|
case P2P_PRESENCE_REQ:
|
|
NDEBUG("P2P_PRESENCE_REQ,dialog[%d]\n",dialogToken);
|
|
break;
|
|
case P2P_PRESENCE_RSP:
|
|
NDEBUG("P2P_PRESENCE_RSP,dialog[%d]\n",dialogToken);
|
|
break;
|
|
case P2P_GO_DISCOVERY:
|
|
NDEBUG("P2P_GO_DISCOVERY,dialog[%d]\n",dialogToken);
|
|
break;
|
|
default:
|
|
NDEBUG("unknown,dialog[%d]\n",dialogToken);
|
|
break;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
NDEBUG("unknown action frame\n");
|
|
}
|
|
/*-------------parse p2p_ie and do some handling----------------*/
|
|
|
|
|
|
/* fill wlan head */
|
|
memset((void *)(txinsn.phdr), 0, sizeof(struct wlan_hdr));
|
|
memcpy((void *)(txinsn.phdr) , mgmt_buf_from_cfg , sizeof(struct ieee80211_mgmt_hrd));
|
|
|
|
/* fill frame content after wlan head */
|
|
memcpy((void *)pbuf , frame_after_wlan_hrd , frame_after_wlan_hrd_len);
|
|
|
|
txinsn.fr_len += frame_after_wlan_hrd_len;
|
|
|
|
if ((rtl8192cd_firetx(priv, &txinsn)) == SUCCESS){
|
|
return SUCCESS;
|
|
} else {
|
|
P2P_DEBUG("TX action fail\n");
|
|
}
|
|
|
|
fail:
|
|
NDEBUG("fail !!!\n");
|
|
|
|
if (txinsn.phdr)
|
|
release_wlanhdr_to_poll(priv, txinsn.phdr);
|
|
if (txinsn.pframe)
|
|
release_mgtbuf_to_poll(priv, txinsn.pframe);
|
|
return FAIL;
|
|
}
|
|
|
|
static int realtek_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|
struct cfg80211_mgmt_tx_params *params,
|
|
u64 *cookie)
|
|
{
|
|
struct rtknl *rtk = wiphy_priv(wiphy);
|
|
struct rtl8192cd_priv *priv = get_priv_from_wdev(rtk, wdev);
|
|
int tx_ch = ieee80211_frequency_to_channel(params->chan->center_freq);
|
|
|
|
int ret = 0;
|
|
u32 cookie_id;
|
|
const struct ieee80211_mgmt *mgmt;
|
|
NLENTER;
|
|
|
|
*cookie = 0;
|
|
|
|
priv->p2pPtr->send_action_id++;
|
|
if(priv->p2pPtr->send_action_id==0)
|
|
priv->p2pPtr->send_action_id++;
|
|
|
|
|
|
*cookie = priv->p2pPtr->send_action_id;
|
|
|
|
mgmt = (const struct ieee80211_mgmt *)params->buf;
|
|
|
|
if (ieee80211_is_mgmt(mgmt->frame_control)) {
|
|
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
|
s32 ie_offset = WLAN_HDR_A3_LEN + _PROBERSP_IE_OFFSET_;
|
|
s32 ie_len = params->len - ie_offset;
|
|
NDEBUG("!!!set probe rsp from cfg80211\n");
|
|
rtk_cfg80211_set_wps_p2p_ie(priv,params->buf+ie_offset,ie_len,MGMT_PROBERSP);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, params->buf, params->len, TRUE, GFP_KERNEL);//GFP_ATOMIC
|
|
return 0;
|
|
} else if (ieee80211_is_disassoc(mgmt->frame_control) ||
|
|
ieee80211_is_deauth(mgmt->frame_control)) {
|
|
NDEBUG("Disconnect STA[%02X%02X%02X:%02X%02X%02X] reason[%d]\n",
|
|
mgmt->da[0],mgmt->da[1],mgmt->da[2],
|
|
mgmt->da[3],mgmt->da[4],mgmt->da[5],mgmt->u.disassoc.reason_code);
|
|
|
|
issue_deauth(priv,mgmt->da,mgmt->u.disassoc.reason_code);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, params->buf, params->len, TRUE, GFP_KERNEL);//GFP_ATOMIC
|
|
return 0;
|
|
} else if (ieee80211_is_action(mgmt->frame_control)) {
|
|
|
|
/* indicate ack before issue frame to avoid racing with rsp frame */
|
|
|
|
//rtk_abort_scan(priv); // abort on going scan
|
|
rtk_cfg80211_mgmt_tx(priv, tx_ch, params->buf, params->len);
|
|
cfg80211_mgmt_tx_status(wdev, *cookie, params->buf, params->len, TRUE, GFP_KERNEL);//GFP_ATOMIC
|
|
//NDEBUG("cookie_id[%02X]\n",priv->p2pPtr->send_action_id);
|
|
|
|
}
|
|
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
#endif //CONFIG_P2P
|
|
|
|
struct cfg80211_ops realtek_cfg80211_ops = {
|
|
.add_virtual_intf = realtek_cfg80211_add_iface,
|
|
.del_virtual_intf = realtek_cfg80211_del_iface,
|
|
.change_virtual_intf = realtek_cfg80211_change_iface,
|
|
.add_key = realtek_cfg80211_add_key,
|
|
.del_key = realtek_cfg80211_del_key,
|
|
.get_key = realtek_cfg80211_get_key,
|
|
.set_default_key = realtek_cfg80211_set_default_key,
|
|
.set_default_mgmt_key = realtek_cfg80211_set_default_mgmt_key,
|
|
//.add_beacon = realtek_cfg80211_add_beacon,
|
|
//.set_beacon = realtek_cfg80211_set_beacon,
|
|
//.del_beacon = realtek_cfg80211_del_beacon,
|
|
.add_station = realtek_cfg80211_add_station,
|
|
.del_station = realtek_cfg80211_del_station,
|
|
.change_station = realtek_cfg80211_change_station,
|
|
.get_station = realtek_cfg80211_get_station,
|
|
.dump_station = realtek_cfg80211_dump_station,
|
|
#if 0//def CONFIG_MAC80211_MESH
|
|
.add_mpath = realtek_cfg80211_add_mpath,
|
|
.del_mpath = realtek_cfg80211_del_mpath,
|
|
.change_mpath = realtek_cfg80211_change_mpath,
|
|
.get_mpath = realtek_cfg80211_get_mpath,
|
|
.dump_mpath = realtek_cfg80211_dump_mpath,
|
|
.set_mesh_params = realtek_cfg80211_set_mesh_params,
|
|
.get_mesh_params = realtek_cfg80211_get_mesh_params,
|
|
#endif
|
|
.change_bss = realtek_cfg80211_change_bss,
|
|
//.set_txq_params = realtek_cfg80211_set_txq_params,
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
|
|
.set_channel = realtek_cfg80211_set_channel,
|
|
#endif
|
|
#ifndef NOT_RTK_BSP
|
|
.suspend = realtek_cfg80211_suspend,
|
|
.resume = realtek_cfg80211_resume,
|
|
#endif
|
|
.scan = realtek_cfg80211_scan,
|
|
#if 0
|
|
.auth = realtek_cfg80211_auth,
|
|
.assoc = realtek_cfg80211_assoc,
|
|
.deauth = realtek_cfg80211_deauth,
|
|
.disassoc = realtek_cfg80211_disassoc,
|
|
#endif
|
|
|
|
#ifndef NOT_RTK_BSP
|
|
.join_ibss = realtek_cfg80211_join_ibss,
|
|
.leave_ibss = realtek_cfg80211_leave_ibss,
|
|
#endif
|
|
.set_wiphy_params = realtek_cfg80211_set_wiphy_params,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
|
|
.set_ap_chanwidth = realtek_cfg80211_set_ap_chanwidth,
|
|
#endif
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
.set_monitor_channel = realtek_cfg80211_set_monitor_channel,
|
|
#endif
|
|
#ifndef NOT_RTK_BSP
|
|
.set_tx_power = realtek_cfg80211_set_tx_power,
|
|
.get_tx_power = realtek_cfg80211_get_tx_power,
|
|
.set_power_mgmt = realtek_cfg80211_set_power_mgmt,
|
|
.set_wds_peer = realtek_cfg80211_set_wds_peer,
|
|
.rfkill_poll = realtek_cfg80211_rfkill_poll,
|
|
//CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
|
|
.set_bitrate_mask = realtek_cfg80211_set_bitrate_mask,
|
|
#endif
|
|
.connect = realtek_cfg80211_connect,
|
|
.disconnect = realtek_cfg80211_disconnect,
|
|
#if defined(P2P_SUPPORT) || defined(RTK_NL80211_HS_CLI)
|
|
.remain_on_channel = realtek_remain_on_channel,
|
|
.cancel_remain_on_channel = realtek_cancel_remain_on_channel,
|
|
.mgmt_tx = realtek_mgmt_tx,
|
|
#endif
|
|
.mgmt_frame_register = realtek_mgmt_frame_register,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0)
|
|
// .channel_switch = realtek_cfg80211_channel_switch,
|
|
#endif
|
|
.dump_survey = realtek_dump_survey,//survey_dump
|
|
.start_ap = realtek_start_ap,
|
|
.change_beacon = realtek_change_beacon,
|
|
.stop_ap = realtek_stop_ap,
|
|
#if 0
|
|
.sched_scan_start = realtek_cfg80211_sscan_start,
|
|
.sched_scan_stop = realtek_cfg80211_sscan_stop,
|
|
.set_bitrate_mask = realtek_cfg80211_set_bitrate,
|
|
.set_cqm_txe_config = realtek_cfg80211_set_txe_config,
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
.set_mac_acl = realtek_set_mac_acl,
|
|
#if defined(DFS)
|
|
.start_radar_detection = realtek_start_radar_detection,
|
|
#endif
|
|
#endif
|
|
};
|
|
|
|
static void rtk_destroy_dev(struct rtknl *rtk)
|
|
{
|
|
device_del( rtk->dev );
|
|
class_destroy( rtk->cl );
|
|
}
|
|
|
|
static void rtk_create_dev(struct rtknl *rtk,int idx)
|
|
{
|
|
/* define class here */
|
|
unsigned char zero[] = {0, 0, 0, 0, 0, 0};
|
|
rtk->cl = class_create(THIS_MODULE, rtk_dev_name[idx]);
|
|
|
|
/* create first device */
|
|
rtk->dev = device_create(rtk->cl, NULL, rtk_wifi_dev[idx], NULL, rtk_dev_name[idx]);
|
|
|
|
dev_set_name(rtk->dev, rtk_dev_name[idx]);
|
|
printk("Device Name = %s \n", dev_name(rtk->dev));
|
|
|
|
printk("VIF_NUM=%d\n", VIF_NUM);
|
|
memset(rtk->ndev_name, 0, VIF_NUM*VIF_NAME_SIZE);
|
|
|
|
//init rtk phy root name
|
|
sprintf(rtk->root_ifname, "wlan%d", idx);
|
|
|
|
//mark_dual ,init with fake mac for diff phy
|
|
rtk_fake_addr[3] += ((unsigned char)idx) ;
|
|
memcpy(rtk->root_mac, rtk_fake_addr, ETH_ALEN);
|
|
}
|
|
|
|
int realtek_cfg80211_destroy(struct rtknl *rtk)
|
|
{
|
|
struct wiphy *wiphy;
|
|
|
|
if ( NULL == rtk )
|
|
return -1;
|
|
|
|
wiphy = rtk->wiphy;
|
|
|
|
// wiphy_unregister(wiphy);
|
|
|
|
rtk_destroy_dev(rtk);
|
|
|
|
wiphy_free(wiphy);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//struct rtknl *realtek_cfg80211_create(struct rtl8192cd_priv *priv)
|
|
struct rtknl *realtek_cfg80211_create(void)
|
|
{
|
|
struct wiphy *wiphy;
|
|
struct rtknl *rtk;
|
|
|
|
//NLENTER;
|
|
|
|
/* create a new wiphy for use with cfg80211 */
|
|
wiphy = wiphy_new(&realtek_cfg80211_ops, sizeof(struct rtknl));
|
|
|
|
if (!wiphy) {
|
|
printk("couldn't allocate wiphy device\n");
|
|
return NULL;
|
|
}
|
|
|
|
rtk = wiphy_priv(wiphy);
|
|
rtk->wiphy = wiphy;
|
|
//rtk->priv = priv; //mark_dual2
|
|
|
|
//sync to global rtk_phy
|
|
if(rtk_phy_idx > RTK_MAX_WIFI_PHY)
|
|
{
|
|
printk("ERROR!! rtk_phy_idx > RTK_MAX_WIFI_PHY\n");
|
|
wiphy_free(wiphy);
|
|
return NULL;
|
|
}
|
|
rtk_create_dev(rtk,rtk_phy_idx);
|
|
rtk_phy[rtk_phy_idx] = rtk;
|
|
rtk_phy_idx++;
|
|
|
|
//priv->rtk = rtk ; //mark_dual2
|
|
|
|
//NLEXIT;
|
|
return rtk;
|
|
}
|
|
|
|
/*cfg p2p*/
|
|
#if 1
|
|
static const struct ieee80211_txrx_stypes rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
|
[NL80211_IFTYPE_ADHOC] = {
|
|
.tx = 0xffff,
|
|
.rx = BIT(IEEE80211_STYPE_ACTION >> 4)
|
|
},
|
|
[NL80211_IFTYPE_STATION] = {
|
|
.tx = 0xffff,
|
|
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
|
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
|
},
|
|
[NL80211_IFTYPE_AP] = {
|
|
.tx = 0xffff,
|
|
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
|
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
|
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
|
|
BIT(IEEE80211_STYPE_ACTION >> 4)
|
|
},
|
|
[NL80211_IFTYPE_AP_VLAN] = {
|
|
/* copy AP */
|
|
.tx = 0xffff,
|
|
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
|
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
|
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
|
|
BIT(IEEE80211_STYPE_ACTION >> 4)
|
|
},
|
|
#if defined(P2P_SUPPORT)
|
|
[NL80211_IFTYPE_P2P_CLIENT] = {
|
|
.tx = 0xffff,
|
|
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
|
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
|
},
|
|
[NL80211_IFTYPE_P2P_GO] = {
|
|
.tx = 0xffff,
|
|
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
|
|
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
|
|
BIT(IEEE80211_STYPE_AUTH >> 4) |
|
|
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
|
|
BIT(IEEE80211_STYPE_ACTION >> 4)
|
|
},
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
#define MAX_REMAIN_ON_CHANNEL_DURATION 5000 //ms
|
|
#define SCAN_IE_LEN_MAX 2304
|
|
#define SSID_SCAN_AMOUNT 1 // for WEXT_CSCAN_AMOUNT 9
|
|
#define MAX_NUM_PMKIDS 32
|
|
#define NL_MAX_INTF 9
|
|
|
|
static const struct ieee80211_iface_limit rtk_if_limits[] = {
|
|
{ .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
|
|
{ .max = 1, .types = BIT(NL80211_IFTYPE_STATION) },
|
|
};
|
|
|
|
static const struct ieee80211_iface_combination rtk_2g_comb = {
|
|
.limits = rtk_if_limits,
|
|
.n_limits = ARRAY_SIZE(rtk_if_limits),
|
|
.max_interfaces = NL_MAX_INTF,
|
|
.num_different_channels = 1,
|
|
};
|
|
|
|
static const struct ieee80211_iface_combination rtk_5g_comb = {
|
|
.limits = rtk_if_limits,
|
|
.n_limits = ARRAY_SIZE(rtk_if_limits),
|
|
.max_interfaces = NL_MAX_INTF,
|
|
.num_different_channels = 1,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
|
BIT(NL80211_CHAN_WIDTH_20) |
|
|
BIT(NL80211_CHAN_WIDTH_40) |
|
|
BIT(NL80211_CHAN_WIDTH_80),
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* enum wiphy_flags - wiphy capability flags
|
|
*
|
|
* @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device
|
|
* has its own custom regulatory domain and cannot identify the
|
|
* ISO / IEC 3166 alpha2 it belongs to. When this is enabled
|
|
* we will disregard the first regulatory hint (when the
|
|
* initiator is %REGDOM_SET_BY_CORE).
|
|
|
|
* @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
|
|
* ignore regulatory domain settings until it gets its own regulatory
|
|
* domain via its regulatory_hint() unless the regulatory hint is
|
|
* from a country IE. After its gets its own regulatory domain it will
|
|
* only allow further regulatory domain settings to further enhance
|
|
* compliance. For example if channel 13 and 14 are disabled by this
|
|
* regulatory domain no user regulatory domain can enable these channels
|
|
* at a later time. This can be used for devices which do not have
|
|
* calibration information guaranteed for frequencies or settings
|
|
* outside of its regulatory domain. If used in combination with
|
|
* WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings
|
|
* will be followed.
|
|
|
|
* @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
|
|
* that passive scan flags and beaconing flags may not be lifted by
|
|
* cfg80211 due to regulatory beacon hints. For more information on beacon
|
|
* hints read the documenation for regulatory_hint_found_beacon()
|
|
|
|
* @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
|
|
* wiphy at all
|
|
|
|
* @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
|
|
* by default -- this flag will be set depending on the kernel's default
|
|
* on wiphy_new(), but can be changed by the driver if it has a good
|
|
* reason to override the default
|
|
|
|
* @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
|
|
* on a VLAN interface)
|
|
|
|
* @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
|
|
|
|
* @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
|
|
* control port protocol ethertype. The device also honours the
|
|
* control_port_no_encrypt flag.
|
|
|
|
* @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
|
|
|
|
* @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
|
|
* auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
|
|
|
|
* @WIPHY_FLAG_SUPPORTS_SCHED_SCAN: The device supports scheduled scans.
|
|
|
|
* @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the firmware.
|
|
* @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP.
|
|
* @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation.
|
|
* @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z)
|
|
* link setup/discovery operations internally. Setup, discovery and
|
|
* teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
|
|
* command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
|
|
* used for asking the driver/firmware to perform a TDLS operation.
|
|
* @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
|
|
* @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
|
|
* when there are virtual interfaces in AP mode by calling
|
|
* cfg80211_report_obss_beacon().
|
|
* @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device
|
|
* responds to probe-requests in hardware.
|
|
* @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
|
|
* @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
|
|
*/
|
|
int realtek_cfg80211_init(struct rtknl *rtk,struct rtl8192cd_priv *priv)
|
|
{
|
|
struct wiphy *wiphy = rtk->wiphy;
|
|
BOOLEAN band_2gig = FALSE, band_5gig = FALSE;
|
|
int ret;
|
|
#ifdef EN_EFUSE
|
|
char efusemac[ETH_ALEN];
|
|
#endif
|
|
char zero[ETH_ALEN] = {0,0,0,0,0,0};
|
|
unsigned char txbf_max_ant, txbf_sounding_dim;
|
|
NLENTER;
|
|
|
|
rtk->priv = priv; //mark_dual
|
|
|
|
rtk_get_band_capa(priv,&band_2gig,&band_5gig);
|
|
|
|
//wiphy->mgmt_stypes = realtek_mgmt_stypes; //_eric_cfg ??
|
|
wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes; /*cfg p2p*/
|
|
|
|
#if defined(SIGNAL_TYPE_UNSPEC)
|
|
wiphy->signal_type=CFG80211_SIGNAL_TYPE_UNSPEC;
|
|
#else
|
|
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; //mark_priv
|
|
#endif
|
|
/* max num of ssids that can be probed during scanning */
|
|
//wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
|
|
wiphy->max_scan_ssids = SSID_SCAN_AMOUNT;
|
|
|
|
/* max num of ssids that can be matched after scan */
|
|
//wiphy->max_match_sets = MAX_PROBED_SSIDS;
|
|
|
|
//wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
|
|
wiphy->max_scan_ie_len = SCAN_IE_LEN_MAX;
|
|
wiphy->max_num_pmkids = MAX_NUM_PMKIDS;
|
|
wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION; /*cfg p2p p2p related*/
|
|
|
|
switch(get_rf_mimo_mode(priv)) {
|
|
case MIMO_1T1R:
|
|
wiphy->available_antennas_tx = 0x1;
|
|
wiphy->available_antennas_rx = 0x1;
|
|
break;
|
|
case MIMO_3T3R:
|
|
wiphy->available_antennas_tx = 0x3;
|
|
wiphy->available_antennas_rx = 0x3;
|
|
break;
|
|
default:
|
|
wiphy->available_antennas_tx = 0x2;
|
|
wiphy->available_antennas_rx = 0x2;
|
|
}
|
|
|
|
/*The device supports roaming feature in the firmware*/ //_eric_cfg ?? support these features ??
|
|
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM ;
|
|
/*device integrates AP SME*/
|
|
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME ;
|
|
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL ;/*cfg p2p ; p2p must use it*/
|
|
if(band_2gig){
|
|
wiphy->interface_modes = BIT(NL80211_IFTYPE_AP)|
|
|
BIT(NL80211_IFTYPE_STATION) | //_eric_cfg station mandatory ??
|
|
BIT(NL80211_IFTYPE_ADHOC) | //wrt-adhoc
|
|
#if defined(P2P_SUPPORT)
|
|
BIT(NL80211_IFTYPE_P2P_CLIENT)|
|
|
BIT(NL80211_IFTYPE_P2P_GO)|
|
|
BIT(NL80211_IFTYPE_P2P_DEVICE)|
|
|
#endif
|
|
BIT(NL80211_IFTYPE_MONITOR);
|
|
}else{
|
|
wiphy->interface_modes = BIT(NL80211_IFTYPE_AP)|
|
|
BIT(NL80211_IFTYPE_STATION) | //_eric_cfg station mandatory ??
|
|
BIT(NL80211_IFTYPE_ADHOC)|
|
|
BIT(NL80211_IFTYPE_MONITOR);
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
|
|
wiphy->max_acl_mac_addrs = NUM_STAT;
|
|
#endif
|
|
//printk("set_wiphy_dev +++ \n");
|
|
set_wiphy_dev(wiphy, rtk->dev); //return wiphy->dev.parent;
|
|
//printk("set_wiphy_dev --- \n");
|
|
|
|
#if defined(EN_EFUSE) && !defined(CUSTOMIZE_FLASH_EFUSE)
|
|
#ifdef CONFIG_WLAN_HAL_8881A
|
|
if (GET_CHIP_VER(priv) != VERSION_8881A)
|
|
#endif
|
|
{
|
|
extern void read_efuse_mac_address(struct rtl8192cd_priv * priv,char * efusemac);
|
|
memset(efusemac,0,ETH_ALEN);
|
|
read_efuse_mac_address(priv,efusemac);
|
|
if( memcmp(efusemac,zero,ETH_ALEN) && !IS_MCAST(efusemac))
|
|
memcpy(rtk->root_mac,efusemac,ETH_ALEN);
|
|
}
|
|
#endif
|
|
memcpy(wiphy->perm_addr, rtk->root_mac, ETH_ALEN);
|
|
memcpy(priv->pmib->dot11Bss.bssid, wiphy->perm_addr, ETH_ALEN);
|
|
|
|
/*
|
|
* Even if the fw has HT support, advertise HT cap only when
|
|
* the firmware has support to override RSN capability, otherwise
|
|
* 4-way handshake would fail.
|
|
*/
|
|
if(band_2gig)
|
|
{
|
|
wiphy->bands[IEEE80211_BAND_2GHZ] = &realtek_band_2ghz;
|
|
switch (get_rf_mimo_mode(priv)) {
|
|
case MIMO_1T1R:
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_highest = cpu_to_le16(150);
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[0] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[1] = 0;
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[2] = 0;
|
|
break;
|
|
case MIMO_2T2R:
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_highest = cpu_to_le16(300);
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[0] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[1] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[2] = 0;
|
|
break;
|
|
case MIMO_3T3R:
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_highest = cpu_to_le16(450);
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[0] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[1] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.mcs.rx_mask[2] = 0xff;
|
|
break;
|
|
default:
|
|
NDEBUG(" Waring, mimo(%d) not support\n", get_rf_mimo_mode(priv));
|
|
break;
|
|
}
|
|
wiphy->iface_combinations = &rtk_2g_comb;
|
|
wiphy->n_iface_combinations = 1;
|
|
}
|
|
|
|
if (band_5gig)
|
|
{
|
|
wiphy->bands[IEEE80211_BAND_5GHZ] = &realtek_band_5ghz;
|
|
switch (get_rf_mimo_mode(priv))
|
|
{
|
|
case MIMO_1T1R:
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_highest = cpu_to_le16(150);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_mask[0] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_mask[1] = 0;
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_mask[2] = 0;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0xfffe);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0xfffe);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.rx_highest = cpu_to_le16(390);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.tx_highest = cpu_to_le16(390);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap &= ~(IEEE80211_VHT_CAP_TXSTBC);
|
|
#endif
|
|
break;
|
|
case MIMO_2T2R:
|
|
/* skip default setting */
|
|
break;
|
|
case MIMO_3T3R:
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_highest = cpu_to_le16(450);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_mask[0] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_mask[1] = 0xff;
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.mcs.rx_mask[2] = 0xff;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0xffea);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0xffea);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.rx_highest = cpu_to_le16(1170);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.vht_mcs.tx_highest = cpu_to_le16(1170);
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= (IEEE80211_VHT_CAP_RXLDPC);
|
|
#endif
|
|
break;
|
|
default:
|
|
NDEBUG(" Waring, mimo(%d) not support\n", get_rf_mimo_mode(priv));
|
|
break;
|
|
}
|
|
|
|
#ifdef CONFIG_WLAN_HAL_8814AE
|
|
if(GET_CHIP_VER(priv)==VERSION_8814A) {
|
|
if (priv->pshare->rf_ft_var.bf_sup_val != 0) {
|
|
txbf_max_ant = priv->pshare->rf_ft_var.bf_sup_val;
|
|
txbf_sounding_dim = priv->pshare->rf_ft_var.bf_sup_val;
|
|
} else if (get_rf_mimo_mode(priv) == MIMO_4T4R) {
|
|
txbf_max_ant = 3;
|
|
txbf_sounding_dim = 3;
|
|
} else if (get_rf_mimo_mode(priv) == MIMO_3T3R) {
|
|
txbf_max_ant = 2;
|
|
txbf_sounding_dim = 3;
|
|
} else if ((get_rf_mimo_mode(priv) == MIMO_2T4R) || (get_rf_mimo_mode(priv) == MIMO_2T2R)) {
|
|
txbf_max_ant = 2;
|
|
txbf_sounding_dim = 1;
|
|
} else {
|
|
txbf_max_ant = 1;
|
|
txbf_sounding_dim = 1;
|
|
}
|
|
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap &= ~IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= (txbf_max_ant << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
|
|
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap &= ~IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
|
|
wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= (txbf_sounding_dim << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
|
|
}
|
|
#endif
|
|
|
|
wiphy->iface_combinations = &rtk_5g_comb;
|
|
wiphy->n_iface_combinations = 1;
|
|
}
|
|
|
|
wiphy->cipher_suites = cipher_suites;
|
|
wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
|
|
|
#if 0//def CONFIG_PM
|
|
wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
|
WIPHY_WOWLAN_DISCONNECT |
|
|
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
|
|
WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
|
|
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
|
|
WIPHY_WOWLAN_4WAY_HANDSHAKE;
|
|
wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
|
|
wiphy->wowlan.pattern_min_len = 1;
|
|
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
|
|
|
|
wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
|
|
|
|
|
|
wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
|
|
wiphy->probe_resp_offload =
|
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
|
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
|
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
|
|
wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
|
|
#endif
|
|
//printk("wiphy_register +++ \n");
|
|
ret = wiphy_register(wiphy);
|
|
//printk("wiphy_register --- \n");
|
|
|
|
if (ret < 0) {
|
|
printk("couldn't register wiphy device\n");
|
|
return ret;
|
|
} else
|
|
printk("register wiphy device:%p\n", wiphy);
|
|
|
|
rtk->wiphy_registered = true;
|
|
|
|
NLEXIT;
|
|
return 0;
|
|
}
|
|
|
|
int realtek_cfg80211_deinit(struct rtl8192cd_priv *priv, struct rtknl *rtk)
|
|
{
|
|
struct wiphy *wiphy = rtk->wiphy;
|
|
|
|
set_wiphy_dev(wiphy, NULL);
|
|
|
|
printk("deinit wiphy: [%p]:[%p]\n", rtk, wiphy);
|
|
|
|
if (rtk->wiphy_registered) {
|
|
wiphy_unregister(wiphy);
|
|
rtk->wiphy_registered = false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif //RTK_NL80211
|
|
|