blob: 0029b2d73b706333f4a23fe96a5b303ae7aa21f6 [file] [log] [blame]
/*
*************************************************************************
* Ralink Tech Inc.
* 5F., No.36, Taiyuan St., Jhubei City,
* Hsinchu County 302,
* Taiwan, R.O.C.
*
* (c) Copyright 2002-2007, Ralink Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
*************************************************************************
*/
#include <linux/firmware.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include "rt_config.h"
unsigned long RTDebugLevel = RT_DEBUG_ERROR;
/* for wireless system event message */
char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = {
/* system status event */
"had associated successfully", /* IW_ASSOC_EVENT_FLAG */
"had disassociated", /* IW_DISASSOC_EVENT_FLAG */
"had deauthenticated", /* IW_DEAUTH_EVENT_FLAG */
"had been aged-out and disassociated", /* IW_AGEOUT_EVENT_FLAG */
"occurred CounterMeasures attack", /* IW_COUNTER_MEASURES_EVENT_FLAG */
"occurred replay counter different in Key Handshaking", /* IW_REPLAY_COUNTER_DIFF_EVENT_FLAG */
"occurred RSNIE different in Key Handshaking", /* IW_RSNIE_DIFF_EVENT_FLAG */
"occurred MIC different in Key Handshaking", /* IW_MIC_DIFF_EVENT_FLAG */
"occurred ICV error in RX", /* IW_ICV_ERROR_EVENT_FLAG */
"occurred MIC error in RX", /* IW_MIC_ERROR_EVENT_FLAG */
"Group Key Handshaking timeout", /* IW_GROUP_HS_TIMEOUT_EVENT_FLAG */
"Pairwise Key Handshaking timeout", /* IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG */
"RSN IE sanity check failure", /* IW_RSNIE_SANITY_FAIL_EVENT_FLAG */
"set key done in WPA/WPAPSK", /* IW_SET_KEY_DONE_WPA1_EVENT_FLAG */
"set key done in WPA2/WPA2PSK", /* IW_SET_KEY_DONE_WPA2_EVENT_FLAG */
"connects with our wireless client", /* IW_STA_LINKUP_EVENT_FLAG */
"disconnects with our wireless client", /* IW_STA_LINKDOWN_EVENT_FLAG */
"scan completed" /* IW_SCAN_COMPLETED_EVENT_FLAG */
"scan terminate! Busy! Enqueue fail!" /* IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG */
};
/* for wireless IDS_spoof_attack event message */
char const *pWirelessSpoofEventText[IW_SPOOF_EVENT_TYPE_NUM] = {
"detected conflict SSID", /* IW_CONFLICT_SSID_EVENT_FLAG */
"detected spoofed association response", /* IW_SPOOF_ASSOC_RESP_EVENT_FLAG */
"detected spoofed reassociation responses", /* IW_SPOOF_REASSOC_RESP_EVENT_FLAG */
"detected spoofed probe response", /* IW_SPOOF_PROBE_RESP_EVENT_FLAG */
"detected spoofed beacon", /* IW_SPOOF_BEACON_EVENT_FLAG */
"detected spoofed disassociation", /* IW_SPOOF_DISASSOC_EVENT_FLAG */
"detected spoofed authentication", /* IW_SPOOF_AUTH_EVENT_FLAG */
"detected spoofed deauthentication", /* IW_SPOOF_DEAUTH_EVENT_FLAG */
"detected spoofed unknown management frame", /* IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG */
"detected replay attack" /* IW_REPLAY_ATTACK_EVENT_FLAG */
};
/* for wireless IDS_flooding_attack event message */
char const *pWirelessFloodEventText[IW_FLOOD_EVENT_TYPE_NUM] = {
"detected authentication flooding", /* IW_FLOOD_AUTH_EVENT_FLAG */
"detected association request flooding", /* IW_FLOOD_ASSOC_REQ_EVENT_FLAG */
"detected reassociation request flooding", /* IW_FLOOD_REASSOC_REQ_EVENT_FLAG */
"detected probe request flooding", /* IW_FLOOD_PROBE_REQ_EVENT_FLAG */
"detected disassociation flooding", /* IW_FLOOD_DISASSOC_EVENT_FLAG */
"detected deauthentication flooding", /* IW_FLOOD_DEAUTH_EVENT_FLAG */
"detected 802.1x eap-request flooding" /* IW_FLOOD_EAP_REQ_EVENT_FLAG */
};
/* timeout -- ms */
void RTMP_SetPeriodicTimer(struct timer_list *pTimer,
IN unsigned long timeout)
{
timeout = ((timeout * OS_HZ) / 1000);
pTimer->expires = jiffies + timeout;
add_timer(pTimer);
}
/* convert NdisMInitializeTimer --> RTMP_OS_Init_Timer */
void RTMP_OS_Init_Timer(struct rt_rtmp_adapter *pAd,
struct timer_list *pTimer,
IN TIMER_FUNCTION function, void *data)
{
init_timer(pTimer);
pTimer->data = (unsigned long)data;
pTimer->function = function;
}
void RTMP_OS_Add_Timer(struct timer_list *pTimer,
IN unsigned long timeout)
{
if (timer_pending(pTimer))
return;
timeout = ((timeout * OS_HZ) / 1000);
pTimer->expires = jiffies + timeout;
add_timer(pTimer);
}
void RTMP_OS_Mod_Timer(struct timer_list *pTimer,
IN unsigned long timeout)
{
timeout = ((timeout * OS_HZ) / 1000);
mod_timer(pTimer, jiffies + timeout);
}
void RTMP_OS_Del_Timer(struct timer_list *pTimer,
OUT BOOLEAN * pCancelled)
{
if (timer_pending(pTimer)) {
*pCancelled = del_timer_sync(pTimer);
} else {
*pCancelled = TRUE;
}
}
void RTMP_OS_Release_Packet(struct rt_rtmp_adapter *pAd, struct rt_queue_entry *pEntry)
{
/*RTMPFreeNdisPacket(pAd, (struct sk_buff *)pEntry); */
}
/* Unify all delay routine by using udelay */
void RTMPusecDelay(unsigned long usec)
{
unsigned long i;
for (i = 0; i < (usec / 50); i++)
udelay(50);
if (usec % 50)
udelay(usec % 50);
}
void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time)
{
time->u.LowPart = jiffies;
}
/* pAd MUST allow to be NULL */
int os_alloc_mem(struct rt_rtmp_adapter *pAd, u8 ** mem, unsigned long size)
{
*mem = kmalloc(size, GFP_ATOMIC);
if (*mem)
return NDIS_STATUS_SUCCESS;
else
return NDIS_STATUS_FAILURE;
}
/* pAd MUST allow to be NULL */
int os_free_mem(struct rt_rtmp_adapter *pAd, void *mem)
{
ASSERT(mem);
kfree(mem);
return NDIS_STATUS_SUCCESS;
}
void *RtmpOSNetPktAlloc(struct rt_rtmp_adapter *pAd, IN int size)
{
struct sk_buff *skb;
/* Add 2 more bytes for ip header alignment */
skb = dev_alloc_skb(size + 2);
return (void *)skb;
}
void *RTMP_AllocateFragPacketBuffer(struct rt_rtmp_adapter *pAd,
unsigned long Length)
{
struct sk_buff *pkt;
pkt = dev_alloc_skb(Length);
if (pkt == NULL) {
DBGPRINT(RT_DEBUG_ERROR,
("can't allocate frag rx %ld size packet\n", Length));
}
if (pkt) {
RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS);
}
return (void *)pkt;
}
void *RTMP_AllocateTxPacketBuffer(struct rt_rtmp_adapter *pAd,
unsigned long Length,
IN BOOLEAN Cached,
void **VirtualAddress)
{
struct sk_buff *pkt;
pkt = dev_alloc_skb(Length);
if (pkt == NULL) {
DBGPRINT(RT_DEBUG_ERROR,
("can't allocate tx %ld size packet\n", Length));
}
if (pkt) {
RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS);
*VirtualAddress = (void *)pkt->data;
} else {
*VirtualAddress = (void *)NULL;
}
return (void *)pkt;
}
void build_tx_packet(struct rt_rtmp_adapter *pAd,
void *pPacket,
u8 *pFrame, unsigned long FrameLen)
{
struct sk_buff *pTxPkt;
ASSERT(pPacket);
pTxPkt = RTPKT_TO_OSPKT(pPacket);
NdisMoveMemory(skb_put(pTxPkt, FrameLen), pFrame, FrameLen);
}
void RTMPFreeAdapter(struct rt_rtmp_adapter *pAd)
{
struct os_cookie *os_cookie;
int index;
os_cookie = (struct os_cookie *)pAd->OS_Cookie;
if (pAd->BeaconBuf)
kfree(pAd->BeaconBuf);
NdisFreeSpinLock(&pAd->MgmtRingLock);
#ifdef RTMP_MAC_PCI
NdisFreeSpinLock(&pAd->RxRingLock);
#ifdef RT3090
NdisFreeSpinLock(&pAd->McuCmdLock);
#endif /* RT3090 // */
#endif /* RTMP_MAC_PCI // */
for (index = 0; index < NUM_OF_TX_RING; index++) {
NdisFreeSpinLock(&pAd->TxSwQueueLock[index]);
NdisFreeSpinLock(&pAd->DeQueueLock[index]);
pAd->DeQueueRunning[index] = FALSE;
}
NdisFreeSpinLock(&pAd->irq_lock);
release_firmware(pAd->firmware);
vfree(pAd); /* pci_free_consistent(os_cookie->pci_dev,sizeof(struct rt_rtmp_adapter),pAd,os_cookie->pAd_pa); */
if (os_cookie)
kfree(os_cookie);
}
BOOLEAN OS_Need_Clone_Packet(void)
{
return FALSE;
}
/*
========================================================================
Routine Description:
clone an input NDIS PACKET to another one. The new internally created NDIS PACKET
must have only one NDIS BUFFER
return - byte copied. 0 means can't create NDIS PACKET
NOTE: internally created char should be destroyed by RTMPFreeNdisPacket
Arguments:
pAd Pointer to our adapter
pInsAMSDUHdr EWC A-MSDU format has extra 14-bytes header. if TRUE, insert this 14-byte hdr in front of MSDU.
*pSrcTotalLen return total packet length. This lenght is calculated with 802.3 format packet.
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
Note:
========================================================================
*/
int RTMPCloneNdisPacket(struct rt_rtmp_adapter *pAd,
IN BOOLEAN pInsAMSDUHdr,
void *pInPacket,
void **ppOutPacket)
{
struct sk_buff *pkt;
ASSERT(pInPacket);
ASSERT(ppOutPacket);
/* 1. Allocate a packet */
pkt = dev_alloc_skb(2048);
if (pkt == NULL) {
return NDIS_STATUS_FAILURE;
}
skb_put(pkt, GET_OS_PKT_LEN(pInPacket));
NdisMoveMemory(pkt->data, GET_OS_PKT_DATAPTR(pInPacket),
GET_OS_PKT_LEN(pInPacket));
*ppOutPacket = OSPKT_TO_RTPKT(pkt);
RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS);
printk("###Clone###\n");
return NDIS_STATUS_SUCCESS;
}
/* the allocated NDIS PACKET must be freed via RTMPFreeNdisPacket() */
int RTMPAllocateNdisPacket(struct rt_rtmp_adapter *pAd,
void **ppPacket,
u8 *pHeader,
u32 HeaderLen,
u8 *pData, u32 DataLen)
{
void *pPacket;
ASSERT(pData);
ASSERT(DataLen);
/* 1. Allocate a packet */
pPacket =
(void **) dev_alloc_skb(HeaderLen + DataLen +
RTMP_PKT_TAIL_PADDING);
if (pPacket == NULL) {
*ppPacket = NULL;
#ifdef DEBUG
printk("RTMPAllocateNdisPacket Fail\n");
#endif
return NDIS_STATUS_FAILURE;
}
/* 2. clone the frame content */
if (HeaderLen > 0)
NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket), pHeader, HeaderLen);
if (DataLen > 0)
NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket) + HeaderLen, pData,
DataLen);
/* 3. update length of packet */
skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen + DataLen);
RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
/* printk("%s : pPacket = %p, len = %d\n", __func__, pPacket, GET_OS_PKT_LEN(pPacket)); */
*ppPacket = pPacket;
return NDIS_STATUS_SUCCESS;
}
/*
========================================================================
Description:
This routine frees a miniport internally allocated char and its
corresponding NDIS_BUFFER and allocated memory.
========================================================================
*/
void RTMPFreeNdisPacket(struct rt_rtmp_adapter *pAd, void *pPacket)
{
dev_kfree_skb_any(RTPKT_TO_OSPKT(pPacket));
}
/* IRQL = DISPATCH_LEVEL */
/* NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same */
/* scatter gather buffer */
int Sniff2BytesFromNdisBuffer(char *pFirstBuffer,
u8 DesiredOffset,
u8 *pByte0, u8 *pByte1)
{
*pByte0 = *(u8 *)(pFirstBuffer + DesiredOffset);
*pByte1 = *(u8 *)(pFirstBuffer + DesiredOffset + 1);
return NDIS_STATUS_SUCCESS;
}
void RTMP_QueryPacketInfo(void *pPacket,
struct rt_packet_info *pPacketInfo,
u8 **pSrcBufVA, u32 * pSrcBufLen)
{
pPacketInfo->BufferCount = 1;
pPacketInfo->pFirstBuffer = (char *)GET_OS_PKT_DATAPTR(pPacket);
pPacketInfo->PhysicalBufferCount = 1;
pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket);
*pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket);
*pSrcBufLen = GET_OS_PKT_LEN(pPacket);
}
void RTMP_QueryNextPacketInfo(void **ppPacket,
struct rt_packet_info *pPacketInfo,
u8 **pSrcBufVA, u32 * pSrcBufLen)
{
void *pPacket = NULL;
if (*ppPacket)
pPacket = GET_OS_PKT_NEXT(*ppPacket);
if (pPacket) {
pPacketInfo->BufferCount = 1;
pPacketInfo->pFirstBuffer =
(char *)GET_OS_PKT_DATAPTR(pPacket);
pPacketInfo->PhysicalBufferCount = 1;
pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket);
*pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket);
*pSrcBufLen = GET_OS_PKT_LEN(pPacket);
*ppPacket = GET_OS_PKT_NEXT(pPacket);
} else {
pPacketInfo->BufferCount = 0;
pPacketInfo->pFirstBuffer = NULL;
pPacketInfo->PhysicalBufferCount = 0;
pPacketInfo->TotalPacketLength = 0;
*pSrcBufVA = NULL;
*pSrcBufLen = 0;
*ppPacket = NULL;
}
}
void *DuplicatePacket(struct rt_rtmp_adapter *pAd,
void *pPacket, u8 FromWhichBSSID)
{
struct sk_buff *skb;
void *pRetPacket = NULL;
u16 DataSize;
u8 *pData;
DataSize = (u16)GET_OS_PKT_LEN(pPacket);
pData = (u8 *)GET_OS_PKT_DATAPTR(pPacket);
skb = skb_clone(RTPKT_TO_OSPKT(pPacket), MEM_ALLOC_FLAG);
if (skb) {
skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
pRetPacket = OSPKT_TO_RTPKT(skb);
}
return pRetPacket;
}
void *duplicate_pkt(struct rt_rtmp_adapter *pAd,
u8 *pHeader802_3,
u32 HdrLen,
u8 *pData,
unsigned long DataSize, u8 FromWhichBSSID)
{
struct sk_buff *skb;
void *pPacket = NULL;
skb = __dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG);
if (skb != NULL) {
skb_reserve(skb, 2);
NdisMoveMemory(skb_tail_pointer(skb), pHeader802_3, HdrLen);
skb_put(skb, HdrLen);
NdisMoveMemory(skb_tail_pointer(skb), pData, DataSize);
skb_put(skb, DataSize);
skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
pPacket = OSPKT_TO_RTPKT(skb);
}
return pPacket;
}
#define TKIP_TX_MIC_SIZE 8
void *duplicate_pkt_with_TKIP_MIC(struct rt_rtmp_adapter *pAd,
void *pPacket)
{
struct sk_buff *skb, *newskb;
skb = RTPKT_TO_OSPKT(pPacket);
if (skb_tailroom(skb) < TKIP_TX_MIC_SIZE) {
/* alloc a new skb and copy the packet */
newskb =
skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE,
GFP_ATOMIC);
dev_kfree_skb_any(skb);
if (newskb == NULL) {
DBGPRINT(RT_DEBUG_ERROR,
("Extend Tx.MIC for packet failed!, dropping packet!\n"));
return NULL;
}
skb = newskb;
}
return OSPKT_TO_RTPKT(skb);
}
void *ClonePacket(struct rt_rtmp_adapter *pAd,
void *pPacket,
u8 *pData, unsigned long DataSize)
{
struct sk_buff *pRxPkt;
struct sk_buff *pClonedPkt;
ASSERT(pPacket);
pRxPkt = RTPKT_TO_OSPKT(pPacket);
/* clone the packet */
pClonedPkt = skb_clone(pRxPkt, MEM_ALLOC_FLAG);
if (pClonedPkt) {
/* set the correct dataptr and data len */
pClonedPkt->dev = pRxPkt->dev;
pClonedPkt->data = pData;
pClonedPkt->len = DataSize;
skb_set_tail_pointer(pClonedPkt, DataSize)
ASSERT(DataSize < 1530);
}
return pClonedPkt;
}
/* */
/* change OS packet DataPtr and DataLen */
/* */
void update_os_packet_info(struct rt_rtmp_adapter *pAd,
struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID)
{
struct sk_buff *pOSPkt;
ASSERT(pRxBlk->pRxPacket);
pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket);
pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
pOSPkt->data = pRxBlk->pData;
pOSPkt->len = pRxBlk->DataSize;
skb_set_tail_pointer(pOSPkt, pOSPkt->len);
}
void wlan_802_11_to_802_3_packet(struct rt_rtmp_adapter *pAd,
struct rt_rx_blk *pRxBlk,
u8 *pHeader802_3,
u8 FromWhichBSSID)
{
struct sk_buff *pOSPkt;
ASSERT(pRxBlk->pRxPacket);
ASSERT(pHeader802_3);
pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket);
pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID);
pOSPkt->data = pRxBlk->pData;
pOSPkt->len = pRxBlk->DataSize;
skb_set_tail_pointer(pOSPkt, pOSPkt->len);
/* */
/* copy 802.3 header */
/* */
/* */
NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3,
LENGTH_802_3);
}
void announce_802_3_packet(struct rt_rtmp_adapter *pAd, void *pPacket)
{
struct sk_buff *pRxPkt;
ASSERT(pPacket);
pRxPkt = RTPKT_TO_OSPKT(pPacket);
/* Push up the protocol stack */
pRxPkt->protocol = eth_type_trans(pRxPkt, pRxPkt->dev);
netif_rx(pRxPkt);
}
struct rt_rtmp_sg_list *
rt_get_sg_list_from_packet(void *pPacket, struct rt_rtmp_sg_list *sg)
{
sg->NumberOfElements = 1;
sg->Elements[0].Address = GET_OS_PKT_DATAPTR(pPacket);
sg->Elements[0].Length = GET_OS_PKT_LEN(pPacket);
return sg;
}
void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen)
{
unsigned char *pt;
int x;
if (RTDebugLevel < RT_DEBUG_TRACE)
return;
pt = pSrcBufVA;
printk("%s: %p, len = %d\n", str, pSrcBufVA, SrcBufLen);
for (x = 0; x < SrcBufLen; x++) {
if (x % 16 == 0)
printk("0x%04x : ", x);
printk("%02x ", ((unsigned char)pt[x]));
if (x % 16 == 15)
printk("\n");
}
printk("\n");
}
/*
========================================================================
Routine Description:
Send log message through wireless event
Support standard iw_event with IWEVCUSTOM. It is used below.
iwreq_data.data.flags is used to store event_flag that is defined by user.
iwreq_data.data.length is the length of the event log.
The format of the event log is composed of the entry's MAC address and
the desired log message (refer to pWirelessEventText).
ex: 11:22:33:44:55:66 has associated successfully
p.s. The requirement of Wireless Extension is v15 or newer.
========================================================================
*/
void RTMPSendWirelessEvent(struct rt_rtmp_adapter *pAd,
u16 Event_flag,
u8 *pAddr, u8 BssIdx, char Rssi)
{
/*union iwreq_data wrqu; */
char *pBuf = NULL, *pBufPtr = NULL;
u16 event, type, BufLen;
u8 event_table_len = 0;
type = Event_flag & 0xFF00;
event = Event_flag & 0x00FF;
switch (type) {
case IW_SYS_EVENT_FLAG_START:
event_table_len = IW_SYS_EVENT_TYPE_NUM;
break;
case IW_SPOOF_EVENT_FLAG_START:
event_table_len = IW_SPOOF_EVENT_TYPE_NUM;
break;
case IW_FLOOD_EVENT_FLAG_START:
event_table_len = IW_FLOOD_EVENT_TYPE_NUM;
break;
}
if (event_table_len == 0) {
DBGPRINT(RT_DEBUG_ERROR,
("%s : The type(%0x02x) is not valid.\n", __func__,
type));
return;
}
if (event >= event_table_len) {
DBGPRINT(RT_DEBUG_ERROR,
("%s : The event(%0x02x) is not valid.\n", __func__,
event));
return;
}
/*Allocate memory and copy the msg. */
pBuf = kmalloc(IW_CUSTOM_MAX_LEN, GFP_ATOMIC);
if (pBuf != NULL) {
/*Prepare the payload */
memset(pBuf, 0, IW_CUSTOM_MAX_LEN);
pBufPtr = pBuf;
if (pAddr)
pBufPtr +=
sprintf(pBufPtr,
"(RT2860) STA(%02x:%02x:%02x:%02x:%02x:%02x) ",
PRINT_MAC(pAddr));
else if (BssIdx < MAX_MBSSID_NUM)
pBufPtr +=
sprintf(pBufPtr, "(RT2860) BSS(wlan%d) ", BssIdx);
else
pBufPtr += sprintf(pBufPtr, "(RT2860) ");
if (type == IW_SYS_EVENT_FLAG_START)
pBufPtr +=
sprintf(pBufPtr, "%s",
pWirelessSysEventText[event]);
else if (type == IW_SPOOF_EVENT_FLAG_START)
pBufPtr +=
sprintf(pBufPtr, "%s (RSSI=%d)",
pWirelessSpoofEventText[event], Rssi);
else if (type == IW_FLOOD_EVENT_FLAG_START)
pBufPtr +=
sprintf(pBufPtr, "%s",
pWirelessFloodEventText[event]);
else
pBufPtr += sprintf(pBufPtr, "%s", "unknown event");
pBufPtr[pBufPtr - pBuf] = '\0';
BufLen = pBufPtr - pBuf;
RtmpOSWrielessEventSend(pAd, IWEVCUSTOM, Event_flag, NULL,
(u8 *)pBuf, BufLen);
/*DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __func__, pBuf)); */
kfree(pBuf);
} else
DBGPRINT(RT_DEBUG_ERROR,
("%s : Can't allocate memory for wireless event.\n",
__func__));
}
void send_monitor_packets(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk)
{
struct sk_buff *pOSPkt;
struct rt_wlan_ng_prism2_header *ph;
int rate_index = 0;
u16 header_len = 0;
u8 temp_header[40] = { 0 };
u_int32_t ralinkrate[256] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 109, 110, 111, 112, 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, 27, 54, 81, 108, 162, 216, 243, 270, /* Last 38 */
54, 108, 162, 216, 324, 432, 486, 540, 14, 29, 43, 57, 87, 115,
130, 144, 29, 59, 87, 115, 173, 230, 260, 288, 30, 60, 90,
120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540,
600, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80
};
ASSERT(pRxBlk->pRxPacket);
if (pRxBlk->DataSize < 10) {
DBGPRINT(RT_DEBUG_ERROR,
("%s : Size is too small! (%d)\n", __func__,
pRxBlk->DataSize));
goto err_free_sk_buff;
}
if (pRxBlk->DataSize + sizeof(struct rt_wlan_ng_prism2_header) >
RX_BUFFER_AGGRESIZE) {
DBGPRINT(RT_DEBUG_ERROR,
("%s : Size is too large! (%zu)\n", __func__,
pRxBlk->DataSize + sizeof(struct rt_wlan_ng_prism2_header)));
goto err_free_sk_buff;
}
pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket);
pOSPkt->dev = get_netdev_from_bssid(pAd, BSS0);
if (pRxBlk->pHeader->FC.Type == BTYPE_DATA) {
pRxBlk->DataSize -= LENGTH_802_11;
if ((pRxBlk->pHeader->FC.ToDs == 1) &&
(pRxBlk->pHeader->FC.FrDs == 1))
header_len = LENGTH_802_11_WITH_ADDR4;
else
header_len = LENGTH_802_11;
/* QOS */
if (pRxBlk->pHeader->FC.SubType & 0x08) {
header_len += 2;
/* Data skip QOS contorl field */
pRxBlk->DataSize -= 2;
}
/* Order bit: A-Ralink or HTC+ */
if (pRxBlk->pHeader->FC.Order) {
header_len += 4;
/* Data skip HTC contorl field */
pRxBlk->DataSize -= 4;
}
/* Copy Header */
if (header_len <= 40)
NdisMoveMemory(temp_header, pRxBlk->pData, header_len);
/* skip HW padding */
if (pRxBlk->RxD.L2PAD)
pRxBlk->pData += (header_len + 2);
else
pRxBlk->pData += header_len;
} /*end if */
if (pRxBlk->DataSize < pOSPkt->len) {
skb_trim(pOSPkt, pRxBlk->DataSize);
} else {
skb_put(pOSPkt, (pRxBlk->DataSize - pOSPkt->len));
} /*end if */
if ((pRxBlk->pData - pOSPkt->data) > 0) {
skb_put(pOSPkt, (pRxBlk->pData - pOSPkt->data));
skb_pull(pOSPkt, (pRxBlk->pData - pOSPkt->data));
} /*end if */
if (skb_headroom(pOSPkt) < (sizeof(struct rt_wlan_ng_prism2_header) + header_len)) {
if (pskb_expand_head
(pOSPkt, (sizeof(struct rt_wlan_ng_prism2_header) + header_len), 0,
GFP_ATOMIC)) {
DBGPRINT(RT_DEBUG_ERROR,
("%s : Reallocate header size of sk_buff fail!\n",
__func__));
goto err_free_sk_buff;
} /*end if */
} /*end if */
if (header_len > 0)
NdisMoveMemory(skb_push(pOSPkt, header_len), temp_header,
header_len);
ph = (struct rt_wlan_ng_prism2_header *)skb_push(pOSPkt,
sizeof(struct rt_wlan_ng_prism2_header));
NdisZeroMemory(ph, sizeof(struct rt_wlan_ng_prism2_header));
ph->msgcode = DIDmsg_lnxind_wlansniffrm;
ph->msglen = sizeof(struct rt_wlan_ng_prism2_header);
strcpy((char *)ph->devname, (char *)pAd->net_dev->name);
ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime;
ph->hosttime.status = 0;
ph->hosttime.len = 4;
ph->hosttime.data = jiffies;
ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime;
ph->mactime.status = 0;
ph->mactime.len = 0;
ph->mactime.data = 0;
ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx;
ph->istx.status = 0;
ph->istx.len = 0;
ph->istx.data = 0;
ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel;
ph->channel.status = 0;
ph->channel.len = 4;
ph->channel.data = (u_int32_t) pAd->CommonCfg.Channel;
ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi;
ph->rssi.status = 0;
ph->rssi.len = 4;
ph->rssi.data =
(u_int32_t) RTMPMaxRssi(pAd,
ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI0,
RSSI_0), ConvertToRssi(pAd,
pRxBlk->
pRxWI->
RSSI1,
RSSI_1),
ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2,
RSSI_2));;
ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal;
ph->signal.status = 0;
ph->signal.len = 4;
ph->signal.data = 0; /*rssi + noise; */
ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise;
ph->noise.status = 0;
ph->noise.len = 4;
ph->noise.data = 0;
if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) {
rate_index =
16 + ((u8)pRxBlk->pRxWI->BW * 16) +
((u8)pRxBlk->pRxWI->ShortGI * 32) +
((u8)pRxBlk->pRxWI->MCS);
} else if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM)
rate_index = (u8)(pRxBlk->pRxWI->MCS) + 4;
else
rate_index = (u8)(pRxBlk->pRxWI->MCS);
if (rate_index < 0)
rate_index = 0;
if (rate_index > 255)
rate_index = 255;
ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate;
ph->rate.status = 0;
ph->rate.len = 4;
ph->rate.data = ralinkrate[rate_index];
ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen;
ph->frmlen.status = 0;
ph->frmlen.len = 4;
ph->frmlen.data = (u_int32_t) pRxBlk->DataSize;
pOSPkt->pkt_type = PACKET_OTHERHOST;
pOSPkt->protocol = eth_type_trans(pOSPkt, pOSPkt->dev);
pOSPkt->ip_summed = CHECKSUM_NONE;
netif_rx(pOSPkt);
return;
err_free_sk_buff:
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
return;
}
/*******************************************************************************
Device IRQ related functions.
*******************************************************************************/
int RtmpOSIRQRequest(struct net_device *pNetDev)
{
#ifdef RTMP_PCI_SUPPORT
struct net_device *net_dev = pNetDev;
struct rt_rtmp_adapter *pAd = NULL;
int retval = 0;
GET_PAD_FROM_NET_DEV(pAd, pNetDev);
ASSERT(pAd);
if (pAd->infType == RTMP_DEV_INF_PCI) {
struct os_cookie *_pObj = (struct os_cookie *)(pAd->OS_Cookie);
RTMP_MSI_ENABLE(pAd);
retval =
request_irq(_pObj->pci_dev->irq, rt2860_interrupt, SA_SHIRQ,
(net_dev)->name, (net_dev));
if (retval != 0)
printk("RT2860: request_irq ERROR(%d)\n", retval);
}
return retval;
#else
return 0;
#endif
}
int RtmpOSIRQRelease(struct net_device *pNetDev)
{
struct net_device *net_dev = pNetDev;
struct rt_rtmp_adapter *pAd = NULL;
GET_PAD_FROM_NET_DEV(pAd, net_dev);
ASSERT(pAd);
#ifdef RTMP_PCI_SUPPORT
if (pAd->infType == RTMP_DEV_INF_PCI) {
struct os_cookie *pObj = (struct os_cookie *)(pAd->OS_Cookie);
synchronize_irq(pObj->pci_dev->irq);
free_irq(pObj->pci_dev->irq, (net_dev));
RTMP_MSI_DISABLE(pAd);
}
#endif /* RTMP_PCI_SUPPORT // */
return 0;
}
/*******************************************************************************
File open/close related functions.
*******************************************************************************/
struct file *RtmpOSFileOpen(char *pPath, int flag, int mode)
{
struct file *filePtr;
filePtr = filp_open(pPath, flag, 0);
if (IS_ERR(filePtr)) {
DBGPRINT(RT_DEBUG_ERROR,
("%s(): Error %ld opening %s\n", __func__,
-PTR_ERR(filePtr), pPath));
}
return (struct file *)filePtr;
}
int RtmpOSFileClose(struct file *osfd)
{
filp_close(osfd, NULL);
return 0;
}
void RtmpOSFileSeek(struct file *osfd, int offset)
{
osfd->f_pos = offset;
}
int RtmpOSFileRead(struct file *osfd, char *pDataPtr, int readLen)
{
/* The object must have a read method */
if (osfd->f_op && osfd->f_op->read) {
return osfd->f_op->read(osfd, pDataPtr, readLen, &osfd->f_pos);
} else {
DBGPRINT(RT_DEBUG_ERROR, ("no file read method\n"));
return -1;
}
}
int RtmpOSFileWrite(struct file *osfd, char *pDataPtr, int writeLen)
{
return osfd->f_op->write(osfd, pDataPtr, (size_t) writeLen,
&osfd->f_pos);
}
/*******************************************************************************
Task create/management/kill related functions.
*******************************************************************************/
int RtmpOSTaskKill(struct rt_rtmp_os_task *pTask)
{
struct rt_rtmp_adapter *pAd;
int ret = NDIS_STATUS_FAILURE;
pAd = (struct rt_rtmp_adapter *)pTask->priv;
#ifdef KTHREAD_SUPPORT
if (pTask->kthread_task) {
kthread_stop(pTask->kthread_task);
ret = NDIS_STATUS_SUCCESS;
}
#else
CHECK_PID_LEGALITY(pTask->taskPID) {
printk("Terminate the task(%s) with pid(%d)!\n",
pTask->taskName, GET_PID_NUMBER(pTask->taskPID));
mb();
pTask->task_killed = 1;
mb();
ret = KILL_THREAD_PID(pTask->taskPID, SIGTERM, 1);
if (ret) {
printk(KERN_WARNING
"kill task(%s) with pid(%d) failed(retVal=%d)!\n",
pTask->taskName, GET_PID_NUMBER(pTask->taskPID),
ret);
} else {
wait_for_completion(&pTask->taskComplete);
pTask->taskPID = THREAD_PID_INIT_VALUE;
pTask->task_killed = 0;
ret = NDIS_STATUS_SUCCESS;
}
}
#endif
return ret;
}
int RtmpOSTaskNotifyToExit(struct rt_rtmp_os_task *pTask)
{
#ifndef KTHREAD_SUPPORT
complete_and_exit(&pTask->taskComplete, 0);
#endif
return 0;
}
void RtmpOSTaskCustomize(struct rt_rtmp_os_task *pTask)
{
#ifndef KTHREAD_SUPPORT
daemonize((char *)&pTask->taskName[0] /*"%s",pAd->net_dev->name */);
allow_signal(SIGTERM);
allow_signal(SIGKILL);
current->flags |= PF_NOFREEZE;
/* signal that we've started the thread */
complete(&pTask->taskComplete);
#endif
}
int RtmpOSTaskAttach(struct rt_rtmp_os_task *pTask,
IN int (*fn) (void *), IN void *arg)
{
int status = NDIS_STATUS_SUCCESS;
#ifdef KTHREAD_SUPPORT
pTask->task_killed = 0;
pTask->kthread_task = NULL;
pTask->kthread_task = kthread_run(fn, arg, pTask->taskName);
if (IS_ERR(pTask->kthread_task))
status = NDIS_STATUS_FAILURE;
#else
pid_number = kernel_thread(fn, arg, RTMP_OS_MGMT_TASK_FLAGS);
if (pid_number < 0) {
DBGPRINT(RT_DEBUG_ERROR,
("Attach task(%s) failed!\n", pTask->taskName));
status = NDIS_STATUS_FAILURE;
} else {
pTask->taskPID = GET_PID(pid_number);
/* Wait for the thread to start */
wait_for_completion(&pTask->taskComplete);
status = NDIS_STATUS_SUCCESS;
}
#endif
return status;
}
int RtmpOSTaskInit(struct rt_rtmp_os_task *pTask,
char *pTaskName, void * pPriv)
{
int len;
ASSERT(pTask);
#ifndef KTHREAD_SUPPORT
NdisZeroMemory((u8 *)(pTask), sizeof(struct rt_rtmp_os_task));
#endif
len = strlen(pTaskName);
len =
len >
(RTMP_OS_TASK_NAME_LEN - 1) ? (RTMP_OS_TASK_NAME_LEN - 1) : len;
NdisMoveMemory(&pTask->taskName[0], pTaskName, len);
pTask->priv = pPriv;
#ifndef KTHREAD_SUPPORT
RTMP_SEM_EVENT_INIT_LOCKED(&(pTask->taskSema));
pTask->taskPID = THREAD_PID_INIT_VALUE;
init_completion(&pTask->taskComplete);
#endif
return NDIS_STATUS_SUCCESS;
}
void RTMP_IndicateMediaState(struct rt_rtmp_adapter *pAd)
{
if (pAd->CommonCfg.bWirelessEvent) {
if (pAd->IndicateMediaState == NdisMediaStateConnected) {
RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG,
pAd->MacTab.Content[BSSID_WCID].
Addr, BSS0, 0);
} else {
RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG,
pAd->MacTab.Content[BSSID_WCID].
Addr, BSS0, 0);
}
}
}
int RtmpOSWrielessEventSend(struct rt_rtmp_adapter *pAd,
u32 eventType,
int flags,
u8 *pSrcMac,
u8 *pData, u32 dataLen)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof(wrqu));
if (flags > -1)
wrqu.data.flags = flags;
if (pSrcMac)
memcpy(wrqu.ap_addr.sa_data, pSrcMac, MAC_ADDR_LEN);
if ((pData != NULL) && (dataLen > 0))
wrqu.data.length = dataLen;
wireless_send_event(pAd->net_dev, eventType, &wrqu, (char *)pData);
return 0;
}
int RtmpOSNetDevAddrSet(struct net_device *pNetDev, u8 *pMacAddr)
{
struct net_device *net_dev;
struct rt_rtmp_adapter *pAd;
net_dev = pNetDev;
GET_PAD_FROM_NET_DEV(pAd, net_dev);
/* work-around for the SuSE due to it has it's own interface name management system. */
{
NdisZeroMemory(pAd->StaCfg.dev_name, 16);
NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name,
strlen(net_dev->name));
}
NdisMoveMemory(net_dev->dev_addr, pMacAddr, 6);
return 0;
}
/*
* Assign the network dev name for created Ralink WiFi interface.
*/
static int RtmpOSNetDevRequestName(struct rt_rtmp_adapter *pAd,
struct net_device *dev,
char *pPrefixStr, int devIdx)
{
struct net_device *existNetDev;
char suffixName[IFNAMSIZ];
char desiredName[IFNAMSIZ];
int ifNameIdx, prefixLen, slotNameLen;
int Status;
prefixLen = strlen(pPrefixStr);
ASSERT((prefixLen < IFNAMSIZ));
for (ifNameIdx = devIdx; ifNameIdx < 32; ifNameIdx++) {
memset(suffixName, 0, IFNAMSIZ);
memset(desiredName, 0, IFNAMSIZ);
strncpy(&desiredName[0], pPrefixStr, prefixLen);
sprintf(suffixName, "%d", ifNameIdx);
slotNameLen = strlen(suffixName);
ASSERT(((slotNameLen + prefixLen) < IFNAMSIZ));
strcat(desiredName, suffixName);
existNetDev = RtmpOSNetDevGetByName(dev, &desiredName[0]);
if (existNetDev == NULL)
break;
else
RtmpOSNetDeviceRefPut(existNetDev);
}
if (ifNameIdx < 32) {
strcpy(&dev->name[0], &desiredName[0]);
Status = NDIS_STATUS_SUCCESS;
} else {
DBGPRINT(RT_DEBUG_ERROR,
("Cannot request DevName with preifx(%s) and in range(0~32) as suffix from OS!\n",
pPrefixStr));
Status = NDIS_STATUS_FAILURE;
}
return Status;
}
void RtmpOSNetDevClose(struct net_device *pNetDev)
{
dev_close(pNetDev);
}
void RtmpOSNetDevFree(struct net_device *pNetDev)
{
ASSERT(pNetDev);
free_netdev(pNetDev);
}
int RtmpOSNetDevAlloc(struct net_device **new_dev_p, u32 privDataSize)
{
/* assign it as null first. */
*new_dev_p = NULL;
DBGPRINT(RT_DEBUG_TRACE,
("Allocate a net device with private data size=%d!\n",
privDataSize));
*new_dev_p = alloc_etherdev(privDataSize);
if (*new_dev_p)
return NDIS_STATUS_SUCCESS;
else
return NDIS_STATUS_FAILURE;
}
struct net_device *RtmpOSNetDevGetByName(struct net_device *pNetDev, char *pDevName)
{
struct net_device *pTargetNetDev = NULL;
pTargetNetDev = dev_get_by_name(dev_net(pNetDev), pDevName);
return pTargetNetDev;
}
void RtmpOSNetDeviceRefPut(struct net_device *pNetDev)
{
/*
every time dev_get_by_name is called, and it has returned a valid struct
net_device*, dev_put should be called afterwards, because otherwise the
machine hangs when the device is unregistered (since dev->refcnt > 1).
*/
if (pNetDev)
dev_put(pNetDev);
}
int RtmpOSNetDevDestory(struct rt_rtmp_adapter *pAd, struct net_device *pNetDev)
{
/* TODO: Need to fix this */
printk("WARNING: This function(%s) not implement yet!\n", __func__);
return 0;
}
void RtmpOSNetDevDetach(struct net_device *pNetDev)
{
unregister_netdev(pNetDev);
}
int RtmpOSNetDevAttach(struct net_device *pNetDev,
struct rt_rtmp_os_netdev_op_hook *pDevOpHook)
{
int ret, rtnl_locked = FALSE;
DBGPRINT(RT_DEBUG_TRACE, ("RtmpOSNetDevAttach()--->\n"));
/* If we need hook some callback function to the net device structrue, now do it. */
if (pDevOpHook) {
struct rt_rtmp_adapter *pAd = NULL;
GET_PAD_FROM_NET_DEV(pAd, pNetDev);
pNetDev->netdev_ops = pDevOpHook->netdev_ops;
/* OS specific flags, here we used to indicate if we are virtual interface */
pNetDev->priv_flags = pDevOpHook->priv_flags;
if (pAd->OpMode == OPMODE_STA) {
pNetDev->wireless_handlers = &rt28xx_iw_handler_def;
}
/* copy the net device mac address to the net_device structure. */
NdisMoveMemory(pNetDev->dev_addr, &pDevOpHook->devAddr[0],
MAC_ADDR_LEN);
rtnl_locked = pDevOpHook->needProtcted;
}
if (rtnl_locked)
ret = register_netdevice(pNetDev);
else
ret = register_netdev(pNetDev);
DBGPRINT(RT_DEBUG_TRACE, ("<---RtmpOSNetDevAttach(), ret=%d\n", ret));
if (ret == 0)
return NDIS_STATUS_SUCCESS;
else
return NDIS_STATUS_FAILURE;
}
struct net_device *RtmpOSNetDevCreate(struct rt_rtmp_adapter *pAd,
int devType,
int devNum,
int privMemSize, char *pNamePrefix)
{
struct net_device *pNetDev = NULL;
int status;
/* allocate a new network device */
status = RtmpOSNetDevAlloc(&pNetDev, 0 /*privMemSize */);
if (status != NDIS_STATUS_SUCCESS) {
/* allocation fail, exit */
DBGPRINT(RT_DEBUG_ERROR,
("Allocate network device fail (%s)...\n",
pNamePrefix));
return NULL;
}
/* find a available interface name, max 32 interfaces */
status = RtmpOSNetDevRequestName(pAd, pNetDev, pNamePrefix, devNum);
if (status != NDIS_STATUS_SUCCESS) {
/* error! no any available ra name can be used! */
DBGPRINT(RT_DEBUG_ERROR,
("Assign interface name (%s with suffix 0~32) failed...\n",
pNamePrefix));
RtmpOSNetDevFree(pNetDev);
return NULL;
} else {
DBGPRINT(RT_DEBUG_TRACE,
("The name of the new %s interface is %s...\n",
pNamePrefix, pNetDev->name));
}
return pNetDev;
}