diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-22 19:54:53 (GMT) |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-22 20:01:40 (GMT) |
commit | ae19ffbadc1b2100285a5b5b3d0a4e0a11390904 (patch) | |
tree | 3c2086ab67398a019089a47ca3f362a4bc6db74f /drivers/staging/rt3090/rt_linux.c | |
parent | 34e84f39a27d059a3e6ec6e8b94aafa702e6f220 (diff) | |
parent | 9173a8ef24a6b1b8031507b35b8ffe5f85a87692 (diff) | |
download | linux-fsl-qoriq-ae19ffbadc1b2100285a5b5b3d0a4e0a11390904.tar.xz |
Merge branch 'master' into for-linus
Diffstat (limited to 'drivers/staging/rt3090/rt_linux.c')
-rw-r--r-- | drivers/staging/rt3090/rt_linux.c | 1623 |
1 files changed, 1623 insertions, 0 deletions
diff --git a/drivers/staging/rt3090/rt_linux.c b/drivers/staging/rt3090/rt_linux.c new file mode 100644 index 0000000..d2241ec --- /dev/null +++ b/drivers/staging/rt3090/rt_linux.c @@ -0,0 +1,1623 @@ +/* + ************************************************************************* + * 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 "rt_config.h" + +ULONG 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( + IN NDIS_MINIPORT_TIMER *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( + IN PRTMP_ADAPTER pAd, + IN NDIS_MINIPORT_TIMER *pTimer, + IN TIMER_FUNCTION function, + IN PVOID data) +{ + init_timer(pTimer); + pTimer->data = (unsigned long)data; + pTimer->function = function; +} + + +VOID RTMP_OS_Add_Timer( + IN NDIS_MINIPORT_TIMER *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( + IN NDIS_MINIPORT_TIMER *pTimer, + IN unsigned long timeout) +{ + timeout = ((timeout*OS_HZ) / 1000); + mod_timer(pTimer, jiffies + timeout); +} + +VOID RTMP_OS_Del_Timer( + IN NDIS_MINIPORT_TIMER *pTimer, + OUT BOOLEAN *pCancelled) +{ + if (timer_pending(pTimer)) + { + *pCancelled = del_timer_sync(pTimer); + } + else + { + *pCancelled = TRUE; + } + +} + +VOID RTMP_OS_Release_Packet( + IN PRTMP_ADAPTER pAd, + IN PQUEUE_ENTRY pEntry) +{ + //RTMPFreeNdisPacket(pAd, (struct sk_buff *)pEntry); +} + +// Unify all delay routine by using udelay +VOID RTMPusecDelay( + IN ULONG usec) +{ + ULONG 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 +NDIS_STATUS os_alloc_mem( + IN RTMP_ADAPTER *pAd, + OUT UCHAR **mem, + IN ULONG size) +{ + *mem = (PUCHAR) kmalloc(size, GFP_ATOMIC); + if (*mem) + return (NDIS_STATUS_SUCCESS); + else + return (NDIS_STATUS_FAILURE); +} + +// pAd MUST allow to be NULL +NDIS_STATUS os_free_mem( + IN PRTMP_ADAPTER pAd, + IN PVOID mem) +{ + + ASSERT(mem); + kfree(mem); + return (NDIS_STATUS_SUCCESS); +} + + + + +PNDIS_PACKET RtmpOSNetPktAlloc( + IN 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 ((PNDIS_PACKET)skb); +} + + +PNDIS_PACKET RTMP_AllocateFragPacketBuffer( + IN PRTMP_ADAPTER pAd, + IN ULONG 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 (PNDIS_PACKET) pkt; +} + + +PNDIS_PACKET RTMP_AllocateTxPacketBuffer( + IN PRTMP_ADAPTER pAd, + IN ULONG Length, + IN BOOLEAN Cached, + OUT PVOID *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 = (PVOID) pkt->data; + } + else + { + *VirtualAddress = (PVOID) NULL; + } + + return (PNDIS_PACKET) pkt; +} + + +VOID build_tx_packet( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET pPacket, + IN PUCHAR pFrame, + IN ULONG FrameLen) +{ + + struct sk_buff *pTxPkt; + + ASSERT(pPacket); + pTxPkt = RTPKT_TO_OSPKT(pPacket); + + NdisMoveMemory(skb_put(pTxPkt, FrameLen), pFrame, FrameLen); +} + +VOID RTMPFreeAdapter( + IN PRTMP_ADAPTER pAd) +{ + POS_COOKIE os_cookie; + int index; + + os_cookie=(POS_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); + + + vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(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 NDIS_PACKET 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: + + ======================================================================== +*/ +NDIS_STATUS RTMPCloneNdisPacket( + IN PRTMP_ADAPTER pAd, + IN BOOLEAN pInsAMSDUHdr, + IN PNDIS_PACKET pInPacket, + OUT PNDIS_PACKET *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() +NDIS_STATUS RTMPAllocateNdisPacket( + IN PRTMP_ADAPTER pAd, + OUT PNDIS_PACKET *ppPacket, + IN PUCHAR pHeader, + IN UINT HeaderLen, + IN PUCHAR pData, + IN UINT DataLen) +{ + PNDIS_PACKET pPacket; + ASSERT(pData); + ASSERT(DataLen); + + // 1. Allocate a packet + pPacket = (PNDIS_PACKET *) dev_alloc_skb(HeaderLen + DataLen + RTMP_PKT_TAIL_PADDING); + if (pPacket == NULL) + { + *ppPacket = NULL; +#ifdef DEBUG + printk("RTMPAllocateNdisPacket Fail\n\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", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket)); + *ppPacket = pPacket; + return NDIS_STATUS_SUCCESS; +} + +/* + ======================================================================== + Description: + This routine frees a miniport internally allocated NDIS_PACKET and its + corresponding NDIS_BUFFER and allocated memory. + ======================================================================== +*/ +VOID RTMPFreeNdisPacket( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET 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 +NDIS_STATUS Sniff2BytesFromNdisBuffer( + IN PNDIS_BUFFER pFirstBuffer, + IN UCHAR DesiredOffset, + OUT PUCHAR pByte0, + OUT PUCHAR pByte1) +{ + *pByte0 = *(PUCHAR)(pFirstBuffer + DesiredOffset); + *pByte1 = *(PUCHAR)(pFirstBuffer + DesiredOffset + 1); + + return NDIS_STATUS_SUCCESS; +} + + +void RTMP_QueryPacketInfo( + IN PNDIS_PACKET pPacket, + OUT PACKET_INFO *pPacketInfo, + OUT PUCHAR *pSrcBufVA, + OUT UINT *pSrcBufLen) +{ + pPacketInfo->BufferCount = 1; + pPacketInfo->pFirstBuffer = (PNDIS_BUFFER)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( + IN PNDIS_PACKET *ppPacket, + OUT PACKET_INFO *pPacketInfo, + OUT PUCHAR *pSrcBufVA, + OUT UINT *pSrcBufLen) +{ + PNDIS_PACKET pPacket = NULL; + + if (*ppPacket) + pPacket = GET_OS_PKT_NEXT(*ppPacket); + + if (pPacket) + { + pPacketInfo->BufferCount = 1; + pPacketInfo->pFirstBuffer = (PNDIS_BUFFER)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; + } +} + + +PNDIS_PACKET DuplicatePacket( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET pPacket, + IN UCHAR FromWhichBSSID) +{ + struct sk_buff *skb; + PNDIS_PACKET pRetPacket = NULL; + USHORT DataSize; + UCHAR *pData; + + DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); + pData = (PUCHAR) 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; + +} + +PNDIS_PACKET duplicate_pkt( + IN PRTMP_ADAPTER pAd, + IN PUCHAR pHeader802_3, + IN UINT HdrLen, + IN PUCHAR pData, + IN ULONG DataSize, + IN UCHAR FromWhichBSSID) +{ + struct sk_buff *skb; + PNDIS_PACKET pPacket = NULL; + + + if ((skb = __dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG)) != 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 +PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET 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); + + +} + + + + +PNDIS_PACKET ClonePacket( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET pPacket, + IN PUCHAR pData, + IN ULONG 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; + pClonedPkt->tail = pClonedPkt->data + pClonedPkt->len; + ASSERT(DataSize < 1530); + } + return pClonedPkt; +} + +// +// change OS packet DataPtr and DataLen +// +void update_os_packet_info( + IN PRTMP_ADAPTER pAd, + IN RX_BLK *pRxBlk, + IN UCHAR 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; + pOSPkt->tail = pOSPkt->data + pOSPkt->len; +} + + +void wlan_802_11_to_802_3_packet( + IN PRTMP_ADAPTER pAd, + IN RX_BLK *pRxBlk, + IN PUCHAR pHeader802_3, + IN UCHAR 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; + pOSPkt->tail = pOSPkt->data + pOSPkt->len; + + // + // copy 802.3 header + // + // + +#ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); +#endif // CONFIG_STA_SUPPORT // + } + + + +void announce_802_3_packet( + IN PRTMP_ADAPTER pAd, + IN PNDIS_PACKET pPacket) +{ + + struct sk_buff *pRxPkt; +#ifdef INF_AMAZON_PPA + int ret = 0; + unsigned int ppa_flags = 0; /* reserved for now */ +#endif // INF_AMAZON_PPA // + + ASSERT(pPacket); + + pRxPkt = RTPKT_TO_OSPKT(pPacket); + +#ifdef CONFIG_STA_SUPPORT +#endif // CONFIG_STA_SUPPORT // + + /* Push up the protocol stack */ +#ifdef IKANOS_VX_1X0 + IKANOS_DataFrameRx(pAd, pRxPkt->dev, pRxPkt, pRxPkt->len); +#else +#ifdef INF_AMAZON_SE +#ifdef BG_FT_SUPPORT + BG_FTPH_PacketFromApHandle(pRxPkt); + return; +#endif // BG_FT_SUPPORT // +#endif // INF_AMAZON_SE // + pRxPkt->protocol = eth_type_trans(pRxPkt, pRxPkt->dev); + +#ifdef INF_AMAZON_PPA + if (ppa_hook_directpath_send_fn && pAd->PPAEnable==TRUE ) + { + memset(pRxPkt->head,0,pRxPkt->data-pRxPkt->head-14); + DBGPRINT(RT_DEBUG_TRACE, ("ppa_hook_directpath_send_fn rx :ret:%d headroom:%d dev:%s pktlen:%d<===\n",ret,skb_headroom(pRxPkt) + ,pRxPkt->dev->name,pRxPkt->len)); + hex_dump("rx packet", pRxPkt->data, 32); + ret = ppa_hook_directpath_send_fn(pAd->g_if_id, pRxPkt, pRxPkt->len, ppa_flags); + pRxPkt=NULL; + return; + + } +#endif // INF_AMAZON_PPA // + +//#ifdef CONFIG_5VT_ENHANCE +// *(int*)(pRxPkt->cb) = BRIDGE_TAG; +//#endif + + { + netif_rx(pRxPkt); + } + +#endif // IKANOS_VX_1X0 // +} + + +PRTMP_SCATTER_GATHER_LIST +rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_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( + IN PRTMP_ADAPTER pAd, + IN USHORT Event_flag, + IN PUCHAR pAddr, + IN UCHAR BssIdx, + IN CHAR Rssi) +{ +#if WIRELESS_EXT >= 15 + + //union iwreq_data wrqu; + PSTRING pBuf = NULL, pBufPtr = NULL; + USHORT event, type, BufLen; + UCHAR 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", __FUNCTION__, type)); + return; + } + + if (event >= event_table_len) + { + DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event)); + return; + } + + //Allocate memory and copy the msg. + if((pBuf = kmalloc(IW_CUSTOM_MAX_LEN, GFP_ATOMIC)) != 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(ra%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, (PUCHAR)pBuf, BufLen); + //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf)); + + kfree(pBuf); + } + else + DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__)); +#else + DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__)); +#endif /* WIRELESS_EXT >= 15 */ +} + + + + +#ifdef CONFIG_STA_SUPPORT +void send_monitor_packets( + IN PRTMP_ADAPTER pAd, + IN RX_BLK *pRxBlk) +{ + struct sk_buff *pOSPkt; + wlan_ng_prism2_header *ph; + int rate_index = 0; + USHORT header_len = 0; + UCHAR 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", __FUNCTION__, pRxBlk->DataSize)); + goto err_free_sk_buff; + } + + if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) + { + DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(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(wlan_ng_prism2_header)+ header_len)) { + if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) { + DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__)); + goto err_free_sk_buff; + } //end if + } //end if + + if (header_len > 0) + NdisMoveMemory(skb_push(pOSPkt, header_len), temp_header, header_len); + + ph = (wlan_ng_prism2_header *) skb_push(pOSPkt, sizeof(wlan_ng_prism2_header)); + NdisZeroMemory(ph, sizeof(wlan_ng_prism2_header)); + + ph->msgcode = DIDmsg_lnxind_wlansniffrm; + ph->msglen = sizeof(wlan_ng_prism2_header); + strcpy((PSTRING) ph->devname, (PSTRING) 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; + +#ifdef DOT11_N_SUPPORT + if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) + { + rate_index = 16 + ((UCHAR)pRxBlk->pRxWI->BW *16) + ((UCHAR)pRxBlk->pRxWI->ShortGI *32) + ((UCHAR)pRxBlk->pRxWI->MCS); + } + else +#endif // DOT11_N_SUPPORT // + if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM) + rate_index = (UCHAR)(pRxBlk->pRxWI->MCS) + 4; + else + rate_index = (UCHAR)(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; + +} +#endif // CONFIG_STA_SUPPORT // + + + +/******************************************************************************* + + File open/close related functions. + + *******************************************************************************/ +RTMP_OS_FD 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", __FUNCTION__, -PTR_ERR(filePtr), pPath)); + } + + return (RTMP_OS_FD)filePtr; +} + +int RtmpOSFileClose(RTMP_OS_FD osfd) +{ + filp_close(osfd, NULL); + return 0; +} + + +void RtmpOSFileSeek(RTMP_OS_FD osfd, int offset) +{ + osfd->f_pos = offset; +} + + +int RtmpOSFileRead(RTMP_OS_FD 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(RTMP_OS_FD osfd, char *pDataPtr, int writeLen) +{ + return osfd->f_op->write(osfd, pDataPtr, (size_t)writeLen, &osfd->f_pos); +} + + +void RtmpOSFSInfoChange(RTMP_OS_FS_INFO *pOSFSInfo, BOOLEAN bSet) +{ + if (bSet) + { + // Save uid and gid used for filesystem access. + // Set user and group to 0 (root) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + pOSFSInfo->fsuid= current->fsuid; + pOSFSInfo->fsgid = current->fsgid; + current->fsuid = current->fsgid = 0; +#else + pOSFSInfo->fsuid = current_fsuid(); + pOSFSInfo->fsgid = current_fsgid(); +#endif + pOSFSInfo->fs = get_fs(); + set_fs(KERNEL_DS); + } + else + { + set_fs(pOSFSInfo->fs); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + current->fsuid = pOSFSInfo->fsuid; + current->fsgid = pOSFSInfo->fsgid; +#endif + } +} + + + +/******************************************************************************* + + Task create/management/kill related functions. + + *******************************************************************************/ +NDIS_STATUS RtmpOSTaskKill( + IN RTMP_OS_TASK *pTask) +{ + RTMP_ADAPTER *pAd; + int ret = NDIS_STATUS_FAILURE; + + pAd = (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( + IN RTMP_OS_TASK *pTask) +{ + +#ifndef KTHREAD_SUPPORT + complete_and_exit(&pTask->taskComplete, 0); +#endif + + return 0; +} + + +void RtmpOSTaskCustomize( + IN RTMP_OS_TASK *pTask) +{ + +#ifndef KTHREAD_SUPPORT + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + daemonize((PSTRING)&pTask->taskName[0]/*"%s",pAd->net_dev->name*/); + + allow_signal(SIGTERM); + allow_signal(SIGKILL); + current->flags |= PF_NOFREEZE; +#else + unsigned long flags; + + daemonize(); + reparent_to_init(); + strcpy(current->comm, &pTask->taskName[0]); + + siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); + + /* Allow interception of SIGKILL only + * Don't allow other signals to interrupt the transmission */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) + spin_lock_irqsave(¤t->sigmask_lock, flags); + flush_signals(current); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); +#endif +#endif + + /* signal that we've started the thread */ + complete(&pTask->taskComplete); + +#endif +} + + +NDIS_STATUS RtmpOSTaskAttach( + IN RTMP_OS_TASK *pTask, + IN int (*fn)(void *), + IN void *arg) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + pid_t pid_number = -1; + +#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; +} + + +NDIS_STATUS RtmpOSTaskInit( + IN RTMP_OS_TASK *pTask, + IN PSTRING pTaskName, + IN VOID *pPriv) +{ + int len; + + ASSERT(pTask); + +#ifndef KTHREAD_SUPPORT + NdisZeroMemory((PUCHAR)(pTask), sizeof(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( + IN PRTMP_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); + } + } +} + + +#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 +//static struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) //sample +struct net_device *alloc_netdev( + int sizeof_priv, + const char *mask, + void (*setup)(struct net_device *)) +{ + struct net_device *dev; + INT alloc_size; + + + /* ensure 32-byte alignment of the private area */ + alloc_size = sizeof (*dev) + sizeof_priv + 31; + + dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL); + if (dev == NULL) + { + DBGPRINT(RT_DEBUG_ERROR, + ("alloc_netdev: Unable to allocate device memory.\n")); + return NULL; + } + + memset(dev, 0, alloc_size); + + if (sizeof_priv) + dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); + + setup(dev); + strcpy(dev->name, mask); + + return dev; +} +#endif // LINUX_VERSION_CODE // + + +int RtmpOSWrielessEventSend( + IN RTMP_ADAPTER *pAd, + IN UINT32 eventType, + IN INT flags, + IN PUCHAR pSrcMac, + IN PUCHAR pData, + IN UINT32 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( + IN PNET_DEV pNetDev, + IN PUCHAR pMacAddr) +{ + struct net_device *net_dev; + RTMP_ADAPTER *pAd; + + net_dev = pNetDev; + //pAd = (RTMP_ADAPTER *)net_dev->priv; + pAd=RTMP_OS_NETDEV_GET_PRIV(pNetDev); + +#ifdef CONFIG_STA_SUPPORT + // work-around for the SuSE due to it has it's own interface name management system. + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + NdisZeroMemory(pAd->StaCfg.dev_name, 16); + NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); + } +#endif // CONFIG_STA_SUPPORT // + + NdisMoveMemory(net_dev->dev_addr, pMacAddr, 6); + + return 0; +} + + + +/* + * Assign the network dev name for created Ralink WiFi interface. + */ +static int RtmpOSNetDevRequestName( + IN RTMP_ADAPTER *pAd, + IN PNET_DEV dev, + IN PSTRING pPrefixStr, + IN INT devIdx) +{ + PNET_DEV existNetDev; + STRING suffixName[IFNAMSIZ]; + STRING 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); + +#ifdef MULTIPLE_CARD_SUPPORT + if (pAd->MC_RowID >= 0) + sprintf(suffixName, "%02d_%d", pAd->MC_RowID, ifNameIdx); + else +#endif // MULTIPLE_CARD_SUPPORT // + 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( + IN PNET_DEV pNetDev) +{ + dev_close(pNetDev); +} + + +void RtmpOSNetDevFree(PNET_DEV pNetDev) +{ + ASSERT(pNetDev); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + free_netdev(pNetDev); +#else + kfree(pNetDev); +#endif +} + + +INT RtmpOSNetDevAlloc( + IN PNET_DEV *new_dev_p, + IN UINT32 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)); +#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 + *new_dev_p = alloc_netdev(privDataSize, "eth%d", ether_setup); +#else + *new_dev_p = alloc_etherdev(privDataSize); +#endif // LINUX_VERSION_CODE // + + if (*new_dev_p) + return NDIS_STATUS_SUCCESS; + else + return NDIS_STATUS_FAILURE; +} + + +PNET_DEV RtmpOSNetDevGetByName(PNET_DEV pNetDev, PSTRING pDevName) +{ + PNET_DEV pTargetNetDev = NULL; + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + pTargetNetDev = dev_get_by_name(dev_net(pNetDev), pDevName); +#else + ASSERT(pNetDev); + pTargetNetDev = dev_get_by_name(pNetDev->nd_net, pDevName); +#endif +#else + pTargetNetDev = dev_get_by_name(pDevName); +#endif // KERNEL_VERSION(2,6,24) // + +#else + int devNameLen; + + devNameLen = strlen(pDevName); + ASSERT((devNameLen <= IFNAMSIZ)); + + for(pTargetNetDev=dev_base; pTargetNetDev!=NULL; pTargetNetDev=pTargetNetDev->next) + { + if (strncmp(pTargetNetDev->name, pDevName, devNameLen) == 0) + break; + } +#endif // KERNEL_VERSION(2,5,0) // + + return pTargetNetDev; +} + + +void RtmpOSNetDeviceRefPut(PNET_DEV pNetDev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + /* + 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); +#endif // LINUX_VERSION_CODE // +} + + +INT RtmpOSNetDevDestory( + IN RTMP_ADAPTER *pAd, + IN PNET_DEV pNetDev) +{ + + // TODO: Need to fix this + printk("WARNING: This function(%s) not implement yet!!!\n", __FUNCTION__); + return 0; +} + + +void RtmpOSNetDevDetach(PNET_DEV pNetDev) +{ + unregister_netdev(pNetDev); +} + + +int RtmpOSNetDevAttach( + IN PNET_DEV pNetDev, + IN 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) + { + PRTMP_ADAPTER pAd = RTMP_OS_NETDEV_GET_PRIV(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 (WIRELESS_EXT < 21) && (WIRELESS_EXT >= 12) + pNetDev->get_wireless_stats = rt28xx_get_wireless_stats; +#endif + +#ifdef CONFIG_STA_SUPPORT +#if WIRELESS_EXT >= 12 + if (pAd->OpMode == OPMODE_STA) + { + pNetDev->wireless_handlers = &rt28xx_iw_handler_def; + } +#endif //WIRELESS_EXT >= 12 +#endif // CONFIG_STA_SUPPORT // + +#ifdef CONFIG_APSTA_MIXED_SUPPORT +#if WIRELESS_EXT >= 12 + if (pAd->OpMode == OPMODE_AP) + { + pNetDev->wireless_handlers = &rt28xx_ap_iw_handler_def; + } +#endif //WIRELESS_EXT >= 12 +#endif // CONFIG_APSTA_MIXED_SUPPORT // + + // 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; +} + + +PNET_DEV RtmpOSNetDevCreate( + IN RTMP_ADAPTER *pAd, + IN INT devType, + IN INT devNum, + IN INT privMemSize, + IN PSTRING 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; +} |