M7350/wlan/8192es/DriverSrcPkg/Driver/rtl8192cd_92es/8192cd_util.c
2024-09-09 08:59:52 +00:00

10028 lines
262 KiB
C
Executable File

/*
* Utility routines
*
* $Id: 8192cd_util.c,v 1.52.2.24 2011/01/10 06:55:07 chuangsw Exp $
*
* Copyright (c) 2009 Realtek Semiconductor Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define _8192CD_UTILS_C_
#ifdef __KERNEL__
#include <linux/circ_buf.h>
#include <linux/sched.h>
#include <linux/if_arp.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/ndisc.h>
#include <linux/icmpv6.h>
#include <linux/vmalloc.h>
#elif defined(__ECOS)
#include <pkgconf/system.h>
#include <pkgconf/devs_eth_rltk_819x_wlan.h>
#include <cyg/io/eth/rltk/819x/wrapper/sys_support.h>
#include <cyg/io/eth/rltk/819x/wrapper/skbuff.h>
#include <cyg/io/eth/rltk/819x/wrapper/timer.h>
#include <cyg/io/eth/rltk/819x/wrapper/wrapper.h>
#endif
#include "./8192cd_cfg.h"
#include "./8192cd.h"
#include "./8192cd_util.h"
#include "./8192cd_headers.h"
#include "./8192cd_debug.h"
#ifdef RTK_NL80211
#include "8192cd_cfg80211.h"
#endif
#ifdef RTL8192CD_VARIABLE_USED_DMEM
#include "./8192cd_dmem.h"
#endif
#if defined(CONFIG_RTL_CUSTOM_PASSTHRU)
#ifdef __KERNEL__
#include <linux/if_vlan.h>
#endif
#endif
#if defined(CONFIG_RTL_FASTBRIDGE)
#include <net/rtl/features/fast_bridge.h>
#endif
#if defined(CONFIG_RTL_SIMPLE_CONFIG)
#include <linux/netdevice.h>
#include "./8192cd_profile.h"
extern unsigned char g_sc_ifname[32];
#endif
#ifdef __ECOS
extern void rtl8192cd_beq_timer(void *task_priv);
extern void rtl8192cd_bkq_timer(void *task_priv);
extern void rtl8192cd_viq_timer(void *task_priv);
extern void rtl8192cd_voq_timer(void *task_priv);
#endif
#if defined(USE_PID_NOTIFY) && defined(LINUX_2_6_27_)
struct pid *_wlanapp_pid;
struct pid *_wlanwapi_pid;
#endif
UINT8 Realtek_OUI[]={0x00, 0xe0, 0x4c};
UINT8 dot11_rate_table[]={2,4,11,22,12,18,24,36,48,72,96,108,0}; // last element must be zero!!
#define WLAN_PKT_FORMAT_ENCAPSULATED 0x01
#define WLAN_PKT_FORMAT_CDP 0x06
#ifndef CONFIG_RTK_MESH // mesh project moves these define to 8190n_headers.h
#define WLAN_PKT_FORMAT_SNAP_RFC1042 0x02
#define WLAN_PKT_FORMAT_SNAP_TUNNEL 0x03
#define WLAN_PKT_FORMAT_IPX_TYPE4 0x04
#define WLAN_PKT_FORMAT_APPLETALK 0x05
#define WLAN_PKT_FORMAT_OTHERS 0x07
#endif
#ifdef __ECOS
#ifndef VLAN_HLEN
#define VLAN_HLEN 4
#endif
#endif
unsigned char SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37};
unsigned char SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3};
unsigned char SNAP_ETH_TYPE_APPLETALK_DDP[2] = {0x80, 0x9B};
unsigned char SNAP_HDR_APPLETALK_DDP[3] = {0x08, 0x00, 0x07}; // Datagram Delivery Protocol
void mem_dump(unsigned char *ptitle, unsigned char *pbuf, int len)
{
char tmpbuf[100];
int i, n = 0;
if (ptitle)
sprintf(tmpbuf, "%s", ptitle);
else
tmpbuf[0] = '\0';
for (i = 0; i < len; ++i ) {
if (!(i & 0x0f)) {
printk("%s\n", tmpbuf);
n = sprintf(tmpbuf, "%03X:\t", i);
}
n += sprintf((tmpbuf+n), " %02X", pbuf[i]);
}
printk("%s\n", tmpbuf);
}
struct rtl_arphdr
{
//for corss platform
__be16 ar_hrd; /* format of hardware address */
__be16 ar_pro; /* format of protocol address */
unsigned char ar_hln; /* length of hardware address */
unsigned char ar_pln; /* length of protocol address */
__be16 ar_op; /* ARP opcode (command) */
};
#ifdef DBG_MEMORY_LEAK
#include <asm/atomic.h>
atomic_t _malloc_cnt = ATOMIC_INIT(0);
atomic_t _malloc_size = ATOMIC_INIT(0);
#endif /* DBG_MEMORY_LEAK */
#ifdef __KERNEL__
inline u8* _rtw_vmalloc(u32 sz)
{
u8 *pbuf;
pbuf = vmalloc(sz);
#ifdef DBG_MEMORY_LEAK
if (pbuf != NULL) {
atomic_inc(&_malloc_cnt);
atomic_add(sz, &_malloc_size);
}
#endif /* DBG_MEMORY_LEAK */
return pbuf;
}
inline u8* _rtw_zvmalloc(u32 sz)
{
u8 *pbuf;
pbuf = _rtw_vmalloc(sz);
if (pbuf != NULL) {
memset(pbuf, 0, sz);
}
return pbuf;
}
inline void _rtw_vmfree(const void *pbuf, u32 sz)
{
if (pbuf)
{
vfree(pbuf);
#ifdef DBG_MEMORY_LEAK
atomic_dec(&_malloc_cnt);
atomic_sub(sz, &_malloc_size);
#endif /* DBG_MEMORY_LEAK */
}
}
#endif // __KERNEL__
u8* _rtw_malloc(u32 sz)
{
u8 *pbuf = NULL;
pbuf = kmalloc(sz, /*GFP_KERNEL*/GFP_ATOMIC);
#ifdef DBG_MEMORY_LEAK
if (pbuf != NULL) {
atomic_inc(&_malloc_cnt);
atomic_add(sz, &_malloc_size);
}
#endif /* DBG_MEMORY_LEAK */
return pbuf;
}
u8* _rtw_zmalloc(u32 sz)
{
u8 *pbuf = _rtw_malloc(sz);
if (pbuf != NULL) {
memset(pbuf, 0, sz);
}
return pbuf;
}
void* rtw_malloc2d(int h, int w, int size)
{
int j;
void **a = (void **) rtw_zmalloc( h*sizeof(void *) + h*w*size );
if(a == NULL)
{
return NULL;
}
for( j=0; j<h; j++ )
a[j] = ((char *)(a+h)) + j*w*size;
return a;
}
void rtw_mfree2d(void *pbuf, int h, int w, int size)
{
rtw_mfree((u8 *)pbuf, h*sizeof(void*) + w*h*size);
}
void _rtw_mfree(const void *pbuf, u32 sz)
{
if (pbuf)
{
kfree(pbuf);
#ifdef DBG_MEMORY_LEAK
atomic_dec(&_malloc_cnt);
atomic_sub(sz, &_malloc_size);
#endif /* DBG_MEMORY_LEAK */
}
}
#ifndef _11s_TEST_MODE_
static
#endif
__inline__ void release_buf_to_poll(struct rtl8192cd_priv *priv, unsigned char *pbuf, struct list_head *phead, unsigned int *count)
{
struct list_head *plist;
#ifdef SMP_SYNC
unsigned long flags;
#endif
if (pbuf == NULL)
{
DEBUG_ERR("Release Null Buf!\n");
return;
}
#if 0
if (*count >= PRE_ALLOCATED_HDR) {
_DEBUG_ERR("over size free buf phead=%lX, *count=%d\n", (unsigned long)phead, *count);
return;
}
#endif
plist = (struct list_head *)((unsigned long)pbuf - sizeof(struct list_head));
SMP_LOCK_BUF(flags);
*count = *count + 1;
list_add_tail(plist, phead);
SMP_UNLOCK_BUF(flags);
}
#ifndef _11s_TEST_MODE_
static
#endif
__inline__ unsigned char *get_buf_from_poll(struct rtl8192cd_priv *priv, struct list_head *phead, unsigned int *count)
{
unsigned char *buf;
struct list_head *plist;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
if(priv)
SMP_LOCK_BUF(flags);
if (list_empty(phead)) {
if(priv)
SMP_UNLOCK_BUF(flags);
// _DEBUG_ERR("phead=%lX buf is empty now!\n", (unsigned long)phead);
return NULL;
}
if (*count == 0) {
if(priv)
SMP_UNLOCK_BUF(flags);
_DEBUG_ERR("phead=%lX under-run!\n", (unsigned long)phead);
return NULL;
}
*count = *count - 1;
plist = phead->next;
list_del_init(plist);
if(priv)
SMP_UNLOCK_BUF(flags);
buf = (UINT8 *)((unsigned long)plist + sizeof (struct list_head));
return buf;
}
__inline__ unsigned int orSTABitMap(STA_BITMAP *map)
{
return (
map->_staMap_
#if (NUM_STAT >32)
|| map->_staMap_ext_1
#if (NUM_STAT >64)
|| map->_staMap_ext_2 || map->_staMap_ext_3
#endif
#endif
);
}
__inline__ unsigned int orForce20_Switch20Map(struct rtl8192cd_priv *priv)
{
return (orSTABitMap(&priv->force_20_sta) || orSTABitMap(&priv->switch_20_sta));
}
/* return 1 or 0*/
unsigned char getSTABitMap(STA_BITMAP *map, int bitIdx)
{
unsigned int ret = 0;
bitIdx--;
if (bitIdx < 32)
ret = map->_staMap_ & BIT(bitIdx);
#if (NUM_STAT >32)
else if (bitIdx <= 64)
ret = map->_staMap_ext_1 & BIT(bitIdx - 32);
#if (NUM_STAT >64)
else if (bitIdx <= 96)
ret = map->_staMap_ext_2 & BIT(bitIdx - 64);
else if (bitIdx <= 128)
ret = map->_staMap_ext_3 & BIT(bitIdx -96);
#endif
#endif
return (ret?1:0);
}
#ifdef RTK_NL80211
int changePreamble(struct rtl8192cd_priv *priv, int preamble)
{
unsigned char *p = (unsigned char *)priv->beaconbuf;
unsigned short *bcn_cap = p+BEACON_MACHDR_LEN+_TIMESTAMP_+_BEACON_ITERVAL_;
if(preamble)
*bcn_cap |= cpu_to_le16(BIT(5));
else
*bcn_cap &= ~(cpu_to_le16(BIT(5)));
return 0;
}
int HideAP(struct rtl8192cd_priv *priv)
{
unsigned char *p = (unsigned char *)priv->beaconbuf;
memset(p + 24 + _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_ + 2, 0, SSID_LEN);
return 0;
}
int DehideAP(struct rtl8192cd_priv *priv)
{
unsigned char *p = (unsigned char *)priv->beaconbuf;
memcpy(p + 24 + _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_ + 2, SSID, SSID_LEN);
*(p + 24 + _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_ + 1) = SSID_LEN;
return 0;
}
#endif
void setSTABitMap(STA_BITMAP *map, int bitIdx)
{
bitIdx--;
if (bitIdx < 32)
map->_staMap_ |= BIT(bitIdx);
#if (NUM_STAT >32)
else if (bitIdx <= 64)
map->_staMap_ext_1 |= BIT(bitIdx - 32);
#if (NUM_STAT >64)
else if (bitIdx <= 96)
map->_staMap_ext_2 |= BIT(bitIdx - 64);
else if (bitIdx <= 128)
map->_staMap_ext_3 |= BIT(bitIdx -96);
#endif
#endif
}
void clearSTABitMap(STA_BITMAP* map, int bitIdx)
{
bitIdx--;
if (bitIdx < 32)
map->_staMap_ &= ~ BIT(bitIdx);
#if (NUM_STAT >32)
else if (bitIdx < 64)
map->_staMap_ext_1 &= ~ BIT(bitIdx - 32);
#if (NUM_STAT >64)
else if (bitIdx < 96)
map->_staMap_ext_2 &= ~ BIT(bitIdx - 64);
else if (bitIdx < 128)
map->_staMap_ext_3 &= ~ BIT(bitIdx - 96);
#endif
#endif
}
#ifdef PRIV_STA_BUF
struct priv_obj_buf {
unsigned char magic[8];
struct list_head list;
struct aid_obj obj;
};
#if defined(WIFI_WMM) && defined(WMM_APSD)
struct priv_apsd_que {
unsigned char magic[8];
struct list_head list;
struct apsd_pkt_queue que;
};
#endif
#if defined(WIFI_WMM)
struct priv_dz_mgt_que {
unsigned char magic[8];
struct list_head list;
struct dz_mgmt_queue que;
};
#endif
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
struct priv_wpa_buf {
unsigned char magic[8];
struct list_head list;
WPA_STA_INFO wpa;
};
#endif
#define MAGIC_CODE_BUF "8192"
#define MAX_PRIV_OBJ_NUM NUM_STAT
#ifdef CONCURRENT_MODE
static struct priv_obj_buf obj_buf[NUM_WLAN_IFACE][MAX_PRIV_OBJ_NUM];
static struct list_head objbuf_list[NUM_WLAN_IFACE];
static int free_obj_buf_num[NUM_WLAN_IFACE];
#if defined(WIFI_WMM) && defined(WMM_APSD)
#define MAX_PRIV_QUE_NUM (MAX_PRIV_OBJ_NUM*4)
static struct priv_apsd_que que_buf[NUM_WLAN_IFACE][MAX_PRIV_QUE_NUM];
static struct list_head quebuf_list[NUM_WLAN_IFACE];
static int free_que_buf_num[NUM_WLAN_IFACE];
#endif
#if defined(WIFI_WMM)
#define MAX_MGT_QUE_NUM (MAX_PRIV_OBJ_NUM)
static struct priv_dz_mgt_que mgt_que_buf[NUM_WLAN_IFACE][MAX_MGT_QUE_NUM];
static struct list_head mgt_quebuf_list[NUM_WLAN_IFACE];
static int free_mgt_que_buf_num[NUM_WLAN_IFACE];
#endif
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
#define MAX_PRIV_WPA_NUM MAX_PRIV_OBJ_NUM
static struct priv_wpa_buf wpa_buf[NUM_WLAN_IFACE][MAX_PRIV_WPA_NUM];
static struct list_head wpabuf_list[NUM_WLAN_IFACE];
static int free_wpa_buf_num[NUM_WLAN_IFACE];
#endif
#else
static struct priv_obj_buf obj_buf[MAX_PRIV_OBJ_NUM];
static struct list_head objbuf_list;
static int free_obj_buf_num;
#if defined(WIFI_WMM) && defined(WMM_APSD)
#define MAX_PRIV_QUE_NUM (MAX_PRIV_OBJ_NUM*4)
static struct priv_apsd_que que_buf[MAX_PRIV_QUE_NUM];
static struct list_head quebuf_list;
static int free_que_buf_num;
#endif
#if defined(WIFI_WMM)
#define MAX_MGT_QUE_NUM (MAX_PRIV_OBJ_NUM)
static struct priv_dz_mgt_que mgt_que_buf[MAX_MGT_QUE_NUM];
static struct list_head mgt_quebuf_list;
static int free_mgt_que_buf_num;
#endif
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
#define MAX_PRIV_WPA_NUM MAX_PRIV_OBJ_NUM
static struct priv_wpa_buf wpa_buf[MAX_PRIV_WPA_NUM];
static struct list_head wpabuf_list;
static int free_wpa_buf_num;
#endif
#endif
void init_priv_sta_buf(struct rtl8192cd_priv *priv)
{
int i;
#ifdef CONCURRENT_MODE
int idx = priv->pshare->wlandev_idx;
memset(&obj_buf[idx], '\0', sizeof(struct priv_obj_buf)*MAX_PRIV_OBJ_NUM);
INIT_LIST_HEAD(&objbuf_list[idx]);
for (i=0; i<MAX_PRIV_OBJ_NUM; i++) {
memcpy(obj_buf[idx][i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&obj_buf[idx][i].list);
list_add_tail(&obj_buf[idx][i].list, &objbuf_list[idx]);
}
free_obj_buf_num[idx] = i;
#if defined(WIFI_WMM) && defined(WMM_APSD)
memset(&que_buf[idx], '\0', sizeof(struct priv_apsd_que)*MAX_PRIV_QUE_NUM);
INIT_LIST_HEAD(&quebuf_list[idx]);
for (i=0; i<MAX_PRIV_QUE_NUM; i++) {
memcpy(que_buf[idx][i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&que_buf[idx][i].list);
list_add_tail(&que_buf[idx][i].list, &quebuf_list[idx]);
}
free_que_buf_num[idx] = i;
#endif
#if defined(WIFI_WMM)
memset(&mgt_que_buf[idx], '\0', sizeof(struct priv_dz_mgt_que)*MAX_MGT_QUE_NUM);
INIT_LIST_HEAD(&mgt_quebuf_list[idx]);
for (i=0; i<MAX_MGT_QUE_NUM; i++) {
memcpy(mgt_que_buf[idx][i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&mgt_que_buf[idx][i].list);
list_add_tail(&mgt_que_buf[idx][i].list, &mgt_quebuf_list[idx]);
}
free_mgt_que_buf_num[idx] = i;
#endif
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
memset(&wpa_buf[idx], '\0', sizeof(struct priv_wpa_buf)*MAX_PRIV_WPA_NUM);
INIT_LIST_HEAD(&wpabuf_list[idx]);
for (i=0; i<MAX_PRIV_WPA_NUM; i++) {
memcpy(wpa_buf[idx][i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&wpa_buf[idx][i].list);
list_add_tail(&wpa_buf[idx][i].list, &wpabuf_list[idx]);
}
free_wpa_buf_num[idx] = i;
#endif
#else
memset(obj_buf, '\0', sizeof(struct priv_obj_buf)*MAX_PRIV_OBJ_NUM);
INIT_LIST_HEAD(&objbuf_list);
for (i=0; i<MAX_PRIV_OBJ_NUM; i++) {
memcpy(obj_buf[i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&obj_buf[i].list);
list_add_tail(&obj_buf[i].list, &objbuf_list);
}
free_obj_buf_num = i;
#if defined(WIFI_WMM) && defined(WMM_APSD)
memset(que_buf, '\0', sizeof(struct priv_apsd_que)*MAX_PRIV_QUE_NUM);
INIT_LIST_HEAD(&quebuf_list);
for (i=0; i<MAX_PRIV_QUE_NUM; i++) {
memcpy(que_buf[i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&que_buf[i].list);
list_add_tail(&que_buf[i].list, &quebuf_list);
}
free_que_buf_num = i;
#endif
#if defined(WIFI_WMM)
memset(&mgt_que_buf, '\0', sizeof(struct priv_dz_mgt_que)*MAX_MGT_QUE_NUM);
INIT_LIST_HEAD(&mgt_quebuf_list);
for (i=0; i<MAX_MGT_QUE_NUM; i++) {
memcpy(mgt_que_buf[i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&mgt_que_buf[i].list);
list_add_tail(&mgt_que_buf[i].list, &mgt_quebuf_list);
}
free_mgt_que_buf_num = i;
#endif
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
memset(wpa_buf, '\0', sizeof(struct priv_wpa_buf)*MAX_PRIV_WPA_NUM);
INIT_LIST_HEAD(&wpabuf_list);
for (i=0; i<MAX_PRIV_WPA_NUM; i++) {
memcpy(wpa_buf[i].magic, MAGIC_CODE_BUF, 4);
INIT_LIST_HEAD(&wpa_buf[i].list);
list_add_tail(&wpa_buf[i].list, &wpabuf_list);
}
free_wpa_buf_num = i;
#endif
#endif
}
struct aid_obj *alloc_sta_obj(struct rtl8192cd_priv *priv)
{
#ifndef SMP_SYNC
unsigned long flags=0;
#endif
struct aid_obj *priv_obj;
if(priv)
SAVE_INT_AND_CLI(flags);
#if defined(__ECOS) && defined(CONFIG_SDIO_HCI)
#ifdef CONCURRENT_MODE
priv_obj = (struct aid_obj *)get_buf_from_poll(priv, &objbuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_obj_buf_num[priv->pshare->wlandev_idx]);
#else
priv_obj = (struct aid_obj *)get_buf_from_poll(priv, &objbuf_list, (unsigned int *)&free_obj_buf_num);
#endif
#else
#ifdef CONCURRENT_MODE
priv_obj = (struct aid_obj *)get_buf_from_poll(NULL, &objbuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_obj_buf_num[priv->pshare->wlandev_idx]);
#else
priv_obj = (struct aid_obj *)get_buf_from_poll(NULL, &objbuf_list, (unsigned int *)&free_obj_buf_num);
#endif
#endif
if(priv)
RESTORE_INT(flags);
#ifdef __KERNEL__
if (priv_obj == NULL)
return ((struct aid_obj *)kmalloc(sizeof(struct aid_obj), GFP_ATOMIC));
else
#endif
return priv_obj;
}
void free_sta_obj(struct rtl8192cd_priv *priv, struct aid_obj *obj)
{
unsigned long offset = (unsigned long)(&((struct priv_obj_buf *)0)->obj);
struct priv_obj_buf *priv_obj = (struct priv_obj_buf *)(((unsigned long)obj) - offset);
#ifndef SMP_SYNC
unsigned long flags;
#endif
if (!memcmp(priv_obj->magic, MAGIC_CODE_BUF, 4) &&
((unsigned long)&priv_obj->obj) == ((unsigned long)obj)) {
SAVE_INT_AND_CLI(flags);
#ifdef CONCURRENT_MODE
release_buf_to_poll(priv, (unsigned char *)obj, &objbuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_obj_buf_num[priv->pshare->wlandev_idx]);
#else
release_buf_to_poll(priv, (unsigned char *)obj, &objbuf_list, (unsigned int *)&free_obj_buf_num);
#endif
RESTORE_INT(flags);
}
else
#ifdef __ECOS
ASSERT(0);
#else
kfree(obj);
#endif
}
#if defined(WIFI_WMM) && defined(WMM_APSD)
static struct apsd_pkt_queue *alloc_sta_que(struct rtl8192cd_priv *priv)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
struct apsd_pkt_queue *priv_que;
SAVE_INT_AND_CLI(flags);
#ifdef CONCURRENT_MODE
priv_que = (struct apsd_pkt_queue*)get_buf_from_poll(priv, &quebuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_que_buf_num[priv->pshare->wlandev_idx]);
#else
priv_que = (struct apsd_pkt_queue*)get_buf_from_poll(priv, &quebuf_list, (unsigned int *)&free_que_buf_num);
#endif
RESTORE_INT(flags);
#ifdef __KERNEL__
if (priv_que == NULL)
return ((struct apsd_pkt_queue *)kmalloc(sizeof(struct apsd_pkt_queue), GFP_ATOMIC));
else
#endif
return priv_que;
}
void free_sta_que(struct rtl8192cd_priv *priv, struct apsd_pkt_queue *que)
{
unsigned long offset = (unsigned long)(&((struct priv_apsd_que *)0)->que);
struct priv_apsd_que *priv_que = (struct priv_apsd_que *)(((unsigned long)que) - offset);
#ifndef SMP_SYNC
unsigned long flags;
#endif
if (!memcmp(priv_que->magic, MAGIC_CODE_BUF, 4) &&
((unsigned long)&priv_que->que) == ((unsigned long)que)) {
SAVE_INT_AND_CLI(flags);
#ifdef CONCURRENT_MODE
release_buf_to_poll(priv, (unsigned char *)que, &quebuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_que_buf_num[priv->pshare->wlandev_idx]);
#else
release_buf_to_poll(priv, (unsigned char *)que, &quebuf_list, (unsigned int *)&free_que_buf_num);
#endif
RESTORE_INT(flags);
}
else
#ifdef __ECOS
ASSERT(0);
#else
kfree(que);
#endif
}
#endif // defined(WIFI_WMM) && defined(WMM_APSD)
#if defined(WIFI_WMM)
static struct dz_mgmt_queue *alloc_sta_mgt_que(struct rtl8192cd_priv *priv)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
struct dz_mgmt_queue *priv_que;
SAVE_INT_AND_CLI(flags);
#ifdef CONCURRENT_MODE
priv_que = (struct dz_mgmt_queue*)get_buf_from_poll(priv, &mgt_quebuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_mgt_que_buf_num[priv->pshare->wlandev_idx]);
#else
priv_que = (struct dz_mgmt_queue*)get_buf_from_poll(priv, &mgt_quebuf_list, (unsigned int *)&free_mgt_que_buf_num);
#endif
RESTORE_INT(flags);
#ifdef __KERNEL__
if (priv_que == NULL)
return ((struct dz_mgmt_queue *)kmalloc(sizeof(struct dz_mgmt_queue), GFP_ATOMIC));
else
#endif
return priv_que;
}
void free_sta_mgt_que(struct rtl8192cd_priv *priv, struct dz_mgmt_queue *que)
{
unsigned long offset = (unsigned long)(&((struct priv_dz_mgt_que *)0)->que);
struct priv_dz_mgt_que *priv_que = (struct priv_dz_mgt_que *)(((unsigned long)que) - offset);
#ifndef SMP_SYNC
unsigned long flags;
#endif
if (!memcmp(priv_que->magic, MAGIC_CODE_BUF, 4) &&
((unsigned long)&priv_que->que) == ((unsigned long)que)) {
SAVE_INT_AND_CLI(flags);
#ifdef CONCURRENT_MODE
release_buf_to_poll(priv, (unsigned char *)que, &mgt_quebuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_mgt_que_buf_num[priv->pshare->wlandev_idx]);
#else
release_buf_to_poll(priv, (unsigned char *)que, &mgt_quebuf_list, (unsigned int *)&free_mgt_que_buf_num);
#endif
RESTORE_INT(flags);
}
else
kfree(que);
}
#endif // defined(WIFI_WMM)
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
static WPA_STA_INFO *alloc_wpa_buf(struct rtl8192cd_priv *priv)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
WPA_STA_INFO *priv_buf;
SAVE_INT_AND_CLI(flags);
#ifdef CONCURRENT_MODE
priv_buf = (WPA_STA_INFO *)get_buf_from_poll(priv, &wpabuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_wpa_buf_num[priv->pshare->wlandev_idx]);
#else
priv_buf = (WPA_STA_INFO *)get_buf_from_poll(priv, &wpabuf_list, (unsigned int *)&free_wpa_buf_num);
#endif
RESTORE_INT(flags);
#ifdef __ECOS
ASSERT(priv_buf != NULL);
return priv_buf;
#else
if (priv_buf == NULL)
return ((WPA_STA_INFO *)kmalloc(sizeof(WPA_STA_INFO), GFP_ATOMIC));
else
return priv_buf;
#endif
}
void free_wpa_buf(struct rtl8192cd_priv *priv, WPA_STA_INFO *buf)
{
unsigned long offset = (unsigned long)(&((struct priv_wpa_buf *)0)->wpa);
struct priv_wpa_buf *priv_buf = (struct priv_wpa_buf *)(((unsigned long)buf) - offset);
#ifndef SMP_SYNC
unsigned long flags;
#endif
if (!memcmp(priv_buf->magic, MAGIC_CODE_BUF, 4) &&
((unsigned long)&priv_buf->wpa) == ((unsigned long)buf)) {
SAVE_INT_AND_CLI(flags);
#ifdef CONCURRENT_MODE
release_buf_to_poll(priv, (unsigned char *)buf, &wpabuf_list[priv->pshare->wlandev_idx], (unsigned int *)&free_wpa_buf_num[priv->pshare->wlandev_idx]);
#else
release_buf_to_poll(priv, (unsigned char *)buf, &wpabuf_list, (unsigned int *)&free_wpa_buf_num);
#endif
RESTORE_INT(flags);
}
else
#ifdef __ECOS
ASSERT(0);
#else
kfree(buf);
#endif
}
#endif // INCLUDE_WPA_PSK
#endif // PRIV_STA_BUF
#ifdef CONFIG_RTL8190_PRIV_SKB
#ifdef CONCURRENT_MODE
static struct sk_buff *dev_alloc_skb_priv(struct rtl8192cd_priv *priv, unsigned int size);
#else
static struct sk_buff *dev_alloc_skb_priv(struct rtl8192cd_priv *priv, unsigned int size);
#endif
#endif
int enque(struct rtl8192cd_priv *priv, int *head, int *tail, unsigned long ffptr, int ffsize, void *elm)
{
// critical section!
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
if (CIRC_SPACE(*head, *tail, ffsize) == 0) {
RESTORE_INT(flags);
return FALSE;
}
*(unsigned long *)(ffptr + (*head)*(sizeof(void *))) = (unsigned long)elm;
*head = (*head + 1) & (ffsize - 1);
RESTORE_INT(flags);
return TRUE;
}
void* deque(struct rtl8192cd_priv *priv, int *head, int *tail, unsigned long ffptr, int ffsize)
{
// critical section!
unsigned int i;
#ifndef SMP_SYNC
unsigned long flags;
#endif
void *elm;
SAVE_INT_AND_CLI(flags);
if (CIRC_CNT(*head, *tail, ffsize) == 0) {
RESTORE_INT(flags);
return NULL;
}
i = *tail;
*tail = (*tail + 1) & (ffsize - 1);
elm = (void*)(*(unsigned long *)(ffptr + i*(sizeof(void *))));
RESTORE_INT(flags);
return elm;
}
void initque(struct rtl8192cd_priv *priv, int *head, int *tail)
{
// critical section!
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
*head = *tail = 0;
RESTORE_INT(flags);
}
int isFFempty(int head, int tail)
{
return (head == tail);
}
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
void _init_txservq(struct tx_servq *ptxservq, int q_num)
{
_rtw_init_listhead(&ptxservq->tx_pending);
_rtw_init_queue(&ptxservq->xframe_queue);
ptxservq->q_num = q_num;
#ifdef CONFIG_SDIO_HCI
ptxservq->ts_used = 0;
#endif
}
#ifdef CONFIG_TCP_ACK_TXAGG
void _init_tcpack_servq(struct tcpack_servq *tcpackq, int q_num)
{
_rtw_init_listhead(&tcpackq->tx_pending);
_rtw_init_queue(&tcpackq->xframe_queue);
tcpackq->q_num = q_num;
}
#endif
#endif // CONFIG_USB_HCI || CONFIG_SDIO_HCI
#ifdef CONFIG_RTK_MESH
unsigned int find_rate_MP(struct rtl8192cd_priv *priv, struct stat_info *pstat, struct ht_cap_elmt * peer_ht_cap, int peer_ht_cap_len, char *peer_rate,int peer_rate_len,int mode, int isBasicRate)
{
unsigned int len, i, hirate, lowrate, rate_limit, OFDM_only=0;
unsigned char *rateset, *p;
if ((get_rf_mimo_mode(priv)== MIMO_1T2R) || (get_rf_mimo_mode(priv)== MIMO_1T1R)) //eric-8814 ?? 3t3r ??
rate_limit = 8;
else if (get_rf_mimo_mode(priv)== MIMO_2T2R)
rate_limit = 16;
else if (get_rf_mimo_mode(priv)== MIMO_3T3R)
rate_limit = 24;
else
rate_limit = 16;
if (pstat) {
rateset = pstat->bssrateset;
len = pstat->bssratelen;
}
else {
rateset = peer_rate;
len = peer_rate_len;
}
hirate = _1M_RATE_;
lowrate = _54M_RATE_;
if (priv->pshare->curr_band == BAND_5G)
OFDM_only = 1;
for(i=0,p=rateset; i<len; i++,p++)
{
if (*p == 0x00)
break;
if ((isBasicRate & 1) && !(*p & 0x80))
continue;
if ((isBasicRate & 2) && !is_CCK_rate(*p & 0x7f))
continue;
if ((*p & 0x7f) > hirate)
if (!OFDM_only || !is_CCK_rate(*p & 0x7f))
hirate = (*p & 0x7f);
if ((*p & 0x7f) < lowrate)
if (!OFDM_only || !is_CCK_rate(*p & 0x7f))
lowrate = (*p & 0x7f);
}
if (pstat) {
if ((mode == 1) && (isBasicRate == 0) && pstat->ht_cap_len) {
for (i=0; i<rate_limit; i++)
{
if (pstat->ht_cap_buf.support_mcs[i/8] & BIT(i%8)) {
hirate = i;
hirate += HT_RATE_ID;
}
}
}
}
else {
if ((mode == 1) && (isBasicRate == 0) && priv->ht_cap_len && peer_ht_cap_len) {
for (i=0; i<rate_limit; i++)
{
if (peer_ht_cap->support_mcs[i/8] & BIT(i%8)) {
hirate = i;
hirate += HT_RATE_ID;
}
}
}
}
if (mode == 0)
return lowrate;
else
return hirate;
}
#endif
// rateset: is the rateset for searching
// mode: 0: find the lowest rate, 1: find the highest rate
// isBasicRate: bit0-1: find from basic rate set, bit0-0: find from supported rate set. bit1-1: find CCK only
unsigned int find_rate(struct rtl8192cd_priv *priv, struct stat_info *pstat, int mode, int isBasicRate)
{
unsigned int len, i, hirate, lowrate, rate_limit, OFDM_only=0;
unsigned char *rateset, *p;
#ifdef CLIENT_MODE
unsigned char totalrateset[32];
#endif
if ((get_rf_mimo_mode(priv)== MIMO_1T2R) || (get_rf_mimo_mode(priv)== MIMO_1T1R)) //eric-8814 ?? 3t3r ??
rate_limit = 8;
else if (get_rf_mimo_mode(priv)== MIMO_2T2R)
rate_limit = 16;
else if (get_rf_mimo_mode(priv)== MIMO_3T3R)
rate_limit = 24;
else
rate_limit = 16;
if (pstat) {
rateset = pstat->bssrateset;
len = pstat->bssratelen;
} else {
#ifdef CLIENT_MODE
if ((OPMODE & WIFI_STATION_STATE) && priv->pmib->dot11Bss.supportrate) {
int i=0;
len = 0;
for (i=0; dot11_rate_table[i]; i++) {
if (priv->pmib->dot11Bss.supportrate & BIT(i)) {
totalrateset[len] = dot11_rate_table[i];
if (priv->pmib->dot11Bss.basicrate & BIT(i))
totalrateset[len] |= 0x80;
len++;
}
}
rateset = totalrateset;
} else
#endif
{
rateset = AP_BSSRATE;
len = AP_BSSRATE_LEN;
}
}
hirate = _1M_RATE_;
lowrate = _54M_RATE_;
if (priv->pshare->curr_band == BAND_5G
#if defined(RTK_5G_SUPPORT)
|| priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G
#endif
)
OFDM_only = 1;
for(i=0,p=rateset; i<len; i++,p++)
{
if (*p == 0x00)
break;
if ((isBasicRate & 1) && !(*p & 0x80))
continue;
if ((isBasicRate & 2) && !is_CCK_rate(*p & 0x7f))
continue;
if ((*p & 0x7f) > hirate)
if (!OFDM_only || !is_CCK_rate(*p & 0x7f))
hirate = (*p & 0x7f);
if ((*p & 0x7f) < lowrate)
if (!OFDM_only || !is_CCK_rate(*p & 0x7f))
lowrate = (*p & 0x7f);
}
if (pstat) {
if ((mode == 1) && (isBasicRate == 0) && pstat->ht_cap_len && (!should_restrict_Nrate(priv, pstat))) {
for (i=0; i<rate_limit; i++)
{
if (pstat->ht_cap_buf.support_mcs[i/8] & BIT(i&0x7)) {
hirate = i;
hirate += HT_RATE_ID;
}
}
}
}
else {
if ((mode == 1) && (isBasicRate == 0) && priv->ht_cap_len) {
for (i=0; i<rate_limit; i++)
{
if (priv->ht_cap_buf.support_mcs[i/8] & BIT(i%8)) {
hirate = i;
hirate += HT_RATE_ID;
}
}
}
}
if (mode == 0)
return lowrate;
else
return hirate;
}
UINT8 get_rate_from_bit_value(int bit_val)
{
int i;
if (bit_val == 0)
return 0;
#ifdef RTK_AC_SUPPORT //vht rate
if(bit_val & BIT(31)) {
i = bit_val - BIT(31);
if(i < VHT_RATE_NUM)
return (VHT_RATE_ID + i);
else
return _NSS1_MCS0_RATE_; //unknown rate value
}
#endif
if(bit_val & BIT(28)) {
i = bit_val - BIT(28);
if((i+16) < HT_RATE_NUM)
return (_MCS16_RATE_ + i);
else
return _MCS0_RATE_; //unknown rate value
}
i = 0;
while ((bit_val & BIT(i)) == 0)
i++;
if (i < 12)
return dot11_rate_table[i];
else if (i < 28)
return ((i - 12) + HT_RATE_ID);
return 0;
}
int get_rate_index_from_ieee_value(UINT8 val)
{
int i;
for (i=0; dot11_rate_table[i]; i++) {
if (val == dot11_rate_table[i]) {
return i;
}
}
_DEBUG_ERR("Local error, invalid input rate for get_rate_index_from_ieee_value() [%d]!!\n", val);
return 0;
}
int get_bit_value_from_ieee_value(UINT8 val)
{
int i=0;
while(dot11_rate_table[i] != 0) {
if (dot11_rate_table[i] == val)
return BIT(i);
i++;
}
return 0;
}
BOOLEAN CheckCts2SelfEnable(UINT8 rtsTxRate)
{
return (rtsTxRate <= _11M_RATE_) ? 1 :0;
}
UINT8 find_rts_rate(struct rtl8192cd_priv *priv, UINT8 TxRate, BOOLEAN bErpProtect)
{
UINT8 rtsTxRate = _6M_RATE_;
if(bErpProtect) // use CCK rate as RTS
{
rtsTxRate = _1M_RATE_;
}
else
{
switch (TxRate)
{
case _NSS2_MCS9_RATE_:
case _NSS2_MCS8_RATE_:
case _NSS2_MCS7_RATE_:
case _NSS2_MCS6_RATE_:
case _NSS2_MCS5_RATE_:
case _NSS2_MCS4_RATE_:
case _NSS2_MCS3_RATE_:
case _NSS1_MCS9_RATE_:
case _NSS1_MCS8_RATE_:
case _NSS1_MCS7_RATE_:
case _NSS1_MCS6_RATE_:
case _NSS1_MCS5_RATE_:
case _NSS1_MCS4_RATE_:
case _NSS1_MCS3_RATE_:
case _MCS15_RATE_:
case _MCS14_RATE_:
case _MCS13_RATE_:
case _MCS12_RATE_:
case _MCS11_RATE_:
case _MCS7_RATE_:
case _MCS6_RATE_:
case _MCS5_RATE_:
case _MCS4_RATE_:
case _MCS3_RATE_:
case _54M_RATE_:
case _48M_RATE_:
case _36M_RATE_:
case _24M_RATE_:
rtsTxRate = _24M_RATE_;
break;
case _NSS2_MCS2_RATE_:
case _NSS2_MCS1_RATE_:
case _NSS1_MCS2_RATE_:
case _NSS1_MCS1_RATE_:
case _MCS10_RATE_:
case _MCS9_RATE_:
case _MCS2_RATE_:
case _MCS1_RATE_:
case _18M_RATE_:
case _12M_RATE_:
rtsTxRate = _12M_RATE_;
break;
case _NSS2_MCS0_RATE_:
case _NSS1_MCS0_RATE_:
case _MCS8_RATE_:
case _MCS0_RATE_:
case _9M_RATE_:
case _6M_RATE_:
rtsTxRate = _6M_RATE_;
break;
case _11M_RATE_:
case _5M_RATE_:
case _2M_RATE_:
case _1M_RATE_:
rtsTxRate = _1M_RATE_;
break;
default:
rtsTxRate = _6M_RATE_;
break;
}
}
if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G) {
if(rtsTxRate < _6M_RATE_)
rtsTxRate = _6M_RATE_;
}
return rtsTxRate;
}
void init_stainfo(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
struct wifi_mib *pmib = priv->pmib;
unsigned long offset;
int i, j;
#if !defined(SMP_SYNC) && defined(CONFIG_RTL_WAPI_SUPPORT)
unsigned long flags;
#endif
#ifdef WDS
static unsigned char bssrateset[32];
unsigned int bssratelen=0;
unsigned int current_tx_rate=0;
#endif
unsigned short bk_aid;
unsigned char bk_hwaddr[MACADDRLEN];
// init linked list header
// BUT do NOT init hash_list
INIT_LIST_HEAD(&pstat->asoc_list);
INIT_LIST_HEAD(&pstat->auth_list);
INIT_LIST_HEAD(&pstat->sleep_list);
INIT_LIST_HEAD(&pstat->defrag_list);
INIT_LIST_HEAD(&pstat->wakeup_list);
INIT_LIST_HEAD(&pstat->frag_list);
#ifdef CONFIG_PCI_HCI
// to avoid add RAtid fail
INIT_LIST_HEAD(&pstat->addRAtid_list);
INIT_LIST_HEAD(&pstat->addrssi_list);
#endif
#ifdef CONFIG_RTK_MESH
INIT_LIST_HEAD(&pstat->mesh_mp_ptr);
#endif // CONFIG_RTK_MESH
#ifdef A4_STA
INIT_LIST_HEAD(&pstat->a4_sta_list);
#endif
#if defined(CONFIG_PCI_HCI)
skb_queue_head_init(&pstat->dz_queue);
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
INIT_LIST_HEAD(&pstat->pspoll_list);
for (i = 0; i < MAX_STA_TX_SERV_QUEUE; ++i) {
_init_txservq(&pstat->tx_queue[i], i);
#ifdef CONFIG_TCP_ACK_TXAGG
_init_tcpack_servq(&pstat->tcpack_queue[i], i);
#endif
}
pstat->pending_cmd = 0;
pstat->asoc_list_refcnt = 0;
#ifdef __ECOS
cyg_flag_init(&pstat->asoc_unref_done);
#else
init_completion(&pstat->asoc_unref_done);
#endif
#endif
#ifdef SW_TX_QUEUE
init_timer(&pstat->swq.beq_timer);
init_timer(&pstat->swq.bkq_timer);
init_timer(&pstat->swq.viq_timer);
init_timer(&pstat->swq.voq_timer);
skb_queue_head_init(&pstat->swq.be_queue);
skb_queue_head_init(&pstat->swq.bk_queue);
skb_queue_head_init(&pstat->swq.vi_queue);
skb_queue_head_init(&pstat->swq.vo_queue);
for(i=BK_QUEUE;i<HIGH_QUEUE;i++) {
// pstat->swq.q_aggnum[i] = priv->pshare->rf_ft_var.swq_aggnum;
pstat->swq.q_aggnum[i] = 2;
}
#endif
// we do NOT reset MAC here
#if defined(WIFI_WMM)
#ifdef DZ_ADDBA_RSP
pstat->dz_addba.used = 0;
#endif
#endif
#ifdef WDS
if (pstat->state & WIFI_WDS) {
bssratelen = pstat->bssratelen;
memcpy(bssrateset, pstat->bssrateset, bssratelen);
current_tx_rate = pstat->current_tx_rate;
}
#endif
// zero out all the rest
bk_aid = pstat->aid;
memcpy(bk_hwaddr, pstat->hwaddr, MACADDRLEN);
offset = (unsigned long)(&((struct stat_info *)0)->auth_seq);
memset((void *)((unsigned long)pstat + offset), 0, sizeof(struct stat_info)-offset);
pstat->aid = bk_aid;
memcpy(pstat->hwaddr, bk_hwaddr, MACADDRLEN);
#ifdef WDS
if (bssratelen) {
pstat->bssratelen = bssratelen;
memcpy(pstat->bssrateset, bssrateset, bssratelen);
pstat->current_tx_rate = current_tx_rate;
pstat->state |= WIFI_WDS;
}
#endif
// some variables need initial value
pstat->ieee8021x_ctrlport = pmib->dot118021xAuthEntry.dot118021xDefaultPort;
pstat->expire_to = priv->expire_to;
pstat->idle_count = 0;
for (i=0; i<8; i++)
for (j=0; j<TUPLE_WINDOW; j++)
pstat->tpcache[i][j] = 0xffff;
// Stanldy mesh: pstat->tpcache[i][j] = j+1 is best solution, because its a hash table, fill slot[i] with i+1 can prevent collision,fix the packet loss of first unicast
pstat->tpcache_mgt = 0xffff;
#ifdef CLIENT_MODE
pstat->tpcache_mcast = 0xffff;
#endif
#ifdef GBWC
for (i=0; i<priv->pmib->gbwcEntry.GBWCNum; i++) {
if (!memcmp(pstat->hwaddr, priv->pmib->gbwcEntry.GBWCAddr[i], MACADDRLEN)) {
pstat->GBWC_in_group = TRUE;
break;
}
}
#endif
// button 2009.05.21
#ifdef INCLUDE_WPA_PSK
pstat->wpa_sta_info->clientHndshkProcessing = pstat->wpa_sta_info->clientHndshkDone = FALSE;
#endif
#ifdef CONFIG_RTK_MESH
pstat->mesh_neighbor_TBL.BSexpire_LLSAperiod = jiffies + MESH_EXPIRE_TO;
#endif //CONFIG_RTK_MESH
memset(pstat->rc_entry, 0, sizeof(pstat->rc_entry));
#ifdef SUPPORT_TX_AMSDU
for (i=0; i<8; i++)
skb_queue_head_init(&pstat->amsdu_tx_que[i]);
#endif
#if defined (HW_ANT_SWITCH) && (defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_92D_SUPPORT))
pstat->CurAntenna = priv->pshare->rf_ft_var.CurAntenna;
#endif
#ifdef CONFIG_IEEE80211W
init_timer(&pstat->SA_timer);
pstat->SA_timer.data = (unsigned long) pstat;
pstat->SA_timer.function = rtl8192cd_sa_query_timer;
#endif
#ifdef CONFIG_RTL_WAPI_SUPPORT
// if (priv->pmib->wapiInfo.wapiType!=wapiDisable)
{
SAVE_INT_AND_CLI(flags);
// wapiAssert(pstat->wapiInfo!=NULL);
if (pstat->wapiInfo==NULL)
{
pstat->wapiInfo = (wapiStaInfo*)kmalloc(sizeof(wapiStaInfo), GFP_ATOMIC);
if (pstat->wapiInfo==NULL)
{
printk("Err: kmalloc wapiStaInfo fail!\n");
}
}
if (pstat->wapiInfo!=NULL)
{
pstat->wapiInfo->priv = priv;
wapiStationInit(pstat);
pstat->wapiInfo->wapiType = priv->pmib->wapiInfo.wapiType;
}
RESTORE_INT(flags);
}
#endif
#ifdef USE_OUT_SRC
#ifdef _OUTSRC_COEXIST
if(IS_OUTSRC_CHIP(priv))
#endif
ODM_CmnInfoPtrArrayHook(ODMPTR , ODM_CMNINFO_STA_STATUS, pstat->aid, pstat);
#endif
#ifdef MULTI_MAC_CLONE
if ((OPMODE & WIFI_STATION_STATE) && priv->pmib->ethBrExtInfo.macclone_enable)
{
pstat->mclone_id = ACTIVE_ID;
memcpy(pstat->sa_addr, GET_MY_HWADDR, MACADDRLEN);
}
#endif
}
#if defined(CONFIG_RTL_ETH_PRIV_SKB_DEBUG)
void dump_sta_dz_queue_num(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#if defined(WIFI_WMM) && defined(WMM_APSD)
int hd, tl;
#endif
// free all skb in dz_queue
printk("---------------------------------------\n");
#if defined(CONFIG_PCI_HCI)
printk("pstat->dz_queue:%d\n",skb_queue_len(&pstat->dz_queue));
#endif
#ifdef SW_TX_QUEUE
printk("swq.be_queue:%d\n",skb_queue_len(&pstat->swq.be_queue));
printk("swq.bk_queue:%d\n",skb_queue_len(&pstat->swq.bk_queue));
printk("swq.vi_queue:%d\n",skb_queue_len(&pstat->swq.vi_queue));
printk("swq.vo_queue:%d\n",skb_queue_len(&pstat->swq.vo_queue));
#endif
#if defined(WIFI_WMM) && defined(WMM_APSD)
hd = pstat->VO_dz_queue->head;
tl = pstat->VO_dz_queue->tail;
printk("VO_dz_queue:%d\n",CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE));
hd = pstat->VI_dz_queue->head;
tl = pstat->VI_dz_queue->tail;
printk("VI_dz_queue:%d\n",CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE));
hd = pstat->BE_dz_queue->head;
tl = pstat->BE_dz_queue->tail;
printk("BE_dz_queue:%d\n",CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE));
hd = pstat->BK_dz_queue->head;
tl = pstat->BK_dz_queue->tail;
printk("BK_dz_queue:%d\n",CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE));
#endif
#if defined(WIFI_WMM)
hd = pstat->MGT_dz_queue->head;
tl = pstat->MGT_dz_queue->tail;
printk("BK_dz_queue:%d\n",CIRC_CNT(hd, tl, NUM_DZ_MGT_QUEUE));
#endif
return;
}
#endif
#ifdef CONFIG_PCI_HCI
void free_sta_tx_skb(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifdef WIFI_WMM
int hd, tl;
#endif
struct sk_buff *pskb;
// free all skb in dz_queue
while (skb_queue_len(&pstat->dz_queue)) {
pskb = skb_dequeue(&pstat->dz_queue);
rtl_kfree_skb(priv, pskb, _SKB_TX_);
}
#ifdef SW_TX_QUEUE
while (skb_queue_len(&pstat->swq.be_queue)) {
pskb = skb_dequeue(&pstat->swq.be_queue);
rtl_kfree_skb(priv, pskb, _SKB_TX_);
}
while (skb_queue_len(&pstat->swq.bk_queue)) {
pskb = skb_dequeue(&pstat->swq.bk_queue);
rtl_kfree_skb(priv, pskb, _SKB_TX_);
}
while (skb_queue_len(&pstat->swq.vi_queue)) {
pskb = skb_dequeue(&pstat->swq.vi_queue);
rtl_kfree_skb(priv, pskb, _SKB_TX_);
}
while (skb_queue_len(&pstat->swq.vo_queue)) {
pskb = skb_dequeue(&pstat->swq.vo_queue);
rtl_kfree_skb(priv, pskb, _SKB_TX_);
}
#endif
#if defined(WIFI_WMM) && defined(WMM_APSD)
hd = pstat->VO_dz_queue->head;
tl = pstat->VO_dz_queue->tail;
while (CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE)) {
pskb = pstat->VO_dz_queue->pSkb[tl];
rtl_kfree_skb(priv, pskb, _SKB_TX_);
tl++;
tl = tl & (NUM_APSD_TXPKT_QUEUE - 1);
}
pstat->VO_dz_queue->head = 0;
pstat->VO_dz_queue->tail = 0;
hd = pstat->VI_dz_queue->head;
tl = pstat->VI_dz_queue->tail;
while (CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE)) {
pskb = pstat->VI_dz_queue->pSkb[tl];
rtl_kfree_skb(priv, pskb, _SKB_TX_);
tl++;
tl = tl & (NUM_APSD_TXPKT_QUEUE - 1);
}
pstat->VI_dz_queue->head = 0;
pstat->VI_dz_queue->tail = 0;
hd = pstat->BE_dz_queue->head;
tl = pstat->BE_dz_queue->tail;
while (CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE)) {
pskb = pstat->BE_dz_queue->pSkb[tl];
rtl_kfree_skb(priv, pskb, _SKB_TX_);
tl++;
tl = tl & (NUM_APSD_TXPKT_QUEUE - 1);
}
pstat->BE_dz_queue->head = 0;
pstat->BE_dz_queue->tail = 0;
hd = pstat->BK_dz_queue->head;
tl = pstat->BK_dz_queue->tail;
while (CIRC_CNT(hd, tl, NUM_APSD_TXPKT_QUEUE)) {
pskb = pstat->BK_dz_queue->pSkb[tl];
rtl_kfree_skb(priv, pskb, _SKB_TX_);
tl++;
tl = tl & (NUM_APSD_TXPKT_QUEUE - 1);
}
pstat->BK_dz_queue->head = 0;
pstat->BK_dz_queue->tail = 0;
#endif
#if defined(WIFI_WMM)
hd = pstat->MGT_dz_queue->head;
tl = pstat->MGT_dz_queue->tail;
while (CIRC_CNT(hd, tl, NUM_DZ_MGT_QUEUE)) {
struct tx_insn *ptx_insn = pstat->MGT_dz_queue->ptx_insn[tl];
release_mgtbuf_to_poll(priv, ptx_insn->pframe);
release_wlanhdr_to_poll(priv, ptx_insn->phdr);
kfree(ptx_insn);
tl++;
tl = tl & (NUM_DZ_MGT_QUEUE - 1);
}
pstat->MGT_dz_queue->head = 0;
pstat->MGT_dz_queue->tail = 0;
#ifdef DZ_ADDBA_RSP
pstat->dz_addba.used = 0;
#endif
#endif
}
#endif // CONFIG_PCI_HCI
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
void free_sta_tx_skb(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int i;
for (i = 0; i < MAX_STA_TX_SERV_QUEUE; ++i) {
#ifdef CONFIG_TCP_ACK_TXAGG
rtw_tcpack_servq_flush(priv, &pstat->tcpack_queue[i]);
#endif
rtw_txservq_flush(priv, &pstat->tx_queue[i]);
}
}
#endif
void free_sta_skb(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int i, j;
struct list_head frag_list;
struct sk_buff *pskb;
unsigned long flags;
free_sta_tx_skb(priv,pstat);
// free all skb in frag_list
INIT_LIST_HEAD(&frag_list);
DEFRAG_LOCK(flags);
list_splice_init(&pstat->frag_list, &frag_list);
DEFRAG_UNLOCK(flags);
unchainned_all_frag(priv, &frag_list);
// free all skb in rc queue
SMP_LOCK_REORDER_CTRL(flags);
for (i=0; i<8; i++) {
pstat->rc_entry[i].start_rcv = FALSE;
for (j=0; j<RC_ENTRY_NUM; j++) {
if (pstat->rc_entry[i].packet_q[j]) {
pskb = pstat->rc_entry[i].packet_q[j];
rtl_kfree_skb(priv, pskb, _SKB_RX_);
pstat->rc_entry[i].packet_q[j] = NULL;
}
}
}
SMP_UNLOCK_REORDER_CTRL(flags);
}
void free_sta_frag_list(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
struct list_head frag_list;
unsigned long flags;
// free all skb in frag_list
INIT_LIST_HEAD(&frag_list);
DEFRAG_LOCK(flags);
list_del_init(&pstat->defrag_list);
list_splice_init(&pstat->frag_list, &frag_list);
pstat->frag_count = 0;
DEFRAG_UNLOCK(flags);
unchainned_all_frag(priv, &frag_list);
}
void release_stainfo(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int i;
unsigned long flags;
if (priv->pshare->is_40m_bw && (pstat->IOTPeer == HT_IOT_PEER_MARVELL))
{
clearSTABitMap(&priv->pshare->marvellMapBit, pstat->aid);
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL_8881A)
if((GET_CHIP_VER(priv)==VERSION_8812E)||(GET_CHIP_VER(priv)==VERSION_8881A)){
}
else
#endif
if ((orSTABitMap(&priv->pshare->marvellMapBit) == 0) &&
(priv->pshare->Reg_RRSR_2 != 0) && (priv->pshare->Reg_81b != 0))
{
#if defined(CONFIG_PCI_HCI)
RTL_W8(RRSR+2, priv->pshare->Reg_RRSR_2);
RTL_W8(0x81b, priv->pshare->Reg_81b);
priv->pshare->Reg_RRSR_2 = 0;
priv->pshare->Reg_81b = 0;
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
notify_40M_RRSR_SC_change(priv);
#endif
}
}
update_intel_sta_bitmap(priv, pstat, 1);
#if defined(WIFI_11N_2040_COEXIST_EXT)
update_40m_staMap(priv, pstat, 1);
#endif
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
// avoid xmit_tasklet deadlock when receiving auth req under heavy TX traffic
#ifdef WDS
pstat->state &= WIFI_WDS;
#else
pstat->state = 0;
#endif
#endif
// flush the stainfo cache
//if (!memcmp(pstat->hwaddr, priv->stainfo_cache.hwaddr, MACADDRLEN))
// memset(&(priv->stainfo_cache), 0, sizeof(priv->stainfo_cache));
if (pstat == priv->pstat_cache)
priv->pstat_cache = NULL;
// delete all list
// BUT do NOT delete hash list
asoc_list_del(priv, pstat);
auth_list_del(priv, pstat);
sleep_list_del(priv, pstat);
wakeup_list_del(priv, pstat);
DEFRAG_LOCK(flags);
if (!list_empty(&(pstat->defrag_list)))
list_del_init(&(pstat->defrag_list));
DEFRAG_UNLOCK(flags);
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
rtw_pspoll_sta_delete(priv, pstat);
#endif
#ifdef CONFIG_PCI_HCI
// to avoid add RAtid fail
if (!list_empty(&(pstat->addRAtid_list)))
list_del_init(&(pstat->addRAtid_list));
if (!list_empty(&(pstat->addrssi_list)))
list_del_init(&(pstat->addrssi_list));
#endif
#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT)
#if defined(CONFIG_USB_HCI)
rtw_flush_h2c_cmd_queue(priv, pstat);
#endif
#elif defined(CONFIG_RTL_88E_SUPPORT)
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
rtw_flush_cmd_queue(priv, pstat);
#endif
#endif
#ifdef SW_TX_QUEUE
#ifdef SMP_SYNC
int locked=0;
SMP_TRY_LOCK_XMIT(flags,locked);
#endif
if (timer_pending(&pstat->swq.beq_timer))
del_timer(&pstat->swq.beq_timer);
if (timer_pending(&pstat->swq.bkq_timer))
del_timer(&pstat->swq.bkq_timer);
if (timer_pending(&pstat->swq.viq_timer))
del_timer(&pstat->swq.viq_timer);
if (timer_pending(&pstat->swq.voq_timer))
del_timer(&pstat->swq.voq_timer);
#ifdef SMP_SYNC
if(locked)
SMP_UNLOCK_XMIT(flags);
#endif
#endif
#ifdef CONFIG_IEEE80211W
if (timer_pending(&pstat->SA_timer))
del_timer(&pstat->SA_timer);
#endif
// free all queued skb
free_sta_skb(priv, pstat);
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
for (i = 0; i < MAX_STA_TX_SERV_QUEUE; ++i) {
_rtw_spinlock_free(&(pstat->tx_queue[i].xframe_queue.lock));
#ifdef CONFIG_TCP_ACK_TXAGG
_rtw_spinlock_free(&(pstat->tcpack_queue[i].xframe_queue.lock));
#endif
}
#endif
#ifdef CONFIG_RTK_MESH
SMP_LOCK_MESH_MP_HDR(flags);
if (!list_empty(&(pstat->mesh_mp_ptr)))
list_del_init(&(pstat->mesh_mp_ptr));
SMP_UNLOCK_MESH_MP_HDR(flags);
pstat->mesh_neighbor_TBL.State = MP_UNUSED; // reset state (clean is high priority)
//yschen 2009-03-04
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID) // 1.Proxy_table in root interface NOW!! 2.Spare for Mesh work with Multiple AP (Please see Mantis 0000107 for detail)
if(IS_ROOT_INTERFACE(priv))
#endif
{
remove_proxy_table(priv, pstat->hwaddr);
clear_route_info(priv, pstat->hwaddr);
}
#endif
#ifdef A4_STA
if (!list_empty(&pstat->a4_sta_list))
list_del_init(&pstat->a4_sta_list);
#endif
// remove key in CAM
if (pstat->dot11KeyMapping.keyInCam == TRUE) {
if (GET_ROOT(priv)->drv_state & DRV_STATE_OPEN) {
if (CamDeleteOneEntry(priv, pstat->hwaddr, 0, 0)) {
pstat->dot11KeyMapping.keyInCam = FALSE;
priv->pshare->CamEntryOccupied--;
}
#if defined(CONFIG_RTL_HW_WAPI_SUPPORT)
/* for wapi, one state take two cam entry */
if (CamDeleteOneEntry(priv, pstat->hwaddr, 0, 0)) {
pstat->dot11KeyMapping.keyInCam = FALSE;
priv->pshare->CamEntryOccupied--;
}
#endif
}
}
SMP_LOCK_REORDER_CTRL(flags);
for (i=0; i<RC_TIMER_NUM; i++)
if (priv->pshare->rc_timer[i].pstat == pstat)
priv->pshare->rc_timer[i].pstat = NULL;
SMP_UNLOCK_REORDER_CTRL(flags);
#ifdef WDS
pstat->state &= WIFI_WDS;
#else
pstat->state = 0;
#endif
#ifdef INDICATE_LINK_CHANGE
indicate_sta_link_change(priv, pstat, DECREASE, __FUNCTION__);
#endif
#ifdef TX_SHORTCUT
memset(pstat->tx_sc_ent, 0, sizeof(pstat->tx_sc_ent));
#endif
#ifdef RX_SHORTCUT
for (i=0; i<RX_SC_ENTRY_NUM; i++)
pstat->rx_sc_ent[i].rx_payload_offset = 0;
#endif
#ifdef INCLUDE_WPA_PSK
if (timer_pending(&pstat->wpa_sta_info->resendTimer)) {
del_timer(&pstat->wpa_sta_info->resendTimer);
}
#endif
release_remapAid(priv, pstat);
#ifdef USE_OUT_SRC
#ifdef _OUTSRC_COEXIST
if(IS_OUTSRC_CHIP(priv))
#endif
ODM_CmnInfoPtrArrayHook(ODMPTR , ODM_CMNINFO_STA_STATUS, pstat->aid, 0);
#endif
#ifdef SUPPORT_TX_AMSDU
for (i=0; i<8; i++)
free_skb_queue(priv, &pstat->amsdu_tx_que[i]);
#endif
#ifdef BEAMFORMING_SUPPORT
if (priv->pmib->dot11RFEntry.txbf == 1 && (GET_CHIP_VER(priv) == VERSION_8812E || GET_CHIP_VER(priv) == VERSION_8192E || GET_CHIP_VER(priv) == VERSION_8814A) )
{
PRT_BEAMFORMING_INFO pBeamformingInfo = &(priv->pshare->BeamformingInfo);
ODM_RT_TRACE(ODMPTR, BEAMFORMING_DEBUG, ODM_DBG_LOUD, ("%s,\n", __FUNCTION__));
pBeamformingInfo->CurDelBFerBFeeEntrySel = BFerBFeeEntry;
if(Beamforming_DeInitEntry(priv, pstat->hwaddr))
Beamforming_Notify(priv);
}
#endif
#if 1
#if defined(BR_SHORTCUT) && defined(RTL_CACHED_BR_STA)
release_brsc_cache(pstat->hwaddr);
#endif
#if defined(CONFIG_RTL_FASTBRIDGE)
rtl_fb_del_entry(pstat->hwaddr);
#endif
#else
#ifdef BR_SHORTCUT
clear_shortcut_cache();
#endif
#endif
#ifdef CONFIG_RTL_WAPI_SUPPORT
free_sta_wapiInfo(priv, pstat);
#endif
}
struct stat_info *alloc_stainfo(struct rtl8192cd_priv *priv, unsigned char *hwaddr, int id)
{
unsigned long flags;
unsigned int i,index;
struct list_head *phead, *plist;
struct stat_info *pstat;
SAVE_INT_AND_CLI(flags);
if (id < 0) { // not from FAST_RECOVERY
// any free sta info?
for(i=0; i<NUM_STAT; i++) {
if (priv->pshare->aidarray[i] && (priv->pshare->aidarray[i]->used == FALSE))
{
priv->pshare->aidarray[i]->priv = priv;
priv->pshare->aidarray[i]->used = TRUE;
pstat = &(priv->pshare->aidarray[i]->station);
memcpy(pstat->hwaddr, hwaddr, MACADDRLEN);
init_stainfo(priv, pstat);
#if defined(CONFIG_RTL_88E_SUPPORT) && defined(TXREPORT)
if (GET_CHIP_VER(priv)==VERSION_8188E) {
#ifdef RATEADAPTIVE_BY_ODM
ODM_RAInfo_Init(ODMPTR, pstat->aid);
#else
priv->pshare->RaInfo[pstat->aid].pstat = pstat;
RateAdaptiveInfoInit(&priv->pshare->RaInfo[pstat->aid]);
#endif
}
#endif
// insert to hash list
hash_list_add(priv, pstat);
RESTORE_INT(flags);
return pstat;
}
}
// allocate new sta info
for(i=0; i<NUM_STAT; i++) {
if (priv->pshare->aidarray[i] == NULL)
break;
}
}
else
i = id;
if (i < NUM_STAT) {
#ifdef RTL8192CD_VARIABLE_USED_DMEM
priv->pshare->aidarray[i] = (struct aid_obj *)rtl8192cd_dmem_alloc(AID_OBJ, &i);
#else
#ifdef PRIV_STA_BUF
priv->pshare->aidarray[i] = alloc_sta_obj(priv);
#else
priv->pshare->aidarray[i] = (struct aid_obj *)kmalloc(sizeof(struct aid_obj), GFP_ATOMIC);
#endif
#endif
if (priv->pshare->aidarray[i] == NULL)
goto no_free_memory;
memset(priv->pshare->aidarray[i], 0, sizeof(struct aid_obj));
#ifdef CONFIG_PCI_HCI
#if defined(WIFI_WMM) && defined(WMM_APSD)
#ifdef PRIV_STA_BUF
priv->pshare->aidarray[i]->station.VO_dz_queue = alloc_sta_que(priv);
#else
priv->pshare->aidarray[i]->station.VO_dz_queue = (struct apsd_pkt_queue *)kmalloc(sizeof(struct apsd_pkt_queue), GFP_ATOMIC);
#endif
if (priv->pshare->aidarray[i]->station.VO_dz_queue == NULL)
goto no_free_memory;
memset(priv->pshare->aidarray[i]->station.VO_dz_queue, 0, sizeof(struct apsd_pkt_queue));
#ifdef PRIV_STA_BUF
priv->pshare->aidarray[i]->station.VI_dz_queue = alloc_sta_que(priv);
#else
priv->pshare->aidarray[i]->station.VI_dz_queue = (struct apsd_pkt_queue *)kmalloc(sizeof(struct apsd_pkt_queue), GFP_ATOMIC);
#endif
if (priv->pshare->aidarray[i]->station.VI_dz_queue == NULL)
goto no_free_memory;
memset(priv->pshare->aidarray[i]->station.VI_dz_queue, 0, sizeof(struct apsd_pkt_queue));
#ifdef PRIV_STA_BUF
priv->pshare->aidarray[i]->station.BE_dz_queue = alloc_sta_que(priv);
#else
priv->pshare->aidarray[i]->station.BE_dz_queue = (struct apsd_pkt_queue *)kmalloc(sizeof(struct apsd_pkt_queue), GFP_ATOMIC);
#endif
if (priv->pshare->aidarray[i]->station.BE_dz_queue == NULL)
goto no_free_memory;
memset(priv->pshare->aidarray[i]->station.BE_dz_queue, 0, sizeof(struct apsd_pkt_queue));
#ifdef PRIV_STA_BUF
priv->pshare->aidarray[i]->station.BK_dz_queue = alloc_sta_que(priv);
#else
priv->pshare->aidarray[i]->station.BK_dz_queue = (struct apsd_pkt_queue *)kmalloc(sizeof(struct apsd_pkt_queue), GFP_ATOMIC);
#endif
if (priv->pshare->aidarray[i]->station.BK_dz_queue == NULL)
goto no_free_memory;
memset(priv->pshare->aidarray[i]->station.BK_dz_queue, 0, sizeof(struct apsd_pkt_queue));
#endif
#if defined(WIFI_WMM)
#ifdef PRIV_STA_BUF
priv->pshare->aidarray[i]->station.MGT_dz_queue = alloc_sta_mgt_que(priv);
#else
priv->pshare->aidarray[i]->station.MGT_dz_queue = (struct dz_mgmt_queue *)kmalloc(sizeof(struct dz_mgmt_queue), GFP_ATOMIC);
#endif
if (priv->pshare->aidarray[i]->station.MGT_dz_queue == NULL)
goto no_free_memory;
memset(priv->pshare->aidarray[i]->station.MGT_dz_queue, 0, sizeof(struct dz_mgmt_queue));
#endif
#endif // CONFIG_PCI_HCI
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
#ifdef PRIV_STA_BUF
priv->pshare->aidarray[i]->station.wpa_sta_info = alloc_wpa_buf(priv);
#else
priv->pshare->aidarray[i]->station.wpa_sta_info = (WPA_STA_INFO *)kmalloc(sizeof(WPA_STA_INFO), GFP_ATOMIC);
#endif
if (priv->pshare->aidarray[i]->station.wpa_sta_info == NULL)
goto no_free_memory;
memset(priv->pshare->aidarray[i]->station.wpa_sta_info, 0, sizeof(WPA_STA_INFO));
#endif
#if defined(WIFI_HAPD) || defined(RTK_NL80211)
memset(priv->pshare->aidarray[i]->station.wpa_ie, 0, 256);
#ifndef HAPD_DRV_PSK_WPS
memset(priv->pshare->aidarray[i]->station.wps_ie, 0, 256);
#endif
#endif
priv->pshare->aidarray[i]->priv = priv;
INIT_LIST_HEAD(&(priv->pshare->aidarray[i]->station.hash_list));
priv->pshare->aidarray[i]->station.aid = i + 1; //aid 0 is reserved for AP
priv->pshare->aidarray[i]->used = TRUE;
pstat = &(priv->pshare->aidarray[i]->station);
#if defined(CONFIG_RTL_88E_SUPPORT) && defined(TXREPORT)
if (GET_CHIP_VER(priv)==VERSION_8188E) {
#ifdef RATEADAPTIVE_BY_ODM
ODM_RAInfo_Init(ODMPTR, pstat->aid);
#else
priv->pshare->RaInfo[i + 1].pstat = pstat;
RateAdaptiveInfoInit(&priv->pshare->RaInfo[i + 1]);
#endif
}
#endif
memcpy(pstat->hwaddr, hwaddr, MACADDRLEN);
init_stainfo(priv, pstat);
// insert to hash list
hash_list_add(priv, pstat);
RESTORE_INT(flags);
return pstat;
}
// no more free sta info, check idle sta
for(i=0; i<NUM_STAT; i++) {
pstat = &(priv->pshare->aidarray[i]->station);
if ((pstat->expire_to == 0)
#ifdef WDS
#ifdef LAZY_WDS
&& ((pstat->state & WIFI_WDS_LAZY) ||
(!(pstat->state & WIFI_WDS_LAZY) && !(pstat->state & WIFI_WDS)))
#else
&& !(pstat->state & WIFI_WDS)
#endif
#endif
)
{
release_stainfo(priv->pshare->aidarray[i]->priv, pstat);
hash_list_del(priv->pshare->aidarray[i]->priv, pstat);
priv->pshare->aidarray[i]->used = TRUE;
priv->pshare->aidarray[i]->priv = priv;
memcpy(pstat->hwaddr, hwaddr, MACADDRLEN);
init_stainfo(priv, pstat);
#if defined(CONFIG_RTL_88E_SUPPORT) && defined(TXREPORT)
if (GET_CHIP_VER(priv)==VERSION_8188E)
#ifdef RATEADAPTIVE_BY_ODM
ODM_RAInfo_Init(ODMPTR, pstat->aid);
#else
RateAdaptiveInfoInit(&priv->pshare->RaInfo[pstat->aid]);
#endif
#endif
// insert to hash list
hash_list_add(priv, pstat);
RESTORE_INT(flags);
return pstat;
}
}
RESTORE_INT(flags);
DEBUG_ERR("AID buf is not enough\n");
return (struct stat_info *)NULL;
no_free_memory:
if (priv->pshare->aidarray[i]) {
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
if (priv->pshare->aidarray[i]->station.wpa_sta_info)
#ifdef PRIV_STA_BUF
free_wpa_buf(priv, priv->pshare->aidarray[i]->station.wpa_sta_info);
#else
kfree(priv->pshare->aidarray[i]->station.wpa_sta_info);
#endif
#endif
#ifdef CONFIG_PCI_HCI
#if defined(WIFI_WMM) && defined(WMM_APSD)
#ifdef PRIV_STA_BUF
if (priv->pshare->aidarray[i]->station.VO_dz_queue)
free_sta_que(priv, priv->pshare->aidarray[i]->station.VO_dz_queue);
if (priv->pshare->aidarray[i]->station.VI_dz_queue)
free_sta_que(priv, priv->pshare->aidarray[i]->station.VI_dz_queue);
if (priv->pshare->aidarray[i]->station.BE_dz_queue)
free_sta_que(priv, priv->pshare->aidarray[i]->station.BE_dz_queue);
if (priv->pshare->aidarray[i]->station.BK_dz_queue)
free_sta_que(priv, priv->pshare->aidarray[i]->station.BK_dz_queue);
#else
if (priv->pshare->aidarray[i]->station.VO_dz_queue)
kfree(priv->pshare->aidarray[i]->station.VO_dz_queue);
if (priv->pshare->aidarray[i]->station.VI_dz_queue)
kfree(priv->pshare->aidarray[i]->station.VI_dz_queue);
if (priv->pshare->aidarray[i]->station.BE_dz_queue)
kfree(priv->pshare->aidarray[i]->station.BE_dz_queue);
if (priv->pshare->aidarray[i]->station.BK_dz_queue)
kfree(priv->pshare->aidarray[i]->station.BK_dz_queue);
#endif
#endif
#if defined(WIFI_WMM)
#ifdef PRIV_STA_BUF
if (priv->pshare->aidarray[i]->station.MGT_dz_queue)
free_sta_mgt_que(priv, priv->pshare->aidarray[i]->station.MGT_dz_queue);
#else
if (priv->pshare->aidarray[i]->station.MGT_dz_queue)
kfree(priv->pshare->aidarray[i]->station.MGT_dz_queue);
#endif
#endif
#endif // CONFIG_PCI_HCI
#ifdef RTL8192CD_VARIABLE_USED_DMEM
rtl8192cd_dmem_free(AID_OBJ, &i);
#else
#ifdef PRIV_STA_BUF
free_sta_obj(priv, priv->pshare->aidarray[i]);
#else
kfree(priv->pshare->aidarray[i]);
#endif
#endif
priv->pshare->aidarray[i] = NULL;
}
RESTORE_INT(flags);
DEBUG_ERR("No free memory to allocate station info\n");
return NULL;
}
int del_station(struct rtl8192cd_priv *priv, struct stat_info *pstat, int send_disasoc)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
DOT11_DISASSOCIATION_IND Disassociation_Ind;
if (!netif_running(priv->dev))
return 0;
if (pstat == NULL)
return 0;
if (!list_empty(&pstat->asoc_list))
{
if (IEEE8021X_FUN)
{
#ifndef WITHOUT_ENQUEUE
memcpy((void *)Disassociation_Ind.MACAddr, (void *)pstat->hwaddr, MACADDRLEN);
Disassociation_Ind.EventId = DOT11_EVENT_DISASSOCIATION_IND;
Disassociation_Ind.IsMoreEvent = 0;
Disassociation_Ind.Reason = _STATS_OTHER_;
Disassociation_Ind.tx_packets = pstat->tx_pkts;
Disassociation_Ind.rx_packets = pstat->rx_pkts;
Disassociation_Ind.tx_bytes = pstat->tx_bytes;
Disassociation_Ind.rx_bytes = pstat->rx_bytes;
DOT11_EnQueue((unsigned long)priv, priv->pevent_queue, (UINT8 *)&Disassociation_Ind,
sizeof(DOT11_DISASSOCIATION_IND));
#endif
#if defined(INCLUDE_WPA_PSK)
#ifdef RTK_NL80211
if (IS_CFG80211_IFACE(priv))
nl80211_psk_indicate_evt(priv, DOT11_EVENT_DISASSOCIATION_IND, pstat->hwaddr, NULL, 0);
else
#endif
psk_indicate_evt(priv, DOT11_EVENT_DISASSOCIATION_IND, pstat->hwaddr, NULL, 0);
#elif defined(WIFI_HAPD) || defined(RTK_NL80211)
nl80211_psk_indicate_evt(priv, DOT11_EVENT_DISASSOCIATION_IND, pstat->hwaddr, NULL, 0);
#endif
#ifdef RTK_NL80211
if (IS_CFG80211_IFACE(priv))
event_indicate_cfg80211(priv, pstat->hwaddr, CFG80211_DEL_STA, NULL);
#endif
#ifdef WIFI_HAPD
event_indicate_hapd(priv, pstat->hwaddr, HAPD_EXIRED, NULL);
#ifdef HAPD_DRV_PSK_WPS
event_indicate(priv, pstat->hwaddr, 2);
#endif
#else
event_indicate(priv, pstat->hwaddr, 2);
#endif
}
if (send_disasoc)
issue_disassoc(priv, pstat->hwaddr, _RSON_UNSPECIFIED_);
if (pstat->expire_to > 0)
{
SAVE_INT_AND_CLI(flags);
cnt_assoc_num(priv, pstat, DECREASE, (char *)__FUNCTION__);
check_sta_characteristic(priv, pstat, DECREASE);
RESTORE_INT(flags);
LOG_MSG("A STA is deleted by application program - %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);
#ifdef CLIENT_MODE
if (OPMODE & WIFI_STATION_STATE) {
OPMODE_VAL(OPMODE & ~(WIFI_AUTH_SUCCESS | WIFI_ASOC_STATE));
start_clnt_lookup(priv, DONTRESCAN);
}
#endif
return 1;
}
int free_stainfo(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
unsigned int i;
if (pstat == (struct stat_info *)NULL)
{
DEBUG_ERR("illegal free an NULL stat obj\n");
return FAIL;
}
for(i=0; i<NUM_STAT; i++)
{
if (priv->pshare->aidarray[i] &&
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
(priv->pshare->aidarray[i]->priv == priv) &&
#endif
(priv->pshare->aidarray[i]->used == TRUE) &&
(&(priv->pshare->aidarray[i]->station) == pstat))
{
DEBUG_INFO("free station info of %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]);
SAVE_INT_AND_CLI(flags);
#ifdef WDS
#ifdef LAZY_WDS
if (!(pstat->state & WIFI_WDS) || (pstat->state & WIFI_WDS_LAZY))
#else
if (!(pstat->state & WIFI_WDS))
#endif
#endif
{
priv->pshare->aidarray[i]->used = FALSE;
// remove from hash_list
hash_list_del(priv, pstat);
#if defined(CONFIG_RTL_88E_SUPPORT) && defined(TXREPORT) && !defined(RATEADAPTIVE_BY_ODM)
if (GET_CHIP_VER(priv)==VERSION_8188E)
priv->pshare->RaInfo[pstat->aid].pstat = NULL;
#endif
}
release_stainfo(priv, pstat);
RESTORE_INT(flags);
return SUCCESS;
}
}
#if defined(CONFIG_RTL_WAPI_SUPPORT)
wapiAssert(pstat->wapiInfo==NULL);
#endif
DEBUG_ERR("pstat can not be freed \n");
return FAIL;
}
/* any station allocated can be searched by hash list */
__MIPS16
__IRAM_IN_865X
struct stat_info *get_stainfo(struct rtl8192cd_priv *priv, const unsigned char *hwaddr)
{
struct list_head *phead, *plist;
struct stat_info *pstat;
unsigned int index;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
#ifdef RTK_NL80211
if(hwaddr == NULL)
return (struct stat_info *)NULL;
#endif
//if (!memcmp(hwaddr, priv->stainfo_cache.hwaddr, MACADDRLEN) && priv->stainfo_cache.pstat)
pstat = priv->pstat_cache;
#ifdef MULTI_MAC_CLONE
if ((priv->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE) && MCLONE_NUM > 0) {
if (pstat && !memcmp(hwaddr, pstat->hwaddr, MACADDRLEN) && pstat->mclone_id == ACTIVE_ID)
return pstat;
}
else
#endif
{
if (pstat && !memcmp(hwaddr, pstat->hwaddr, MACADDRLEN))
return pstat;
}
index = wifi_mac_hash(hwaddr);
phead = &priv->stat_hash[index];
SMP_LOCK_HASH_LIST(flags);
plist = phead->next;
while (plist != phead)
{
pstat = list_entry(plist, struct stat_info ,hash_list);
plist = plist->next;
if (!(memcmp((void *)pstat->hwaddr, (void *)hwaddr, MACADDRLEN))) { // if found the matched address
#ifdef MULTI_MAC_CLONE
if (!(priv->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE) ||
((priv->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE) &&
!priv->pmib->ethBrExtInfo.macclone_enable) ||
((priv->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE) &&
priv->pmib->ethBrExtInfo.macclone_enable & (pstat->mclone_id == ACTIVE_ID)))
#endif
{
priv->pstat_cache = pstat;
goto exit;
}
}
#ifdef CONFIG_PCI_HCI
if (plist == plist->next)
break;
#endif
}
pstat = NULL;
exit:
SMP_UNLOCK_HASH_LIST(flags);
return pstat;
}
#ifdef HW_FILL_MACID
__MIPS16
__IRAM_IN_865X
struct stat_info *get_HW_mapping_sta(struct rtl8192cd_priv *priv, unsigned char macID)
{
struct aid_obj *obj;
if(macID > 0)
{
if((macID >= 0x7E))
return (struct stat_info *)NULL;
else
return &(priv->pshare->aidarray[macID-1]->station);
/*
obj = priv->pshare->aidarray[macID-1];
if(obj->priv == priv)
return &(priv->pshare->aidarray[macID-1]->station);
else
{
printk("obj error at macID %x \n",macID);
return (struct stat_info *)NULL;
}*/
}
}
#endif // #ifdef HW_FILL_MACID
/* aid is only meaningful for assocated stations... */
struct stat_info *get_aidinfo(struct rtl8192cd_priv *priv, unsigned int aid)
{
struct list_head *plist, *phead;
struct stat_info *pstat = NULL;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
if (aid == 0)
return (struct stat_info *)NULL;
SMP_LOCK_ASOC_LIST(flags);
phead = &priv->asoc_list;
plist = phead->next;
while (plist != phead)
{
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
if (pstat->aid == aid)
goto exit;
}
pstat = NULL;
exit:
SMP_UNLOCK_ASOC_LIST(flags);
return pstat;
}
#if defined(TXREPORT)
struct stat_info *get_macidinfo(struct rtl8192cd_priv *priv, unsigned int aid)
{
struct list_head *plist, *phead;
struct stat_info *pstat = NULL;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
if (aid == 0)
return (struct stat_info *)NULL;
SMP_LOCK_ASOC_LIST(flags);
phead = &priv->asoc_list;
plist = phead->next;
while (plist != phead)
{
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
if (REMAP_AID(pstat) == aid)
goto exit;
}
pstat = NULL;
exit:
SMP_UNLOCK_ASOC_LIST(flags);
return pstat;
}
#endif
int IS_BSSID(struct rtl8192cd_priv *priv, unsigned char *da)
{
unsigned char *bssid;
bssid = priv->pmib->dot11StationConfigEntry.dot11Bssid;
if (!memcmp(da, bssid, 6))
return TRUE;
else
return FALSE;
}
int IS_MCAST(unsigned char *da)
{
if ((*da) & 0x01)
return TRUE;
else
return FALSE;
}
int IS_BCAST2(unsigned char *da)
{
if ((*da) == 0xff)
return TRUE;
else
return FALSE;
}
UINT8 oui_rfc1042[] = {0x00, 0x00, 0x00};
UINT8 oui_8021h[] = {0x00, 0x00, 0xf8};
UINT8 oui_cisco[] = {0x00, 0x00, 0x0c};
int p80211_stt_findproto(UINT16 proto)
{
/* Always return found for now. This is the behavior used by the */
/* Zoom Win95 driver when 802.1h mode is selected */
/* TODO: If necessary, add an actual search we'll probably
need this to match the CMAC's way of doing things.
Need to do some testing to confirm.
*/
if (proto == 0x80f3 || /* APPLETALK */
proto == 0x8137 ) /* DIX II IPX */
return 1;
return 0;
}
void eth_2_llc(struct wlan_ethhdr_t *pethhdr, struct llc_snap *pllc_snap)
{
pllc_snap->llc_hdr.dsap=pllc_snap->llc_hdr.ssap=0xAA;
pllc_snap->llc_hdr.ctl=0x03;
if (p80211_stt_findproto(ntohs(pethhdr->type))) {
memcpy((void *)pllc_snap->snap_hdr.oui, oui_8021h, WLAN_IEEE_OUI_LEN);
}
else {
memcpy((void *)pllc_snap->snap_hdr.oui, oui_rfc1042, WLAN_IEEE_OUI_LEN);
}
pllc_snap->snap_hdr.type = pethhdr->type;
}
void eth2_2_wlanhdr(struct rtl8192cd_priv *priv, struct wlan_ethhdr_t *pethhdr, struct tx_insn *txcfg)
{
unsigned char *pframe = txcfg->phdr;
unsigned int to_fr_ds = get_tofr_ds(pframe);
switch (to_fr_ds)
{
case 0x00:
memcpy(GetAddr1Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
memcpy(GetAddr2Ptr(pframe), (const void *)pethhdr->saddr, WLAN_ADDR_LEN);
memcpy(GetAddr3Ptr(pframe), BSSID, WLAN_ADDR_LEN);
break;
case 0x01:
{
#ifdef MCAST2UI_REFINE
if (txcfg->fr_type == _SKB_FRAME_TYPE_)
memcpy(GetAddr1Ptr(pframe), (const void *) &((struct sk_buff *)txcfg->pframe)->cb[10], WLAN_ADDR_LEN);
else
#endif
memcpy(GetAddr1Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
memcpy(GetAddr2Ptr(pframe), BSSID, WLAN_ADDR_LEN);
memcpy(GetAddr3Ptr(pframe), (const void *)pethhdr->saddr, WLAN_ADDR_LEN);
}
break;
case 0x02:
{
memcpy(GetAddr1Ptr(pframe), BSSID, WLAN_ADDR_LEN);
memcpy(GetAddr2Ptr(pframe), (const void *)pethhdr->saddr, WLAN_ADDR_LEN);
memcpy(GetAddr3Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
}
break;
case 0x03:
#ifdef WDS
#ifdef MP_TEST
if (OPMODE & WIFI_MP_STATE)
memcpy(GetAddr1Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
else
#endif
#ifdef CONFIG_RTK_MESH
if(txcfg->is_11s)
memcpy(GetAddr1Ptr(pframe), txcfg->nhop_11s, WLAN_ADDR_LEN);
else
#endif
memcpy(GetAddr1Ptr(pframe), priv->pmib->dot11WdsInfo.entry[txcfg->wdsIdx].macAddr, WLAN_ADDR_LEN);
#ifdef MP_TEST
if (OPMODE & WIFI_MP_STATE)
memcpy(GetAddr2Ptr(pframe), priv->dev->dev_addr, WLAN_ADDR_LEN);
else
#endif
#ifdef __DRAYTEK_OS__
memcpy(GetAddr2Ptr(pframe), priv->dev->dev_addr, WLAN_ADDR_LEN);
#else
#ifdef CONFIG_RTK_MESH
if(txcfg->is_11s)
memcpy(GetAddr2Ptr(pframe), GET_MY_HWADDR, WLAN_ADDR_LEN);
else
#endif // CONFIG_RTK_MESH
memcpy(GetAddr2Ptr(pframe), priv->wds_dev[txcfg->wdsIdx]->dev_addr , WLAN_ADDR_LEN);
#endif
memcpy(GetAddr3Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
memcpy(GetAddr4Ptr(pframe), (const void *)pethhdr->saddr, WLAN_ADDR_LEN);
#ifdef CONFIG_RTK_MESH
if(txcfg->is_11s && is_qos_data(pframe))
memset( pframe+WLAN_HDR_A4_LEN, 0, 2); // qos
#endif // CONFIG_RTK_MESH
#else // not WDS
#ifdef CONFIG_RTK_MESH
if(txcfg->is_11s) {
memcpy(GetAddr1Ptr(pframe), txcfg->nhop_11s, WLAN_ADDR_LEN);
memcpy(GetAddr2Ptr(pframe), GET_MY_HWADDR, WLAN_ADDR_LEN);
memcpy(GetAddr3Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
memcpy(GetAddr4Ptr(pframe), (const void *)pethhdr->saddr, WLAN_ADDR_LEN);
//if((*pframe) & 0x80) //if qos is enable, the bit 7 of frame control will set to 1
if(is_qos_data(pframe))
memset(pframe+WLAN_HDR_A4_LEN, 0, 2); // qos
} else
#endif // CONFIG_RTK_MESH
#ifdef A4_STA
if (priv->pshare->rf_ft_var.a4_enable && txcfg->pstat &&
(txcfg->pstat->state & WIFI_A4_STA)) {
memcpy(GetAddr1Ptr(pframe), txcfg->pstat->hwaddr, WLAN_ADDR_LEN);
memcpy(GetAddr2Ptr(pframe), GET_MY_HWADDR, WLAN_ADDR_LEN);
memcpy(GetAddr3Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
memcpy(GetAddr4Ptr(pframe), (const void *)pethhdr->saddr, WLAN_ADDR_LEN);
}
else
#endif
{
DEBUG_ERR("no support for WDS!\n");
memcpy(GetAddr1Ptr(pframe), (const void *)pethhdr->daddr, WLAN_ADDR_LEN);
memcpy(GetAddr2Ptr(pframe), (const void *)BSSID, WLAN_ADDR_LEN);
memcpy(GetAddr3Ptr(pframe), (const void *)pethhdr->saddr, WLAN_ADDR_LEN);
} // else of if(txcfg->is_11s)
#endif // WDS
break;
}
}
int skb_p80211_to_ether(struct net_device *dev, int wep_mode, struct rx_frinfo *pfrinfo)
{
UINT to_fr_ds;
INT payload_length;
INT payload_offset, trim_pad;
UINT8 daddr[WLAN_ETHADDR_LEN];
UINT8 saddr[WLAN_ETHADDR_LEN];
UINT8 *pframe;
#ifdef CONFIG_RTK_MESH
INT mesh_header_len=0;
#endif
struct wlan_hdr *w_hdr;
struct wlan_ethhdr_t *e_hdr;
struct wlan_llc_t *e_llc;
struct wlan_snap_t *e_snap;
struct rtl8192cd_priv *priv = GET_DEV_PRIV(dev);
int wlan_pkt_format;
struct sk_buff *skb = get_pskb(pfrinfo);
#ifdef RX_SHORTCUT
extern int get_rx_sc_free_entry(struct stat_info *pstat, unsigned char *pframe);
int privacy, idx=0;
struct rx_sc_entry *prxsc_entry = NULL;
struct wlan_hdr wlanhdr;
#ifndef MESH_AMSDU
struct stat_info *pstat = get_stainfo(priv, GetAddr2Ptr(skb->data));
#else
struct stat_info *pstat;
if (pfrinfo->is_11s & 8)
pstat = NULL;
else
pstat = get_stainfo(priv, GetAddr2Ptr(skb->data));
#endif // MESH_AMSDU
#endif // RX_SHORTCUT
pframe = get_pframe(pfrinfo);
to_fr_ds = get_tofr_ds(pframe);
#ifndef MESH_AMSDU
payload_offset = get_hdrlen(priv, pframe);
#else
// Get_hdrlen needs to access pframe+32
// When is_11s=8, the length of a frame might be less than 32 bytes, so we need to protect it
if( pfrinfo->is_11s &8 )
payload_offset = 0;
else
payload_offset = get_hdrlen(priv, pframe);
#endif // MESH_AMSDU
trim_pad = 0; // _CRCLNG_ has beed subtracted in isr
w_hdr = (struct wlan_hdr *)pframe;
#ifdef MESH_AMSDU
if( pfrinfo->is_11s &8 )
{
struct wlan_ethhdr_t eth;
struct MESH_HDR* mhdr = (struct MESH_HDR*) (pframe+sizeof(struct wlan_ethhdr_t));
const short mlen = (mhdr->mesh_flag &1) ? 16 : 4;
memcpy( &eth, pframe, sizeof(struct wlan_ethhdr_t));
if( mlen &16 )
memcpy(&eth, mhdr->DestMACAddr, WLAN_ETHADDR_LEN<<1 );
memcpy(skb_pull(skb, mlen), &eth, sizeof(struct wlan_ethhdr_t));
return SUCCESS;
}
#endif
if ( to_fr_ds == 0x00) {
memcpy(daddr, (const void *)w_hdr->addr1, WLAN_ETHADDR_LEN);
memcpy(saddr, (const void *)w_hdr->addr2, WLAN_ETHADDR_LEN);
}
else if( to_fr_ds == 0x01) {
memcpy(daddr, (const void *)w_hdr->addr1, WLAN_ETHADDR_LEN);
memcpy(saddr, (const void *)w_hdr->addr3, WLAN_ETHADDR_LEN);
}
else if( to_fr_ds == 0x02) {
memcpy(daddr, (const void *)w_hdr->addr3, WLAN_ETHADDR_LEN);
memcpy(saddr, (const void *)w_hdr->addr2, WLAN_ETHADDR_LEN);
}
else {
#ifdef CONFIG_RTK_MESH
// WIFI_11S_MESH = WIFI_QOS_DATA
if(pfrinfo->is_11s &1) {
memcpy(daddr, (const void *)pfrinfo->mesh_header.DestMACAddr, WLAN_ETHADDR_LEN);
memcpy(saddr, (const void *)pfrinfo->mesh_header.SrcMACAddr, WLAN_ETHADDR_LEN);
mesh_header_len = 16;
}
else
#endif // CONFIG_RTK_MESH
{
memcpy(daddr, (const void *)w_hdr->addr3, WLAN_ETHADDR_LEN);
memcpy(saddr, (const void *)w_hdr->addr4, WLAN_ETHADDR_LEN);
}
}
if (GetPrivacy(pframe)) {
#ifdef CONFIG_RTL_WAPI_SUPPORT
if ((wep_mode == _WAPI_SMS4_)) {
payload_offset += (WAPI_EXT_LEN-WAPI_ALIGNMENT_OFFSET);
trim_pad += (SMS4_MIC_LEN);
} else
#endif
if (((wep_mode == _WEP_40_PRIVACY_) || (wep_mode == _WEP_104_PRIVACY_))) {
payload_offset += 4;
trim_pad += 4;
}
else if ((wep_mode == _TKIP_PRIVACY_)) {
payload_offset += 8;
trim_pad += (8 + 4);
}
else if ((wep_mode == _CCMP_PRIVACY_)) {
payload_offset += 8;
trim_pad += 8;
}
else {
DEBUG_ERR("drop pkt due to unallowed wep_mode privacy=%d\n", wep_mode);
return FAIL;
}
}
#if defined(CONFIG_RTL_HW_WAPI_SUPPORT)
skb->len -= WAPI_ALIGNMENT_OFFSET;
#endif
payload_length = skb->len - payload_offset - trim_pad;
#ifdef CONFIG_RTK_MESH
payload_length -= mesh_header_len;
#endif
if (payload_length <= 0) {
DEBUG_ERR("drop pkt due to payload_length<=0\n");
return FAIL;
}
e_hdr = (struct wlan_ethhdr_t *) (pframe + payload_offset);
e_llc = (struct wlan_llc_t *) (pframe + payload_offset);
e_snap = (struct wlan_snap_t *) (pframe + payload_offset + sizeof(struct wlan_llc_t));
if ((e_llc->dsap==0xaa) && (e_llc->ssap==0xaa) && (e_llc->ctl==0x03))
{
if (!memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)) {
wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_RFC1042;
if(!memcmp(&e_snap->type, SNAP_ETH_TYPE_IPX, 2))
wlan_pkt_format = WLAN_PKT_FORMAT_IPX_TYPE4;
else if(!memcmp(&e_snap->type, SNAP_ETH_TYPE_APPLETALK_AARP, 2))
wlan_pkt_format = WLAN_PKT_FORMAT_APPLETALK;
}
else if (!memcmp(e_snap->oui, SNAP_HDR_APPLETALK_DDP, WLAN_IEEE_OUI_LEN) &&
!memcmp(&e_snap->type, SNAP_ETH_TYPE_APPLETALK_DDP, 2))
wlan_pkt_format = WLAN_PKT_FORMAT_APPLETALK;
else if (!memcmp(e_snap->oui, oui_8021h, WLAN_IEEE_OUI_LEN))
wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_TUNNEL;
else if (!memcmp(e_snap->oui, oui_cisco, WLAN_IEEE_OUI_LEN))
wlan_pkt_format = WLAN_PKT_FORMAT_CDP;
else {
DEBUG_ERR("drop pkt due to invalid frame format!\n");
return FAIL;
}
}
else if ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) &&
(memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))
wlan_pkt_format = WLAN_PKT_FORMAT_ENCAPSULATED;
else
wlan_pkt_format = WLAN_PKT_FORMAT_OTHERS;
DEBUG_INFO("Convert 802.11 to 802.3 in format %d\n", wlan_pkt_format);
if ((wlan_pkt_format == WLAN_PKT_FORMAT_SNAP_RFC1042) ||
(wlan_pkt_format == WLAN_PKT_FORMAT_SNAP_TUNNEL) ||
(wlan_pkt_format == WLAN_PKT_FORMAT_CDP)) {
/* Test for an overlength frame */
payload_length = payload_length - sizeof(struct wlan_llc_t) - sizeof(struct wlan_snap_t);
if ((payload_length+WLAN_ETHHDR_LEN) > WLAN_MAX_ETHFRM_LEN) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
DEBUG_WARN("SNAP frame too large (%d>%d)\n",
(payload_length+WLAN_ETHHDR_LEN), WLAN_MAX_ETHFRM_LEN);
}
#ifdef RX_SHORTCUT
if (!priv->pmib->dot11OperationEntry.disable_rxsc && pstat) {
#ifdef CONFIG_RTK_MESH
if (pfrinfo->is_11s)
privacy = get_sta_encrypt_algthm(priv, pstat);
else
#endif // CONFIG_RTK_MESH
#ifdef WDS
if (pfrinfo->to_fr_ds == 3)
privacy = priv->pmib->dot11WdsInfo.wdsPrivacy;
else
#endif
privacy = get_sta_encrypt_algthm(priv, pstat);
if ((GetFragNum(pframe)==0) &&
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
(!pfrinfo->is_11s || !IS_MCAST(pfrinfo->da)) &&
#endif
((privacy == 0) ||
#ifdef CONFIG_RTL_WAPI_SUPPORT
(privacy==_WAPI_SMS4_) ||
#endif
#ifdef CONFIG_IEEE80211W
(!UseSwCrypto(priv, pstat, IS_MCAST(GetAddr1Ptr(pframe)), 0))))
#else
(!UseSwCrypto(priv, pstat, IS_MCAST(GetAddr1Ptr(pframe))))))
#endif
{
idx = get_rx_sc_free_entry(pstat, pframe);
prxsc_entry = &pstat->rx_sc_ent[idx];
memcpy((void *)&wlanhdr, pframe, pfrinfo->hdr_len);
}
}
#endif // RX_SHORTCUT
/* chop 802.11 header from skb. */
skb_pull(skb, payload_offset);
if ((wlan_pkt_format == WLAN_PKT_FORMAT_SNAP_RFC1042) ||
(wlan_pkt_format == WLAN_PKT_FORMAT_SNAP_TUNNEL))
{
/* chop llc header from skb. */
skb_pull(skb, sizeof(struct wlan_llc_t));
/* chop snap header from skb. */
skb_pull(skb, sizeof(struct wlan_snap_t));
}
#ifdef CONFIG_RTK_MESH
/* chop mesh header from skb. */
skb_pull(skb, mesh_header_len);
#endif
/* create 802.3 header at beginning of skb. */
e_hdr = (struct wlan_ethhdr_t *)skb_push(skb, WLAN_ETHHDR_LEN);
if (wlan_pkt_format == WLAN_PKT_FORMAT_CDP)
e_hdr->type = payload_length;
else
e_hdr->type = e_snap->type;
memcpy((void *)e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
memcpy((void *)e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
/* chop off the 802.11 CRC */
skb_trim(skb, payload_length + WLAN_ETHHDR_LEN);
#ifdef RX_SHORTCUT
if (prxsc_entry) {
if ((e_hdr->type != htons(0x888e)) && // for WIFI_SIMPLE_CONFIG
#ifdef CONFIG_RTL_WAPI_SUPPORT
(e_hdr->type != htons(ETH_P_WAPI)) &&
#endif
(e_hdr->type != htons(ETH_P_ARP)) &&
(wlan_pkt_format != WLAN_PKT_FORMAT_CDP)) {
memcpy((void *)&prxsc_entry->rx_wlanhdr, &wlanhdr, pfrinfo->hdr_len);
memcpy((void *)&prxsc_entry->rx_ethhdr, (const void *)e_hdr, sizeof(struct wlan_ethhdr_t));
prxsc_entry->rx_payload_offset = payload_offset;
prxsc_entry->rx_trim_pad = trim_pad;
pstat->rx_privacy = GetPrivacy(pframe);
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
if ( (pfrinfo->is_11s &3) && (pfrinfo->mesh_header.mesh_flag &1))
{
memcpy((void *)&prxsc_entry->rx_wlanhdr.meshhdr.DestMACAddr, (const void *)pfrinfo->mesh_header.DestMACAddr, WLAN_ETHADDR_LEN);
memcpy((void *)&prxsc_entry->rx_wlanhdr.meshhdr.SrcMACAddr, (const void *)pfrinfo->mesh_header.SrcMACAddr, WLAN_ETHADDR_LEN);
}
#endif
}
}
#endif
}
else if ((wlan_pkt_format == WLAN_PKT_FORMAT_OTHERS) ||
(wlan_pkt_format == WLAN_PKT_FORMAT_APPLETALK) ||
(wlan_pkt_format == WLAN_PKT_FORMAT_IPX_TYPE4)) {
/* Test for an overlength frame */
if ( (payload_length + WLAN_ETHHDR_LEN) > WLAN_MAX_ETHFRM_LEN ) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
DEBUG_WARN("IPX/AppleTalk frame too large (%d>%d)\n",
(payload_length + WLAN_ETHHDR_LEN), WLAN_MAX_ETHFRM_LEN);
}
/* chop 802.11 header from skb. */
skb_pull(skb, payload_offset);
#ifdef CONFIG_RTK_MESH
/* chop mesh header from skb. */
skb_pull(skb, mesh_header_len);
#endif
/* create 802.3 header at beginning of skb. */
e_hdr = (struct wlan_ethhdr_t *)skb_push(skb, WLAN_ETHHDR_LEN);
memcpy((void *)e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
memcpy((void *)e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
e_hdr->type = htons(payload_length);
/* chop off the 802.11 CRC */
skb_trim(skb, payload_length+WLAN_ETHHDR_LEN);
}
else if (wlan_pkt_format == WLAN_PKT_FORMAT_ENCAPSULATED) {
if ( payload_length > WLAN_MAX_ETHFRM_LEN ) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
DEBUG_WARN("Encapsulated frame too large (%d>%d)\n",
payload_length, WLAN_MAX_ETHFRM_LEN);
}
/* Chop off the 802.11 header. */
skb_pull(skb, payload_offset);
#ifdef CONFIG_RTK_MESH
/* chop mesh header from skb. */
skb_pull(skb, mesh_header_len);
#endif
/* chop off the 802.11 CRC */
skb_trim(skb, payload_length);
}
#ifdef __KERNEL__
#ifdef LINUX_2_6_22_
skb_reset_mac_header(skb);
#else
skb->mac.raw = (unsigned char *) skb->data; /* new MAC header */
#endif
#endif
return SUCCESS;
}
int strip_amsdu_llc(struct rtl8192cd_priv *priv, struct sk_buff *skb, struct stat_info *pstat)
{
INT payload_length;
INT payload_offset;
UINT8 daddr[WLAN_ETHADDR_LEN];
UINT8 saddr[WLAN_ETHADDR_LEN];
struct wlan_ethhdr_t *e_hdr;
struct wlan_llc_t *e_llc;
struct wlan_snap_t *e_snap;
int pkt_format;
memcpy(daddr, skb->data, MACADDRLEN);
memcpy(saddr, skb->data+MACADDRLEN, MACADDRLEN);
payload_length = skb->len - WLAN_ETHHDR_LEN;
payload_offset = WLAN_ETHHDR_LEN;
e_hdr = (struct wlan_ethhdr_t *) (skb->data + payload_offset);
e_llc = (struct wlan_llc_t *) (skb->data + payload_offset);
e_snap = (struct wlan_snap_t *) (skb->data + payload_offset + sizeof(struct wlan_llc_t));
if ((e_llc->dsap==0xaa) && (e_llc->ssap==0xaa) && (e_llc->ctl==0x03))
{
if (!memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)) {
pkt_format = WLAN_PKT_FORMAT_SNAP_RFC1042;
if(!memcmp(&e_snap->type, SNAP_ETH_TYPE_IPX, 2))
pkt_format = WLAN_PKT_FORMAT_IPX_TYPE4;
else if(!memcmp(&e_snap->type, SNAP_ETH_TYPE_APPLETALK_AARP, 2))
pkt_format = WLAN_PKT_FORMAT_APPLETALK;
}
else if (!memcmp(e_snap->oui, SNAP_HDR_APPLETALK_DDP, WLAN_IEEE_OUI_LEN) &&
!memcmp(&e_snap->type, SNAP_ETH_TYPE_APPLETALK_DDP, 2))
pkt_format = WLAN_PKT_FORMAT_APPLETALK;
else if (!memcmp(e_snap->oui, oui_8021h, WLAN_IEEE_OUI_LEN))
pkt_format = WLAN_PKT_FORMAT_SNAP_TUNNEL;
else if (!memcmp(e_snap->oui, oui_cisco, WLAN_IEEE_OUI_LEN))
pkt_format = WLAN_PKT_FORMAT_CDP;
else {
DEBUG_ERR("drop pkt due to invalid frame format!\n");
return FAIL;
}
}
else if ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) &&
(memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))
pkt_format = WLAN_PKT_FORMAT_ENCAPSULATED;
else
pkt_format = WLAN_PKT_FORMAT_OTHERS;
DEBUG_INFO("Convert 802.11 to 802.3 in format %d\n", pkt_format);
if ((pkt_format == WLAN_PKT_FORMAT_SNAP_RFC1042) ||
(pkt_format == WLAN_PKT_FORMAT_SNAP_TUNNEL) ||
(pkt_format == WLAN_PKT_FORMAT_CDP)) {
/* Test for an overlength frame */
payload_length = payload_length - sizeof(struct wlan_llc_t) - sizeof(struct wlan_snap_t);
if ((payload_length+WLAN_ETHHDR_LEN) > WLAN_MAX_ETHFRM_LEN) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
DEBUG_WARN("SNAP frame too large (%d>%d)\n",
(payload_length+WLAN_ETHHDR_LEN), WLAN_MAX_ETHFRM_LEN);
}
/* chop 802.11 header from skb. */
skb_pull(skb, payload_offset);
if ((pkt_format == WLAN_PKT_FORMAT_SNAP_RFC1042) ||
(pkt_format == WLAN_PKT_FORMAT_SNAP_TUNNEL))
{
/* chop llc header from skb. */
skb_pull(skb, sizeof(struct wlan_llc_t));
/* chop snap header from skb. */
skb_pull(skb, sizeof(struct wlan_snap_t));
}
/* create 802.3 header at beginning of skb. */
e_hdr = (struct wlan_ethhdr_t *)skb_push(skb, WLAN_ETHHDR_LEN);
if (pkt_format == WLAN_PKT_FORMAT_CDP)
e_hdr->type = payload_length;
else
e_hdr->type = e_snap->type;
memcpy((void *)e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
memcpy((void *)e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
/* chop off the 802.11 CRC */
skb_trim(skb, payload_length + WLAN_ETHHDR_LEN);
}
else if ((pkt_format == WLAN_PKT_FORMAT_OTHERS) ||
(pkt_format == WLAN_PKT_FORMAT_APPLETALK) ||
(pkt_format == WLAN_PKT_FORMAT_IPX_TYPE4)) {
/* Test for an overlength frame */
if ( (payload_length + WLAN_ETHHDR_LEN) > WLAN_MAX_ETHFRM_LEN ) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
DEBUG_WARN("IPX/AppleTalk frame too large (%d>%d)\n",
(payload_length + WLAN_ETHHDR_LEN), WLAN_MAX_ETHFRM_LEN);
}
/* chop 802.11 header from skb. */
skb_pull(skb, payload_offset);
/* create 802.3 header at beginning of skb. */
e_hdr = (struct wlan_ethhdr_t *)skb_push(skb, WLAN_ETHHDR_LEN);
memcpy((void *)e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
memcpy((void *)e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
e_hdr->type = htons(payload_length);
/* chop off the 802.11 CRC */
skb_trim(skb, payload_length+WLAN_ETHHDR_LEN);
}
else if (pkt_format == WLAN_PKT_FORMAT_ENCAPSULATED) {
if ( payload_length > WLAN_MAX_ETHFRM_LEN ) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
DEBUG_WARN("Encapsulated frame too large (%d>%d)\n",
payload_length, WLAN_MAX_ETHFRM_LEN);
}
/* Chop off the 802.11 header. */
skb_pull(skb, payload_offset);
/* chop off the 802.11 CRC */
skb_trim(skb, payload_length);
}
#ifdef __KERNEL__
#ifdef LINUX_2_6_22_
skb_reset_mac_header(skb);
#else
skb->mac.raw = (unsigned char *) skb->data; /* new MAC header */
#endif
#endif
return SUCCESS;
}
unsigned int get_sta_encrypt_algthm(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
unsigned int privacy = 0;
#ifdef CONFIG_RTK_MESH
if( isMeshPoint(pstat) )
return priv->pmib->dot11sKeysTable.dot11Privacy ;
#endif
#ifdef CONFIG_RTL_WAPI_SUPPORT
if (pstat&&pstat->wapiInfo&&pstat->wapiInfo->wapiType!=wapiDisable)
{
return _WAPI_SMS4_;
}
else
#endif
{
if (priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm) {
if (pstat)
privacy = pstat->dot11KeyMapping.dot11Privacy;
else
DEBUG_ERR("pstat == NULL\n");
}
else
{
// legacy system
privacy = priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm; //could be wep40 or wep104
}
}
return privacy;
}
unsigned int get_mcast_encrypt_algthm(struct rtl8192cd_priv *priv)
{
unsigned int privacy;
#ifdef CONFIG_RTL_WAPI_SUPPORT
if (priv->pmib->wapiInfo.wapiType!=wapiDisable)
{
return _WAPI_SMS4_;
} else
#endif
{
if (priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm) {
// check station info
privacy = priv->pmib->dot11GroupKeysTable.dot11Privacy;
}
else { // legacy system
privacy = priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm;//must be wep40 or wep104
}
}
return privacy;
}
unsigned int get_privacy(struct rtl8192cd_priv *priv, struct stat_info *pstat,
unsigned int *iv, unsigned int *icv, unsigned int *mic)
{
unsigned int privacy;
*iv = 0;
*icv = 0;
*mic = 0;
privacy = get_sta_encrypt_algthm(priv, pstat);
switch (privacy)
{
#ifdef CONFIG_RTL_WAPI_SUPPORT
case _WAPI_SMS4_:
*iv = WAPI_PN_LEN+2;
*icv = 0;
#if defined(CONFIG_RTL_HW_WAPI_SUPPORT)
#ifdef CONFIG_IEEE80211W
if(!(UseSwCrypto(priv, pstat, (pstat ? FALSE : TRUE), 0)))
#else
if(!(UseSwCrypto(priv, pstat, (pstat ? FALSE : TRUE))))
#endif
*mic = 0; //HW will take care of the mic
else
*mic = SMS4_MIC_LEN;
#else
*mic = SMS4_MIC_LEN;
#endif
break;
#endif
case _NO_PRIVACY_:
*iv = 0;
*icv = 0;
*mic = 0;
break;
case _WEP_40_PRIVACY_:
case _WEP_104_PRIVACY_:
*iv = 4;
*icv = 4;
*mic = 0;
break;
case _TKIP_PRIVACY_:
*iv = 8;
*icv = 4;
*mic = 0; // mic of TKIP is msdu based
break;
case _CCMP_PRIVACY_:
*iv = 8;
*icv = 0;
*mic = 8;
break;
default:
DEBUG_WARN("un-awared encrypted type %d\n", privacy);
*iv = *icv = *mic = 0;
break;
}
return privacy;
}
unsigned int get_mcast_privacy(struct rtl8192cd_priv *priv, unsigned int *iv, unsigned int *icv,
unsigned int *mic)
{
unsigned int privacy;
*iv = 0;
*icv = 0;
*mic = 0;
privacy = get_mcast_encrypt_algthm(priv);
switch (privacy)
{
#ifdef CONFIG_RTL_WAPI_SUPPORT
case _WAPI_SMS4_:
*iv = WAPI_PN_LEN+2;
*icv = 0;
#if defined(CONFIG_RTL_HW_WAPI_SUPPORT)
#ifdef CONFIG_IEEE80211W
if(!(UseSwCrypto(priv, NULL, TRUE),0))
#else
if(!(UseSwCrypto(priv, NULL, TRUE)))
#endif
*mic = 0; //HW will take care of the mic
else
*mic = SMS4_MIC_LEN;
#else
*mic = SMS4_MIC_LEN;
#endif
break;
#endif
case _NO_PRIVACY_:
*iv = 0;
*icv = 0;
*mic = 0;
break;
case _WEP_40_PRIVACY_:
case _WEP_104_PRIVACY_:
*iv = 4;
*icv = 4;
*mic = 0;
break;
case _TKIP_PRIVACY_:
*iv = 8;
*icv = 4;
*mic = 0; // mic of TKIP is msdu based
break;
case _CCMP_PRIVACY_:
*iv = 8;
*icv = 0;
*mic = 8;
break;
default:
DEBUG_WARN("un-awared encrypted type %d\n", privacy);
*iv = 0;
*icv = 0;
*mic = 0;
break;
}
return privacy;
}
unsigned char * get_da(unsigned char *pframe)
{
unsigned char *da;
unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
switch (to_fr_ds) {
case 0x00: // ToDs=0, FromDs=0
da = GetAddr1Ptr(pframe);
break;
case 0x01: // ToDs=0, FromDs=1
da = GetAddr1Ptr(pframe);
break;
case 0x02: // ToDs=1, FromDs=0
da = GetAddr3Ptr(pframe);
break;
default: // ToDs=1, FromDs=1
da = GetAddr3Ptr(pframe);
break;
}
return da;
}
unsigned char * get_sa(unsigned char *pframe)
{
unsigned char *sa;
unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
switch (to_fr_ds) {
case 0x00: // ToDs=0, FromDs=0
sa = GetAddr2Ptr(pframe);
break;
case 0x01: // ToDs=0, FromDs=1
sa = GetAddr3Ptr(pframe);
break;
case 0x02: // ToDs=1, FromDs=0
sa = GetAddr2Ptr(pframe);
break;
default: // ToDs=1, FromDs=1
sa = GetAddr4Ptr(pframe);
break;
}
return sa;
}
__MIPS16
__IRAM_IN_865X
unsigned char get_hdrlen(struct rtl8192cd_priv *priv, UINT8 *pframe)
{
if (GetFrameType(pframe) == WIFI_DATA_TYPE)
{
#ifdef CONFIG_RTK_MESH
if ((get_tofr_ds(pframe) == 0x03) && ( (GetFrameSubType(pframe) == WIFI_11S_MESH) || (GetFrameSubType(pframe) == WIFI_11S_MESH_ACTION)))
{
if(GetFrameSubType(pframe) == WIFI_11S_MESH) // DATA frame, qos might be on (TRUE on 8186)
{
return WLAN_HDR_A4_QOS_LEN;
} // WIFI_11S_MESH
else // WIFI_11S_MESH_ACTION frame, although qos flag is on, the qos field(2bytes) is not used for 8186
{
if(is_mesh_6addr_format_without_qos(pframe)) {
return WLAN_HDR_A6_MESH_DATA_LEN;
} else {
return WLAN_HDR_A4_MESH_DATA_LEN;
}
}
} // end of get_tofr_ds == 0x03 & (MESH DATA or MESH ACTION)
else
#endif // CONFIG_RTK_MESH
if (is_qos_data(pframe)) {
if (get_tofr_ds(pframe) == 0x03)
return WLAN_HDR_A4_QOS_LEN;
else
return WLAN_HDR_A3_QOS_LEN;
}
else {
if (get_tofr_ds(pframe) == 0x03)
return WLAN_HDR_A4_LEN;
else
return WLAN_HDR_A3_LEN;
}
}
else if (GetFrameType(pframe) == WIFI_MGT_TYPE)
return WLAN_HDR_A3_LEN;
else if (GetFrameType(pframe) == WIFI_CTRL_TYPE)
{
if (GetFrameSubType(pframe) == WIFI_PSPOLL)
return 16;
else if (GetFrameSubType(pframe) == WIFI_BLOCKACK_REQ)
return 16;
else if (GetFrameSubType(pframe) == WIFI_BLOCKACK)
return 16;
else
{
#ifdef _DEBUG_RTL8192CD_
printk("unallowed control pkt type! 0x%04X\n", GetFrameSubType(pframe));
#endif
return 0;
}
}
else
{
#ifdef _DEBUG_RTL8192CD_
printk("unallowed pkt type! 0x%04X\n", GetFrameType(pframe));
#endif
return 0;
}
}
unsigned char *get_mgtbuf_from_poll(struct rtl8192cd_priv *priv)
{
unsigned char *ret;
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
ret = get_buf_from_poll(priv, &priv->pshare->wlanbuf_list, (unsigned int *)&priv->pshare->pwlanbuf_poll->count);
RESTORE_INT(flags);
return ret;
}
void release_mgtbuf_to_poll(struct rtl8192cd_priv *priv, unsigned char *pbuf)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
release_buf_to_poll(priv, pbuf, &priv->pshare->wlanbuf_list, (unsigned int *)&priv->pshare->pwlanbuf_poll->count);
RESTORE_INT(flags);
}
unsigned char *get_wlanhdr_from_poll(struct rtl8192cd_priv *priv)
{
unsigned char *pbuf;
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
pbuf = get_buf_from_poll(priv, &priv->pshare->wlan_hdrlist, (unsigned int *)&priv->pshare->pwlan_hdr_poll->count);
#ifdef TX_EARLY_MODE
pbuf += 8;
#endif
RESTORE_INT(flags);
return pbuf;
}
void release_wlanhdr_to_poll(struct rtl8192cd_priv *priv, unsigned char *pbuf)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
if (pbuf == NULL)
{
DEBUG_ERR("Err: Free Null Buf!\n");
return;
}
SAVE_INT_AND_CLI(flags);
#ifdef TX_EARLY_MODE
pbuf -= 8;
#endif
release_buf_to_poll(priv, pbuf, &priv->pshare->wlan_hdrlist, (unsigned int *)&priv->pshare->pwlan_hdr_poll->count);
RESTORE_INT(flags);
}
//__MIPS16
__IRAM_IN_865X
unsigned char *get_wlanllchdr_from_poll(struct rtl8192cd_priv *priv)
{
unsigned char *pbuf;
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
pbuf = get_buf_from_poll(priv, &priv->pshare->wlanllc_hdrlist, (unsigned int *)&priv->pshare->pwlanllc_hdr_poll->count);
#ifdef TX_EARLY_MODE
pbuf += 8;
#endif
RESTORE_INT(flags);
return pbuf;
}
void release_wlanllchdr_to_poll(struct rtl8192cd_priv *priv, unsigned char *pbuf)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
#ifdef TX_EARLY_MODE
pbuf -= 8;
#endif
release_buf_to_poll(priv, pbuf, &priv->pshare->wlanllc_hdrlist, (unsigned int *)&priv->pshare->pwlanllc_hdr_poll->count);
RESTORE_INT(flags);
}
unsigned char *get_icv_from_poll(struct rtl8192cd_priv *priv)
{
unsigned char *ret;
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
ret = get_buf_from_poll(priv, &priv->pshare->wlanicv_list, (unsigned int *)&priv->pshare->pwlanicv_poll->count);
RESTORE_INT(flags);
return ret;
}
void release_icv_to_poll(struct rtl8192cd_priv *priv, unsigned char *pbuf)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
release_buf_to_poll(priv, pbuf, &priv->pshare->wlanicv_list, (unsigned int *)&priv->pshare->pwlanicv_poll->count);
RESTORE_INT(flags);
}
unsigned char *get_mic_from_poll(struct rtl8192cd_priv *priv)
{
unsigned char *ret;
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
ret = get_buf_from_poll(priv, &priv->pshare->wlanmic_list, (unsigned int *)&priv->pshare->pwlanmic_poll->count);
RESTORE_INT(flags);
return ret;
}
void release_mic_to_poll(struct rtl8192cd_priv *priv, unsigned char *pbuf)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
release_buf_to_poll(priv, pbuf, &priv->pshare->wlanmic_list, (unsigned int *)&priv->pshare->pwlanmic_poll->count);
RESTORE_INT(flags);
}
unsigned short get_pnl(union PN48 *ptsc)
{
return (((ptsc->_byte_.TSC1) << 8) | (ptsc->_byte_.TSC0));
}
unsigned int get_pnh(union PN48 *ptsc)
{
return (((ptsc->_byte_.TSC5) << 24) |
((ptsc->_byte_.TSC4) << 16) |
((ptsc->_byte_.TSC3) << 8) |
(ptsc->_byte_.TSC2));
}
#ifdef CONFIG_IEEE80211W
int UseSwCrypto(struct rtl8192cd_priv *priv, struct stat_info *pstat, int isMulticast, int isPMF)
#else
int UseSwCrypto(struct rtl8192cd_priv *priv, struct stat_info *pstat, int isMulticast)
#endif
{
#ifdef CONFIG_IEEE80211W
if (isPMF)
return 1;
#endif
if (SWCRYPTO)
return 1;
else // hw crypto
{
#ifdef CONFIG_RTK_MESH
if( isMeshPoint(pstat) )
return 0;
// return (pstat->dot11KeyMapping.keyInCam || isMulticast) ? 0 : 1;
#endif
#ifdef WDS
if (pstat && (pstat->state & WIFI_WDS) && !(pstat->state & WIFI_ASOC_STATE)) {
#ifndef CONFIG_RTL8186_KB
if (!pstat->dot11KeyMapping.keyInCam)
return 1;
else
#endif
return 0;
}
#endif
if (priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm
#ifdef CONFIG_RTL_WAPI_SUPPORT
|| priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WAPI_SMS4_
#endif
) {
if (isMulticast) { // multicast
if (!priv->pmib->dot11GroupKeysTable.keyInCam)
return 1;
else
return 0;
}
else {
if (!pstat->dot11KeyMapping.keyInCam)
return 1;
else // key is in CAM
return 0;
}
}
else { // legacy 802.11 auth (wep40 || wep104)
#ifdef MBSSID
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable)
{
if (GET_ROOT(priv)->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) {
if (isMulticast)
return 1;
else {
if (!pstat->dot11KeyMapping.keyInCam)
return 1;
else // key is in CAM
return 0;
}
}
}
#endif
#ifdef USE_WEP_DEFAULT_KEY
if (GET_ROOT(priv)->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE)
{
if (pstat && (pstat->state & WIFI_ASOC_STATE))
return 0;
}
if (isMulticast && !priv->pmib->dot11GroupKeysTable.keyInCam)
return 1;
#else
if (isMulticast) {
if (!priv->pmib->dot11GroupKeysTable.keyInCam)
return 1;
}
else {
if (!pstat->dot11KeyMapping.keyInCam)
return 1;
}
#endif
return 0;
}
}
}
void check_protection_shortslot(struct rtl8192cd_priv *priv)
{
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL_8881A)
if((GET_CHIP_VER(priv)== VERSION_8812E)||(GET_CHIP_VER(priv)== VERSION_8881A))
return;
#endif
if (priv->pmib->dot11ErpInfo.nonErpStaNum == 0 &&
priv->pmib->dot11ErpInfo.olbcDetected == 0)
{
if (priv->pmib->dot11ErpInfo.protection) {
priv->pmib->dot11ErpInfo.protection = 0;
//priv->pshare->phw->RTSInitRate_Candidate = 0x8; // 24Mbps
}
}
else
{
if (!priv->pmib->dot11StationConfigEntry.protectionDisabled &&
priv->pmib->dot11ErpInfo.protection == 0) {
priv->pmib->dot11ErpInfo.protection = 1;
//priv->pshare->phw->RTSInitRate_Candidate = 0x3; // 11Mbps
}
}
if (priv->pmib->dot11ErpInfo.nonErpStaNum == 0)
{
if (priv->pmib->dot11ErpInfo.shortSlot == 0)
{
priv->pmib->dot11ErpInfo.shortSlot = 1;
#ifdef MBSSID
if ((IS_ROOT_INTERFACE(priv))
#ifdef UNIVERSAL_REPEATER
|| (IS_VXD_INTERFACE(priv))
#endif
)
#endif
set_slot_time(priv, priv->pmib->dot11ErpInfo.shortSlot);
SET_SHORTSLOT_IN_BEACON_CAP;
DEBUG_INFO("set short slot time\n");
}
}
else
{
if (priv->pmib->dot11ErpInfo.shortSlot)
{
priv->pmib->dot11ErpInfo.shortSlot = 0;
#ifdef MBSSID
if ((IS_ROOT_INTERFACE(priv))
#ifdef UNIVERSAL_REPEATER
|| (IS_VXD_INTERFACE(priv))
#endif
)
#endif
set_slot_time(priv, priv->pmib->dot11ErpInfo.shortSlot);
RESET_SHORTSLOT_IN_BEACON_CAP;
DEBUG_INFO("reset short slot time\n");
}
}
}
void check_sta_characteristic(struct rtl8192cd_priv *priv, struct stat_info *pstat, int act)
{
if (act == INCREASE) {
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) && !isErpSta(pstat)) {
priv->pmib->dot11ErpInfo.nonErpStaNum++;
check_protection_shortslot(priv);
if (!pstat->useShortPreamble)
priv->pmib->dot11ErpInfo.longPreambleStaNum++;
}
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) && (pstat->ht_cap_len == 0))
priv->ht_legacy_sta_num++;
}
else {
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) && !isErpSta(pstat)) {
priv->pmib->dot11ErpInfo.nonErpStaNum--;
check_protection_shortslot(priv);
if (!pstat->useShortPreamble && priv->pmib->dot11ErpInfo.longPreambleStaNum > 0)
priv->pmib->dot11ErpInfo.longPreambleStaNum--;
}
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) && (pstat->ht_cap_len == 0))
priv->ht_legacy_sta_num--;
}
}
int should_forbid_Nmode(struct rtl8192cd_priv *priv)
{
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11N))
return 0;
if (priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _NO_PRIVACY_)
return 0;
if (!(priv->pmib->dot11nConfigEntry.dot11nLgyEncRstrct & BIT(3)))
return 0;
// if pure TKIP, change N mode to G mode
if (priv->pmib->dot11nConfigEntry.dot11nLgyEncRstrct & BIT(1)) {
if (priv->pmib->dot1180211AuthEntry.dot11EnablePSK ||
priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm) {
if ((priv->pmib->dot1180211AuthEntry.dot11WPACipher == 2) &&
(priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher == 0))
return 1;
else if ((priv->pmib->dot1180211AuthEntry.dot11WPACipher == 0) &&
(priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher == 2))
return 1;
else if ((priv->pmib->dot1180211AuthEntry.dot11WPACipher == 2) &&
(priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher == 2))
return 1;
}
}
// if WEP, forbid N mode
if ((priv->pmib->dot11nConfigEntry.dot11nLgyEncRstrct & BIT(0)) &&
((priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_40_PRIVACY_) ||
(priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_104_PRIVACY_)))
return 1;
return 0;
}
#ifdef RTK_AC_SUPPORT //for 11ac logo
int is_mixed_mode(struct rtl8192cd_priv *priv)
{
if((priv->pmib->dot1180211AuthEntry.dot11EnablePSK == 3)
&& (priv->pmib->dot1180211AuthEntry.dot11WPACipher & BIT(1))
&& (priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher & BIT(1))
&& (priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == 2))
{
return 1;
}
else
return 0;
}
#endif
int should_restrict_Nrate(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
if (OPMODE & WIFI_AP_STATE)
{
if (pstat->is_legacy_encrpt == 1) {
if (priv->pmib->dot11nConfigEntry.dot11nLgyEncRstrct & BIT(1)) {
if (!pstat->is_realtek_sta || (priv->pmib->dot11nConfigEntry.dot11nLgyEncRstrct & BIT(2)))
return 1;
}
}
else if (pstat->is_legacy_encrpt == 2) {
if (priv->pmib->dot11nConfigEntry.dot11nLgyEncRstrct & BIT(0)) {
if (!pstat->is_realtek_sta || (priv->pmib->dot11nConfigEntry.dot11nLgyEncRstrct & BIT(2)))
return 1;
}
}
#ifdef RTK_AC_SUPPORT //for 11ac logo // Cheat for mixed mode
if(AC_SIGMA_MODE != AC_SIGMA_NONE) {
if(is_mixed_mode(priv))
return 1;
}
#endif
#ifdef WDS
else if (pstat->state & WIFI_WDS) {
if ((priv->pmib->dot11WdsInfo.wdsPrivacy == _WEP_40_PRIVACY_) ||
(priv->pmib->dot11WdsInfo.wdsPrivacy == _WEP_104_PRIVACY_) ||
(priv->pmib->dot11WdsInfo.wdsPrivacy == _TKIP_PRIVACY_))
return 1;
}
#endif
}
// Client mode IOT issue, Button 2009.07.17
#ifdef CLIENT_MODE
else if(OPMODE & WIFI_STATION_STATE)
{
if(!pstat->is_realtek_sta && (pstat->IOTPeer != HT_IOT_PEER_MARVELL) && pstat->is_legacy_encrpt)
return 1;
}
#endif
return 0;
}
#ifdef WDS
int getWdsIdxByDev(struct rtl8192cd_priv *priv, struct net_device *dev)
{
int i;
#ifdef LAZY_WDS
int max_num;
if (priv->pmib->dot11WdsInfo.wdsEnabled == WDS_LAZY_ENABLE)
max_num = NUM_WDS;
else
max_num = priv->pmib->dot11WdsInfo.wdsNum;
for (i=0; i<max_num; i++) {
#else
for (i=0; i<priv->pmib->dot11WdsInfo.wdsNum; i++) {
#endif
if (dev == priv->wds_dev[i])
return i;
}
return -1;
}
struct net_device *getWdsDevByAddr(struct rtl8192cd_priv *priv, unsigned char *addr)
{
int i;
#ifdef LAZY_WDS
int max_num;
if (priv->pmib->dot11WdsInfo.wdsEnabled == WDS_LAZY_ENABLE)
max_num = NUM_WDS;
else
max_num = priv->pmib->dot11WdsInfo.wdsNum;
for (i=0; i<max_num; i++) {
#else
for (i=0; i<priv->pmib->dot11WdsInfo.wdsNum; i++) {
#endif
if (!memcmp(priv->pmib->dot11WdsInfo.entry[i].macAddr, addr, 6))
return priv->wds_dev[i];
}
return NULL;
}
#endif // WDS
void validate_oper_rate(struct rtl8192cd_priv *priv)
{
unsigned int supportedRates;
unsigned int basicRates;
if (OPMODE & WIFI_AP_STATE)
{
supportedRates = priv->pmib->dot11StationConfigEntry.dot11SupportedRates;
basicRates = priv->pmib->dot11StationConfigEntry.dot11BasicRates;
#ifndef CONFIG_RTL8186_KB
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11B) {
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11G)) {
// if use B only, mask G high rate
supportedRates &= 0xf;
basicRates &= 0xf;
}
}
else {
// if use A or G mode, mask B low rate
supportedRates &= 0xff0;
basicRates &= 0xff0;
}
if (supportedRates == 0) {
if (priv->pmib->dot11BssType.net_work_type & (WIRELESS_11G | WIRELESS_11A))
supportedRates = 0xff0;
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11B)
supportedRates |= 0xf;
PRINT_INFO("invalid supproted rate, use default value [%x]!\n", supportedRates);
}
if (basicRates == 0) {
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11A)
//basicRates = 0x1f0;
//11a basic rate is 6/12/24M
basicRates = 0x150;
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11B)
basicRates = 0xf;
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) {
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11B))
basicRates = 0x1f0;
}
PRINT_INFO("invalid basic rate, use default value [%x]!\n", basicRates);
}
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) {
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11B) {
if ((basicRates & 0xf) == 0) // if no CCK rates. jimmylin 2004/12/02
basicRates |= 0xf;
if ((supportedRates & 0xf) == 0) // if no CCK rates. jimmylin 2004/12/02
supportedRates |= 0xf;
}
if ((supportedRates & 0xff0) == 0) { // no ERP rate existed
supportedRates |= 0xff0;
PRINT_INFO("invalid supported rate for 11G, use default value [%x]!\n",
supportedRates);
}
}
#endif // !CONFIG_RTL8186_KB
priv->supported_rates = supportedRates;
priv->basic_rates = basicRates;
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) {
if (priv->pmib->dot11nConfigEntry.dot11nSupportedMCS == 0)
priv->pmib->dot11nConfigEntry.dot11nSupportedMCS = 0xffff;
}
}
#ifdef CLIENT_MODE
else
{
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) {
if (priv->pmib->dot11BssType.net_work_type & (WIRELESS_11B | WIRELESS_11G))
priv->dual_band = 1;
else
priv->dual_band = 0;
}
else
priv->dual_band = 0;
if (priv->dual_band) {
// for 2.4G band
supportedRates = priv->pmib->dot11StationConfigEntry.dot11SupportedRates;
basicRates = priv->pmib->dot11StationConfigEntry.dot11BasicRates;
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11B) {
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11G)) {
supportedRates &= 0xf;
basicRates &= 0xf;
}
if ((supportedRates & 0xf) == 0)
supportedRates |= 0xf;
if ((basicRates & 0xf) == 0)
basicRates |= 0xf;
}
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) {
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11B)) {
supportedRates &= 0xff0;
basicRates &= 0xff0;
}
if ((supportedRates & 0xff0) == 0)
supportedRates |= 0xff0;
if ((basicRates & 0xff0) == 0)
basicRates |= 0x1f0;
}
priv->supported_rates = supportedRates;
priv->basic_rates = basicRates;
// for 5G band
supportedRates = priv->pmib->dot11StationConfigEntry.dot11SupportedRates;
basicRates = priv->pmib->dot11StationConfigEntry.dot11BasicRates;
supportedRates &= 0xff0;
basicRates &= 0xff0;
if (supportedRates == 0)
supportedRates |= 0xff0;
if (basicRates == 0)
basicRates |= 0x1f0;
priv->supported_rates_alt = supportedRates;
priv->basic_rates_alt = basicRates;
}
else {
supportedRates = priv->pmib->dot11StationConfigEntry.dot11SupportedRates;
basicRates = priv->pmib->dot11StationConfigEntry.dot11BasicRates;
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11B) {
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11G)) {
supportedRates &= 0xf;
basicRates &= 0xf;
}
if ((supportedRates & 0xf) == 0)
supportedRates |= 0xf;
if ((basicRates & 0xf) == 0)
basicRates |= 0xf;
}
if (priv->pmib->dot11BssType.net_work_type & (WIRELESS_11G | WIRELESS_11A)) {
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11B)) {
supportedRates &= 0xff0;
basicRates &= 0xff0;
}
if ((supportedRates & 0xff0) == 0)
supportedRates |= 0xff0;
if ((basicRates & 0xff0) == 0)
basicRates |= 0x1f0;
}
priv->supported_rates = supportedRates;
priv->basic_rates = basicRates;
}
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) {
if (priv->pmib->dot11nConfigEntry.dot11nSupportedMCS == 0)
priv->pmib->dot11nConfigEntry.dot11nSupportedMCS = 0xffff;
}
}
#endif
#if defined(RTK_AC_SUPPORT)
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11AC) {
if (IS_TEST_CHIP(priv)) {
if(get_rf_mimo_mode(priv) == MIMO_1T1R) {
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap &= 0x0ff;
priv->pmib->dot11acConfigEntry.dot11SupportedVHT = 0xfffc;
} else {
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap &= 0x3fcff;
priv->pmib->dot11acConfigEntry.dot11SupportedVHT = 0xfff0;
}
} else {
if(get_rf_mimo_mode(priv) == MIMO_1T1R) {
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap &= 0x3ff;
priv->pmib->dot11acConfigEntry.dot11SupportedVHT |= 0xfffc;
if(!priv->pmib->dot11acConfigEntry.dot11VHT_TxMap)
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap = 0x3ff;
if(priv->pmib->dot11acConfigEntry.dot11SupportedVHT == 0xffff)
priv->pmib->dot11acConfigEntry.dot11SupportedVHT = 0xfffe;
} else if (get_rf_mimo_mode(priv) == MIMO_2T2R) { //eric_8814
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap &= 0xfffff;
priv->pmib->dot11acConfigEntry.dot11SupportedVHT |= 0xfff0;
if(!priv->pmib->dot11acConfigEntry.dot11VHT_TxMap)
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap = 0xfffff;
if(priv->pmib->dot11acConfigEntry.dot11SupportedVHT == 0xffff)
priv->pmib->dot11acConfigEntry.dot11SupportedVHT = 0xfffa;
} else if ((get_rf_mimo_mode(priv) == MIMO_3T3R) ||(get_rf_mimo_mode(priv) == MIMO_4T4R)) { //eric_8814
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap &= 0x3fffffff;
priv->pmib->dot11acConfigEntry.dot11SupportedVHT |= 0xffc0;
if(!priv->pmib->dot11acConfigEntry.dot11VHT_TxMap)
priv->pmib->dot11acConfigEntry.dot11VHT_TxMap = 0x3fffffff;
if(priv->pmib->dot11acConfigEntry.dot11SupportedVHT == 0xffff)
priv->pmib->dot11acConfigEntry.dot11SupportedVHT = 0xffda;
}
}
}
#endif
}
void get_oper_rate(struct rtl8192cd_priv *priv)
{
unsigned int supportedRates=0;
unsigned int basicRates=0;
unsigned char val;
int i, idx=0;
memset(AP_BSSRATE, 0, sizeof(AP_BSSRATE));
AP_BSSRATE_LEN = 0;
if (OPMODE & WIFI_AP_STATE) {
supportedRates = priv->supported_rates;
basicRates = priv->basic_rates;
}
#ifdef CLIENT_MODE
else {
if (priv->dual_band && (priv->pshare->curr_band == BAND_5G)) {
supportedRates = priv->supported_rates_alt;
basicRates = priv->basic_rates_alt;
}
else {
supportedRates = priv->supported_rates;
basicRates = priv->basic_rates;
}
}
#endif
for (i=0; dot11_rate_table[i]; i++) {
int bit_mask = 1 << i;
if (supportedRates & bit_mask) {
val = dot11_rate_table[i];
#ifdef SUPPORT_SNMP_MIB
SNMP_MIB_ASSIGN(dot11SupportedDataRatesSet[i], ((unsigned int)val));
SNMP_MIB_ASSIGN(dot11OperationalRateSet[i], ((unsigned char)val));
#endif
if (basicRates & bit_mask)
val |= 0x80;
AP_BSSRATE[idx] = val;
AP_BSSRATE_LEN++;
idx++;
}
}
#ifdef SUPPORT_SNMP_MIB
SNMP_MIB_ASSIGN(dot11SupportedDataRatesNum, ((unsigned char)AP_BSSRATE_LEN));
#endif
}
// bssrate_ie: _SUPPORTEDRATES_IE_ get supported rate set
// bssrate_ie: _EXT_SUPPORTEDRATES_IE_ get extended supported rate set
int get_bssrate_set(struct rtl8192cd_priv *priv, int bssrate_ie, unsigned char **pbssrate, int *bssrate_len)
{
int i;
#ifdef CONFIG_RTL_92D_SUPPORT
if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G)
#else
if ((priv->pshare->curr_band == BAND_5G)||(priv->pmib->dot11nConfigEntry.dot11nUse40M == HT_CHANNEL_WIDTH_80)) //AC2G_256QAM
#endif
{
#ifdef P2P_SUPPORT
if(bssrate_ie == _SUPPORTED_RATES_NO_CCK_ ){
*pbssrate = &dot11_rate_table[4];
*bssrate_len = 8;
return TRUE;
}
#endif
if (bssrate_ie == _SUPPORTEDRATES_IE_ )
{
for(i=0; i<AP_BSSRATE_LEN; i++)
if (!is_CCK_rate(AP_BSSRATE[i] & 0x7f))
break;
if (i == AP_BSSRATE_LEN)
return FALSE;
else {
*pbssrate = &AP_BSSRATE[i];
*bssrate_len = AP_BSSRATE_LEN - i;
return TRUE;
}
}
else
return FALSE;
}
else
{
if (bssrate_ie == _SUPPORTEDRATES_IE_)
{
*pbssrate = AP_BSSRATE;
if (AP_BSSRATE_LEN > 8)
*bssrate_len = 8;
else
*bssrate_len = AP_BSSRATE_LEN;
return TRUE;
}
#ifdef P2P_SUPPORT
else if( bssrate_ie == _SUPPORTED_RATES_NO_CCK_){
*pbssrate = &dot11_rate_table[4];
*bssrate_len = 8;
return TRUE;
}
#endif
else
{
if (AP_BSSRATE_LEN > 8) {
*pbssrate = &AP_BSSRATE[8];
*bssrate_len = AP_BSSRATE_LEN - 8;
return TRUE;
}
else
return FALSE;
}
}
}
struct channel_list{
unsigned char channel[31];
unsigned char len;
};
static struct channel_list reg_channel_2_4g[] = {
/* FCC */ {{1,2,3,4,5,6,7,8,9,10,11},11},
/* IC */ {{1,2,3,4,5,6,7,8,9,10,11},11},
/* ETSI */ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13},
/* SPAIN */ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13},
/* FRANCE */ {{10,11,12,13},4},
/* MKK */ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14},
/* ISRAEL */ {{3,4,5,6,7,8,9,10,11,12,13},11},
/* MKK1 */ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14},
/* MKK2 */ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14},
/* MKK3 */ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14},
/* NCC (Taiwan) */ {{1,2,3,4,5,6,7,8,9,10,11},11},
/* RUSSIAN */ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13},
/* CN */ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13},
/* Global */ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14},
/* World_wide */ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13},
/* Test */ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14},
/* 5M10M */ {{},0},
/* SG */ {{1,2,3,4,5,6,7,8,9,10,11},11},
/* KR */ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13},
};
#ifdef DFS
static struct channel_list reg_channel_5g_full_band[] = {
/* FCC */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},20},
/* IC */ {{36,40,44,48,52,56,60,64,149,153,157,161},12},
/* ETSI */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},19},
/* SPAIN */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},19},
/* FRANCE */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},19},
/* MKK */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},19},
/* ISRAEL */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140},19},
/* MKK1 */ {{34,38,42,46},4},
/* MKK2 */ {{36,40,44,48},4},
/* MKK3 */ {{36,40,44,48,52,56,60,64},8},
/* NCC (Taiwan) */ {{56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},15},
/* RUSSIAN */ {{36,40,44,48,52,56,60,64,132,136,140,149,153,157,161,165},16},
/* CN */ {{36,40,44,48,52,56,60,64,149,153,157,161,165},13},
/* Global */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},20},
/* World_wide */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},20},
/* Test */ {{36,40,44,48, 52,56,60,64, 100,104,108,112, 116,120,124,128, 132,136,140,144, 149,153,157,161, 165,169,173,177}, 28},
/* 5M10M */ {{146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170}, 25},
/* SG */ {{36,40,44,48,149,153,157,161,165},9},
/* KR */ {{36,40,44,48,52,56,60,64,100,104,108,112,116,136,140,149,153,157,161,165},20},
};
struct channel_list reg_channel_5g_not_dfs_band[] = {
/* FCC */ {{36,40,44,48,149,153,157,161,165},9},
/* IC */ {{36,40,44,48,149,153,157,161},8},
/* ETSI */ {{36,40,44,48},4},
/* SPAIN */ {{36,40,44,48},4},
/* FRANCE */ {{36,40,44,48},4},
/* MKK */ {{36,40,44,48},4},
/* ISRAEL */ {{36,40,44,48},4},
/* MKK1 */ {{34,38,42,46},4},
/* MKK2 */ {{36,40,44,48},4},
/* MKK3 */ {{36,40,44,48},4},
/* NCC (Taiwan) */ {{56,60,64,149,153,157,161,165},8},
/* RUSSIAN */ {{36,40,44,48,149,153,157,161,165},9},
/* CN */ {{36,40,44,48,149,153,157,161,165},9},
/* Global */ {{36,40,44,48,149,153,157,161,165},9},
/* World_wide */ {{36,40,44,48,149,153,157,161,165},9},
/* Test */ {{36,40,44,48, 149,153,157,161, 165,169,173,177}, 12},
/* 5M10M */ {{146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170}, 25},
/* SG */ {{36,40,44,48,149,153,157,161,165},9},
/* KR */ {{36,40,44,48,149,153,157,161,165},9},
};
#else
// Exclude DFS channels
static struct channel_list reg_channel_5g_full_band[] = {
/* FCC */ {{36,40,44,48,149,153,157,161,165},9},
/* IC */ {{36,40,44,48,149,153,157,161},8},
/* ETSI */ {{36,40,44,48},4},
/* SPAIN */ {{36,40,44,48},4},
/* FRANCE */ {{36,40,44,48},4},
/* MKK */ {{36,40,44,48},4},
/* ISRAEL */ {{36,40,44,48},4},
/* MKK1 */ {{34,38,42,46},4},
/* MKK2 */ {{36,40,44,48},4},
/* MKK3 */ {{36,40,44,48},4},
/* NCC (Taiwan) */ {{56,60,64,149,153,157,161,165},8},
/* RUSSIAN */ {{36,40,44,48,149,153,157,161,165},9},
/* CN */ {{36,40,44,48,149,153,157,161,165},9},
/* Global */ {{36,40,44,48,149,153,157,161,165},9},
/* World_wide */ {{36,40,44,48,149,153,157,161,165},9},
/* Test */ {{36,40,44,48, 52,56,60,64, 100,104,108,112, 116,120,124,128, 132,136,140,144, 149,153,157,161, 165,169,173,177}, 28},
/* 5M10M */ {{146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170}, 25},
/* SG */ {{36,40,44,48,149,153,157,161,165},9},
/* KR */ {{36,40,44,48,149,153,157,161,165},9},
};
#endif
int is_available_channel(struct rtl8192cd_priv *priv, unsigned char channel) {
if(priv->pmib->dot11DFSEntry.disable_DFS == 1) {
if((channel >= 52 && channel <= 140))
return 0;
}
if((priv->pmib->dot11RFEntry.band5GSelected & PHY_BAND_5G_1) &&
(channel >= 36 && channel <= 48))
return 1;
else if((priv->pmib->dot11RFEntry.band5GSelected & PHY_BAND_5G_2) &&
(channel >= 52 && channel <= 64))
return 1;
else if((priv->pmib->dot11RFEntry.band5GSelected & PHY_BAND_5G_3) &&
(channel >= 100 && channel <= 144))
return 1;
else if((priv->pmib->dot11RFEntry.band5GSelected & PHY_BAND_5G_4) &&
(channel >= 149 && channel <= 177))
return 1;
else if((priv->pmib->dot11RFEntry.band5GSelected & PHY_BAND_5G_4) &&
(channel >= 146 && channel <= 177) &&
(priv->pmib->dot11nConfigEntry.dot11nUse40M == 4 ||priv->pmib->dot11nConfigEntry.dot11nUse40M == 5))
return 1;
else
return 0;
}
int is_available_NonDFS_channel(struct rtl8192cd_priv *priv, unsigned char channel)
{
if((priv->pmib->dot11RFEntry.band5GSelected == PHY_BAND_5G_3))
return 0;
else
return 1;
}
#define MAX_NUM_80M_CH 7
unsigned int CH_80m[MAX_NUM_80M_CH]={36,52,100,116,132,149,165};
int is80MChannel(unsigned int chnl_list[], unsigned int chnl_num,unsigned int channel)
{
int idx;
int chNO;
int baseCH=0;
idx = -1;
if( (CH_80m[MAX_NUM_80M_CH-1] <= channel) && ((CH_80m[MAX_NUM_80M_CH-1]+8) >= channel))
baseCH = CH_80m[MAX_NUM_80M_CH-1];
else
{
for(chNO=0;chNO<MAX_NUM_80M_CH-1;chNO++) {
if(CH_80m[chNO] <= channel && CH_80m[chNO+1] > channel) {
baseCH = CH_80m[chNO];
break;
}
}
}
if(baseCH == 0)
_DEBUG_ERR("Channel is out of scope\n");
for(idx=0;idx<chnl_num;idx++) {
// available_chnl is sorted.
if(chnl_list[idx] == baseCH)
break;
}
if(idx == chnl_num || idx + 3 >= chnl_num)
return 0;
if(chnl_list[idx+1] == baseCH + 4 &&
chnl_list[idx+2] == baseCH + 8 &&
chnl_list[idx+3] == baseCH + 12)
return 1;
else
return 0;
}
#define MAX_NUM_40M_CH 14
unsigned int CH_40m[MAX_NUM_40M_CH]={36,44,52,60,100,108,116,124,132,140,149,157,165,173};
int is40MChannel(unsigned int chnl_list[], unsigned int chnl_num,unsigned int channel)
{
int idx;
int chNO;
int baseCH=0;
idx = -1;
if( (CH_40m[MAX_NUM_40M_CH-1] <= channel) && ((CH_40m[MAX_NUM_40M_CH-1]+4) >= channel))
baseCH = CH_40m[MAX_NUM_40M_CH-1];
else
{
for(chNO=0;chNO<MAX_NUM_40M_CH-1;chNO++) {
if(CH_40m[chNO] <= channel && CH_40m[chNO+1] > channel) {
baseCH = CH_40m[chNO];
break;
}
}
}
if(baseCH == 0)
_DEBUG_ERR("Channel is out of scope\n");
for(idx=0;idx<chnl_num;idx++) {
// available_chnl is sorted.
if(chnl_list[idx] == baseCH)
break;
}
if(idx == chnl_num || idx + 1 >= chnl_num)
return 0;
if(chnl_list[idx+1] == baseCH + 4)
return 1;
else
return 0;
}
int find80MChannel(unsigned int chnl_list[], unsigned int chnl_num) {
int i,j;
unsigned int random;
unsigned int num;
#ifdef __ECOS
{
unsigned char random_buf[4];
get_random_bytes(random_buf, 4);
random = random_buf[3];
}
#else
get_random_bytes(&random, 4);
#endif
num = random % chnl_num;
for(i=num;i<chnl_num+num;i++) {
j=i;
if (j>=chnl_num)
j=j-chnl_num;
if(is80MChannel(chnl_list,chnl_num,chnl_list[j]))
return chnl_list[j];
}
return -1;
}
int find40MChannel(unsigned int chnl_list[], unsigned int chnl_num)
{
int i,j;
unsigned int random;
unsigned int num;
#ifdef __ECOS
{
unsigned char random_buf[4];
get_random_bytes(random_buf, 4);
random = random_buf[3];
}
#else
get_random_bytes(&random, 4);
#endif
num = random % chnl_num;
for(i=num;i<chnl_num+num;i++) {
j=i;
if (j>=chnl_num)
j=j-chnl_num;
if(is40MChannel(chnl_list,chnl_num,chnl_list[j]))
return chnl_list[j];
}
return -1;
}
int get_available_channel(struct rtl8192cd_priv *priv)
{
int i, reg;
struct channel_list *ch_5g_lst=NULL;
priv->available_chnl_num = 0;
reg = priv->pmib->dot11StationConfigEntry.dot11RegDomain;
if ((reg < DOMAIN_FCC) || (reg >= DOMAIN_MAX))
return FAIL;
if (priv->pmib->dot11BssType.net_work_type & (WIRELESS_11B | WIRELESS_11G) ||
((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) &&
!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11A))) {
#if 0 //def AC2G_256QAM
if(is_ac2g(priv)) //if 2.4G + 11ac mode, force available channels = 1, 5, 9, 13
{
priv->available_chnl[0]=1;
priv->available_chnl[1]=5;
priv->available_chnl[2]=9;
priv->available_chnl[3]=13;
priv->available_chnl_num=4;
}
else
#endif
{
for (i=0; i<reg_channel_2_4g[reg-1].len; i++)
priv->available_chnl[i] = reg_channel_2_4g[reg-1].channel[i];
priv->available_chnl_num += reg_channel_2_4g[reg-1].len;
}
}
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) {
ch_5g_lst = reg_channel_5g_full_band;
for (i=0; i<ch_5g_lst[reg-1].len; i++) {
if(is_available_channel(priv,ch_5g_lst[reg-1].channel[i]))
priv->available_chnl[priv->available_chnl_num++] = ch_5g_lst[reg-1].channel[i];
}
//for (i=0; i<ch_5g_lst[reg-1].len; i++)
// priv->available_chnl[priv->available_chnl_num+i] = ch_5g_lst[reg-1].channel[i];
//priv->available_chnl_num += ch_5g_lst[reg-1].len;
#ifdef DFS
/* remove the blocked channels from available_chnl[32] */
if (priv->NOP_chnl_num)
for (i=0; i<priv->NOP_chnl_num; i++)
RemoveChannel(priv, priv->available_chnl, &priv->available_chnl_num, priv->NOP_chnl[i]);
priv->Not_DFS_chnl_num = 0;
for (i=0; i<reg_channel_5g_not_dfs_band[reg-1].len; i++) {
if(is_available_NonDFS_channel(priv,reg_channel_5g_not_dfs_band[reg-1].channel[i]))
priv->Not_DFS_chnl[priv->Not_DFS_chnl_num++] = reg_channel_5g_not_dfs_band[reg-1].channel[i];
}
#endif
}
// add by david ---------------------------------------------------
if (priv->pmib->dot11RFEntry.dot11ch_low || priv->pmib->dot11RFEntry.dot11ch_hi) {
unsigned int tmpbuf[100];
int num=0;
for (i=0; i<priv->available_chnl_num; i++) {
if ( (priv->pmib->dot11RFEntry.dot11ch_low &&
priv->available_chnl[i] < priv->pmib->dot11RFEntry.dot11ch_low) ||
(priv->pmib->dot11RFEntry.dot11ch_hi &&
priv->available_chnl[i] > priv->pmib->dot11RFEntry.dot11ch_hi))
continue;
else
tmpbuf[num++] = priv->available_chnl[i];
}
if (num) {
memcpy(priv->available_chnl, tmpbuf, num*4);
priv->available_chnl_num = num;
}
}
//------------------------------------------------------ 2007-04-14
return SUCCESS;
}
void cnt_assoc_num(struct rtl8192cd_priv *priv, struct stat_info *pstat, int act, char *func)
{
#ifdef CONFIG_RTL_92D_SUPPORT
int i;
#endif
#ifdef INDICATE_LINK_CHANGE
if (!IEEE8021X_FUN && ((_NO_PRIVACY_ == priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm) ||
(_WEP_40_PRIVACY_ == priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm) ||
(_WEP_104_PRIVACY_ == priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm))) {
indicate_sta_link_change(priv, pstat, act, func);
}
#endif
if (act == INCREASE) {
if (priv->assoc_num <= NUM_STAT) {
priv->assoc_num++;
#ifdef TLN_STATS
if (priv->assoc_num > priv->wifi_stats.max_sta) {
priv->wifi_stats.max_sta = priv->assoc_num;
priv->wifi_stats.max_sta_timestamp = priv->up_time;
}
#endif
priv->pshare->total_assoc_num++;
#if defined(CONFIG_RTL_88E_SUPPORT) && defined(TXREPORT)
if (GET_CHIP_VER(priv) == VERSION_8188E) {
#if defined(CONFIG_PCI_HCI)
RTL8188E_AssignTxReportMacId(priv);
if (priv->pshare->total_assoc_num == 1)
RTL8188E_ResumeTxReport(priv);
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
notify_tx_report_change(priv);
#endif
}
#endif
#if 0
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
if (IS_ROOT_INTERFACE(priv))
#endif
{
if (priv->assoc_num > 1)
check_DIG_by_rssi(priv, 0); // force DIG temporary off for association after the fist one
}
#endif
if (pstat->ht_cap_len) {
priv->pshare->ht_sta_num++;
if (priv->pshare->iot_mode_enable && (priv->pshare->ht_sta_num == 1)
#ifdef RTL_MANUAL_EDCA
&& (priv->pmib->dot11QosEntry.ManualEDCA == 0)
#endif
) {
#ifdef USE_OUT_SRC
#ifdef _OUTSRC_COEXIST
if(IS_OUTSRC_CHIP(priv))
#endif
IotEdcaSwitch(priv, priv->pshare->iot_mode_enable);
#endif
#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
#ifdef _OUTSRC_COEXIST
if(!IS_OUTSRC_CHIP(priv))
#endif
IOT_EDCA_switch(priv, priv->pmib->dot11BssType.net_work_type, priv->pshare->iot_mode_enable);
#endif
}
#ifdef WIFI_11N_2040_COEXIST
if (priv->pmib->dot11nConfigEntry.dot11nCoexist && priv->pshare->is_40m_bw &&
(priv->pmib->dot11BssType.net_work_type & (WIRELESS_11N|WIRELESS_11G))) {
if (pstat->ht_cap_buf.ht_cap_info & cpu_to_le16(_HTCAP_40M_INTOLERANT_)) {
if (OPMODE & WIFI_AP_STATE) {
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
unsigned int force_20_stamap;
force_20_stamap = orSTABitMap(&priv->force_20_sta);
setSTABitMap(&priv->force_20_sta, pstat->aid);
// force all STA switch TXBW to 20M
if (0 == force_20_stamap)
update_RAMask_to_FW(priv, 1);
#else
setSTABitMap(&priv->force_20_sta, pstat->aid);
#endif
#if defined(WIFI_11N_2040_COEXIST_EXT)
clearSTABitMap(&priv->pshare->_40m_staMap, pstat->aid);
#endif
}
}
}
#endif
check_NAV_prot_len(priv, pstat, 0);
}
#ifdef CONFIG_RTL_8812_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8812E) {
UpdateHalMSRRPT8812(priv, pstat, INCREASE);
RTL8812_MACID_PAUSE(priv, 0, REMAP_AID(pstat));
}
#endif
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
if(pstat->aid <128)
{
GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, INCREASE);
GET_HAL_INTERFACE(priv)->SetMACIDSleepHandler(priv, 0, REMAP_AID(pstat));
pstat->txpause_flag = 0;
pstat->bDrop = 0;
}
}
#endif
#if defined(CONFIG_WLAN_HAL_8814AE)
#ifdef HW_FILL_MACID
// set Drop = 0;
if (GET_CHIP_VER(priv) == VERSION_8814A) {
// if(pstat->aid <128)
// {
// GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, INCREASE);
// pstat->bDrop = 0;
// }
//Init fill mac address,Init fill CRC5
GET_HAL_INTERFACE(priv)->SetTxRPTHandler(priv, REMAP_AID(pstat), TXRPT_VAR_MAC_ADDRESS, &pstat->hwaddr);
GET_HAL_INTERFACE(priv)->SetCRC5ToRPTBufferHandler(priv,CRC5(&pstat->hwaddr,6), REMAP_AID(pstat),1);
}
#endif //#ifdef HW_FILL_MACID
#endif
} else {
DEBUG_ERR("Association Number Error (%d)!\n", NUM_STAT);
}
} else {
if (priv->assoc_num > 0) {
priv->assoc_num--;
priv->pshare->total_assoc_num--;
#if defined(CONFIG_RTL_88E_SUPPORT) && defined(TXREPORT)
if (GET_CHIP_VER(priv) == VERSION_8188E) {
#if defined(CONFIG_PCI_HCI)
if (!priv->pshare->total_assoc_num)
RTL8188E_SuspendTxReport(priv);
else
RTL8188E_AssignTxReportMacId(priv);
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
notify_tx_report_change(priv);
#endif
}
#endif
#if defined(CONFIG_POWER_SAVE)
if (priv->pshare->total_assoc_num == 0 && GET_ROOT(priv)->pmib->dot11OperationEntry.ps_level == 2)
{
rtw_lock_suspend_timeout(priv, 2000);
}
#endif
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
if (0 == priv->assoc_num) {
rtw_txservq_flush(priv, &priv->tx_mc_queue);
}
#endif
#if 0
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
if (IS_ROOT_INTERFACE(priv))
#endif
if (!priv->assoc_num) {
#ifdef INTERFERENCE_CONTROL
if (priv->pshare->rf_ft_var.nbi_filter_enable)
check_NBI_by_rssi(priv, 0xFF); // force NBI on while no station associated
#else
#if defined(CONFIG_PCI_HCI)
check_DIG_by_rssi(priv, 0); // force DIG off while no station associated
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
notify_check_DIG_by_rssi(priv, 0);
#endif
#endif
}
#endif
if (pstat->ht_cap_len) {
if (--priv->pshare->ht_sta_num < 0) {
printk("ht_sta_num error\n"); // this should not happen
} else {
if (priv->pshare->iot_mode_enable && !priv->pshare->ht_sta_num
#ifdef RTL_MANUAL_EDCA
&& (priv->pmib->dot11QosEntry.ManualEDCA == 0)
#endif
) {
#ifdef USE_OUT_SRC
#ifdef _OUTSRC_COEXIST
if(IS_OUTSRC_CHIP(priv))
#endif
IotEdcaSwitch(priv, priv->pshare->iot_mode_enable);
#endif
#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
#ifdef _OUTSRC_COEXIST
if(!IS_OUTSRC_CHIP(priv))
#endif
IOT_EDCA_switch(priv, priv->pmib->dot11BssType.net_work_type, priv->pshare->iot_mode_enable);
#endif
}
#ifdef WIFI_11N_2040_COEXIST
if (priv->pmib->dot11nConfigEntry.dot11nCoexist && priv->pshare->is_40m_bw &&
(priv->pmib->dot11BssType.net_work_type & (WIRELESS_11N|WIRELESS_11G))) {
if (pstat->ht_cap_buf.ht_cap_info & cpu_to_le16(_HTCAP_40M_INTOLERANT_)) {
if (OPMODE & WIFI_AP_STATE) {
clearSTABitMap(&priv->force_20_sta, pstat->aid);
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
update_RAMask_to_FW(priv, 0);
#endif
SetTxPowerLevel(priv);
}
}
}
#endif
check_NAV_prot_len(priv, pstat, 1);
}
}
#ifdef CONFIG_RTL_8812_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8812E) {
UpdateHalMSRRPT8812(priv, pstat, DECREASE);
}
#endif
#if defined(CONFIG_WLAN_HAL_8881A) || defined(CONFIG_WLAN_HAL_8192EE)
if ((GET_CHIP_VER(priv) == VERSION_8881A) || (GET_CHIP_VER(priv) == VERSION_8192E)) {
if(pstat->aid <127)
{
GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, DECREASE);
pstat->bDrop = 1;
}
}
#endif
#if defined(CONFIG_WLAN_HAL_8814AE)
#ifdef HW_FILL_MACID
if (GET_CHIP_VER(priv) == VERSION_8814A) {
// if(pstat->aid <127)
// {
// GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, DECREASE);
// pstat->bDrop = 1;
// }
// Set hwaddr zero
u1Byte hwaddr = {0x00,0x00,0x00,0x00,0x00,0x00};
GET_HAL_INTERFACE(priv)->SetTxRPTHandler(priv, REMAP_AID(pstat), TXRPT_VAR_MAC_ADDRESS, &hwaddr);
GET_HAL_INTERFACE(priv)->SetCRC5ToRPTBufferHandler(priv,CRC5(&hwaddr,6), REMAP_AID(pstat),0);
}
#endif //#ifdef HW_FILL_MACID
#endif
} else {
DEBUG_ERR("Association Number Error (0)!\n");
}
}
#ifdef CONFIG_RTL_92D_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8192D){
for (i=NUM_STAT-1; i>=0 ; i--){
if (priv->pshare->aidarray[i]!=NULL){
if (priv->pshare->aidarray[i]->used)
break;
}
}
priv->pshare->max_fw_macid = priv->pshare->aidarray[i]->station.aid+1; // fw check macid num from 1~32, so we add 1 to index.
if (priv->pshare->max_fw_macid > (NUM_STAT+1))
priv->pshare->max_fw_macid = (NUM_STAT+1);
}
#endif
DEBUG_INFO("assoc_num%s(%d) in %s %02X%02X%02X%02X%02X%02X\n",
act?"++":"--",
priv->assoc_num,
func,
pstat->hwaddr[0],
pstat->hwaddr[1],
pstat->hwaddr[2],
pstat->hwaddr[3],
pstat->hwaddr[4],
pstat->hwaddr[5]);
}
#ifdef INDICATE_LINK_CHANGE
void indicate_sta_link_change(struct rtl8192cd_priv *priv, struct stat_info *pstat, int act, char *func)
{
DOT11_LINK_CHANGE_IND LinkChange_Ind;
if ((INCREASE == act) && !pstat->link_up) {
pstat->link_up = 1;
// do something about STA addition
} else if ((DECREASE == act) && pstat->link_up) {
pstat->link_up = 0;
// do something about STA removal
} else {
return;
}
memcpy(LinkChange_Ind.MACAddr, pstat->hwaddr, MACADDRLEN);
LinkChange_Ind.EventId = DOT11_EVENT_LINK_CHANGE_IND;
LinkChange_Ind.IsMoreEvent = 0;
LinkChange_Ind.LinkStatus = pstat->link_up;
DOT11_EnQueue((unsigned long)priv, priv->pevent_queue, (UINT8 *)&LinkChange_Ind,
sizeof(DOT11_LINK_CHANGE_IND));
DEBUG_INFO("%s%s in %s %02X%02X%02X%02X%02X%02X\n",
__func__,
act ? "++" : "--",
func,
pstat->hwaddr[0], pstat->hwaddr[1], pstat->hwaddr[2],
pstat->hwaddr[3], pstat->hwaddr[4], pstat->hwaddr[5]);
}
#endif // INDICATE_LINK_CHANGE
/*
* Use this function to get the number of associated station, no matter
* it is expired or not. And don't count WDS peers in.
*/
int get_assoc_sta_num(struct rtl8192cd_priv *priv, int mode)
{
struct list_head *phead, *plist;
struct stat_info *pstat;
int sta_num;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
sta_num = 0;
phead = &priv->asoc_list;
SMP_LOCK_ASOC_LIST(flags);
plist = phead->next;
while (plist != phead) {
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
#ifdef CONFIG_RTK_MESH
if(mode == 1) {
if(isPossibleNeighbor(pstat))
continue;
}
#endif
if ((pstat->state & WIFI_ASOC_STATE)
#ifdef NOT_RTK_BSP
&& pstat->expire_to
#endif
)
{
sta_num++;
}
}
SMP_UNLOCK_ASOC_LIST(flags);
return sta_num;
}
void event_indicate(struct rtl8192cd_priv *priv, unsigned char *mac, int event)
{
#ifdef __KERNEL__
#ifdef USE_CHAR_DEV
if (priv->pshare->chr_priv && priv->pshare->chr_priv->asoc_fasync)
kill_fasync(&priv->pshare->chr_priv->asoc_fasync, SIGIO, POLL_IN);
#endif
#ifdef USE_PID_NOTIFY
if (priv->pshare->wlanapp_pid > 0)
#ifdef LINUX_2_6_27_
{
kill_pid(_wlanapp_pid, SIGIO, 1);
}
#else
kill_proc(priv->pshare->wlanapp_pid, SIGIO, 1);
#endif
#endif
#endif
#ifdef __DRAYTEK_OS__
if (event == 2)
cb_disassoc_indicate(priv->dev, mac);
#endif
#ifdef GREEN_HILL
extern void indicate_to_upper(int reason, unsigned char *addr);
if (event > 0)
indicate_to_upper(event, mac);
#endif
#ifdef __ECOS
#ifdef RTLPKG_DEVS_ETH_RLTK_819X_IWCONTROL
extern cyg_flag_t iw_flag;
cyg_flag_setbits(&iw_flag, 0x1);
#else
#ifdef RTLPKG_DEVS_ETH_RLTK_819X_WLAN_WPS
extern cyg_flag_t wsc_flag;
cyg_flag_setbits(&wsc_flag, 0x1);
#endif
#endif
#endif
}
#ifdef WIFI_HAPD
int event_indicate_hapd(struct rtl8192cd_priv *priv, unsigned char *mac, int event, unsigned char *extra)
{
struct net_device *dev = (struct net_device *)priv->dev;
union iwreq_data wreq;
if(OPMODE & WIFI_AP_STATE)
{
printk("event_indicate_hapd +++, event =0x%x\n", event);
memset(&wreq, 0, sizeof(wreq));
if(event == HAPD_EXIRED)
{
memcpy(wreq.addr.sa_data, mac, 6);
wireless_send_event(dev, IWEVEXPIRED, &wreq, NULL);
return 0;
}
else if(event == HAPD_REGISTERED)
{
memcpy(wreq.addr.sa_data, mac, 6);
wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL);
return 0;
}
else if(event == HAPD_MIC_FAILURE)
{
char buf[6];
memcpy(buf, mac, 6);
wreq.data.flags = event;
wreq.data.length = 6;
wireless_send_event(dev, IWEVCUSTOM, &wreq, buf);
return 0;
}
else if(event == HAPD_WPS_PROBEREQ)
{
wreq.data.flags = event;
wreq.data.length = sizeof(struct _DOT11_PROBE_REQUEST_IND);
wireless_send_event(dev, IWEVGENIE, &wreq, extra); //IW_CUSTOM_MAX is 256, can NOT afford _DOT11_PROBE_REQUEST_IND
return 0;
}
else{
//Not used yet
wreq.data.flags = event;
wireless_send_event(dev, IWEVCUSTOM, &wreq, extra);
return 0;
}
}
return -1;
}
#endif
#ifdef WIFI_WPAS
int event_indicate_wpas(struct rtl8192cd_priv *priv, unsigned char *mac, int event, unsigned char *extra)
{
struct net_device *dev = (struct net_device *)priv->dev;
union iwreq_data wreq;
if(OPMODE & WIFI_STATION_STATE)
{
printk("event_indicate_wpas +++ event = 0x%x\n", event);
memset(&wreq, 0, sizeof(wreq));
if(event == WPAS_EXIRED)
{
memcpy(wreq.addr.sa_data, mac, 6);
wireless_send_event(dev, IWEVEXPIRED, &wreq, NULL);
return 0;
}
else if(event == WPAS_REGISTERED)
{
memcpy(wreq.addr.sa_data, mac, 6);
wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
return 0;
}
else if(event == WPAS_MIC_FAILURE)
{
#ifdef WIFI_WPAS_CLI
struct iw_michaelmicfailure ev;
memset(&ev, 0, sizeof(ev));
// if (hdr->addr1[0] & 0x01)
// ev.flags |= IW_MICFAILURE_GROUP;
// else
// ev.flags |= IW_MICFAILURE_PAIRWISE;
ev.src_addr.sa_family = ARPHRD_ETHER;
memcpy(ev.src_addr.sa_data, mac, ETH_ALEN);
wreq.data.length = sizeof(ev);
wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wreq, (char *)&ev);
#else
char buf[6];
memcpy(buf, mac, 6);
wreq.data.flags = event;
wreq.data.length = 6;
wireless_send_event(dev, IWEVCUSTOM, &wreq, buf);
return 0;
#endif
}
else if(event == WPAS_ASSOC_INFO)
{
wreq.data.flags = event;
wreq.data.length = sizeof(struct _WPAS_ASSOCIATION_INFO);
wireless_send_event(dev, IWEVCUSTOM, &wreq, extra); //IW_CUSTOM_MAX is 256, can NOT afford _DOT11_PROBE_REQUEST_IND
return 0;
}
else if(event == WPAS_SCAN_DONE)
{
wireless_send_event(dev, SIOCGIWSCAN, &wreq, NULL);
return 0;
}
#ifdef WIFI_WPAS_CLI
else if (event == WPAS_DISCON)
{
wreq.ap_addr.sa_family = ARPHRD_ETHER;
memset(wreq.ap_addr.sa_data, 0, ETH_ALEN);
wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
return 0;
}
#endif
else
{
//Not used yet
wreq.data.flags = event;
wireless_send_event(dev, IWEVCUSTOM, &wreq, extra);
return 0;
}
}
return -1;
}
#endif
#ifdef CONFIG_RTL_WAPI_SUPPORT
void wapi_event_indicate(struct rtl8192cd_priv *priv)
{
#ifdef LINUX_2_6_27_
struct pid *pid;
#endif
if (priv->pshare->wlanwapi_pid > 0)
{
#ifdef LINUX_2_6_27_
kill_pid(_wlanwapi_pid, SIGIO, 1);
#else
kill_proc(priv->pshare->wlanwapi_pid, SIGIO, 1);
#endif
}
}
#endif
#ifdef USE_WEP_DEFAULT_KEY
void init_DefaultKey_Enc(struct rtl8192cd_priv *priv, unsigned char *key, int algorithm)
{
unsigned char defaultmac[4][6];
int i;
memset(defaultmac, 0, sizeof(defaultmac));
for(i=0; i<4; i++)
defaultmac[i][5] = i;
for(i=0; i<4; i++)
{
CamDeleteOneEntry(priv, defaultmac[i], i, 1);
if (key == NULL)
CamAddOneEntry(priv, defaultmac[i], i,
(priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm)<<2,
1, priv->pmib->dot11DefaultKeysTable.keytype[i].skey);
else
CamAddOneEntry(priv, defaultmac[i], i,
algorithm<<2,
1, key);
}
priv->pshare->CamEntryOccupied += 4;
}
#endif
#ifdef UNIVERSAL_REPEATER
//
// Disable AP function in virtual interface
//
void disable_vxd_ap(struct rtl8192cd_priv *priv)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
if ((priv==NULL) || !(priv->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE))
return;
if (!(priv->drv_state & DRV_STATE_VXD_AP_STARTED))
return;
else
priv->drv_state &= ~DRV_STATE_VXD_AP_STARTED;
DEBUG_INFO("Disable vxd AP\n");
if (IS_DRV_OPEN(priv))
rtl8192cd_close(priv->dev);
SAVE_INT_AND_CLI(flags);
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
GET_HAL_INTERFACE(priv)->DisableVXDAPHandler(priv);
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif
{//not HAL
#if defined(CONFIG_PCI_HCI) || (defined(CONFIG_USB_HCI) && defined(CONFIG_SUPPORT_USB_INT) && defined(CONFIG_INTERRUPT_BASED_TXBCN))
#ifdef CONFIG_RTL_88E_SUPPORT
if (GET_CHIP_VER(priv)==VERSION_8188E) {
priv->pshare->InterruptMask &= ~(HIMR_88E_BcnInt | HIMR_88E_TBDOK | HIMR_88E_TBDER);
RTL_W32(REG_88E_HIMR, priv->pshare->InterruptMask);
} else
#endif
{
RTL_W32(HIMR, RTL_R32(HIMR) & ~(HIMR_BCNDOK0));
}
#endif
//RTL_W16(ATIMWND, 2);
RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_NOLINK & NETYPE_Mask) << NETYPE_SHIFT));
}
RESTORE_INT(flags);
}
//
// Enable AP function in virtual interface
//
void enable_vxd_ap(struct rtl8192cd_priv *priv)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
if ((priv==NULL) || !(priv->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) ||
!(priv->drv_state & DRV_STATE_VXD_INIT))
return;
if (priv->drv_state & DRV_STATE_VXD_AP_STARTED)
return;
else
priv->drv_state |= DRV_STATE_VXD_AP_STARTED;
DEBUG_INFO("Enable vxd AP\n");
priv->pmib->dot11RFEntry.dot11channel = GET_ROOT(priv)->pmib->dot11Bss.channel;
//priv->pmib->dot11BssType.net_work_type = GET_ROOT_PRIV(priv)->oper_band;
priv->pmib->dot11BssType.net_work_type = GET_ROOT(priv)->pmib->dot11BssType.net_work_type &
GET_ROOT(priv)->pmib->dot11Bss.network;
if (!IS_DRV_OPEN(priv))
rtl8192cd_open(priv->dev);
else {
//priv->oper_band = priv->pmib->dot11BssType.net_work_type;
validate_oper_rate(priv);
get_oper_rate(priv);
}
memcpy(priv->pmib->dot11StationConfigEntry.dot11Bssid, GET_ROOT(priv)->pmib->dot11OperationEntry.hwaddr, MACADDRLEN);
memcpy(GET_MY_HWADDR, priv->pmib->dot11StationConfigEntry.dot11Bssid, MACADDRLEN);
memcpy(priv->pmib->dot11Bss.bssid, priv->pmib->dot11StationConfigEntry.dot11Bssid, MACADDRLEN);
SAVE_INT_AND_CLI(flags);
priv->ht_cap_len = 0;
init_beacon(priv);
#if defined(CONFIG_PCI_HCI) || (defined(CONFIG_USB_HCI) && defined(CONFIG_SUPPORT_USB_INT) && defined(CONFIG_INTERRUPT_BASED_TXBCN))
#ifdef CONFIG_RTL_88E_SUPPORT
if (GET_CHIP_VER(priv)==VERSION_8188E) {
priv->pshare->InterruptMask |= HIMR_88E_BcnInt | HIMR_88E_TBDOK | HIMR_88E_TBDER;
RTL_W32(REG_88E_HIMR, priv->pshare->InterruptMask);
} else
#endif
{
RTL_W32(HIMR, RTL_R32(HIMR) | HIMR_BCNDOK0);
}
#endif
//RTL_W16(ATIMWND, 0x0030);
RTL_W32(CR, (RTL_R32(CR) & ~(NETYPE_Mask << NETYPE_SHIFT)) | ((NETYPE_AP & NETYPE_Mask) << NETYPE_SHIFT));
#ifdef CONFIG_RTL_92C_SUPPORT
if (!IS_TEST_CHIP(priv))
#endif
{
RTL_W8(0x422, RTL_R8(0x422) | BIT(6));
RTL_W8(BCN_CTRL, 0);
RTL_W8(0x553, 1);
RTL_W8(BCN_CTRL, DIS_TSF_UPDATE_N| EN_BCN_FUNCTION | DIS_SUB_STATE_N | EN_TXBCN_RPT);
}
RESTORE_INT(flags);
}
#endif // UNIVERSAL_REPEATER
#ifdef GBWC
void rtl8192cd_GBWC_timer(unsigned long task_priv)
{
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
struct sk_buff *pskb;
if (!(priv->drv_state & DRV_STATE_OPEN))
return;
if (priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_DISABLE)
return;
priv->GBWC_consuming_Q = 1;
// clear bandwidth control counter
priv->GBWC_tx_count = 0;
priv->GBWC_rx_count = 0;
// consume Tx queue
while(1)
{
pskb = (struct sk_buff *)deque(priv, &(priv->GBWC_tx_queue.head), &(priv->GBWC_tx_queue.tail),
(unsigned long)(priv->GBWC_tx_queue.pSkb), NUM_TXPKT_QUEUE);
if (pskb == NULL)
break;
#ifdef ENABLE_RTL_SKB_STATS
rtl_atomic_dec(&priv->rtl_tx_skb_cnt);
#endif
if (rtl8192cd_start_xmit_noM2U(pskb, pskb->dev))
rtl_kfree_skb(priv, pskb, _SKB_TX_);
}
// consume Rx queue
while(1)
{
pskb = (struct sk_buff *)deque(priv, &(priv->GBWC_rx_queue.head), &(priv->GBWC_rx_queue.tail),
(unsigned long)(priv->GBWC_rx_queue.pSkb), NUM_TXPKT_QUEUE);
if (pskb == NULL)
break;
rtl_netif_rx(priv, pskb, (struct stat_info *)*(unsigned int *)&(pskb->cb[4]));
}
priv->GBWC_consuming_Q = 0;
mod_timer(&priv->GBWC_timer, jiffies + GBWC_TO);
}
#endif
unsigned char fw_was_full(struct rtl8192cd_priv *priv)
{
struct list_head *phead;
struct list_head *plist;
struct stat_info *pstat;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
unsigned char is_full;
phead = &priv->asoc_list;
if(list_empty(phead))
return 0;
is_full = 0;
SMP_LOCK_ASOC_LIST(flags);
plist = phead->next;
while (plist != phead) {
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
if( pstat->sta_in_firmware != 1)
{
is_full = 1;
goto exit;
}
}
exit:
SMP_UNLOCK_ASOC_LIST(flags);
return is_full;
}
int realloc_RATid(struct rtl8192cd_priv *priv)
{
struct list_head *phead;
struct list_head *plist;
struct stat_info *pstat =NULL, *pstat_chosen = NULL;
unsigned int max_through_put = 0;
unsigned int have_chosen = 0;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
phead = &priv->asoc_list;
if(list_empty(phead))
return 0;
SMP_LOCK_ASOC_LIST(flags);
plist = phead->next;
while (plist != phead) {
int temp_through_put ;
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
if (pstat->sta_in_firmware == 1)// STA has rate adaptive
continue;
if (pstat->expire_to == 0) // exclude expired STA
continue;
temp_through_put = pstat->tx_avarage + pstat->rx_avarage;
if (temp_through_put >= max_through_put){
pstat_chosen = pstat;
max_through_put = temp_through_put;
have_chosen = 1;
}
}
SMP_UNLOCK_ASOC_LIST(flags);
if (have_chosen == 0)
return 0;
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
GET_HAL_INTERFACE(priv)->UpdateHalRAMaskHandler(priv, pstat_chosen, 3);
} else
#endif
#ifdef CONFIG_RTL_8812_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8812E) {
UpdateHalRAMask8812(priv, pstat_chosen, 3);
} else
#endif
#ifdef CONFIG_RTL_88E_SUPPORT
if (GET_CHIP_VER(priv)==VERSION_8188E) {
#ifdef TXREPORT
add_RATid(priv, pstat);
#endif
} else
#endif
{
#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT)
if(CHIP_VER_92X_SERIES(priv))
add_update_RATid(priv, pstat_chosen);
#endif
}
return 1;
}
void update_remapAid(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int array_idx;
if(pstat->sta_in_firmware == 1)
return; /*already exists, just return*/
if(priv->pshare->fw_free_space) {
/*find an empty slot*/
for (array_idx = 0; array_idx < NUM_STAT; array_idx++) {
if (priv->pshare->remapped_aidarray[array_idx] == 0)
break;
}
if (array_idx == NUM_STAT) {
/*WARNING: THIS SHOULD NOT HAPPEN*/
printk("add AID fail!!\n");
BUG();
return;
}
pstat->remapped_aid = array_idx + 1;
priv->pshare->remapped_aidarray[array_idx] = pstat->aid;
pstat->sta_in_firmware = 1; // this value will updated in expire_timer
priv->pshare->fw_free_space --;
}
else { /* free space run out, share the same aid*/
pstat->remapped_aid = priv->pshare->fw_support_sta_num;
pstat->sta_in_firmware = 0;
}
}
void release_remapAid(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int i;
if (pstat->sta_in_firmware == 1)
{
for(i = 0; i < NUM_STAT; i++) {
if(priv->pshare->remapped_aidarray[i] == pstat->aid){
priv->pshare->remapped_aidarray[i] = 0;
break;
}
}
priv->pshare->fw_free_space ++;
pstat->remapped_aid = 0;
pstat->sta_in_firmware = -1;
DEBUG_INFO("Remove id %d from ratr\n", pstat->aid);
}
}
unsigned int is_h2c_buf_occupy(struct rtl8192cd_priv *priv)
{
unsigned int occupied = 0;
if (
#ifdef CONFIG_RTL_92C_SUPPORT
(IS_TEST_CHIP(priv) && RTL_R8(0x1c0+priv->pshare->fw_q_fifo_count)) ||
#endif
(RTL_R8(0x1cc) & BIT(priv->pshare->fw_q_fifo_count)))
occupied++;
return occupied;
}
#if defined(UNIVERSAL_REPEATER)
int under_apmode_repeater(struct rtl8192cd_priv *priv)
{
int ret = 0;
if(IS_ROOT_INTERFACE(priv))
{
if(IS_DRV_OPEN(GET_VXD_PRIV(priv)))
{
if((priv->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) &&
(GET_VXD_PRIV(priv)->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE))
ret = 1;
}
}
else if(IS_VXD_INTERFACE(priv))
{
if(IS_DRV_OPEN(priv))
{
if((GET_ROOT(priv)->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) &&
(priv->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE))
ret = 1;
}
}
return ret;
}
#endif
short signin_h2c_cmd(struct rtl8192cd_priv *priv, unsigned int content, unsigned short ext_content)
{
int c=0;
#ifdef MP_TEST
if (priv->pshare->rf_ft_var.mp_specific)
goto SigninFAIL;
#endif
/*
* Check if h2c cmd signin buffer is occupied,
* for Power Saving related functions only
*/
//if ((content & 0x7f) < H2C_CMD_RSSI) {
while (is_h2c_buf_occupy(priv)) {
delay_us(10);
if(++c ==30)
{
printk("signin_h2c_cmd() failed! [content = %x , ext_content = %x]\n", content, ext_content);
goto SigninFAIL;
}
}
//}
/*
* signin reg in order to fit hw requirement
*/
if(content & BIT(7))
RTL_W16(0x88+(priv->pshare->fw_q_fifo_count*2), ext_content);
RTL_W32(HMEBOX_0+(priv->pshare->fw_q_fifo_count*4), content);
//printk("(smcc) sign in h2c %x\n", HMEBOX_0+(priv->pshare->fw_q_fifo_count*4));
#if defined(TESTCHIP_SUPPORT) && defined(CONFIG_RTL_92C_SUPPORT)
/*
* set own bit
*/
if(IS_TEST_CHIP(priv))
RTL_W8(0x1c0+priv->pshare->fw_q_fifo_count, 1);
#endif
/*
* rollover ring buffer count
*/
if (++priv->pshare->fw_q_fifo_count > 3)
priv->pshare->fw_q_fifo_count = 0;
return 0;
SigninFAIL:
return 1;
}
void set_ps_cmd(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
unsigned int content = 0;
if(! CHIP_VER_92X_SERIES(priv))
return;
SAVE_INT_AND_CLI(flags);
/*
* set ps state
*/
if (pstat->state & WIFI_SLEEP_STATE)
content |= BIT(24);
/*
* set macid
*/
content |= REMAP_AID(pstat) << 8;
/*
* set cmd id
*/
content |= H2C_CMD_PS;
signin_h2c_cmd(priv, content, 0);
RESTORE_INT(flags);
}
#ifdef TX_SHORTCUT
#if defined(CONFIG_PCI_HCI)
__inline__ void clearTxShortCutBufSize(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int i;
for (i=0; i<TX_SC_ENTRY_NUM; i++) {
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
GET_HAL_INTERFACE(priv)->SetShortCutTxBuffSizeHandler(priv, pstat->tx_sc_ent[i].hal_hw_desc, 0);
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif // CONFIG_WLAN_HAL
{//not HAL
pstat->tx_sc_ent[i].hwdesc1.Dword7 &= set_desc(~TX_TxBufSizeMask);
}
}
}
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
__inline__ void clearTxShortCutBufSize(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int i, j;
for (i = 0; i < NR_NET80211_UP; ++i) {
for (j = 0; j < TX_SC_ENTRY_NUM; ++j)
pstat->tx_sc_ent[i][j].hwdesc1.Dword7 &= set_desc(~TX_TxBufSizeMask);
}
}
#endif
#endif // TX_SHORTCUT
#ifdef CONFIG_PCI_HCI
void add_ps_timer(unsigned long task_priv)
{
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
struct stat_info *pstat = NULL;
unsigned int set_timer = 0;
unsigned long flags = 0;
if (!(priv->drv_state & DRV_STATE_OPEN))
return;
if (timer_pending(&priv->add_ps_timer))
del_timer_sync(&priv->add_ps_timer);
#ifdef PCIE_POWER_SAVING
if ((priv->pwr_state == L2) || (priv->pwr_state == L1))
return;
#endif
if (!list_empty(&priv->addps_list)) {
pstat = list_entry(priv->addps_list.next, struct stat_info, addps_list);
if (!pstat)
return ;
if (!is_h2c_buf_occupy(priv)) {
set_ps_cmd(priv, pstat);
if (!list_empty(&pstat->addps_list)) {
SAVE_INT_AND_CLI(flags);
SMP_LOCK(flags);
list_del_init(&pstat->addps_list);
RESTORE_INT(flags);
SMP_UNLOCK(flags);
}
if (!list_empty(&priv->addps_list))
set_timer++;
} else {
set_timer++;
}
}
if (set_timer)
mod_timer(&priv->add_ps_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(50)); // 50 ms
}
#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT)
void add_update_ps(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
//#ifdef CONFIG_RTL_8812_SUPPORT
if(! CHIP_VER_92X_SERIES(priv))
return;
//#endif
if (is_h2c_buf_occupy(priv)) {
if (list_empty(&pstat->addps_list)) {
SAVE_INT_AND_CLI(flags);
list_add_tail(&(pstat->addps_list), &(priv->addps_list));
RESTORE_INT(flags);
if (!timer_pending(&priv->add_ps_timer))
mod_timer(&priv->add_ps_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(50)); // 50 ms
}
} else {
set_ps_cmd(priv, pstat);
}
}
#endif
#endif // CONFIG_PCI_HCI
void update_intel_sta_bitmap(struct rtl8192cd_priv *priv, struct stat_info *pstat, int release)
{
if (pstat->IOTPeer != HT_IOT_PEER_INTEL)
return;
if (release) {
clearSTABitMap(&priv->pshare->intel_sta_bitmap, pstat->aid);
} else { // join
setSTABitMap(&priv->pshare->intel_sta_bitmap, pstat->aid);
}
}
#if defined(WIFI_11N_2040_COEXIST_EXT)
void update_40m_staMap(struct rtl8192cd_priv *priv, struct stat_info *pstat, int release)
{
if(pstat) {
if(release || (pstat->tx_bw == HT_CHANNEL_WIDTH_20))
clearSTABitMap(&priv->pshare->_40m_staMap, pstat->aid);
else
setSTABitMap(&priv->pshare->_40m_staMap, pstat->aid);
}
}
void checkBandwidth(struct rtl8192cd_priv *priv)
{
int i;
unsigned int _40m_stamap = orSTABitMap(&priv->pshare->_40m_staMap);
int FA_counter = priv->pshare->FA_total_cnt;
if(!priv->pshare->rf_ft_var.bws_enable)
return;
#ifdef MP_TEST
if ( (OPMODE & WIFI_MP_STATE)|| priv->pshare->rf_ft_var.mp_specific)
return ;
#endif
if (priv->pmib->dot11RFEntry.phyBandSelect == PHY_BAND_5G)
return ;
#ifdef WDS
if (priv->pmib->dot11WdsInfo.wdsEnabled)
return;
#endif
if (!(OPMODE & WIFI_AP_STATE))
return;
#ifdef UNIVERSAL_REPEATER
if (IS_DRV_OPEN(GET_VXD_PRIV(priv)))
return;
#endif
if (timer_pending(&priv->ss_timer) || priv->ss_req_ongoing)
return;
#if defined(USE_OUT_SRC)
if(IS_OUTSRC_CHIP(priv))
FA_counter = ODMPTR->FalseAlmCnt.Cnt_all;
#endif
if ((priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) && (!_40m_stamap) ) {
if (priv->pmib->dot11nConfigEntry.dot11nUse40M == HT_CHANNEL_WIDTH_10)
priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_10;
else if (priv->pmib->dot11nConfigEntry.dot11nUse40M == HT_CHANNEL_WIDTH_5)
priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_5;
else
priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_20;
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan);
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
update_RAMask_to_FW(priv, 1);
#endif
SetTxPowerLevel(priv);
}
if( priv->pmib->dot11nConfigEntry.dot11nCoexist
&& !orSTABitMap(&priv->pshare->intel_sta_bitmap)) {
#if defined(CONFIG_PCI_HCI)
if((FA_counter> priv->pshare->rf_ft_var.bws_Thd)&&((RTL_R8(0xc50) & 0x7f) >= 0x32))
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
u1Byte IGI = RTL_R8(0xc50) & 0x7f;
if (((FA_counter> priv->pshare->rf_ft_var.bws_Thd) && (IGI >= 0x32)) || (IGI >= 0x42))
#endif
{
if(priv->pshare->is_40m_bw != HT_CHANNEL_WIDTH_20) {
priv->pshare->is_40m_bw = HT_CHANNEL_WIDTH_20;
priv->ht_cap_len = 0; // reconstruct ie
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N)
construct_ht_ie(priv, priv->pshare->is_40m_bw, priv->pshare->offset_2nd_chan);
}
} else {
if(priv->pshare->is_40m_bw != priv->pmib->dot11nConfigEntry.dot11nUse40M) {
priv->pshare->is_40m_bw = priv->pmib->dot11nConfigEntry.dot11nUse40M;
priv->ht_cap_len = 0; // reconstruct ie
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N)
construct_ht_ie(priv, priv->pshare->is_40m_bw, priv->pshare->offset_2nd_chan);
}
}
}
if( _40m_stamap && (priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) &&
((priv->pmib->dot11nConfigEntry.dot11nUse40M != HT_CHANNEL_WIDTH_20))) {
if(priv->pmib->dot11nConfigEntry.dot11nCoexist) {
priv->pshare->is_40m_bw = priv->pmib->dot11nConfigEntry.dot11nUse40M;
priv->ht_cap_len = 0; // reconstruct ie
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N)
construct_ht_ie(priv, priv->pshare->is_40m_bw, priv->pshare->offset_2nd_chan);
}
priv->pshare->CurrentChannelBW = priv->pmib->dot11nConfigEntry.dot11nUse40M;
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan);
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
update_RAMask_to_FW(priv, 1);
#endif
}
}
#endif
#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT)
#ifdef CONFIG_PCI_HCI
void add_RATid_timer(unsigned long task_priv)
{
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
struct stat_info *pstat = NULL;
unsigned int set_timer = 0;
unsigned long flags = 0;
if (!(priv->drv_state & DRV_STATE_OPEN))
return;
if (timer_pending(&priv->add_RATid_timer))
del_timer_sync(&priv->add_RATid_timer);
#ifdef PCIE_POWER_SAVING
if ((priv->pwr_state == L2) || (priv->pwr_state == L1))
return;
#endif
if (!list_empty(&priv->addRAtid_list)) {
pstat = list_entry(priv->addRAtid_list.next, struct stat_info, addRAtid_list);
if (!pstat)
return;
if (!is_h2c_buf_occupy(priv)) {
add_RATid(priv, pstat);
if (!list_empty(&pstat->addRAtid_list)) {
SAVE_INT_AND_CLI(flags);
SMP_LOCK(flags);
list_del_init(&pstat->addRAtid_list);
RESTORE_INT(flags);
SMP_UNLOCK(flags);
}
if (!list_empty(&priv->addRAtid_list))
set_timer++;
} else {
set_timer++;
}
}
if (set_timer)
mod_timer(&priv->add_RATid_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(50)); // 50 ms
}
void add_update_RATid(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
if (is_h2c_buf_occupy(priv)) {
if (list_empty(&pstat->addRAtid_list)) {
SAVE_INT_AND_CLI(flags);
list_add_tail(&(pstat->addRAtid_list), &(priv->addRAtid_list));
RESTORE_INT(flags);
if (!timer_pending(&priv->add_RATid_timer))
mod_timer(&priv->add_RATid_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(50)); // 50 ms
}
} else {
add_RATid(priv, pstat);
}
}
#endif // CONFIG_PCI_HCI
#endif
#ifdef SDIO_AP_OFFLOAD
void set_ap_ps_mode(struct rtl8192cd_priv *priv, unsigned char *data)
{
int mode;
if (strlen(data) == 0)
return;
mode = _atoi(data, 16);
if (mode == 0x00) {
ap_offload_activate(priv, OFFLOAD_PROHIBIT_USER);
} else {
ap_offload_deactivate(priv, OFFLOAD_PROHIBIT_USER);
}
}
void ap_offload_deactivate(struct rtl8192cd_priv *priv, int reason)
{
_irqL irqL;
_enter_critical(&priv->pshare->offload_lock, &irqL);
#ifdef CONFIG_POWER_SAVE
if (!priv->pshare->offload_prohibited) {
if (IS_DRV_OPEN(GET_ROOT(priv))) {
del_timer(&priv->pshare->ps_timer);
priv->pshare->ps_timer_expires = 0;
rtw_lock_suspend(priv);
}
}
#endif
priv->pshare->offload_prohibited |= reason;
_exit_critical(&priv->pshare->offload_lock, &irqL);
if (IS_DRV_OPEN(GET_ROOT(priv))) {
if ((RTW_STS_SUSPEND == priv->pshare->pwr_state)
#ifdef CONFIG_POWER_SAVE
|| (priv->pshare->offload_function_ctrl > RTW_PM_PREPROCESS)
#endif
)
ap_offload_exit(GET_ROOT(priv));
}
}
void ap_offload_activate(struct rtl8192cd_priv *priv, int reason)
{
_irqL irqL;
_enter_critical(&priv->pshare->offload_lock, &irqL);
priv->pshare->offload_prohibited &= ~reason;
_exit_critical(&priv->pshare->offload_lock, &irqL);
if (IS_DRV_OPEN(GET_ROOT(priv))) {
#ifdef CONFIG_POWER_SAVE
rtw_lock_suspend_timeout(priv, 2000);
#else
mod_timer(&priv->pshare->ps_timer, jiffies + POWER_DOWN_T0);
#endif
}
}
#endif // SDIO_AP_OFFLOAD
void send_h2c_cmd_detect_wps_gpio(struct rtl8192cd_priv *priv, unsigned int gpio_num, unsigned int enable, unsigned int high_active)
{
#ifndef SMP_SYNC
unsigned long flags;
#endif
unsigned int content = 0;
SAVE_INT_AND_CLI(flags);
content = gpio_num << 16;
/*
* enable firmware to detect wps gpio
*/
if (enable)
content |= BIT(8);
/*
* rising edge trigger
*/
if (high_active)
content |= BIT(9);
/*
* set cmd id
*/
content |= H2C_CMD_AP_WPS_CTRL;
signin_h2c_cmd(priv, content, 0);
printk("signin ap_wps_ctrl h2c: 0x%08X\n", content);
RESTORE_INT(flags);
}
#ifdef RTK_QUE
void rtk_queue_init(struct ring_que *que)
{
memset(que, '\0', sizeof(struct ring_que));
que->qmax = MAX_PRE_ALLOC_SKB_NUM;
}
static int rtk_queue_tail(struct rtl8192cd_priv *priv, struct ring_que *que, struct sk_buff *skb)
{
int next;
unsigned long x;
SAVE_INT_AND_CLI(x);
SMP_LOCK_SKB(x);
if (que->head == que->qmax)
next = 0;
else
next = que->head + 1;
if (que->qlen >= que->qmax || next == que->tail) {
printk("%s: ring-queue full!\n", __FUNCTION__);
RESTORE_INT(x);
SMP_UNLOCK_SKB(x);
return 0;
}
que->ring[que->head] = skb;
que->head = next;
que->qlen++;
RESTORE_INT(x);
SMP_UNLOCK_SKB(x);
return 1;
}
__IRAM_IN_865X
static struct sk_buff *rtk_dequeue(struct rtl8192cd_priv *priv, struct ring_que *que)
{
struct sk_buff *skb;
unsigned long x;
SAVE_INT_AND_CLI(x);
SMP_LOCK_SKB(x);
if (que->qlen <= 0 || que->tail == que->head) {
RESTORE_INT(x);
SMP_UNLOCK_SKB(x);
return NULL;
}
skb = que->ring[que->tail];
if (que->tail == que->qmax)
que->tail = 0;
else
que->tail++;
que->qlen--;
RESTORE_INT(x);
SMP_UNLOCK_SKB(x);
return (struct sk_buff *)skb;
}
void free_rtk_queue(struct rtl8192cd_priv *priv, struct ring_que *skb_que)
{
struct sk_buff *skb;
while (skb_que->qlen > 0) {
skb = rtk_dequeue(priv, skb_que);
if (skb == NULL)
break;
dev_kfree_skb_any(skb);
}
}
#endif // RTK_QUE
#ifdef DELAY_REFILL_RX_BUF
#ifdef CONFIG_WLAN_HAL
extern int refill_rx_ring_88XX(struct rtl8192cd_priv * priv, struct sk_buff * skb, unsigned char * data, unsigned int q_num, PHCI_RX_DMA_QUEUE_STRUCT_88XX cur_q);
#endif
extern int refill_rx_ring(struct rtl8192cd_priv *priv, struct sk_buff *skb, unsigned char *data);
#endif
#ifdef __ECOS
#ifdef DELAY_REFILL_RX_BUF
int __MIPS16 rtk_wifi_delay_refill(struct sk_buff *pskb)
{
struct rtl8192cd_priv *priv;
struct rtl8192cd_hw *phw;
struct sk_buff *skb=(struct sk_buff *)pskb;
int ret=0;
if(!(pskb && pskb->priv))
return ret;
priv=(struct rtl8192cd_priv *)pskb->priv;
phw=GET_HW(priv);
#ifdef CONFIG_WLAN_HAL
unsigned int q_num;
PHCI_RX_DMA_MANAGER_88XX prx_dma;
PHCI_RX_DMA_QUEUE_STRUCT_88XX cur_q;
#endif // CONFIG_WLAN_HAL
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
if (!(priv->drv_state & DRV_STATE_OPEN)){
/* return 0 means can't refill (because interface be closed or not opened yet) to rx ring but relesae to skb_poll*/
ret=0;
}else{
q_num = 0;
prx_dma = (PHCI_RX_DMA_MANAGER_88XX)(_GET_HAL_DATA(priv)->PRxDMA88XX);
cur_q = &(prx_dma->rx_queue[q_num]);
ret = refill_rx_ring_88XX(priv, NULL, NULL, q_num, cur_q);
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, cur_q->rxbd_ok_cnt);
cur_q->rxbd_ok_cnt = 0;
}
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif
{
if (phw->cur_rx_refill != phw->cur_rx) {
ret=refill_rx_ring(priv, NULL, NULL);
}
}
return ret;
}
#endif
#endif
#if !(defined(__ECOS) && defined(CONFIG_SDIO_HCI))
void refill_skb_queue(struct rtl8192cd_priv *priv)
{
struct sk_buff *skb;
#ifdef DELAY_REFILL_RX_BUF
struct rtl8192cd_hw *phw=GET_HW(priv);
#ifdef CONFIG_WLAN_HAL
unsigned int q_num;
PHCI_RX_DMA_MANAGER_88XX prx_dma;
PHCI_RX_DMA_QUEUE_STRUCT_88XX cur_q;
if (IS_HAL_CHIP(priv)) {
q_num = 0;
prx_dma = (PHCI_RX_DMA_MANAGER_88XX)(_GET_HAL_DATA(priv)->PRxDMA88XX);
cur_q = &(prx_dma->rx_queue[q_num]);
}
#endif // CONFIG_WLAN_HAL
#endif
#ifdef NOT_RTK_BSP
while (skb_queue_len(&priv->pshare->skb_queue) < MAX_PRE_ALLOC_SKB_NUM)
#else
while (priv->pshare->skb_queue.qlen < MAX_PRE_ALLOC_SKB_NUM)
#endif
{
#ifdef CONFIG_RTL8190_PRIV_SKB
skb = dev_alloc_skb_priv(priv, RX_BUF_LEN);
#else
skb = dev_alloc_skb(RX_BUF_LEN);
#endif
if (skb == NULL) {
// DEBUG_ERR("dev_alloc_skb() failed!\n");
return;
}
#ifdef DELAY_REFILL_RX_BUF
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
if (cur_q->cur_host_idx != ((cur_q->host_idx + cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num)) {
refill_rx_ring_88XX(priv, skb, NULL, q_num, cur_q);
continue;
}
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif // CONFIG_WLAN_HAL
{//not HAL
if (phw->cur_rx_refill != phw->cur_rx) {
refill_rx_ring(priv, skb, NULL);
continue;
}
}
#endif
#ifdef RTK_QUE
rtk_queue_tail(priv, &priv->pshare->skb_queue, skb);
#else
#ifdef __ECOS
skb_queue_tail(&priv->pshare->skb_queue, skb);
#else
__skb_queue_tail(&priv->pshare->skb_queue, skb);
#endif
#endif
}
#ifdef DELAY_REFILL_RX_BUF
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, cur_q->rxbd_ok_cnt);
cur_q->rxbd_ok_cnt = 0;
}
#endif // CONFIG_WLAN_HAL
#endif
}
__MIPS16
__IRAM_IN_865X
struct sk_buff *alloc_skb_from_queue(struct rtl8192cd_priv *priv)
{
struct sk_buff *skb=NULL;
#ifdef NOT_RTK_BSP
if (skb_queue_len(&priv->pshare->skb_queue) < 2)
#else
if (priv->pshare->skb_queue.qlen == 0)
#endif
{
// struct sk_buff *skb;
#ifdef CONFIG_RTL8190_PRIV_SKB
#ifdef CONCURRENT_MODE
skb = dev_alloc_skb_priv(priv, RX_BUF_LEN);
#else
skb = dev_alloc_skb_priv(priv, RX_BUF_LEN);
#endif
#else
skb = dev_alloc_skb(RX_BUF_LEN);
#endif
if (skb == NULL) {
DEBUG_ERR("dev_alloc_skb() failed!\n");
}
return skb;
}
#ifdef RTK_QUE
skb = rtk_dequeue(priv, &priv->pshare->skb_queue);
#else
#ifdef __ECOS
skb = skb_dequeue(&priv->pshare->skb_queue);
#else
skb = __skb_dequeue(&priv->pshare->skb_queue);
#endif
#endif
if (skb == NULL) {
DEBUG_ERR("skb_dequeue() failed!\n");
}
return skb;
}
void free_skb_queue(struct rtl8192cd_priv *priv, struct sk_buff_head *skb_que)
{
struct sk_buff *skb;
#ifndef SMP_SYNC
unsigned long flags;
#endif
while (skb_que->qlen > 0) {
// 2009.09.08
SAVE_INT_AND_CLI(flags);
skb = __skb_dequeue(skb_que);
RESTORE_INT(flags);
if (skb == NULL)
break;
dev_kfree_skb_any(skb);
}
}
#endif // !(__ECOS && CONFIG_SDIO_HCI)
#ifdef FAST_RECOVERY
struct backup_info {
struct aid_obj *sta[NUM_STAT];
struct Dot11KeyMappingsEntry gkey;
#ifdef WDS
struct wds_info wds;
#endif
};
void *backup_sta(struct rtl8192cd_priv *priv)
{
int i;
struct backup_info *pBackup;
pBackup = (struct backup_info *)kmalloc((sizeof(struct backup_info)), GFP_ATOMIC);
if (pBackup == NULL) {
printk("%s: kmalloc() failed!\n", __FUNCTION__);
return NULL;
}
memset(pBackup, '\0', sizeof(struct backup_info));
for (i=0; i<NUM_STAT; i++) {
if (priv->pshare->aidarray[i] && priv->pshare->aidarray[i]->used) {
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
if (priv != priv->pshare->aidarray[i]->priv)
continue;
#endif
pBackup->sta[i] = (struct aid_obj *)kmalloc((sizeof(struct aid_obj)), GFP_ATOMIC);
if (pBackup->sta[i] == NULL) {
printk("%s: kmalloc(sta) failed!\n", __FUNCTION__);
for (--i; i>=0; --i) {
if (pBackup->sta[i]) {
#ifdef CONFIG_RTL_WAPI_SUPPORT
free_sta_wapiInfo(priv, &pBackup->sta[i]->station);
#endif
kfree(pBackup->sta[i]);
}
}
kfree(pBackup);
return NULL;
}
memcpy(pBackup->sta[i], priv->pshare->aidarray[i], sizeof(struct aid_obj));
#ifdef CONFIG_RTL_WAPI_SUPPORT
// prevent backup station.wapiInfo from being freed during recovery preiod
priv->pshare->aidarray[i]->station.wapiInfo = NULL;
#endif
}
}
#ifdef WDS
memcpy(&pBackup->wds, &priv->pmib->dot11WdsInfo, sizeof(struct wds_info));
#endif
memcpy(&pBackup->gkey, &priv->pmib->dot11GroupKeysTable, sizeof(struct Dot11KeyMappingsEntry));
return (void *)pBackup;
}
void restore_backup_sta(struct rtl8192cd_priv *priv, void *pInfo)
{
unsigned int i, offset;
struct stat_info *pstat;
unsigned char key_combo[32];
struct backup_info *pBackup=(struct backup_info *)pInfo;
#ifdef CONFIG_RTK_MESH
unsigned char is_11s_MP = FALSE;
unsigned long flags;
#endif
int retVal;
for (i=0; i<NUM_STAT; i++) {
if (pBackup->sta[i]) {
#ifdef CONFIG_RTK_MESH // Restore Establish MP ONLY
if ((1 == GET_MIB(priv)->dot1180211sInfo.mesh_enable) && !isSTA2(pBackup->sta[i]->station)) {
UINT8 State = pBackup->sta[i]->station.mesh_neighbor_TBL.State;
if ((State == MP_SUPERORDINATE_LINK_UP) || (State == MP_SUBORDINATE_LINK_UP)
|| (State == MP_SUPERORDINATE_LINK_DOWN) || (State == MP_SUBORDINATE_LINK_DOWN_E))
is_11s_MP = TRUE;
else // is MP, but not establish, Give up.
{
kfree(pBackup->sta[i]);
continue;
}
}
#endif
pstat = alloc_stainfo(priv, pBackup->sta[i]->station.hwaddr, i);
if (!pstat) {
printk("%s: alloc_stainfo() failed!\n", __FUNCTION__);
for (; i<NUM_STAT; i++) {
if (pBackup->sta[i]) {
#ifdef CONFIG_RTL_WAPI_SUPPORT
free_sta_wapiInfo(priv, &pBackup->sta[i]->station);
#endif
kfree(pBackup->sta[i]);
}
}
kfree(pBackup);
return;
}
#ifdef CONFIG_RTL_WAPI_SUPPORT
// free new allocated wapiInfo before restore backup wapiInfo
if (pstat->wapiInfo) free_sta_wapiInfo(priv, pstat);
#endif
offset = (unsigned long)(&((struct stat_info *)0)->aid);
memcpy(((unsigned char *)pstat)+offset,
((unsigned char *)&pBackup->sta[i]->station)+offset, sizeof(struct stat_info)-offset);
asoc_list_add(priv, pstat);
if (pstat->sta_in_firmware == 1) {
priv->pshare->remapped_aidarray[pstat->remapped_aid-1] = pstat->aid;
priv->pshare->fw_free_space--;
}
#ifdef CONFIG_RTK_MESH
if (TRUE == is_11s_MP) {
is_11s_MP = FALSE;
SMP_LOCK_MESH_MP_HDR(flags);
list_add_tail(&pstat->mesh_mp_ptr, &priv->mesh_mp_hdr);
SMP_UNLOCK_MESH_MP_HDR(flags);
mesh_cnt_ASSOC_PeerLink_CAP(priv, pstat, INCREASE);
}
#endif
#ifdef WDS
if (!(pstat->state & WIFI_WDS))
#endif
if (pstat->expire_to > 0)
cnt_assoc_num(priv, pstat, INCREASE, (char *)__FUNCTION__);
if ((pstat->expire_to > 0)
#ifdef WDS
|| (pstat->state & WIFI_WDS)
#endif
) {
check_sta_characteristic(priv, pstat, INCREASE);
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11N)
construct_ht_ie(priv, priv->pshare->is_40m_bw, priv->pshare->offset_2nd_chan);
#ifndef USE_WEP_DEFAULT_KEY
set_keymapping_wep(priv, pstat);
#endif
if (!SWCRYPTO && pstat->dot11KeyMapping.keyInCam == TRUE) {
#ifdef CONFIG_RTL_HW_WAPI_SUPPORT
if (pstat->wapiInfo && (pstat->wapiInfo->wapiType != wapiDisable)) {
wapiStaInfo *wapiInfo = pstat->wapiInfo;
retVal = CamAddOneEntry(priv,
pstat->hwaddr,
wapiInfo->wapiUCastKeyId, /* keyid */
DOT11_ENC_WAPI<<2, /* type */
0, /* use default key */
wapiInfo->wapiUCastKey[wapiInfo->wapiUCastKeyId].dataKey);
if (retVal) {
priv->pshare->CamEntryOccupied++;
retVal = CamAddOneEntry(priv,
pstat->hwaddr,
wapiInfo->wapiUCastKeyId, /* keyid */
DOT11_ENC_WAPI<<2, /* type */
1, /* use default key */
wapiInfo->wapiUCastKey[wapiInfo->wapiUCastKeyId].micKey);
if (retVal) {
//pstat->dot11KeyMapping.keyInCam = TRUE;
priv->pshare->CamEntryOccupied++;
} else {
retVal = CamDeleteOneEntry(priv, pstat->hwaddr, wapiInfo->wapiUCastKeyId, 0);
if (retVal) {
priv->pshare->CamEntryOccupied--;
pstat->dot11KeyMapping.keyInCam = FALSE;
}
}
} else {
pstat->dot11KeyMapping.keyInCam = FALSE;
}
} else
#endif // CONFIG_RTL_HW_WAPI_SUPPORT
if (pstat->dot11KeyMapping.dot11Privacy) {
memcpy(key_combo,
pstat->dot11KeyMapping.dot11EncryptKey.dot11TTKey.skey,
pstat->dot11KeyMapping.dot11EncryptKey.dot11TTKeyLen);
memcpy(&key_combo[pstat->dot11KeyMapping.dot11EncryptKey.dot11TTKeyLen],
pstat->dot11KeyMapping.dot11EncryptKey.dot11TMicKey1.skey,
pstat->dot11KeyMapping.dot11EncryptKey.dot11TMicKeyLen);
#ifdef MULTI_MAC_CLONE
if ((OPMODE & WIFI_STATION_STATE) && priv->pmib->ethBrExtInfo.macclone_enable)
retVal = CamAddOneEntry(priv, pstat->sa_addr, pstat->dot11KeyMapping.keyid,
pstat->dot11KeyMapping.dot11Privacy<<2, 0, key_combo);
else
#endif
retVal = CamAddOneEntry(priv, pstat->hwaddr, pstat->dot11KeyMapping.keyid,
pstat->dot11KeyMapping.dot11Privacy<<2, 0, key_combo);
if (retVal)
priv->pshare->CamEntryOccupied++;
else
pstat->dot11KeyMapping.keyInCam = FALSE;
}
}
}
// to avoid add RAtid fail
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
GET_HAL_INTERFACE(priv)->UpdateHalRAMaskHandler(priv, pstat, 3);
} else
#endif
#ifdef CONFIG_RTL_8812_SUPPORT
if(GET_CHIP_VER(priv)== VERSION_8812E) {
UpdateHalRAMask8812(priv, pstat, 3);
} else
#endif
#ifdef CONFIG_RTL_88E_SUPPORT
if (GET_CHIP_VER(priv)==VERSION_8188E) {
#ifdef TXREPORT
add_RATid(priv, pstat);
#endif
} else
#endif
{
#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT)
add_update_RATid(priv, pstat);
#endif
}
kfree(pBackup->sta[i]);
if (priv->pshare->is_40m_bw && (pstat->IOTPeer == HT_IOT_PEER_MARVELL))
{
setSTABitMap(&priv->pshare->marvellMapBit, pstat->aid);
#if defined(CONFIG_RTL_8812_SUPPORT)||defined(CONFIG_WLAN_HAL)
if((GET_CHIP_VER(priv)== VERSION_8812E)||(IS_HAL_CHIP(priv))){
}
else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif
{//not HAL
if (priv->pshare->Reg_RRSR_2 == 0 && priv->pshare->Reg_81b == 0){
priv->pshare->Reg_RRSR_2 = RTL_R8(RRSR+2);
priv->pshare->Reg_81b = RTL_R8(0x81b);
RTL_W8(RRSR+2, priv->pshare->Reg_RRSR_2 | 0x60);
RTL_W8(0x81b, priv->pshare->Reg_81b | 0x0E);
}
}
}
update_intel_sta_bitmap(priv, pstat, 0);
#if defined(WIFI_11N_2040_COEXIST_EXT)
update_40m_staMap(priv, pstat, 0);
#endif
}
}
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
update_RAMask_to_FW(priv, 1);
#endif
SetTxPowerLevel(priv);
memcpy(&priv->pmib->dot11GroupKeysTable, &pBackup->gkey, sizeof(struct Dot11KeyMappingsEntry));
if (!SWCRYPTO && priv->pmib->dot11GroupKeysTable.keyInCam) {
#ifdef CONFIG_RTL_HW_WAPI_SUPPORT
if (priv->pmib->wapiInfo.wapiType != wapiDisable)
{
const uint8 CAM_CONST_BCAST[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
retVal = CamAddOneEntry(priv,
CAM_CONST_BCAST,
priv->wapiMCastKeyId<<1, /* keyid */
DOT11_ENC_WAPI<<2, /* type */
0, /* use default key */
priv->wapiMCastKey[priv->wapiMCastKeyId].dataKey);
if (retVal) {
retVal = CamAddOneEntry(priv,
CAM_CONST_BCAST,
(priv->wapiMCastKeyId<<1)+1, /* keyid */
DOT11_ENC_WAPI<<2, /* type */
1, /* use default key */
priv->wapiMCastKey[priv->wapiMCastKeyId].micKey);
if (retVal) {
priv->pshare->CamEntryOccupied++;
// priv->pmib->dot11GroupKeysTable.keyInCam = TRUE;
} else {
retVal = CamDeleteOneEntry(priv, CAM_CONST_BCAST, 1, 0);
if (retVal)
priv->pmib->dot11GroupKeysTable.keyInCam = FALSE;
}
} else {
priv->pmib->dot11GroupKeysTable.keyInCam = FALSE;
}
} else
#endif // CONFIG_RTL_HW_WAPI_SUPPORT
{
memcpy(key_combo,
priv->pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKey.skey,
priv->pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKeyLen);
memcpy(&key_combo[priv->pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TTKeyLen],
priv->pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TMicKey1.skey,
priv->pmib->dot11GroupKeysTable.dot11EncryptKey.dot11TMicKeyLen);
retVal = CamAddOneEntry(priv, (unsigned char *)"\xff\xff\xff\xff\xff\xff", priv->pmib->dot11GroupKeysTable.keyid,
priv->pmib->dot11GroupKeysTable.dot11Privacy<<2, 0, key_combo);
if (retVal)
priv->pshare->CamEntryOccupied++;
else
priv->pmib->dot11GroupKeysTable.keyInCam = FALSE;
}
}
#ifdef WDS
memcpy(&priv->pmib->dot11WdsInfo, &pBackup->wds, sizeof(struct wds_info));
#endif
kfree(pInfo);
}
#endif // FAST_RECOVERY
#ifdef CONFIG_RTL8190_PRIV_SKB
#if defined(CONFIG_RTL8196B_GW_8M) || defined(CONFIG_RTL8196C_AP_ROOT) || defined(CONFIG_RTL8196C_CLIENT_ONLY) || defined(CONFIG_RTL_8198_AP_ROOT) || defined(__ECOS)
#ifdef __LINUX_2_6__
#define SKB_BUF_SIZE (MIN_RX_BUF_LEN+sizeof(struct skb_shared_info)+128+128)
#else
#define SKB_BUF_SIZE (MIN_RX_BUF_LEN+sizeof(struct skb_shared_info)+128)
#endif
#else
#ifdef __LINUX_2_6__
#define SKB_BUF_SIZE (MIN_RX_BUF_LEN+sizeof(struct skb_shared_info)+128+128)
#else
#define SKB_BUF_SIZE (MIN_RX_BUF_LEN+sizeof(struct skb_shared_info)+128)
#endif
#endif
#define MAGIC_CODE "8190"
struct priv_skb_buf {
unsigned char magic[4];
unsigned int buf_pointer;
#ifdef CONCURRENT_MODE
struct rtl8192cd_priv *root_priv;
#endif
struct list_head list;
unsigned char buf[SKB_BUF_SIZE];
};
#ifdef DUALBAND_ONLY
#define REAL_MAX_SKB (MAX_SKB_NUM/2)
#else
#define REAL_MAX_SKB (MAX_SKB_NUM)
#endif
#ifdef CONCURRENT_MODE
static struct priv_skb_buf skb_buf[NUM_WLAN_IFACE][REAL_MAX_SKB];
static struct list_head skbbuf_list[NUM_WLAN_IFACE];
#ifdef CONFIG_WIRELESS_LAN_MODULE
static int skb_free_num[NUM_WLAN_IFACE] = {REAL_MAX_SKB, REAL_MAX_SKB};
#else
int skb_free_num[NUM_WLAN_IFACE] = {REAL_MAX_SKB, REAL_MAX_SKB};
#endif
#else
static struct priv_skb_buf skb_buf[REAL_MAX_SKB];
static struct list_head skbbuf_list;
static struct rtl8192cd_priv *root_priv;
#ifdef CONFIG_WIRELESS_LAN_MODULE
static int skb_free_num = REAL_MAX_SKB;
#else
int skb_free_num = REAL_MAX_SKB;
#endif
#endif
extern struct sk_buff *dev_alloc_8190_skb(unsigned char *data, int size);
void init_priv_skb_buf(struct rtl8192cd_priv *priv)
{
panic_printk("\n\n#######################################################\n");
panic_printk("SKB_BUF_SIZE=%d MAX_SKB_NUM=%d\n",SKB_BUF_SIZE,MAX_SKB_NUM);
panic_printk("#######################################################\n\n");
int i;
#ifdef CONCURRENT_MODE
int idx = priv->pshare->wlandev_idx;
memset(skb_buf[idx], '\0', sizeof(struct priv_skb_buf)*REAL_MAX_SKB);
INIT_LIST_HEAD(&skbbuf_list[idx]);
for (i=0; i<REAL_MAX_SKB; i++) {
memcpy(skb_buf[idx][i].magic, MAGIC_CODE, 4);
skb_buf[idx][i].root_priv = priv;
skb_buf[idx][i].buf_pointer = (unsigned int)&skb_buf[idx][i];
INIT_LIST_HEAD(&skb_buf[idx][i].list);
list_add_tail(&skb_buf[idx][i].list, &skbbuf_list[idx]);
}
#else
memset(skb_buf, '\0', sizeof(struct priv_skb_buf)*REAL_MAX_SKB);
INIT_LIST_HEAD(&skbbuf_list);
for (i=0; i<REAL_MAX_SKB; i++) {
memcpy(skb_buf[i].magic, MAGIC_CODE, 4);
skb_buf[i].buf_pointer = (unsigned int)&skb_buf[i];
INIT_LIST_HEAD(&skb_buf[i].list);
list_add_tail(&skb_buf[i].list, &skbbuf_list);
}
root_priv = priv;
#endif
}
#ifdef CONCURRENT_MODE
static __inline__ unsigned char *get_priv_skb_buf(struct rtl8192cd_priv *priv)
{
int i;
#ifndef SMP_SYNC
unsigned long flags;
#endif
unsigned char *data;
SAVE_INT_AND_CLI(flags);
i = priv->pshare->wlandev_idx;
data = get_buf_from_poll(priv, &skbbuf_list[i], (unsigned int *)&skb_free_num[i]);
RESTORE_INT(flags);
return data;
}
#else
static __inline__ unsigned char *get_priv_skb_buf(struct rtl8192cd_priv *priv)
{
unsigned char *ret;
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
ret = get_buf_from_poll(root_priv, &skbbuf_list, (unsigned int *)&skb_free_num);
RESTORE_INT(flags);
return ret;
}
#endif
#if defined(DUALBAND_ONLY) && defined(CONFIG_RTL8190_PRIV_SKB)
extern u32 if_priv[];
void merge_pool(struct rtl8192cd_priv *priv)
{
unsigned char *buf;
unsigned long offset = (unsigned long)(&((struct priv_skb_buf *)0)->buf);
struct priv_skb_buf *priv_buf;
int next_idx;
int idx = priv->pshare->wlandev_idx;
if (idx == 0)
next_idx = 1;
else
next_idx = 0;
while (1) {
if (skb_free_num[idx] >= REAL_MAX_SKB*2)
break;
buf = get_priv_skb_buf((struct rtl8192cd_priv *)if_priv[next_idx]);
if (buf == NULL)
break;
priv_buf = (struct priv_skb_buf *)(((unsigned long)buf) - offset);
priv_buf->root_priv = priv;
release_buf_to_poll(priv, buf, &skbbuf_list[idx], (unsigned int *)&skb_free_num[idx]);
}
}
void split_pool(struct rtl8192cd_priv *priv)
{
unsigned char *buf;
unsigned long offset = (unsigned long)(&((struct priv_skb_buf *)0)->buf);
struct priv_skb_buf *priv_buf;
int next_idx;
int idx = priv->pshare->wlandev_idx;
if (idx == 0)
next_idx = 1;
else
next_idx = 0;
while (1) {
if (skb_free_num[idx] <= REAL_MAX_SKB)
break;
buf = get_priv_skb_buf(priv);
if (buf == NULL)
break;
priv_buf = (struct priv_skb_buf *)(((unsigned long)buf) - offset);
priv_buf->root_priv = (struct rtl8192cd_priv *)if_priv[next_idx];
release_buf_to_poll((struct rtl8192cd_priv *)if_priv[next_idx],
buf, &skbbuf_list[next_idx], (unsigned int *)&skb_free_num[next_idx]);
}
}
#endif
__IRAM_IN_865X
#ifdef CONCURRENT_MODE
static struct sk_buff *dev_alloc_skb_priv(struct rtl8192cd_priv *priv, unsigned int size)
{
struct sk_buff *skb;
unsigned char *data = get_priv_skb_buf(priv);
if (data == NULL) {
// _DEBUG_ERR("wlan: priv skb buffer empty!\n");
return NULL;
}
skb = dev_alloc_8190_skb(data, size);
if (skb == NULL) {
free_rtl8190_priv_buf(data);
return NULL;
}
return skb;
}
#else
static struct sk_buff *dev_alloc_skb_priv(struct rtl8192cd_priv *priv, unsigned int size)
{
struct sk_buff *skb;
unsigned char *data = get_priv_skb_buf(priv);
if (data == NULL) {
// _DEBUG_ERR("wlan: priv skb buffer empty!\n");
return NULL;
}
skb = dev_alloc_8190_skb(data, size);
if (skb == NULL) {
free_rtl8190_priv_buf(data);
return NULL;
}
return skb;
}
#endif
int is_rtl8190_priv_buf(unsigned char *head)
{
unsigned long offset = (unsigned long)(&((struct priv_skb_buf *)0)->buf);
struct priv_skb_buf *priv_buf = (struct priv_skb_buf *)(((unsigned long)head) - offset);
if (!memcmp(priv_buf->magic, MAGIC_CODE, 4) &&
(priv_buf->buf_pointer == (unsigned int)priv_buf))
return 1;
else
return 0;
}
__IRAM_IN_865X
void free_rtl8190_priv_buf(unsigned char *head)
{
#ifdef CONCURRENT_MODE
unsigned long offset = (unsigned long)(&((struct priv_skb_buf *)0)->buf);
struct priv_skb_buf *priv_buf = (struct priv_skb_buf *)(((unsigned long)head) - offset);
struct rtl8192cd_priv *priv = priv_buf->root_priv;
int i = priv->pshare->wlandev_idx;
#ifndef SMP_SYNC
unsigned long x;
#endif
#ifdef DELAY_REFILL_RX_BUF
int ret;
#ifdef SMP_SYNC
unsigned long flags;
int locked, cpuid;
#endif
#ifdef CONFIG_WLAN_HAL
unsigned int q_num;
PHCI_RX_DMA_MANAGER_88XX prx_dma;
PHCI_RX_DMA_QUEUE_STRUCT_88XX cur_q;
#endif // CONFIG_WLAN_HAL
#ifdef SMP_SYNC
locked = 0;
SMP_TRY_LOCK_RECV(flags,locked);
#endif
SAVE_INT_AND_CLI(x);
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
if (!(priv->drv_state & DRV_STATE_OPEN)){
/* return 0 means can't refill (because interface be closed or not opened yet) to rx ring but relesae to skb_poll*/
ret=0;
}else{
q_num = 0;
prx_dma = (PHCI_RX_DMA_MANAGER_88XX)(_GET_HAL_DATA(priv)->PRxDMA88XX);
cur_q = &(prx_dma->rx_queue[q_num]);
ret = refill_rx_ring_88XX(priv, NULL, head, q_num, cur_q);
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, cur_q->rxbd_ok_cnt);
cur_q->rxbd_ok_cnt = 0;
}
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif
{//not HAL
ret = refill_rx_ring(priv, NULL, head);
}
if (ret) {
#ifdef SMP_SYNC
if(locked)
SMP_UNLOCK_RECV(flags);
#endif
RESTORE_INT(x);
return;
}
else {
release_buf_to_poll(priv, head, &skbbuf_list[i], (unsigned int *)&skb_free_num[i]);
}
#ifdef SMP_SYNC
if(locked)
SMP_UNLOCK_RECV(flags);
#endif
RESTORE_INT(x);
#else // ! DELAY_REFILL_RX_BUF
SAVE_INT_AND_CLI(x);
release_buf_to_poll(priv, head, &skbbuf_list[i], (unsigned int *)&skb_free_num[i]);
RESTORE_INT(x);
#endif
#else // ! CONCURRENT_MODE
unsigned long x;
struct rtl8192cd_priv *priv = root_priv;
#if 0
if (!is_rtl8190_priv_buf(head)) {
printk("wlan: free invalid priv skb buf!\n");
return;
}
#endif
#ifdef DELAY_REFILL_RX_BUF
#ifdef CONFIG_WLAN_HAL
unsigned int q_num;
PHCI_RX_DMA_MANAGER_88XX prx_dma;
PHCI_RX_DMA_QUEUE_STRUCT_88XX cur_q;
#endif
int ret;
#ifdef SMP_SYNC
unsigned long flags;
int locked, cpuid;
cpuid = smp_processor_id();
locked = 0;
SMP_TRY_LOCK_RECV(flags,locked,cpuid);
#endif
SAVE_INT_AND_CLI(x);
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
// Currently, only one queue for rx...
if (!(priv->drv_state & DRV_STATE_OPEN)){
/* return 0 means can't refill (because interface be closed or not opened yet) to rx ring but relesae to skb_poll*/
ret=0;
}else{
q_num = 0;
prx_dma = (PHCI_RX_DMA_MANAGER_88XX)(_GET_HAL_DATA(priv)->PRxDMA88XX);
cur_q = &(prx_dma->rx_queue[q_num]);
ret = refill_rx_ring_88XX(priv, NULL, head, q_num, cur_q);
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, cur_q->rxbd_ok_cnt);
cur_q->rxbd_ok_cnt = 0;
}
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif
{//not HAL
ret = refill_rx_ring(priv, NULL, head);
}
if (ret) {
#ifdef SMP_SYNC
if(locked)
SMP_UNLOCK_RECV(flags);
#endif
RESTORE_INT(x);
return;
} else {
release_buf_to_poll(root_priv, head, &skbbuf_list, (unsigned int *)&skb_free_num);
}
#ifdef SMP_SYNC
if(locked)
SMP_UNLOCK_RECV(flags);
#endif
RESTORE_INT(x);
#else // ! DELAY_REFILL_RX_BUF
SAVE_INT_AND_CLI(x);
release_buf_to_poll(root_priv, head, &skbbuf_list, (unsigned int *)&skb_free_num);
RESTORE_INT(x);
#endif
#endif
}
#endif //CONFIG_RTL8190_PRIV_SKB
/*
unsigned int set_fw_reg(struct rtl8192cd_priv *priv, unsigned int cmd, unsigned int val, unsigned int with_val)
{
static unsigned int delay_count;
delay_count = 10;
do {
if (!RTL_R32(0x2c0))
break;
delay_us(5);
delay_count--;
} while (delay_count);
delay_count = 10;
if (with_val == 1)
RTL_W32(0x2c4, val);
RTL_W32(0x2c0, cmd);
do {
if (!RTL_R32(0x2c0))
break;
delay_us(5);
delay_count--;
} while (delay_count);
return 0;
}
void set_fw_A2_entry(struct rtl8192cd_priv *priv, unsigned int cmd, unsigned char *addr)
{
unsigned int delay_count = 10;
do{
if (!RTL_R32(0x2c0))
break;
delay_us(5);
delay_count--;
} while (delay_count);
delay_count = 10;
RTL_W32(0x2c4, addr[3]<<24 | addr[2]<<16 | addr[1]<<8 | addr[0]);
RTL_W32(0x2c8, addr[5]<<8 | addr[4]);
RTL_W32(0x2c0, cmd);
do{
if (!RTL_R32(0x2c0))
break;
delay_us(5);
delay_count--;
} while (delay_count);
}
*/
//#if defined(TXREPORT) || defined(SW_ANT_SWITCH) || defined(USE_OUT_SRC)
#if 1
struct stat_info* findNextSTA(struct rtl8192cd_priv *priv, int *idx)
{
int i;
for(i= *idx; i<NUM_STAT; i++) {
if (priv->pshare->aidarray[i] && priv->pshare->aidarray[i]->used == TRUE) {
*idx = (i+1);
if (priv->pshare->aidarray[i]->station.sta_in_firmware != 1)
continue;
return &(priv->pshare->aidarray[i]->station);
}
}
return NULL;
}
#endif
int is_DFS_channel(int channelVal)
{
if( channelVal >= 52 && channelVal <= 140 ){
return 1;
}else{
return 0;
}
}
int is_passive_channel(struct rtl8192cd_priv *priv , int domain, int chan)
{
#ifdef DFS
/*during DFS channel , do passive scan*/
if( (chan >= 52 && chan <= 140) && !priv->pmib->dot11DFSEntry.disable_DFS){
return 1;
}
#endif
#if 0/*when the mib "w52_passive_scan" enabled , do passive scan in ch W52(ch 36 40 44 48)*/
else if(((chan >= 36) && (chan <= 48))
&& priv->pmib->dot11StationConfigEntry.w52_passive_scan ){
return 1;
}
#endif
#if 0
else if ((chan >= 12 && chan <= 14) && (domain == DOMAIN_GLOBAL || domain == DOMAIN_WORLD_WIDE)){
return 1;
}
#endif
return 0;
}
void init_STA_SWQAggNum(struct rtl8192cd_priv *priv)
{
#ifdef SW_TX_QUEUE
struct stat_info *sta;
int i, Idx = 0;
while(1) {
sta = findNextSTA(priv, &Idx);
if(sta) {
if(sta->tx_avarage> (1<<16)) {
for(i=BK_QUEUE;i<HIGH_QUEUE;i++) {
sta->swq.q_aggnum[i] = priv->pshare->rf_ft_var.swq_aggnum>>1;
}
}
} else {
return;
}
}
#endif
}
#if defined(TXREPORT)
void requestTxReport(struct rtl8192cd_priv *priv)
{
int h2ccmd, counter=20;
struct stat_info *sta;
if( priv->pshare->sta_query_idx == -1)
return;
while(is_h2c_buf_occupy(priv)) {
delay_ms(2);
if(--counter==0)
break;
}
if(!counter)
return;
h2ccmd= AP_REQ_RPT;
sta = findNextSTA(priv, &priv->pshare->sta_query_idx);
if(sta)
h2ccmd |= (REMAP_AID(sta)<<24);
else {
priv->pshare->sta_query_idx = -1;
return;
}
sta = findNextSTA(priv, &priv->pshare->sta_query_idx);
if(sta) {
h2ccmd |= (REMAP_AID(sta)<<16);
} else {
priv->pshare->sta_query_idx = -1;
}
signin_h2c_cmd(priv, h2ccmd , 0);
DEBUG_INFO("signin h2c:%x\n", h2ccmd);
}
/*
inital tx rate report from fw
---------------------------------------------------------
0 -> cck 1 12 -> MCS0 44 -> 1NSS-MCS0
1 -> cck 2 13 -> MCS1 45 -> 1NSS-MCS1
2 -> cck 5.5 14 -> MCS2 46 -> 1NSS-MCS2
3 -> cck 11 15 -> MCS3 47 -> 1NSS-MCS3
------------ 16 -> MCS4 48 -> 1NSS-MCS4
4 -> ofdm 6 17 -> MCS5 49 -> 1NSS-MCS5
5 -> ofdm 9 18 -> MCS6 50 -> 1NSS-MCS6
6 -> ofdm 12 19 -> MCS7 51 -> 1NSS-MCS7
7 -> ofdm 18 20 -> MCS8 52 -> 1NSS-MCS8
8 -> ofdm 24 21 -> MCS9 53 -> 1NSS-MCS9
9 -> ofdm 36 22 -> MCS10 54 -> 2NSS-MCS0
10 -> ofdm 48 23 -> MCS11 55 -> 2NSS-MCS1
11 -> ofdm 54 24 -> MCS12 56 -> 2NSS-MCS2
25 -> MCS13 57 -> 2NSS-MCS3
26 -> MCS14 58 -> 2NSS-MCS4
27 -> MCS15 59 -> 2NSS-MCS5
60 -> 2NSS-MCS6
61 -> 2NSS-MCS7
62 -> 2NSS-MCS8
63 -> 2NSS-MCS9
---------------------------------------------------------
*/
#ifdef FOR_DISPLAY_RATE
void get_inital_tx_rate2string(unsigned char txrate ){
static unsigned char rateStr[16];
if(txrate>=44 && txrate<=53){
printk("VHT 1SS-MCS%d\n",txrate-44);
}
else if(txrate>=54 && txrate<=63){
printk("VHT 2SS-MCS%d\n",txrate-54);
}
else if(txrate>=12 && txrate<=27){
printk("MCS%d\n",txrate-12);
}
else if(txrate>=0 && txrate<=3){
if(txrate==0)
printk("CCK-1\n");
else if(txrate==1)
printk("CCK-2\n");
else if(txrate==2)
printk("CCK-5.5\n");
else if(txrate==3)
printk("CCK-11\n");
}
else if(txrate>=4 && txrate<=11){
if(txrate==4)
printk("OFDM-6\n");
else if(txrate==5)
printk("OFDM-9\n");
else if(txrate==6)
printk("OFDM-12\n");
else if(txrate==7)
printk("OFDM-18\n");
else if(txrate==8)
printk("OFDM-24\n");
else if(txrate==9)
printk("OFDM-36\n");
else if(txrate==10)
printk("OFDM-48\n");
else if(txrate==11)
printk("OFDM-54\n");
}
}
//#define FDEBUG(fmt, args...) panic_printk("[%s %d]"fmt,__FUNCTION__,__LINE__,## args)
#endif
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
void update_RAMask_to_FW(struct rtl8192cd_priv *priv, int forceUpdate)
{
int idx = 0;
struct stat_info *pstat = NULL;
if( !IS_HAL_CHIP(priv) && GET_CHIP_VER(priv)!= VERSION_8812E)
return;
if (!forceUpdate && !( priv->pshare->is_40m_bw
#ifdef WIFI_11N_2040_COEXIST
&& !((((GET_MIB(priv))->dot11OperationEntry.opmode) & WIFI_AP_STATE)
&& priv->pmib->dot11nConfigEntry.dot11nCoexist
&& (priv->bg_ap_timeout || orForce20_Switch20Map(priv)
))
#endif
))
return;
pstat = findNextSTA(priv, &idx);
while(pstat) {
if(forceUpdate) {
#ifdef CONFIG_RTL_8812_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8812E)
UpdateHalRAMask8812(priv, pstat, 3);
else
#endif
{
#ifdef CONFIG_WLAN_HAL
GET_HAL_INTERFACE(priv)->UpdateHalRAMaskHandler(priv, pstat, 3);
#endif
}
} else {
if(!pstat->tx_bw_fw && pstat->tx_bw) {
#ifdef CONFIG_RTL_8812_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8812E)
UpdateHalRAMask8812(priv, pstat, 3);
else
#endif
{
#ifdef CONFIG_WLAN_HAL
GET_HAL_INTERFACE(priv)->UpdateHalRAMaskHandler(priv, pstat, 3);
#endif
}
}
}
pstat = findNextSTA(priv, &idx);
}
}
// TODO: Filen, check 8192E code below
void txrpt_handler_8812(struct rtl8192cd_priv *priv, struct tx_rpt *report, struct stat_info *pstat)
{
static unsigned char initial_rate = 0x7f;
static unsigned char legacyRA =0 ;
static unsigned int autoRate1=0;
/*under auto rate case , pstat->current_tx_rate just for display but it'll be changed,
so, take care! if under fixed rate case don't enter below block*/
if(!pstat)
return;
if(pstat->sta_in_firmware == 1)
{
if( should_restrict_Nrate(priv, pstat) && is_fixedMCSTxRate(priv, pstat)){
legacyRA = 1;
}
autoRate1= is_auto_rate(priv, pstat);
if( !(legacyRA || autoRate1) )
return;
//FDEBUG("STA[%02x%02x%02x:%02x%02x%02x]auto rate ,txfail=%d , txok=%d , rate=",
// pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5],
// report->txfail, report->txok );
//get_inital_tx_rate2string(report->initil_tx_rate&0x3f);
initial_rate = report->initil_tx_rate ;
if ((initial_rate & 0x7f) == 0x7f)
return;
if ((initial_rate&0x3f) < 12) {
pstat->current_tx_rate = dot11_rate_table[initial_rate&0x3f];
pstat->ht_current_tx_info &= ~TX_USE_SHORT_GI;
} else {
if((initial_rate&0x3f) >= 44){
pstat->current_tx_rate = VHT_RATE_ID+((initial_rate&0x3f) -44);
}else{
pstat->current_tx_rate = HT_RATE_ID+((initial_rate&0x3f) -12);
}
if (initial_rate & BIT(7))
pstat->ht_current_tx_info |= TX_USE_SHORT_GI;
else
pstat->ht_current_tx_info &= ~TX_USE_SHORT_GI;
}
priv->pshare->current_tx_rate = pstat->current_tx_rate;
priv->pshare->ht_current_tx_info = pstat->ht_current_tx_info;
}
}
#endif
#ifdef CONFIG_WLAN_HAL
void APReqTXRptHandler(
struct rtl8192cd_priv *priv,
pu1Byte pbuf
)
{
PAPREQTXRPT pparm = (PAPREQTXRPT)pbuf;
struct tx_rpt rpt1;
unsigned char MacID = 0xff;
unsigned char idx = 0;
int j;
{
for (j = 0; j < 2; j++) {
MacID = pparm->txrpt[j].RPT_MACID;
if (MacID == 0xff)
continue;
rpt1.macid = MacID;
if (rpt1.macid) {
rpt1.txok = le16_to_cpu(pparm->txrpt[j].RPT_TXOK);
rpt1.txfail = le16_to_cpu(pparm->txrpt[j].RPT_TXFAIL);
rpt1.initil_tx_rate = pparm->txrpt[j].RPT_InitialRate;
txrpt_handler(priv, &rpt1); // add inital tx rate handle for 8812E
}
idx += 6;
}
}
}
#endif
void _txrpt_handler(struct rtl8192cd_priv *priv, struct stat_info *pstat, struct tx_rpt *report)
{
if ((0 == report->txok) && (0 == report->txfail))
return;
priv->net_stats.tx_errors += report->txfail;
pstat->tx_fail += report->txfail;
pstat->tx_pkts += report->txfail;
if (pstat->txrpt_tx_ok_chk_cnt <= 10)
pstat->tx_pkts += report->txok;
if (pstat->txrpt_tx_bytes_pre == pstat->tx_bytes) {
if (report->txok) {
pstat->txrpt_tx_ok_chk_cnt++;
}
} else {
pstat->txrpt_tx_bytes_pre = pstat->tx_bytes;
pstat->txrpt_tx_ok_chk_cnt = 0;
}
DEBUG_INFO("debug[%02X%02X%02X%02X%02X%02X]:id=%d,ok=%d,fail=%d\n",
pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5],
report->macid, report->txok, report->txfail);
#ifdef DETECT_STA_EXISTANCE
#ifdef CONFIG_WLAN_HAL
if(IS_HAL_CHIP(priv))
{
DetectSTAExistance88XX(priv, report, pstat);
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
#endif
{//not HAL
// Check for STA existance; added by Annie, 2010-08-10.Not support now
#if (defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_92D_SUPPORT)|| defined(CONFIG_RTL_8812_SUPPORT))
if (CHIP_VER_92X_SERIES(priv) || (GET_CHIP_VER(priv)== VERSION_8812E))
DetectSTAExistance(priv, report, pstat);
#endif
#ifdef CONFIG_RTL_88E_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8188E)
RTL8188E_DetectSTAExistance(priv, report, pstat);
#endif
}
#endif // DETECT_STA_EXISTANCE
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
if( GET_CHIP_VER(priv)== VERSION_8812E || IS_HAL_CHIP(priv))
txrpt_handler_8812(priv, report, pstat);
#endif
}
void txrpt_handler(struct rtl8192cd_priv *priv, struct tx_rpt *report)
{
struct stat_info *pstat;
#ifdef MBSSID
int i;
#endif
pstat = get_macidinfo(priv, report->macid);
if(pstat) {
_txrpt_handler(priv, pstat, report);
return;
}
#ifdef UNIVERSAL_REPEATER
if (IS_DRV_OPEN(GET_VXD_PRIV(priv))) {
pstat = get_macidinfo(GET_VXD_PRIV(priv), report->macid);
if(pstat) {
_txrpt_handler(GET_VXD_PRIV(priv), pstat, report);
return;
}
}
#endif
#ifdef MBSSID
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable) {
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
if (IS_DRV_OPEN(priv->pvap_priv[i])) {
pstat = get_macidinfo(priv->pvap_priv[i], report->macid);
if(pstat) {
_txrpt_handler(priv->pvap_priv[i], pstat, report);
return;
}
}
}
}
#endif
}
void C2H_isr(struct rtl8192cd_priv *priv)
{
struct tx_rpt rpt1;
int j, tmp32, idx=0x1a2;
#ifndef SMP_SYNC
unsigned long flags;
#endif
SAVE_INT_AND_CLI(flags);
tmp32 = RTL_R16(0x1a0);
if( (tmp32&0xff)==0xc2 ) {
for(j=0; j<2; j++) {
rpt1.macid= (0x1f) & RTL_R8(idx+4);
if(rpt1.macid) {
#ifdef _BIG_ENDIAN_
rpt1.txok = le16_to_cpu(RTL_R16(idx+2));
rpt1.txfail = le16_to_cpu(RTL_R16(idx));
#else
rpt1.txok = be16_to_cpu(RTL_R16(idx+2));
rpt1.txfail = be16_to_cpu(RTL_R16(idx));
#endif
txrpt_handler(priv, &rpt1);
}
idx+=6;
}
}
RTL_W8( 0x1af, 0);
requestTxReport(priv);
RESTORE_INT(flags);
}
#endif
static int _is_hex(char c)
{
return (((c >= '0') && (c <= '9')) ||
((c >= 'A') && (c <= 'F')) ||
((c >= 'a') && (c <= 'f')));
}
int rtl_string_to_hex(char *string, unsigned char *key, int len)
{
char tmpBuf[4];
int idx, ii=0;
for (idx=0; idx<len; idx+=2) {
tmpBuf[0] = string[idx];
tmpBuf[1] = string[idx+1];
tmpBuf[2] = 0;
if ( !_is_hex(tmpBuf[0]) || !_is_hex(tmpBuf[1]))
return 0;
key[ii++] = (unsigned char) _atoi(tmpBuf,16);
}
return 1;
}
#if defined(CONFIG_RTL_CUSTOM_PASSTHRU)
#ifdef __ECOS
INT32 rtl_isWlanPassthruFrame(UINT8 *data)
#else
INT32 rtl_isPassthruFrame(UINT8 *data)
#endif
{
int ret;
#ifdef __ECOS
ret = FAILED;
#else
ret = FAIL;
#endif
if (passThruStatusWlan)
{
if (passThruStatusWlan&IP6_PASSTHRU_MASK)
{
if ((*((UINT16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_IPV6)) ||
((*((UINT16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_8021Q))&&(*((UINT16*)(data+(ETH_ALEN<<1)+VLAN_HLEN))==__constant_htons(ETH_P_IPV6))))
{
ret = SUCCESS;
}
}
#if defined(CONFIG_RTL_CUSTOM_PASSTHRU_PPPOE)
if (passThruStatusWlan&PPPOE_PASSTHRU_MASK)
{
if (((*((UINT16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_PPP_SES))||(*((UINT16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_PPP_DISC))) ||
((*((UINT16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_8021Q))&&((*((UINT16*)(data+(ETH_ALEN<<1)+VLAN_HLEN))==__constant_htons(ETH_P_PPP_SES))||(*((UINT16*)(data+(ETH_ALEN<<1)+VLAN_HLEN))==__constant_htons(ETH_P_PPP_DISC)))))
{
ret = SUCCESS;
}
}
#endif
}
return ret;
}
#endif
#ifdef HS2_SUPPORT
void calcu_sta_v6ip(struct stat_info *pstat)
{
struct in6_addr addrp;
addrp.s6_addr[0] = 0xfe;
addrp.s6_addr[1] = 0x80;
addrp.s6_addr[2] = 0x00;
addrp.s6_addr[3] = 0x00;
addrp.s6_addr[4] = 0x00;
addrp.s6_addr[5] = 0x00;
addrp.s6_addr[6] = 0x00;
addrp.s6_addr[7] = 0x00;
addrp.s6_addr[8] = pstat->hwaddr[0] | 0x02;
addrp.s6_addr[9] = pstat->hwaddr[1];
addrp.s6_addr[10] = pstat->hwaddr[2];
addrp.s6_addr[11] = 0xff;
addrp.s6_addr[12] = 0xfe;
addrp.s6_addr[13] = pstat->hwaddr[3];
addrp.s6_addr[14] = pstat->hwaddr[4];
addrp.s6_addr[15] = pstat->hwaddr[5];
ipv6_addr_copy(&pstat->sta_v6ip, &addrp);
}
void staip_snooping_byarp(struct sk_buff *pskb, struct stat_info *pstat)
{
struct arphdr *arp = (struct arphdr *)(pskb->data + ETH_HLEN);
unsigned char *arp_ptr = (unsigned char *)(arp + 1);
if((arp->ar_pro == __constant_htons(ETH_P_IP)) && (arp->ar_op == htons(ARPOP_REQUEST))) {
//find sender ip
arp_ptr += arp->ar_hln;
//backup sender ip
if ((*arp_ptr == 0) && (*(arp_ptr+1) == 0) && (*(arp_ptr+2) == 0) && (*(arp_ptr+3) == 0))
return;
else {
memcpy(pstat->sta_ip, arp_ptr, 4);
panic_printk("ARP cache ip=%d.%d.%d.%d\n", pstat->sta_ip[0],pstat->sta_ip[1],pstat->sta_ip[2],pstat->sta_ip[3]);
}
}
}
void stav6ip_snooping_bynsolic(struct sk_buff *pskb, struct stat_info *pstat)
{
struct ipv6hdr *hdr = (struct ipv6hdr *)(pskb->data+ETH_HLEN);
struct icmp6hdr *icmphdr;
int pkt_len, type;
if (hdr->version != 6)
return;
if (hdr->hop_limit != 255)
return;
pkt_len = ntohs(hdr->payload_len);
if (pkt_len>0)
{
icmphdr = (struct icmp6hdr *)(pskb->data+ETH_HLEN+sizeof(*hdr));
type = icmphdr->icmp6_type;
if (type == NDISC_NEIGHBOUR_SOLICITATION)
{
if ((hdr->saddr.s6_addr32[0] == 0) && (hdr->saddr.s6_addr32[1] == 0) && (hdr->saddr.s6_addr32[2] == 0) && (hdr->saddr.s6_addr32[3] == 0)) {
struct in6_addr *target = (struct in6_addr *) (icmphdr + 1);
if ((target->s6_addr32[0] == 0) && (target->s6_addr32[1] == 0) && (target->s6_addr32[2] == 0) && (target->s6_addr32[3] == 0)) {
return;
}
else {
printk("rcv multicast ns duplicate addr\n");
ipv6_addr_copy(&pstat->sta_v6ip, target);
}
}
else {
printk("rcv multicast ns\n");
ipv6_addr_copy(&pstat->sta_v6ip, &hdr->saddr);
}
}
}
}
#if 0
void stav6ip_snooping_bynadvert(struct sk_buff *pskb, struct stat_info *pstat)
{
struct ipv6hdr *hdr = (struct ipv6hdr *)(pskb->data+ETH_HLEN);
struct icmp6hdr *icmphdr;
int pkt_len, type;
if (hdr->version != 6)
return;
if (hdr->hop_limit != 255)
return;
pkt_len = ntohs(hdr->payload_len);
if (pkt_len>0)
{
icmphdr = (struct icmp6hdr *)(pskb->data+ETH_HLEN+sizeof(*hdr));
type = icmphdr->icmp6_type;
if (type == NDISC_NEIGHBOUR_ADVERTISEMENT)
{
if ((hdr->saddr.s6_addr32[0] == 0) && (hdr->saddr.s6_addr32[1] == 0) && (hdr->saddr.s6_addr32[2] == 0) && (hdr->saddr.s6_addr32[3] == 0)) {
return;
}
else {
printk("rcv unsolicited neighbor advert multicast\n");
ipv6_addr_copy(&pstat->sta_v6ip, &hdr->saddr);
}
}
}
}
#endif
void staip_snooping_bydhcp(struct sk_buff *pskb, struct rtl8192cd_priv *priv) //struct stat_info *pstat)
{
#define DHCP_MAGIC 0x63825363
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
#if 0
__u16 check;
__u32 saddr;
__u32 daddr;
#endif
};
struct udphdr {
__u16 source;
__u16 dest;
__u16 len;
__u16 check;
};
struct dhcpMessage {
u_int8_t op;
u_int8_t htype;
u_int8_t hlen;
u_int8_t hops;
u_int32_t xid;
u_int16_t secs;
u_int16_t flags;
u_int32_t ciaddr;
u_int32_t yiaddr;
u_int32_t siaddr;
u_int32_t giaddr;
u_int8_t chaddr[16];
u_int8_t sname[64];
u_int8_t file[128];
u_int32_t cookie;
#if 0
u_int8_t options[308]; /* 312 - cookie */
#endif
};
struct stat_info *pstat;
struct iphdr* iph;
struct udphdr *udph;
struct dhcpMessage *dhcph;
struct list_head *phead, *plist;
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
iph = (struct iphdr *)(pskb->data + ETH_HLEN);
udph = (struct udphdr *)((unsigned int)iph + (iph->ihl << 2));
dhcph = (struct dhcpMessage *)((unsigned int)udph + sizeof(struct udphdr));
phead = &priv->asoc_list;
SMP_LOCK_ASOC_LIST(flags);
plist = phead->next;
while (phead && (plist != phead))
{
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
if (!memcmp(pstat->hwaddr, &dhcph->chaddr[0], 6)) {
if (dhcph->op == 2) //dhcp reply
{
if (dhcph->yiaddr != 0) {
memcpy(pstat->sta_ip, &dhcph->yiaddr, 4);
printk("dhcp give yip=%d.%d.%d.%d\n", pstat->sta_ip[0],pstat->sta_ip[1],pstat->sta_ip[2],pstat->sta_ip[3]);
}
}
SMP_UNLOCK_ASOC_LIST(flags);
return;
}
}
SMP_UNLOCK_ASOC_LIST(flags);
}
extern __MIPS16 __IRAM_IN_865X int __rtl8192cd_start_xmit_out(struct sk_buff *skb, struct stat_info *pstat);
int check_nei_advt(struct rtl8192cd_priv *priv, struct sk_buff *skb)
{
struct ipv6hdr *hdr = (struct ipv6hdr *)(skb->data+ETH_HLEN);
struct icmp6hdr *icmpv6;
unsigned int pkt_len;
int type;
pkt_len = ntohs(hdr->payload_len);
if (pkt_len>0)
{
icmpv6 = (struct icmp6hdr *)(skb->data+ETH_HLEN+sizeof(*hdr));
type = icmpv6->icmp6_type;
//printk("pkt len=%d,type=%d\n", pkt_len, type);
if (type == NDISC_NEIGHBOUR_ADVERTISEMENT)
{
printk("drop nei advr\n");
return 1;
}
else
return 0;
}
return 0;
}
int proxy_icmpv6_ndisc(struct rtl8192cd_priv *priv, struct sk_buff *skb)
{
struct sk_buff *newskb = NULL;
struct in6_addr *addrp;
struct ipv6hdr *hdr = (struct ipv6hdr *)(skb->data+ETH_HLEN);
struct ipv6hdr *replyhdr;
struct icmp6hdr *icmpv6_nsolic;
struct icmp6hdr *icmpv6_nadvt;
struct stat_info *pstat;
struct list_head *phead, *plist;
unsigned int pkt_len;
int type;
HS2_DEBUG_TRACE(2, "proxy_icmpv6_ndisc\n");
if (hdr->version != 6)
return 0;
pkt_len = ntohs(hdr->payload_len);
if (pkt_len>0)
{
icmpv6_nsolic = (struct icmp6hdr *)(skb->data+ETH_HLEN+sizeof(*hdr));
type = icmpv6_nsolic->icmp6_type;
//printk("pkt len=%d,type=%d\n", pkt_len, type);
if (type == NDISC_NEIGHBOUR_SOLICITATION)
{
HS2_DEBUG_TRACE(2, "NDISC_NEIGHBOUR_SOLICITATION\n");
if (!memcmp(skb->data+ETH_ALEN, priv->pmib->dot11StationConfigEntry.dot11Bssid, ETH_ALEN))
{
HS2_DEBUG_TRACE(2, "v6:arp req src mac=BSSID\n");
return 0;
}
if (ipv6_addr_loopback(&hdr->daddr))
{
HS2_DEBUG_TRACE(2, "v6:loopback\n");
return 0;
}
//search target ip mapping pstat mac
phead = &priv->asoc_list;
plist = phead->next;
while (phead && (plist != phead))
{
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
addrp = (struct in6_addr *)(icmpv6_nsolic+1);
if (ipv6_addr_equal(&pstat->sta_v6ip, addrp))
{
#if defined(CONFIG_RTL865X_ETH_PRIV_SKB) || defined(CONFIG_RTL_ETH_PRIV_SKB)
extern struct sk_buff *priv_skb_copy(struct sk_buff *skb);
newskb = priv_skb_copy(skb);
#else
newskb = skb_copy(skb, GFP_ATOMIC);
#endif
//printk("compare ok!!\n");
if (newskb == NULL)
{
priv->ext_stats.tx_drops++;
HS2_DEBUG_ERR("alloc icmpv6 neighbor advertisement skb null!!\n");
rtl_kfree_skb(priv, skb, _SKB_TX_);
return 1;
}
else
{
unsigned char *opt;
int len;
//da
memcpy(newskb->data, newskb->data+ETH_ALEN, 6);
//sa
memcpy(newskb->data+ETH_ALEN, pstat->hwaddr, 6);
replyhdr = (struct ipv6hdr *)(newskb->data+ETH_HLEN);
ipv6_addr_copy(&replyhdr->saddr, &pstat->sta_v6ip);
ipv6_addr_copy(&replyhdr->daddr, &hdr->saddr);
icmpv6_nadvt = (struct icmp6hdr *)(newskb->data+ETH_HLEN+sizeof(*hdr));
icmpv6_nadvt->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
icmpv6_nadvt->icmp6_solicited = 1;
icmpv6_nadvt->icmp6_override = 0;
//target ip
opt = (unsigned char *)(newskb->data+ETH_HLEN+sizeof(*replyhdr)+sizeof(struct icmp6hdr));
ipv6_addr_copy((struct in6_addr *)opt, &pstat->sta_v6ip);
opt += sizeof(struct in6_addr);
//option
opt[0] = 2; // Type: Target link-layer addr
opt[1] = 1; // Length: 1 (8 bytes)
memcpy(opt+2, pstat->hwaddr, ETH_ALEN);
icmpv6_nadvt->icmp6_cksum = 0;
len = sizeof(struct icmp6hdr)+sizeof(struct in6_addr)+8;
icmpv6_nadvt->icmp6_cksum = csum_ipv6_magic(&replyhdr->saddr, &replyhdr->daddr, len,
IPPROTO_ICMPV6, csum_partial(icmpv6_nadvt, len, 0));
rtl_kfree_skb(priv, skb, _SKB_TX_);
if (ipv6_addr_equal(&replyhdr->saddr, &replyhdr->daddr))
{
printk("v6:tip=sip!!\n");
dev_kfree_skb_any(newskb);
return 1;
}
if ((pstat = get_stainfo(priv, newskb->data)) != NULL)
{
int i;
HS2_DEBUG_TRACE(2, "v6:da in wlan\n");
newskb->cb[2] = (char)0xff; // not do aggregation
memcpy(newskb->cb+10,newskb->data,6);
HS2_DEBUG_INFO("data=");
for(i=0;i<ETH_HLEN+sizeof(*replyhdr)+sizeof(struct icmp6hdr)+sizeof(struct in6_addr)+8;i++) {
HS2_DEBUG_INFO("%02x ",newskb->data[i]);
}
HS2_DEBUG_INFO("\n");
//dev_kfree_skb_any(newskb);
__rtl8192cd_start_xmit(newskb, priv->dev, 1);
}
else
{
HS2_DEBUG_TRACE(2, "v6:da in lan\n");
if (newskb->dev)
#ifdef __LINUX_2_6__
newskb->protocol = eth_type_trans(newskb, newskb->dev);
else
#endif
newskb->protocol = eth_type_trans(newskb, priv->dev);
#if defined(__LINUX_2_6__) && defined(RX_TASKLET) && !defined(CONFIG_RTL8672) && !defined(__LINUX_3_10__)
netif_receive_skb(newskb);
#else
netif_rx(newskb);
#endif
}
return 1;
}
}
}
}
}
return 0;
}
int proxy_arp_handle(struct rtl8192cd_priv *priv, struct sk_buff *skb)
{
struct sk_buff *newskb = NULL;
struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
unsigned char *arp_ptr = (unsigned char *)(arp + 1), *psender, *ptarget, *psender_bak;
struct stat_info *pstat;
struct list_head *phead, *plist;
int k;
unsigned char *tmp = (unsigned char *)(skb->data);
/*if((arp->ar_pro == __constant_htons(ETH_P_IP)) && (arp->ar_op == htons(ARPOP_REQUEST)||arp->ar_op == htons(ARPOP_REPLY)))
{
arp_ptr += arp->ar_hln;
psender_bak = arp_ptr;
//target ip
arp_ptr += (arp->ar_hln + arp->ar_pln);
ptarget = arp_ptr;
if (!memcmp(psender_bak,ptarget,4))
{
printk("gratuitous ARP Request or Reply\n");
return 0;
}
}*/
HS2_DEBUG_TRACE(2, "Proxy ARP handle\n");
if((arp->ar_pro == __constant_htons(ETH_P_IP)) && (arp->ar_op == htons(ARPOP_REQUEST)))
{
//{
// int j;
// printk("orin==>");
// for(j=0;j<skb->len;j++)
// printk("0x%02x:",*(skb->data+j));
// printk("\n");
//}
//sender ip
arp_ptr += arp->ar_hln;
psender_bak = arp_ptr;
//target ip
arp_ptr += (arp->ar_hln + arp->ar_pln);
ptarget = arp_ptr;
if (!memcmp(skb->data+ETH_ALEN, priv->pmib->dot11StationConfigEntry.dot11Bssid, ETH_ALEN))
{
HS2_DEBUG_TRACE(1, "arp req src mac=BSSID\n");
return 0;
}
if (ipv4_is_loopback(ptarget) || ipv4_is_multicast(ptarget))
{
HS2_DEBUG_TRACE(1, "loopback or muticast!!\n");
return 0;
}
//search target ip mapping pstat mac
phead = &priv->asoc_list;
plist = phead->next;
while (phead && (plist != phead))
{
pstat = list_entry(plist, struct stat_info, asoc_list);
plist = plist->next;
HS2_DEBUG_INFO("Proxy ARP: Find Destination in Assocation List, sta_ip=%d.%d.%d.%d\n",pstat->sta_ip[0],pstat->sta_ip[1],pstat->sta_ip[2],pstat->sta_ip[3]);
if (!memcmp(pstat->sta_ip, ptarget, 4))
{
panic_printk("Proxy ARP: Find Destination in Assocation List\n");
#if defined(CONFIG_RTL865X_ETH_PRIV_SKB) || defined(CONFIG_RTL_ETH_PRIV_SKB)
extern struct sk_buff *priv_skb_copy(struct sk_buff *skb);
newskb = priv_skb_copy(skb);
#else
newskb = skb_copy(skb, GFP_ATOMIC);
#endif
if (newskb == NULL)
{
priv->ext_stats.tx_drops++;
HS2_DEBUG_ERR("alloc arp rsp skb null!!\n");
rtl_kfree_skb(priv, skb, _SKB_TX_);
return 1;
}
else
{
// ======================
// build new arp response
// ======================
//da
memcpy(newskb->data, newskb->data+ETH_ALEN, 6);
//memcpy(newskb->data, priv->pmib->dot11StationConfigEntry.dot11Bssid, 6);
//sa
memcpy(newskb->data+ETH_ALEN, pstat->hwaddr, 6);
//memcpy(newskb->data+ETH_ALEN, priv->pmib->dot11StationConfigEntry.dot11Bssid, 6);
//arp response
arp = (struct arphdr *)(newskb->data + ETH_HLEN);
arp_ptr = (unsigned char *)(arp + 1);
arp->ar_op = htons(ARPOP_REPLY);
//sender mac and ip
memcpy(arp_ptr, pstat->hwaddr, 6);
arp_ptr += arp->ar_hln;
psender = (unsigned char *)arp_ptr;
memcpy(psender, ptarget, 4);
//printk("sender mac and ip:%02x:%02x:%02x:%02x:%02x:%02x,%d.%d.%d.%d\n",pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5],ptarget[0],ptarget[1],ptarget[2],ptarget[3]);
//target mac and ip
arp_ptr += arp->ar_pln;
memcpy(arp_ptr, newskb->data, 6);
//memcpy(newskb->data, priv->pmib->dot11StationConfigEntry.dot11Bssid, 6);
arp_ptr += arp->ar_hln;
ptarget = arp_ptr;
memcpy((unsigned char *)ptarget, (unsigned char *)psender_bak, 4);
//printk("target mac and ip:%02x:%02x:%02x:%02x:%02x:%02x,%d.%d.%d.%d\n",newskb->data[0],newskb->data[1],newskb->data[2],newskb->data[3],newskb->data[4],newskb->data[5],ptarget[0],ptarget[1],ptarget[2],ptarget[3]);
rtl_kfree_skb(priv, skb, _SKB_TX_);
if (!memcmp(ptarget, psender, 4))
{
HS2_DEBUG_TRACE(2, "target ip = sender ip!!\n");
dev_kfree_skb_any(newskb);
return 1;
}
if ((pstat = get_stainfo(priv, newskb->data)) != NULL)
{
//struct sk_buff_head *pqueue;
//struct timer_list *ptimer;
//void (*timer_hook)(unsigned long task_priv);
//if (newskb->dev)
//#ifdef __LINUX_2_6__
// newskb->protocol = eth_type_trans(newskb, newskb->dev);
// else
//#endif
// newskb->protocol = eth_type_trans(newskb, priv->dev);
// printk("enq\n");
// pqueue = &pstat->swq.be_queue;
// ptimer = &pstat->swq.beq_timer;
// timer_hook = rtl8192cd_beq_timer;
// skb_queue_tail(pqueue, newskb);
// ptimer->data = (unsigned long)pstat;
// ptimer->function = timer_hook; //rtl8190_tmp_timer;
// mod_timer(ptimer, jiffies + 1);
// SAVE_INT_AND_CLI(x);
//pstat = get_stainfo(priv, newskb->data);
HS2_DEBUG_TRACE(1, "da in wlan\n");
//__rtl8192cd_start_xmit_out(newskb, pstat);
newskb->cb[2] = (char)0xff; // not do aggregation
memcpy(newskb->cb+10,newskb->data,6);
__rtl8192cd_start_xmit(newskb, priv->dev, 1);
// RESTORE_INT(x);
}
else
{
HS2_DEBUG_TRACE(1, "da in lan\n");
if (newskb->dev)
#ifdef __LINUX_2_6__
newskb->protocol = eth_type_trans(newskb, newskb->dev);
else
#endif
newskb->protocol = eth_type_trans(newskb, priv->dev);
#if defined(__LINUX_2_6__) && defined(RX_TASKLET) && !defined(CONFIG_RTL8672)
netif_receive_skb(newskb);
#else
netif_rx(newskb);
#endif
}
return 1;
}
}
}
}
//drop packet
return 0;
}
void rtl8192cd_cu_cntdwn_timer(unsigned long task_priv)
{
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
int val;
if (!(priv->drv_state & DRV_STATE_OPEN))
return;
if (timer_pending(&priv->cu_cntdwn_timer))
{
del_timer_sync(&priv->cu_cntdwn_timer);
}
if ((val = read_bbp_ch_load(priv)) == -1)
{
//printk("bbp not ready!!!\n");
mod_timer(&priv->cu_cntdwn_timer, jiffies + RTL_MILISECONDS_TO_JIFFIES(10));
}
else
{
priv->chbusytime += val;
priv->cu_cntdwn--;
if (priv->cu_cntdwn == 0)
{
priv->channel_utilization = (priv->chbusytime*255)/(priv->pmib->hs2Entry.channel_utili_beaconIntval * priv->pmib->dot11StationConfigEntry.dot11BeaconPeriod * 1024);
//printk("ch=%d\n", priv->channel_utilization);
priv->chbusytime = 0;
priv->cu_cntdwn = priv->cu_initialcnt;
}
start_bbp_ch_load(priv);
mod_timer(&priv->cu_cntdwn_timer, jiffies + CU_TO);
}
}
#endif
#ifdef USE_TXQUEUE
int init_txq_pool(struct list_head *head, unsigned char **ppool)
{
unsigned char *ptr;
unsigned int i;
struct txq_node *pnode;
INIT_LIST_HEAD(head);
ptr = kmalloc(TXQUEUE_SIZE * sizeof(struct txq_node), GFP_ATOMIC);
if (!ptr) {
printk("ERRORL: %s failed\n", __FUNCTION__);
*ppool = NULL;
return -1;
}
pnode = (struct txq_node *)ptr;
for (i=0; i<TXQUEUE_SIZE; i++)
{
pnode[i].skb = NULL;
pnode[i].dev = NULL;
list_add_tail(&(pnode[i].list), head);
}
*ppool = ptr;
return 0;
}
void free_txq_pool(struct list_head *head, unsigned char *ppool)
{
if (ppool)
kfree(ppool);
INIT_LIST_HEAD(head);
}
void append_skb_to_txq_head(struct txq_list_head *head, struct rtl8192cd_priv *priv, struct sk_buff *skb, struct net_device *dev, struct list_head *pool)
{
struct txq_node *pnode = NULL;
if (list_empty(pool))
{
DEBUG_ERR("%s: No unused node in pool, this should not happend, fix me.\n", __FUNCTION__);
rtl_kfree_skb(priv, skb, _SKB_TX_);
DEBUG_ERR("TX DROP: exceed the tx queue!\n");
priv->ext_stats.tx_drops++;
return;
}
pnode = (struct txq_node *)pool->next;
list_del(pool->next);
pnode->skb = skb;
pnode->dev = dev;
add_txq_head(head, pnode);
}
void append_skb_to_txq_tail(struct txq_list_head *head, struct rtl8192cd_priv *priv, struct sk_buff *skb, struct net_device *dev, struct list_head *pool)
{
struct txq_node *pnode = NULL;
if (list_empty(pool))
{
DEBUG_ERR("%s: No unused node in pool, this should not happend, fix me.\n", __FUNCTION__);
rtl_kfree_skb(priv, skb, _SKB_TX_);
DEBUG_ERR("TX DROP: exceed the tx queue!\n");
priv->ext_stats.tx_drops++;
return;
}
pnode = (struct txq_node *)pool->next;
list_del(pool->next);
pnode->skb = skb;
pnode->dev = dev;
add_txq_tail(head, pnode);
}
void remove_skb_from_txq(struct txq_list_head *head, struct sk_buff **pskb, struct net_device **pdev, struct list_head *pool)
{
struct txq_node *pnode = NULL;
if (is_txq_empty(head))
{
*pskb = NULL;
*pdev = NULL;
return;
}
pnode = deq_txq(head);
*pskb = pnode->skb;
*pdev = pnode->dev;
pnode->skb = NULL;
pnode->dev = NULL;
list_add_tail(&pnode->list, pool);
}
#endif
#ifdef TLN_STATS
void stats_conn_rson_counts(struct rtl8192cd_priv *priv, unsigned int reason)
{
switch (reason) {
case _RSON_UNSPECIFIED_:
priv->ext_wifi_stats.rson_UNSPECIFIED_1++;
break;
case _RSON_AUTH_NO_LONGER_VALID_:
priv->ext_wifi_stats.rson_AUTH_INVALID_2++;
break;
case _RSON_DEAUTH_STA_LEAVING_:
priv->ext_wifi_stats.rson_DEAUTH_STA_LEAVING_3++;
break;
case _RSON_INACTIVITY_:
priv->ext_wifi_stats.rson_INACTIVITY_4++;
break;
case _RSON_UNABLE_HANDLE_:
priv->ext_wifi_stats.rson_RESOURCE_INSUFFICIENT_5++;
break;
case _RSON_CLS2_:
priv->ext_wifi_stats.rson_UNAUTH_CLS2FRAME_6++;
break;
case _RSON_CLS3_:
priv->ext_wifi_stats.rson_UNAUTH_CLS3FRAME_7++;
break;
case _RSON_DISAOC_STA_LEAVING_:
priv->ext_wifi_stats.rson_DISASSOC_STA_LEAVING_8++;
break;
case _RSON_ASOC_NOT_AUTH_:
priv->ext_wifi_stats.rson_ASSOC_BEFORE_AUTH_9++;
break;
case _RSON_INVALID_IE_:
priv->ext_wifi_stats.rson_INVALID_IE_13++;
break;
case _RSON_MIC_FAILURE_:
priv->ext_wifi_stats.rson_MIC_FAILURE_14++;
break;
case _RSON_4WAY_HNDSHK_TIMEOUT_:
priv->ext_wifi_stats.rson_4WAY_TIMEOUT_15++;
break;
case _RSON_GROUP_KEY_UPDATE_TIMEOUT_:
priv->ext_wifi_stats.rson_GROUP_KEY_TIMEOUT_16++;
break;
case _RSON_DIFF_IE_:
priv->ext_wifi_stats.rson_DIFF_IE_17++;
break;
case _RSON_MLTCST_CIPHER_NOT_VALID_:
priv->ext_wifi_stats.rson_MCAST_CIPHER_INVALID_18++;
break;
case _RSON_UNICST_CIPHER_NOT_VALID_:
priv->ext_wifi_stats.rson_UCAST_CIPHER_INVALID_19++;
break;
case _RSON_AKMP_NOT_VALID_:
priv->ext_wifi_stats.rson_AKMP_INVALID_20++;
break;
case _RSON_UNSUPPORT_RSNE_VER_:
priv->ext_wifi_stats.rson_UNSUPPORT_RSNIE_VER_21++;
break;
case _RSON_INVALID_RSNE_CAP_:
priv->ext_wifi_stats.rson_RSNIE_CAP_INVALID_22++;
break;
case _RSON_IEEE_802DOT1X_AUTH_FAIL_:
priv->ext_wifi_stats.rson_802_1X_AUTH_FAIL_23++;
break;
default:
priv->ext_wifi_stats.rson_OUT_OF_SCOPE++;
/*panic_printk("incorrect reason(%d) for statistics\n", reason);*/
break;
}
priv->wifi_stats.rejected_sta++;
}
void stats_conn_status_counts(struct rtl8192cd_priv *priv, unsigned int status)
{
switch (status) {
case _STATS_SUCCESSFUL_:
priv->wifi_stats.connected_sta++;
break;
case _STATS_FAILURE_:
priv->ext_wifi_stats.status_FAILURE_1++;
break;
case _STATS_CAP_FAIL_:
priv->ext_wifi_stats.status_CAP_FAIL_10++;
break;
case _STATS_NO_ASOC_:
priv->ext_wifi_stats.status_NO_ASSOC_11++;
break;
case _STATS_OTHER_:
priv->ext_wifi_stats.status_OTHER_12++;
break;
case _STATS_NO_SUPP_ALG_:
priv->ext_wifi_stats.status_NOT_SUPPORT_ALG_13++;
break;
case _STATS_OUT_OF_AUTH_SEQ_:
priv->ext_wifi_stats.status_OUT_OF_AUTH_SEQ_14++;
break;
case _STATS_CHALLENGE_FAIL_:
priv->ext_wifi_stats.status_CHALLENGE_FAIL_15++;
break;
case _STATS_AUTH_TIMEOUT_:
priv->ext_wifi_stats.status_AUTH_TIMEOUT_16++;
break;
case _STATS_UNABLE_HANDLE_STA_:
priv->ext_wifi_stats.status_RESOURCE_INSUFFICIENT_17++;
break;
case _STATS_RATE_FAIL_:
priv->ext_wifi_stats.status_RATE_FAIL_18++;
break;
default:
priv->ext_wifi_stats.status_OUT_OF_SCOPE++;
/*panic_printk("incorrect status(%d) for statistics\n", status);*/
break;
}
if (status != _STATS_SUCCESSFUL_)
priv->wifi_stats.rejected_sta++;
}
#endif
#ifdef SW_TX_QUEUE
void adjust_swq_setting(struct rtl8192cd_priv *priv, struct stat_info *pstat, int i, int mode)
{
int thd;
if(pstat->swq.q_used[i]) {
if (mode == CHECK_DEC_AGGN) {
if (pstat->swq.q_aggnum[i] <= 2)
thd = priv->pshare->rf_ft_var.timeout_thd;
else if (pstat->swq.q_aggnum[i] <= 4)
thd = priv->pshare->rf_ft_var.timeout_thd2;
else
thd = priv->pshare->rf_ft_var.timeout_thd3;
if ((pstat->swq.q_TOCount[i] >= thd)&& ((pstat->swq.q_TOCount[i] % thd) == 0)) {
--(pstat->swq.q_aggnum[i]);
if (pstat->swq.q_aggnum[i] <= 2)
pstat->swq.q_aggnum[i] = 2;
if (++pstat->swq.q_aggnumIncSlow[i] >= MAX_BACKOFF_CNT)
pstat->swq.q_aggnumIncSlow[i] = MAX_BACKOFF_CNT;
DEBUG_INFO("dec,aid:%d,cnt:%d\n", pstat->aid, pstat->swq.q_TOCount[i]);
}
}
else {
if (pstat->swq.q_aggnum[i] <= 2)
thd = priv->pshare->rf_ft_var.timeout_thd-10;
else if (pstat->swq.q_aggnum[i] <= 4)
thd = priv->pshare->rf_ft_var.timeout_thd2-30;
else
thd = priv->pshare->rf_ft_var.timeout_thd3-50;
if(pstat->swq.q_TOCount[i]< thd) {
int step = 1;
if(pstat->swq.q_TOCount[i]< thd/5)
step = 5;
else if(pstat->swq.q_TOCount[i]< thd/3)
step = 3;
pstat->swq.q_aggnum[i] += step;
if (pstat->swq.q_aggnum[i] > priv->pshare->rf_ft_var.swq_aggnum)
pstat->swq.q_aggnum[i] = priv->pshare->rf_ft_var.swq_aggnum;
//panic_printk("inc,aid:%d,cnt:%d,%d\n", pstat->aid, pstat->swq.q_TOCount[i], pstat->swq.q_aggnum[BE_QUEUE]);
}
}
}
}
#endif
#if defined(CONFIG_RTL_ULINKER)
int get_wlan_opmode(struct net_device *dev)
{
int opmode = -1;
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)dev->priv;
if (netif_running(dev)) {
if ((priv->pmib->dot11OperationEntry.opmode) & WIFI_AP_STATE)
opmode = 0;
else
opmode = 1;
}
return opmode;
}
#endif
#if defined(RF_MIMO_SWITCH) || defined(RF_MIMO_PS)
void Do_BB_Reset(struct rtl8192cd_priv *priv)
{
unsigned char tmp_reg2 = 0;
tmp_reg2 = RTL_R8(0x2);
tmp_reg2 &= (~BIT(0));
RTL_W8(0x2, tmp_reg2);
tmp_reg2 |= BIT(0);
RTL_W8(0x2, tmp_reg2);
}
void Assert_BB_Reset(struct rtl8192cd_priv *priv)
{
unsigned char tmp_reg2 = 0;
tmp_reg2 = RTL_R8(0x2);
tmp_reg2 &= (~BIT(0));
RTL_W8(0x2, tmp_reg2);
}
void Release_BB_Reset(struct rtl8192cd_priv *priv)
{
unsigned char tmp_reg2 = 0;
tmp_reg2 = RTL_R8(0x2);
tmp_reg2 |= BIT(0);
RTL_W8(0x2, tmp_reg2);
}
void RF_MIMO_check_timer(unsigned long task_priv)
{
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
int i=0, assoc_num = priv->assoc_num;
if (!(priv->drv_state & DRV_STATE_OPEN))
return;
if(get_rf_mimo_mode(priv) != MIMO_2T2R)
return;
if(priv->auto_channel || timer_pending(&priv->ss_timer)) {
#ifdef CONFIG_PCI_HCI
goto end;
#else
return;
#endif
}
#ifdef MCR_WIRELESS_EXTEND
return;
#endif
#ifdef MP_TEST
if (((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific))
return;
#endif
if(0
#ifdef WDS
|| (priv->pmib->dot11WdsInfo.wdsEnabled)
#endif
#ifdef UNIVERSAL_REPEATER
|| (IS_DRV_OPEN(GET_VXD_PRIV(priv)))
#endif
) {
if(MIMO_mode_switch(priv, MIMO_2T2R)) {
#if defined(WIFI_11N_2040_COEXIST_EXT)
if((priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) && (priv->pmib->dot11nConfigEntry.dot11nUse40M != HT_CHANNEL_WIDTH_20)) {
priv->pshare->CurrentChannelBW = priv->pmib->dot11nConfigEntry.dot11nUse40M;
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan);
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
update_RAMask_to_FW(priv, 1);
#endif
SetTxPowerLevel(priv);
}
#endif
}
return;
}
if(priv->pshare->rf_ft_var.rf_mode ==0) {
#ifdef MBSSID
if (priv->pmib->miscEntry.vap_enable){
for (i=0; i<RTL8192CD_NUM_VWLAN; ++i)
assoc_num += priv->pvap_priv[i]-> assoc_num;
}
#endif
if(assoc_num) {
if(MIMO_mode_switch(priv, MIMO_2T2R)) {
#if defined(WIFI_11N_2040_COEXIST_EXT)
if((priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) && (priv->pmib->dot11nConfigEntry.dot11nUse40M != HT_CHANNEL_WIDTH_20)) {
priv->pshare->CurrentChannelBW = priv->pmib->dot11nConfigEntry.dot11nUse40M;
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan);
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
update_RAMask_to_FW(priv, 1);
#endif
SetTxPowerLevel(priv);
}
#endif
// reset bb for 8812 to avoid rx hang
//if (GET_CHIP_VER(priv) == VERSION_8812E)
//Do_BB_Reset(priv);
}
}
else {
#if defined(WIFI_11N_2040_COEXIST_EXT)
if((priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40)|| (priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_80)) {
priv->pshare->CurrentChannelBW = HT_CHANNEL_WIDTH_20;
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan);
}
#endif
if(MIMO_mode_switch(priv, MIMO_1T1R)) {
// reset bb for 8812 to avoid rx hang
//if (GET_CHIP_VER(priv) == VERSION_8812E)
//Do_BB_Reset(priv);
}
}
} else if (priv->pshare->rf_ft_var.rf_mode == 2) {
if(MIMO_mode_switch(priv, MIMO_2T2R)) {
#if defined(WIFI_11N_2040_COEXIST_EXT)
if((priv->pshare->CurrentChannelBW == HT_CHANNEL_WIDTH_20) && (priv->pmib->dot11nConfigEntry.dot11nUse40M != HT_CHANNEL_WIDTH_20)) {
priv->pshare->CurrentChannelBW = priv->pmib->dot11nConfigEntry.dot11nUse40M;
SwBWMode(priv, priv->pshare->CurrentChannelBW, priv->pshare->offset_2nd_chan);
SwChnl(priv, priv->pmib->dot11RFEntry.dot11channel, priv->pshare->offset_2nd_chan);
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
update_RAMask_to_FW(priv, 1);
#endif
SetTxPowerLevel(priv);
}
#endif
}
} else if (priv->pshare->rf_ft_var.rf_mode == 1) {
MIMO_mode_switch(priv, MIMO_1T1R);
}
#ifdef CONFIG_PCI_HCI
end:
mod_timer(&priv->ps_timer, jiffies + IDLE_T0);
#endif
}
/*
* 92es sdio debug using GPIO 14 to trigger
*/
int switch_gpio14_mode(struct rtl8192cd_priv *priv, unsigned char *data)
{
int mode = _atoi(data, 16);
RTL_W32(0x4c, RTL_R32(0x4c) & ~BIT(22));
RTL_W32(0x60, RTL_R32(0x60) & ~BIT(30));
RTL_W32(0x60, RTL_R32(0x60) | BIT(22));
if ( mode == 0x01 ) {
RTL_W32(0x60, RTL_R32(0x60) | BIT(14));
printk("goip high\n");
} else if ( mode == 0x02) {
RTL_W32(0x60, RTL_R32(0x60) & ~BIT(14));
printk("goip low\n");
}
}
int assign_MIMO_TR_Mode(struct rtl8192cd_priv *priv, unsigned char *data)
{
#define dprintf printk
int mode = _atoi(data, 16);
if (strlen(data) == 0) {
printk("tr mode.\n");
printk("mimo 1: swith to 1T\n");
printk("mimo 2: switch to 2T\n");
printk("mimo 0: auto\n");
return 0;
}
if (mode == 0x01) {
MIMO_mode_switch(priv, MIMO_1T1R);
priv->pshare->rf_ft_var.rf_mode = 1;
} else if (mode == 0x02) {
MIMO_mode_switch(priv, MIMO_2T2R);
priv->pshare->rf_ft_var.rf_mode = 2;
} else {
priv->pshare->rf_ft_var.rf_mode = 0;
}
return 0;
}
#endif
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
struct list_head* asoc_list_get_next(struct rtl8192cd_priv *priv, struct list_head *plist)
{
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
struct list_head *phead, *plist_next;
struct stat_info *pstat;
phead = &priv->asoc_list;
SMP_LOCK_ASOC_LIST(flags);
plist_next = plist->next;
if (plist_next != phead) {
pstat = list_entry(plist_next, struct stat_info, asoc_list);
pstat->asoc_list_refcnt++;
#ifdef __ECOS
cyg_flag_maskbits(&pstat->asoc_unref_done, ~0x1);
#else
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0))
reinit_completion(&pstat->asoc_unref_done);
#else
INIT_COMPLETION(pstat->asoc_unref_done);
#endif
#endif
}
SMP_UNLOCK_ASOC_LIST(flags);
if (plist != phead) {
pstat = list_entry(plist, struct stat_info, asoc_list);
asoc_list_unref(priv, pstat);
}
return plist_next;
}
void asoc_list_unref(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
SMP_LOCK_ASOC_LIST(flags);
BUG_ON(0 == pstat->asoc_list_refcnt);
pstat->asoc_list_refcnt--;
if (0 == pstat->asoc_list_refcnt) {
list_del_init(&pstat->asoc_list);
#ifdef __ECOS
cyg_flag_setbits(&pstat->asoc_unref_done, 0x1);
#else
complete(&pstat->asoc_unref_done);
#endif
}
SMP_UNLOCK_ASOC_LIST(flags);
}
// The function returns whether it had linked to asoc_list before removing.
int asoc_list_del(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
int ret = 0, wait = 0;
#ifdef __KERNEL__
might_sleep();
#endif
SMP_LOCK_ASOC_LIST(flags);
if (0 != pstat->asoc_list_refcnt) {
pstat->asoc_list_refcnt--;
if (0 ==pstat->asoc_list_refcnt) {
// if (!list_empty(&pstat->asoc_list)) {
list_del_init(&pstat->asoc_list);
ret = 1;
// }
} else {
wait = 1;
}
}
SMP_UNLOCK_ASOC_LIST(flags);
if (wait) {
#ifdef __ECOS
cyg_flag_wait(&pstat->asoc_unref_done, 0x01, CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR);
#else
wait_for_completion(&pstat->asoc_unref_done);
#endif
ret = 1;
}
return ret;
}
int asoc_list_add(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
#ifdef SMP_SYNC
unsigned long flags = 0;
#endif
int ret = 0;
SMP_LOCK_ASOC_LIST(flags);
if (list_empty(&pstat->asoc_list)) {
list_add_tail(&pstat->asoc_list, &priv->asoc_list);
pstat->asoc_list_refcnt = 1;
ret = 1;
}
SMP_UNLOCK_ASOC_LIST(flags);
return ret;
}
#endif // CONFIG_USB_HCI || CONFIG_SDIO_HCI
#ifdef WIFI_SIMPLE_CONFIG
#define IGNORE_DISCON_TIMEOUT 3
void wsc_disconn_list_add(struct rtl8192cd_priv *priv, unsigned char *hwaddr)
{
struct wsc_disconn_entry *entry;
unsigned long flags;
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (NULL == entry)
return;
INIT_LIST_HEAD(&entry->list);
memcpy(entry->addr, hwaddr, MACADDRLEN);
entry->state = WSC_DISCON_STATE_RECV_EAP_FAIL;
entry->expire_to = IGNORE_DISCON_TIMEOUT;
spin_lock_irqsave(&priv->wsc_disconn_list_lock, flags);
list_add_tail(&entry->list, &priv->wsc_disconn_list);
spin_unlock_irqrestore(&priv->wsc_disconn_list_lock, flags);
}
void wsc_disconn_list_expire(struct rtl8192cd_priv *priv)
{
struct list_head *phead, *plist;
struct wsc_disconn_entry *entry;
unsigned long flags;
phead = &priv->wsc_disconn_list;
if (list_empty(phead))
return;
spin_lock_irqsave(&priv->wsc_disconn_list_lock, flags);
plist = phead->next;
while (plist != phead) {
entry = list_entry(plist, struct wsc_disconn_entry, list);
plist = plist->next;
entry->expire_to--;
if (0 == entry->expire_to) {
list_del(&entry->list);
kfree(entry);
}
}
spin_unlock_irqrestore(&priv->wsc_disconn_list_lock, flags);
}
void wsc_disconn_list_update(struct rtl8192cd_priv *priv, unsigned char *hwaddr)
{
struct list_head *phead, *plist;
struct wsc_disconn_entry *entry;
unsigned long flags;
phead = &priv->wsc_disconn_list;
if (list_empty(phead))
return;
spin_lock_irqsave(&priv->wsc_disconn_list_lock, flags);
plist = phead->next;
while (plist != phead) {
entry = list_entry(plist, struct wsc_disconn_entry, list);
plist = plist->next;
if (!memcmp(entry->addr, hwaddr, MACADDRLEN)) {
if (WSC_DISCON_STATE_RECV_EAP_FAIL == entry->state)
entry->state = WSC_DISCON_STATE_IGNORE;
break;
}
}
spin_unlock_irqrestore(&priv->wsc_disconn_list_lock, flags);
}
int wsc_disconn_list_check(struct rtl8192cd_priv *priv, unsigned char *hwaddr)
{
struct list_head *phead, *plist;
struct wsc_disconn_entry *entry;
unsigned long flags;
int status;
phead = &priv->wsc_disconn_list;
if (list_empty(phead))
return FALSE;
spin_lock_irqsave(&priv->wsc_disconn_list_lock, flags);
plist = phead->next;
while (plist != phead) {
entry = list_entry(plist, struct wsc_disconn_entry, list);
plist = plist->next;
if (!memcmp(entry->addr, hwaddr, MACADDRLEN)) {
list_del(&entry->list);
spin_unlock_irqrestore(&priv->wsc_disconn_list_lock, flags);
status = (WSC_DISCON_STATE_IGNORE == entry->state) ? TRUE : FALSE;
kfree(entry);
return status;
}
}
spin_unlock_irqrestore(&priv->wsc_disconn_list_lock, flags);
return FALSE;
}
void wsc_disconn_list_flush(struct rtl8192cd_priv *priv)
{
struct list_head *phead, *plist;
struct wsc_disconn_entry *entry;
unsigned long flags;
phead = &priv->wsc_disconn_list;
if (list_empty(phead))
return;
spin_lock_irqsave(&priv->wsc_disconn_list_lock, flags);
plist = phead->next;
while (plist != phead) {
entry = list_entry(plist, struct wsc_disconn_entry, list);
plist = plist->next;
kfree(entry);
}
spin_unlock_irqrestore(&priv->wsc_disconn_list_lock, flags);
}
#endif // WIFI_SIMPLE_CONFIG
//return value: Auto site-survey level
//0(SS_LV_WSTA), STA connect to root AP/VAP
//1(SS_LV_WOSTA), No STA connected to root AP/VAP
//2(SS_LV_ROOTFUNCOFF), root AP only and func_off=1
int get_ss_level(struct rtl8192cd_priv *priv)
{
int idx=0;
if( GET_ROOT(priv)->pmib->miscEntry.func_off ){
#ifdef MBSSID
if(GET_ROOT(priv)->pmib->miscEntry.vap_enable==0)
return SS_LV_ROOTFUNCOFF;
else{
for (idx=0; idx<RTL8192CD_NUM_VWLAN; idx++) {
if (IS_DRV_OPEN(GET_ROOT(priv)->pvap_priv[idx])&&
(GET_ROOT(priv)->pvap_priv[idx]->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) &&
(GET_ROOT(priv)->pvap_priv[idx]->assoc_num)){
return SS_LV_WSTA;
}
}
}
#else
return SS_LV_ROOTFUNCOFF;
#endif
}
else{
if((GET_ROOT(priv)->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) && GET_ROOT(priv)->assoc_num)
return SS_LV_WSTA;
#ifdef MBSSID
if(GET_ROOT(priv)->pmib->miscEntry.vap_enable==1) {
for (idx=0; idx<RTL8192CD_NUM_VWLAN; idx++) {
if (IS_DRV_OPEN(GET_ROOT(priv)->pvap_priv[idx])&&
(GET_ROOT(priv)->pvap_priv[idx]->pmib->dot11OperationEntry.opmode & WIFI_AP_STATE) &&
(GET_ROOT(priv)->pvap_priv[idx]->assoc_num))
{
return SS_LV_WSTA;
}
}
}
#endif
}
//default
return SS_LV_WOSTA;
}
void syncMulticastCipher(struct rtl8192cd_priv *priv, struct bss_desc *bss_target)
{
int mcipher = 1;
// set Multicast Cipher as same as AP's
if (priv->pmib->dot11RsnIE.rsnie[0] == _RSN_IE_1_) {
if(bss_target->t_stamp[0] & BIT(4))
mcipher = 4;
else if(bss_target->t_stamp[0] & BIT(2))
mcipher = 2;
priv->pmib->dot11RsnIE.rsnie[11] = mcipher;
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
priv->wpa_global_info->AuthInfoBuf[11] = mcipher;
#endif
} else if(priv->pmib->dot11RsnIE.rsnie[0] == _RSN_IE_2_) {
if(bss_target->t_stamp[0] & BIT(20))
mcipher = 4;
else if(bss_target->t_stamp[0] & BIT(18))
mcipher = 2;
priv->pmib->dot11RsnIE.rsnie[7] = mcipher;
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD) || defined(RTK_NL80211)
priv->wpa_global_info->AuthInfoBuf[7] = mcipher;
#ifdef CONFIG_IEEE80211W_CLI
if ((bss_target->t_stamp[1] & PMF_REQ) == PMF_REQ) {
PMFDEBUG("AP PMF capability = Required\n");
priv->support_pmf = TRUE;
} else if (bss_target->t_stamp[1] & PMF_CAP) {
PMFDEBUG("AP PMF capability = MFPC\n");
priv->support_pmf = TRUE;
} else {
priv->support_pmf = FALSE;
}
#endif
#endif
}
}
unsigned int isDHCPpkt(struct sk_buff *pskb)
{
#define DHCP_MAGIC 0x63825363
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
#if 0
__u16 check;
__u32 saddr;
__u32 daddr;
#endif
};
struct udphdr {
__u16 source;
__u16 dest;
__u16 len;
__u16 check;
};
struct dhcpMessage {
u_int8_t op;
u_int8_t htype;
u_int8_t hlen;
u_int8_t hops;
u_int32_t xid;
u_int16_t secs;
u_int16_t flags;
u_int32_t ciaddr;
u_int32_t yiaddr;
u_int32_t siaddr;
u_int32_t giaddr;
u_int8_t chaddr[16];
u_int8_t sname[64];
u_int8_t file[128];
u_int32_t cookie;
#if 0
u_int8_t options[308]; /* 312 - cookie */
#endif
};
unsigned short protocol = 0;
struct iphdr* iph;
struct udphdr *udph;
struct dhcpMessage *dhcph;
protocol = *((unsigned short *)(pskb->data + 2 * ETH_ALEN));
if(protocol == __constant_htons(ETH_P_IP)) { /* IP */
iph = (struct iphdr *)(pskb->data + ETH_HLEN);
if(iph->protocol == 17) { /* UDP */
udph = (struct udphdr *)((unsigned long)iph + (iph->ihl << 2));
dhcph = (struct dhcpMessage *)((unsigned long)udph + sizeof(struct udphdr));
if ((unsigned long)dhcph & 0x03) { //not 4-byte alignment
u_int32_t cookie;
char *pdhcphcookie;
char *pcookie = (char *)&cookie;
pdhcphcookie = (char *)&dhcph->cookie;
pcookie[0] = pdhcphcookie[0];
pcookie[1] = pdhcphcookie[1];
pcookie[2] = pdhcphcookie[2];
pcookie[3] = pdhcphcookie[3];
if(cookie == htonl(DHCP_MAGIC))
return TRUE;
}
else {
if(dhcph->cookie == htonl(DHCP_MAGIC))
return TRUE;
}
}
}
return FALSE;
}
#ifdef UNIVERSAL_REPEATER
#if defined (__ECOS) || defined(RTK_NL80211) || (defined(CONFIG_OPENWRT_SDK) && defined(__LINUX_3_10__))//wrt-dhcp //TBD //eric-sync ?? __LINUX_3_10__
int send_arp_response(struct rtl8192cd_priv *priv, unsigned int *dip, unsigned int *sip, unsigned char *dmac, unsigned char *smac)
{
return -1;
}
#else
int send_arp_response(struct rtl8192cd_priv *priv, unsigned int *dip, unsigned int *sip, unsigned char *dmac, unsigned char *smac)
{
unsigned int ret = -1;
struct sk_buff *arp_skb = NULL;
struct rtl_arphdr *arp=NULL;
unsigned char *ptr;
int hlen, tlen;
hlen = LL_RESERVED_SPACE(priv->dev);
tlen = priv->dev->needed_tailroom;
arp_skb = __alloc_skb(arp_hdr_len(priv->dev) + hlen + tlen, GFP_ATOMIC, 0, -1);
if (arp_skb == NULL)
goto err_out;
skb_reserve(arp_skb, LL_RESERVED_SPACE(priv->dev));
skb_reset_network_header(arp_skb);
arp = (struct rtl_arphdr *) skb_put(arp_skb, arp_hdr_len(priv->dev));
arp_skb->dev = priv->dev;
arp_skb->protocol = htons(ETH_P_ARP);
#if 0
//without consideration of VLAN
//#ifdef CONFIG_RTK_VLAN_SUPPORT
arp_skb->tag = arp_tag;
#if defined(CONFIG_RTK_VLAN_NEW_FEATURE)
arp_skb->src_info = arp_info;
#endif
#endif
if (dev_hard_header(arp_skb, priv->dev, ETH_P_ARP, dmac, smac, arp_skb->len) < 0) {
kfree_skb(arp_skb);
goto err_out;
}
// ======================
// build new arp response
// ======================
//arp response
ptr = (unsigned char *)(arp + 1);
arp->ar_op = htons(ARPOP_REPLY);
arp->ar_hrd = htons(priv->dev->type);
arp->ar_pro = htons(ETH_P_IP);
arp->ar_hln = priv->dev->addr_len;;
arp->ar_pln = 4; //for ipv4
//sender mac and ip
memcpy(ptr, smac, 6);
ptr += arp->ar_hln;
memcpy(ptr, sip, 4);
//printk("sender mac and ip:%02x:%02x:%02x:%02x:%02x:%02x,%d.%d.%d.%d\n",pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5],pstat->sta_ip[0],pstat->sta_ip[1],pstat->sta_ip[2],pstat->sta_ip[3]);
//target mac and ip
ptr += arp->ar_pln;
memcpy(ptr, dmac, MACADDRLEN);
ptr += arp->ar_hln;
memcpy(ptr, dip, 4);
//printk("target mac and ip:%02x:%02x:%02x:%02x:%02x:%02x,%d.%d.%d.%d\n",newskb->data[0],newskb->data[1],newskb->data[2],newskb->data[3],newskb->data[4],newskb->data[5],ptarget[0],ptarget[1],ptarget[2],ptarget[3]);
#ifdef MULTI_MAC_CLONE
*(unsigned int *)&(arp_skb->cb[40]) = 0x86518192;
#endif
if(arp_skb){
int i=0;
arp_skb->cb[2] = (char)0xff; // not do aggregation
memcpy(arp_skb->cb+10,arp_skb->data,6);
SMP_LOCK_XMIT(x);
if(__rtl8192cd_start_xmit(arp_skb, priv->dev, 1)) {
DEBUG_ERR("%s %d ARP response sent failed\n",__func__,__LINE__);
} else {
ret = 0;
DEBUG_INFO("%s %d ARP response for %02x:%02x:%02x:%02x:%02x:%02x to %s sent\n",__func__,__LINE__,
smac[0],smac[1],smac[2],smac[3],smac[4],smac[5],priv->dev->name);
for(i=0;i<arp_skb->len;i++){
DEBUG_INFO("%02x",arp_skb->data[i]);
if(i/16 && ((i%16) == 0))
DEBUG_INFO("\n");
}
DEBUG_INFO("\n");
}
SMP_UNLOCK_XMIT(x);
} else {
DEBUG_ERR("%s %d Alloc skb failed\n",__func__,__LINE__);
}
return ret;
err_out:
return ret;
}
#endif
void snoop_STA_IP(struct sk_buff *pskb, struct rtl8192cd_priv *priv)
{
#define DHCP_MAGIC 0x63825363
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
#if 0
__u16 check;
__u32 saddr;
__u32 daddr;
#endif
};
struct udphdr {
__u16 source;
__u16 dest;
__u16 len;
__u16 check;
};
struct dhcpMessage {
u_int8_t op;
u_int8_t htype;
u_int8_t hlen;
u_int8_t hops;
u_int32_t xid;
u_int16_t secs;
u_int16_t flags;
u_int32_t ciaddr;
u_int32_t yiaddr;
u_int32_t siaddr;
u_int32_t giaddr;
u_int8_t chaddr[16];
u_int8_t sname[64];
u_int8_t file[128];
u_int32_t cookie;
#if 0
u_int8_t options[308]; /* 312 - cookie */
#endif
};
struct rtl8192cd_priv *ap_priv;
struct stat_info *pstat;
struct iphdr* iph;
struct udphdr *udph;
struct dhcpMessage *dhcph;
struct list_head *phead, *plist;
iph = (struct iphdr *)(pskb->data + ETH_HLEN);
udph = (struct udphdr *)((unsigned int)iph + (iph->ihl << 2));
dhcph = (struct dhcpMessage *)((unsigned int)udph + sizeof(struct udphdr));
if(IS_VXD_INTERFACE(priv)) {
ap_priv = GET_ROOT(priv);
} else {
DEBUG_INFO("Receive DHCP response but interface is not VXD\n");
return ;
}
//dhcp reply only
if(ap_priv && IS_DRV_OPEN(ap_priv) && (dhcph->op == 2)) {
unsigned char sta_ip[4];
memcpy(sta_ip,&dhcph->yiaddr,4);
DEBUG_INFO("[%s]External DHCP Server give IP[%d.%d.%d.%d]\n",priv->dev->name,sta_ip[0],sta_ip[1],sta_ip[2],sta_ip[3]);
if( send_arp_response(priv,&dhcph->siaddr,&dhcph->yiaddr,pskb->data+MACADDRLEN,&dhcph->chaddr[0]) )
DEBUG_ERR("Send ARP failed\n");
return;
}
}
#endif //UNIVERSAL_REPEATER
/* Do defered channel scan when,
1.There is not any station connected to active AP interafce(Root AP/VAP)
2.Scan is not requested by wscd
3.Scan is not requested by Station mode without any VAP
*/
int should_defer_ss(struct rtl8192cd_priv *priv)
{
int ret=0;
if(GET_ROOT(priv)->pmib->dot11OperationEntry.opmode & (WIFI_STATION_STATE|WIFI_ADHOC_STATE)) {
ret = 0;
} else {
if(get_ss_level(priv) < SS_LV_ROOTFUNCOFF) {
if((priv->site_survey->ss_channel == 100) && (priv->pmib->miscEntry.ss_delay)) {
ret=1;
DEBUG_INFO("%s Sitesurvey defered\n",priv->dev->name);
}
}
}
if(priv->ss_req_ongoing == SSFROM_WSC)
ret = 0;
return ret;
}
#ifdef RTK_NL80211
void copy_wps_ie(struct rtl8192cd_priv *priv, unsigned char *wps_ie, unsigned char mgmt_type)
{
/*T(1) L(1) V , wps_ie[1]==L => LEN = value of (L) + sizeof(T)+sizeof(L), cy wang note*/
unsigned int wps_ie_len = (wps_ie[1] + 2);
if(wps_ie_len > 256){
NDEBUG2("WPS_IE length > 256 !! Can NOT copy !!\n");
return;
}
if(OPMODE & WIFI_AP_STATE)
priv->pmib->wscEntry.wsc_enable = 2; //Enable WPS for AP mode
else if(OPMODE & WIFI_STATION_STATE)
priv->pmib->wscEntry.wsc_enable = 1;
if (mgmt_type == MGMT_BEACON) {
NDEBUG2("WSC:Set Beacon IE[%d]\n",wps_ie_len);
priv->pmib->wscEntry.beacon_ielen = wps_ie_len;
memcpy((void *)priv->pmib->wscEntry.beacon_ie, wps_ie, wps_ie_len);
}
else if (mgmt_type == MGMT_PROBERSP) {
NDEBUG2("WSC:Set Probe Rsp IE[%d]\n",wps_ie_len);
priv->pmib->wscEntry.probe_rsp_ielen = wps_ie_len;
memcpy((void *)priv->pmib->wscEntry.probe_rsp_ie, wps_ie, wps_ie_len);
}
else if (mgmt_type == MGMT_PROBEREQ) {
NDEBUG2("WSC:Set Probe Req IE[%d]\n",wps_ie_len);
priv->pmib->wscEntry.probe_req_ielen= wps_ie_len;
memcpy((void *)priv->pmib->wscEntry.probe_req_ie, wps_ie, wps_ie_len);
}
else if ((mgmt_type == MGMT_ASSOCRSP) || (mgmt_type == MGMT_ASSOCREQ)) { //wrt-wps-clnt
NDEBUG2("WSC:Set Assoc IE[%d]\n",wps_ie_len);
priv->pmib->wscEntry.assoc_ielen = wps_ie_len;
memcpy((void *)priv->pmib->wscEntry.assoc_ie, wps_ie, wps_ie_len);
}
}
/**
* rtk_get_wps_ie - Search WPS IE from a series of IEs
* @in_ie: Address of IEs to search
* @in_len: Length limit from in_ie
* @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
* @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
*
* Returns: The address of the WPS IE found, or NULL
*/
u8* rtk_get_wps_ie(u8 *in_ie, int in_len, u8 *wps_ie, int *wps_ielen)
{
int cnt=0;
u8 eid=0;
u8 *wpsie_ptr=NULL;
u8 WSC_OUI[4] = {0x00, 0x50, 0xf2, 0x04};
if(wps_ielen){
*wps_ielen = 0;
}
if(!in_ie || in_len<=0)
return wpsie_ptr;
while(cnt<in_len)
{
eid = in_ie[cnt];
if((eid==_VENDOR_SPECIFIC_IE_)&&( !memcmp(&in_ie[cnt+2], WSC_OUI, 4)))
{
wpsie_ptr = &in_ie[cnt];
if(wps_ie){
memcpy(wps_ie, &in_ie[cnt], in_ie[cnt+1]+2);
}
if(wps_ielen){
*wps_ielen = in_ie[cnt+1]+2;
}
cnt+=in_ie[cnt+1]+2;
break;
}
else
{
cnt+=in_ie[cnt+1]+2; //goto next
}
}
return wpsie_ptr;
}
#endif
#ifdef USE_OUT_SRC
unsigned char *Get_Adaptivity_Version(void)
{
return ADAPTIVITY_VERSION;
}
#endif
#if defined(CONFIG_RTL_SIMPLE_CONFIG)
int rtk_sc_start_simple_config(struct rtl8192cd_priv *priv)
{
int i=0;
unsigned char null_mac[]={0,0,0,0,0,0};
#if defined(__ECOS)
#ifdef UNIVERSAL_REPEATER
if(IS_VXD_INTERFACE(priv))
sprintf(g_sc_ifname, "%s0", priv->dev->name);
else
#endif
#endif
strcpy(g_sc_ifname, priv->dev->name);
rtk_sc_set_para(priv);
if(priv->pmib->dot11StationConfigEntry.sc_debug)
panic_printk("Start simple config now!\n");
rtk_sc_clean_profile_value();
#if 0 //eric-sc
{
if(priv->pmib->dot11StationConfigEntry.sc_debug)
panic_printk("\nFORCE ENABLE LDPC FOR SIMPLE CONFIG!!\n\n");
RTL_W8(0x913, RTL_R8(0x913)|0x02);
}
#endif
priv->simple_config_could_fix = 0;
rtk_sc_set_value(SC_FIX_CHANNEL, 0);
#ifdef UNIVERSAL_REPEATER
if(IS_VXD_INTERFACE(priv))
{
if(priv->simple_config_status == 0)
memcpy(priv->pmib->dot11Bss.bssid, null_mac, MACADDRLEN);
}
#endif
if(priv->simple_config_status == 0)
priv->simple_config_status = 1;
priv->pmib->dot11StationConfigEntry.sc_status = 1;
priv->pmib->dot11StationConfigEntry.sc_vxd_rescan_time = CHECK_VXD_SC_TIMEOUT;
RTL_W32(RCR, RTL_R32(RCR) | RCR_AAP); //Accept Destination Address packets.
return 0;
}
int rtk_sc_start_connect_target(struct rtl8192cd_priv *priv)
{
int i=0;
if(priv->pmib->dot11StationConfigEntry.sc_fix_channel >= 0)
priv->pmib->dot11StationConfigEntry.sc_fix_channel = 0;
if(priv->pmib->dot11StationConfigEntry.sc_reset_beacon_psk == 1)
{
#if defined(INCLUDE_WPA_PSK) || defined(WIFI_HAPD)
if (priv->pmib->dot1180211AuthEntry.dot11EnablePSK) {
watchdog_stop(priv);
psk_init(priv);
watchdog_resume(priv);
}
#endif
if( (priv->pmib->dot11StationConfigEntry.sc_sync_vxd_to_root == 1) && IS_VXD_INTERFACE(priv))
{
watchdog_stop(GET_ROOT(priv));
if (GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11EnablePSK) {
psk_init(GET_ROOT(priv));
}
init_beacon(GET_ROOT(priv));
watchdog_resume(GET_ROOT(priv));
}
}
else
{
#ifdef UNIVERSAL_REPEATER
if(IS_VXD_INTERFACE(priv))
{
#ifdef MBSSID
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable) {
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
if (IS_DRV_OPEN(priv->pvap_priv[i]))
priv->pvap_priv[i]->pmib->dot11OperationEntry.keep_rsnie = 1;
}
}
#endif
}
#endif
RTL_W32(RCR, RTL_R32(RCR) & ~RCR_AAP); // Disable Accept Destination Address packets.
#ifdef CONFIG_RTL_8198C
/* rtl8192cd_ss_timer-->start_clnt_lookup-->rtk_sc_check_security-->rtk_sc_start_connect_target
* ss_timer call SMP_LOCK, so we should call unlock before close interface
*/
unsigned long flags;
SMP_UNLOCK(flags);
#endif
if(priv->pmib->dot11StationConfigEntry.sc_fix_channel > 0)
priv->pmib->dot11StationConfigEntry.sc_fix_channel = 0;
RTL_W8(TXPAUSE, 0xff);
rtl8192cd_close(priv->dev);
#ifdef UNIVERSAL_REPEATER
if( (priv->pmib->dot11StationConfigEntry.sc_sync_vxd_to_root == 1) && IS_VXD_INTERFACE(priv))
{
GET_ROOT(priv)->pmib->dot11StationConfigEntry.sc_enabled = 0;
rtl8192cd_close(GET_ROOT(priv)->dev);
rtl8192cd_open(GET_ROOT(priv)->dev);
while(!netif_running(GET_ROOT(priv)->dev))
delay_ms(10);
}
#endif
rtl8192cd_open(priv->dev);
RTL_W8(TXPAUSE, 0x00);
#ifdef CONFIG_RTL_8198C
SMP_LOCK(flags);
#endif
}
rtk_sc_set_value(SC_PRIV_STATUS, 5);
rtk_sc_set_value(SC_STATUS, 5);
return 0;
}
#ifdef UNIVERSAL_REPEATER
int rtk_sc_sync_vxd_to_root(struct rtl8192cd_priv * priv)
{
if(IS_VXD_INTERFACE(priv))
{
if(priv->pmib->dot11StationConfigEntry.sc_sync_vxd_to_root == 1)
{
GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11AuthAlgrthm = priv->pmib->dot1180211AuthEntry.dot11AuthAlgrthm;
GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm = priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm;
GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11EnablePSK = priv->pmib->dot1180211AuthEntry.dot11EnablePSK;
GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11PrivacyKeyIndex = priv->pmib->dot1180211AuthEntry.dot11PrivacyKeyIndex;
GET_ROOT(priv)->pmib->dot118021xAuthEntry.dot118021xAlgrthm = priv->pmib->dot118021xAuthEntry.dot118021xAlgrthm;
GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11WPA2Cipher = priv->pmib->dot1180211AuthEntry.dot11WPA2Cipher;
GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11WPACipher = priv->pmib->dot1180211AuthEntry.dot11WPACipher;
strcpy(GET_ROOT(priv)->pmib->dot1180211AuthEntry.dot11PassPhrase, priv->pmib->dot1180211AuthEntry.dot11PassPhrase);
strcpy(&(GET_ROOT(priv)->pmib->dot11DefaultKeysTable.keytype[0]), &(priv->pmib->dot11DefaultKeysTable.keytype[0]));
strcpy(GET_ROOT(priv)->pmib->dot11StationConfigEntry.dot11DesiredSSID, priv->pmib->dot11StationConfigEntry.dot11DesiredSSID);
strcpy(GET_ROOT(priv)->pmib->dot11StationConfigEntry.dot11SSIDtoScan, priv->pmib->dot11StationConfigEntry.dot11SSIDtoScan);
GET_ROOT(priv)->pmib->dot11StationConfigEntry.dot11DesiredSSIDLen= priv->pmib->dot11StationConfigEntry.dot11DesiredSSIDLen;
GET_ROOT(priv)->pmib->dot11StationConfigEntry.dot11SSIDtoScanLen= priv->pmib->dot11StationConfigEntry.dot11SSIDtoScanLen;
}
}
return 0;
}
#else
int rtk_sc_sync_vxd_to_root(struct rtl8192cd_priv * priv)
{
return 0;
}
#endif
int rtk_sc_stop_simple_config(struct rtl8192cd_priv *priv)
{
int i=0, ack_num=0;
int sc_security_type = priv->pmib->dot11StationConfigEntry.sc_security_type;
if (OPMODE & WIFI_ASOC_STATE)
{
rtk_sc_set_value(SC_ENABLED, 0);
rtk_sc_set_value(SC_PRIV_STATUS, 0);
rtk_sc_set_value(SC_STATUS, 10+sc_security_type);
}
else
rtk_sc_set_value(SC_STATUS, -1);
rtk_sc_set_value(SC_FIX_CHANNEL, 0);
return 0;
}
struct net_device * rtl_get_dev_by_wlan_name(char *name)
{
#if defined(__ECOS)
return rtl_getDevByName(name);
#else
return __dev_get_by_name(&init_net, name);
#endif
}
int rtk_sc_set_value(unsigned int id, unsigned int value)
{
struct net_device *dev;
dev=rtl_get_dev_by_wlan_name(g_sc_ifname);
struct rtl8192cd_priv *priv = GET_DEV_PRIV(dev);
switch(id)
{
case SC_ENABLED:
priv->pmib->dot11StationConfigEntry.sc_enabled = value;
break;
case SC_DURATION_TIME:
priv->pmib->dot11StationConfigEntry.sc_duration_time = value;
break;
case SC_GET_SYNC_TIME:
priv->pmib->dot11StationConfigEntry.sc_get_sync_time = value;
break;
case SC_GET_PROFILE_TIME:
priv->pmib->dot11StationConfigEntry.sc_get_profile_time = value;
break;
case SC_VXD_RESCAN_TIME:
priv->pmib->dot11StationConfigEntry.sc_vxd_rescan_time = value;
break;
case SC_PIN_ENABLED:
priv->pmib->dot11StationConfigEntry.sc_pin_enabled = value;
break;
case SC_STATUS:
priv->pmib->dot11StationConfigEntry.sc_status = value;
break;
case SC_DEBUG:
priv->pmib->dot11StationConfigEntry.sc_debug = value;
break;
case SC_CHECK_LINK_TIME:
priv->pmib->dot11StationConfigEntry.sc_check_link_time = value;
break;
case SC_SYNC_VXD_TO_ROOT:
priv->pmib->dot11StationConfigEntry.sc_sync_vxd_to_root = value;
break;
case SC_ACK_ROUND:
priv->pmib->dot11StationConfigEntry.sc_ack_round = value;
break;
case SC_CONTROL_IP:
priv->pmib->dot11StationConfigEntry.sc_control_ip = value;
break;
case SC_PRIV_STATUS:
priv->simple_config_status = value;
break;
case SC_CONFIG_TIME:
priv->simple_config_time = value;
break;
case SC_FIX_CHANNEL:
if(priv->pmib->dot11StationConfigEntry.sc_fix_channel >= 0){
if ( (value > 0) && priv->simple_config_could_fix)
priv->pmib->dot11StationConfigEntry.sc_fix_channel = value;
else
priv->pmib->dot11StationConfigEntry.sc_fix_channel = value;
}
break;
case SC_FROM_TO_DS:
if(value == 2)
{
if(priv->pmib->dot11StationConfigEntry.sc_debug)
panic_printk("receive fromDS is 0, toDS is 1 packet\n");
priv->pmib->dot11StationConfigEntry.sc_get_sync_time = 120;
}
else if(value == 1)
{
if(priv->pmib->dot11StationConfigEntry.sc_debug)
panic_printk("receive fromDS is 1, toDS is 0 packet\n");
}
#if 0
if(priv->site_survey->ss_channel > 14 && priv->pmib->dot11StationConfigEntry.sc_fix_channel>=0)
{
priv->pmib->dot11StationConfigEntry.sc_fix_channel = PHY_QueryRFReg(priv,RF92CD_PATH_A,0x18,0xff,1);
if(priv->pmib->dot11StationConfigEntry.sc_debug)
panic_printk("Simple Config 5G switch to remote AP channel(center) %d\n", priv->pmib->dot11StationConfigEntry.sc_fix_channel );
}
#endif
break;
default:
break;
}
return 0;
}
int rtk_sc_get_value(unsigned int id)
{
struct net_device *dev;
int value=0;
dev=rtl_get_dev_by_wlan_name(g_sc_ifname);
struct rtl8192cd_priv *priv = GET_DEV_PRIV(dev);
switch(id)
{
case SC_ENABLED:
value = priv->pmib->dot11StationConfigEntry.sc_enabled;
break;
case SC_DURATION_TIME:
value = priv->pmib->dot11StationConfigEntry.sc_duration_time;
break;
case SC_GET_SYNC_TIME:
value = priv->pmib->dot11StationConfigEntry.sc_get_sync_time;
break;
case SC_GET_PROFILE_TIME:
value = priv->pmib->dot11StationConfigEntry.sc_get_profile_time;
break;
case SC_VXD_RESCAN_TIME:
value = priv->pmib->dot11StationConfigEntry.sc_vxd_rescan_time;
break;
case SC_PIN_ENABLED:
value = priv->pmib->dot11StationConfigEntry.sc_pin_enabled;
break;
case SC_STATUS:
value = priv->pmib->dot11StationConfigEntry.sc_status;
break;
case SC_DEBUG:
value = priv->pmib->dot11StationConfigEntry.sc_debug;
break;
case SC_CHECK_LINK_TIME:
value = priv->pmib->dot11StationConfigEntry.sc_check_link_time;
break;
case SC_SYNC_VXD_TO_ROOT:
value = priv->pmib->dot11StationConfigEntry.sc_sync_vxd_to_root;
break;
case SC_ACK_ROUND:
value = priv->pmib->dot11StationConfigEntry.sc_ack_round;
break;
case SC_CONTROL_IP:
value = priv->pmib->dot11StationConfigEntry.sc_control_ip;
break;
case SC_PRIV_STATUS:
value = priv->simple_config_status;
break;
case SC_CONFIG_TIME:
value = priv->simple_config_time;
break;
case SC_CHECK_LEVEL:
value = priv->pmib->dot11StationConfigEntry.sc_check_level;
break;
case SC_IGNORE_OVERLAP:
value = priv->pmib->dot11StationConfigEntry.sc_ignore_overlap;
break;
case SC_FIX_CHANNEL:
value = priv->pmib->dot11StationConfigEntry.sc_fix_channel;
default:
break;
}
return value;
}
int rtk_sc_set_string_value(unsigned int id, unsigned char *value)
{
struct net_device *dev;
int i=0;
dev=rtl_get_dev_by_wlan_name(g_sc_ifname);
struct rtl8192cd_priv *priv = GET_DEV_PRIV(dev);
switch(id)
{
case SC_PIN:
strcpy(priv->pmib->dot11StationConfigEntry.sc_pin, value);
break;
case SC_DEFAULT_PIN:
strcpy(priv->pmib->dot11StationConfigEntry.sc_default_pin, value);
break;
case SC_PASSWORD:
strcpy(priv->pmib->dot11StationConfigEntry.sc_passwd, value);
break;
case SC_DEVICE_NAME:
strcpy(priv->pmib->dot11StationConfigEntry.sc_device_name, value);
break;
case SC_DEVICE_TYPE:
strcpy(priv->pmib->dot11StationConfigEntry.sc_device_type, value);
break;
case SC_SSID:
strcpy(priv->pmib->dot11StationConfigEntry.dot11DesiredSSID, value);
strcpy(priv->pmib->dot11StationConfigEntry.dot11SSIDtoScan, value);
priv->pmib->dot11StationConfigEntry.dot11DesiredSSIDLen= strlen(value);
priv->pmib->dot11StationConfigEntry.dot11SSIDtoScanLen= strlen(value);
break;
case SC_BSSID:
for(i=0; i<6; i++)
{
priv->pmib->dot11StationConfigEntry.dot11DesiredBssid[i] = value[i];
}
break;
default:
panic_printk("RTL Simple Config don't support this mib setting now!\n");
}
return 0;
}
int rtk_sc_get_string_value(unsigned int id, unsigned char *value)
{
struct net_device *dev;
dev=rtl_get_dev_by_wlan_name(g_sc_ifname);
struct rtl8192cd_priv *priv = GET_DEV_PRIV(dev);
switch(id)
{
case SC_PIN:
strcpy(value, priv->pmib->dot11StationConfigEntry.sc_pin);
break;
case SC_DEFAULT_PIN:
strcpy(value, priv->pmib->dot11StationConfigEntry.sc_default_pin);
break;
case SC_PASSWORD:
strcpy(value, priv->pmib->dot11StationConfigEntry.sc_passwd);
break;
case SC_DEVICE_NAME:
strcpy(value, priv->pmib->dot11StationConfigEntry.sc_device_name);
break;
case SC_DEVICE_TYPE:
strcpy(value, priv->pmib->dot11StationConfigEntry.sc_device_type);
break;
default:
panic_printk("RTL Simple Config don't support this mib setting now!\n");
break;
}
return 0;
}
int set_wep_key(struct rtl8192cd_priv *priv, int type)
{
int i, length;
unsigned char value;
unsigned char wep_key[26]={0};
if(type == 0)
length=10;
else if(type == 1)
length=26;
for(i=0; i<length; i++)
{
value = priv->pmib->dot11StationConfigEntry.sc_passwd[i];
if((value >=0x30) && (value <=0x39))
value -= 0x30;
else if((value >= 'a')&&(value <= 'z'))
value -= 0x57;
else if((value >= 'A')&&(value <= 'Z'))
value -= 0x37;
value &= 0xf;
if(i%2 == 0)
wep_key[i/2] = value<<4;
else
wep_key[i/2] += value;
}
memcpy(&(GET_MIB(priv)->dot11DefaultKeysTable.keytype[0]), wep_key, length/2);
}
int rtk_sc_check_security(struct rtl8192cd_priv * priv,struct bss_desc * bss)
{
int length=0, i=0;
int status = rtk_sc_get_value(SC_STATUS);
length = strlen(priv->pmib->dot11StationConfigEntry.sc_passwd);
if ((bss->capability&BIT(4)) == 0)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11AuthAlgrthm = 0;
GET_MIB(priv)->dot1180211AuthEntry.dot11PrivacyAlgrthm=_NO_PRIVACY_;
GET_MIB(priv)->dot1180211AuthEntry.dot11EnablePSK = 0;
rtk_sc_set_value(SC_CHECK_LINK_TIME, 2);
GET_MIB(priv)->dot11StationConfigEntry.sc_security_type= 0;
GET_MIB(priv)->dot11RsnIE.rsnielen = 0;
GET_MIB(priv)->dot118021xAuthEntry.dot118021xAlgrthm= 0;
}
else if((bss->capability&BIT(4)))
{
if(bss->t_stamp[0] == 0)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11EnablePSK = 0;
if((length == 5) || (length == 10))
{
GET_MIB(priv)->dot1180211AuthEntry.dot11PrivacyAlgrthm = _WEP_40_PRIVACY_;
if(length == 5)
{
memcpy(&(GET_MIB(priv)->dot11DefaultKeysTable.keytype[0]), priv->pmib->dot11StationConfigEntry.sc_passwd, 5);
priv->pmib->dot11StationConfigEntry.sc_security_type= 1;
}
else if(length == 10)
{
set_wep_key(priv, 0);
priv->pmib->dot11StationConfigEntry.sc_security_type= 2;
}
GET_MIB(priv)->dot1180211AuthEntry.dot11PrivacyKeyIndex = 0;
}
else if((length == 13) || (length == 26))
{
GET_MIB(priv)->dot1180211AuthEntry.dot11PrivacyAlgrthm = _WEP_104_PRIVACY_;
if(length == 13)
{
memcpy(&(GET_MIB(priv)->dot11DefaultKeysTable.keytype[0]), priv->pmib->dot11StationConfigEntry.sc_passwd, 13);
priv->pmib->dot11StationConfigEntry.sc_security_type= 3;
}
else
{
set_wep_key(priv, 1);
priv->pmib->dot11StationConfigEntry.sc_security_type= 4;
}
GET_MIB(priv)->dot1180211AuthEntry.dot11PrivacyKeyIndex = 0;
}
GET_MIB(priv)->dot11RsnIE.rsnielen = 0;
GET_MIB(priv)->dot118021xAuthEntry.dot118021xAlgrthm= 0;
rtk_sc_set_value(SC_CHECK_LINK_TIME, 2);
}
else
{
GET_MIB(priv)->dot1180211AuthEntry.dot11AuthAlgrthm = 2;
GET_MIB(priv)->dot1180211AuthEntry.dot11PrivacyAlgrthm = 2;
strcpy((char *)GET_MIB(priv)->dot1180211AuthEntry.dot11PassPhrase, priv->pmib->dot11StationConfigEntry.sc_passwd);
if(bss->t_stamp[0] & 0xffff0000)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11EnablePSK = 2;
if(((bss->t_stamp[0] & 0xf0000000) >> 28) == 0x4)
{
GET_MIB(priv)->dot118021xAuthEntry.dot118021xAlgrthm = 1;
}
if(((bss->t_stamp[0] & 0x0f000000) >> 24) == 0x5)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11WPA2Cipher = 8;
priv->pmib->dot11StationConfigEntry.sc_security_type= 5;
}
else if(((bss->t_stamp[0] & 0x0f000000) >> 24) == 0x4)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11WPA2Cipher = 8;
priv->pmib->dot11StationConfigEntry.sc_security_type= 5;
}
else if(((bss->t_stamp[0] & 0x0f000000) >> 24) == 0x1)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11WPA2Cipher = 2;
priv->pmib->dot11StationConfigEntry.sc_security_type= 6;
}
}
else if(bss->t_stamp[0] & 0x0000ffff)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11EnablePSK = 1;
if(((bss->t_stamp[0] & 0x0000f000) >> 12) == 0x4)
{
GET_MIB(priv)->dot118021xAuthEntry.dot118021xAlgrthm = 0;
}
if(((bss->t_stamp[0] & 0x00000f00) >> 8) == 0x5)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11WPACipher = 8;
priv->pmib->dot11StationConfigEntry.sc_security_type= 7;
}
else if(((bss->t_stamp[0] & 0x00000f00) >> 8) == 0x4)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11WPACipher = 8;
priv->pmib->dot11StationConfigEntry.sc_security_type= 7;
}
else if(((bss->t_stamp[0] & 0x00000f00) >> 8) == 0x1)
{
GET_MIB(priv)->dot1180211AuthEntry.dot11WPACipher = 2;
priv->pmib->dot11StationConfigEntry.sc_security_type= 8;
}
}
}
}
if(status == 3)
{
rtk_sc_set_value(SC_PRIV_STATUS, 4);
rtk_sc_set_value(SC_STATUS, 4);
}
rtk_sc_sync_vxd_to_root(priv);
rtk_sc_set_value(SC_CONFIG_TIME, 0);
rtk_sc_start_connect_target(priv);
return 0;
}
int rtk_sc_get_magic(unsigned int *magic, unsigned int len)
{
int i=0;
unsigned int magic_num[32] = {60, 62, 68, 70, 76, 78, 80, 82};
for(i=0; i<len; i++)
magic[i] = magic_num[i];
return 0;
}
int rtk_sc_is_channel_fixed(struct rtl8192cd_priv * priv)
{
struct rtl8192cd_priv * priv_root = GET_ROOT(priv);
if(priv->pmib->dot11StationConfigEntry.sc_enabled == 1 && priv->simple_config_could_fix == 1) {
if(priv->pmib->dot11StationConfigEntry.sc_fix_channel > 0)
return 1;
else if((priv->pmib->dot11StationConfigEntry.sc_fix_channel < 0)
&& (priv->pmib->dot11StationConfigEntry.sc_status == 2 || priv->pmib->dot11StationConfigEntry.sc_status == 3)
)
return 1;
}
#ifdef UNIVERSAL_REPEATER
if(IS_DRV_OPEN(GET_VXD_PRIV(priv_root))&&
GET_VXD_PRIV(priv_root)->pmib->dot11StationConfigEntry.sc_enabled && priv->simple_config_could_fix == 1) {
if(GET_VXD_PRIV(priv_root)->pmib->dot11StationConfigEntry.sc_fix_channel > 0)
return 1;
else if((GET_VXD_PRIV(priv_root)->pmib->dot11StationConfigEntry.sc_fix_channel < 0) &&
(GET_VXD_PRIV(priv_root)->pmib->dot11StationConfigEntry.sc_status == 2
|| GET_VXD_PRIV(priv_root)->pmib->dot11StationConfigEntry.sc_status == 3)
)
return 1;
}
#endif
return 0;
}
int rtk_sc_get_scan_offset(struct rtl8192cd_priv * priv, int channel, int bw)
{
int scan_offset = HT_2NDCH_OFFSET_DONTCARE;
if(bw) {
if(channel >= 36) {
if((channel>144) ? ((channel-1)%8) : (channel%8))
scan_offset = HT_2NDCH_OFFSET_ABOVE;
else
scan_offset = HT_2NDCH_OFFSET_BELOW;
} else {
if(channel < 5)
scan_offset = HT_2NDCH_OFFSET_ABOVE;
else if(channel > 9)
scan_offset = HT_2NDCH_OFFSET_BELOW;
else {
if(GET_ROOT(priv)->pshare->offset_2nd_chan == HT_2NDCH_OFFSET_ABOVE)
scan_offset = HT_2NDCH_OFFSET_BELOW;
else
scan_offset = HT_2NDCH_OFFSET_ABOVE;
}
}
}
return scan_offset;
}
int rtk_sc_during_simple_config_scan(struct rtl8192cd_priv * priv)
{
struct rtl8192cd_priv * priv_root = GET_ROOT(priv);
if(priv->pmib->dot11StationConfigEntry.sc_enabled == 1) {
if(priv->simple_config_status == 1)
return 1;
}
#ifdef UNIVERSAL_REPEATER
if(IS_DRV_OPEN(GET_VXD_PRIV(priv_root))&&
GET_VXD_PRIV(priv_root)->pmib->dot11StationConfigEntry.sc_enabled) {
if(GET_VXD_PRIV(priv_root)->simple_config_status == 1)
return 1;
}
#endif
return 0;
}
#endif