📄 rtusb_data.c
字号:
/*
***************************************************************************
* Ralink Tech Inc.
* 4F, No. 2 Technology 5th Rd.
* Science-based Industrial Park
* Hsin-chu, Taiwan, R.O.C.
*
* (c) Copyright 2002-2006, 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. *
* *
************************************************************************
Module Name:
rtmp_data.c
Abstract:
Ralink USB driver Tx/Rx functions
Revision History:
Who When What
-------- ---------- ----------------------------------------------
*/
#include "rt_config.h"
#include <net/iw_handler.h>
extern UCHAR Phy11BGNextRateUpward[]; // defined in mlme.c
UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8};
UCHAR EAPOL_LLC_SNAP[]= {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e};
UCHAR EAPOL[] = {0x88, 0x8e};
UCHAR IPX[] = {0x81, 0x37};
UCHAR APPLE_TALK[] = {0x80, 0xf3};
UCHAR RateIdToPlcpSignal[12] = {
0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec
11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14
9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14
UCHAR OfdmSignalToRateId[16] = {
RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 0, 1, 2, 3 respectively
RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 4, 5, 6, 7 respectively
RATE_48, RATE_24, RATE_12, RATE_6, // OFDM PLCP Signal = 8, 9, 10, 11 respectively
RATE_54, RATE_36, RATE_18, RATE_9, // OFDM PLCP Signal = 12, 13, 14, 15 respectively
};
UCHAR default_cwmin[]={CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1, CW_MIN_IN_BITS-2};
UCHAR default_cwmax[]={CW_MAX_IN_BITS, CW_MAX_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1};
UCHAR default_sta_aifsn[]={3,7,2,2};
UCHAR MapUserPriorityToAccessCategory[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO};
// Macro for rx indication
VOID REPORT_ETHERNET_FRAME_TO_LLC(
IN PRTMP_ADAPTER pAd,
IN PUCHAR p8023hdr,
IN PUCHAR pData,
IN ULONG DataSize,
IN struct net_device *net_dev)
{
struct sk_buff *pSkb;
#ifdef RTMP_EMBEDDED
if ((pSkb = __dev_alloc_skb(DataSize + LENGTH_802_3 + 2, GFP_DMA|GFP_ATOMIC)) != NULL)
#else
if ((pSkb = dev_alloc_skb(DataSize + LENGTH_802_3 + 2)) != NULL)
#endif
{
pSkb->dev = net_dev;
skb_reserve(pSkb, 2); // 16 byte align the IP header
memcpy(skb_put(pSkb, LENGTH_802_3), p8023hdr, LENGTH_802_3);
memcpy(skb_put(pSkb, DataSize), pData, DataSize);
pSkb->protocol = eth_type_trans(pSkb, net_dev);
netif_rx(pSkb);
pAd->net_dev->last_rx = jiffies;
pAd->stats.rx_packets++;
pAd->Counters8023.GoodReceives++;
}
}
// Enqueue this frame to MLME engine
// We need to enqueue the whole frame because MLME need to pass data type
// information from 802.11 header
#define REPORT_MGMT_FRAME_TO_MLME(_pAd, _pFrame, _FrameSize, _Rssi, _PlcpSignal) \
{ \
MlmeEnqueueForRecv(_pAd, (UCHAR)_Rssi, _FrameSize, _pFrame, (UCHAR)_PlcpSignal); \
}
// NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same
// scatter gather buffer
NDIS_STATUS Sniff2BytesFromNdisBuffer(
IN struct sk_buff *pFirstSkb,
IN UCHAR DesiredOffset,
OUT PUCHAR pByte0,
OUT PUCHAR pByte1)
{
PUCHAR pBufferVA;
ULONG BufferLen, AccumulateBufferLen, BufferBeginOffset;
pBufferVA = (PVOID)pFirstSkb->data;
BufferLen = pFirstSkb->len;
BufferBeginOffset = 0;
AccumulateBufferLen = BufferLen;
*pByte0 = *(PUCHAR)(pBufferVA + DesiredOffset - BufferBeginOffset);
*pByte1 = *(PUCHAR)(pBufferVA + DesiredOffset - BufferBeginOffset + 1);
return NDIS_STATUS_SUCCESS;
}
/*
========================================================================
Routine Description:
This routine classifies outgoing frames into several AC (Access
Category) and enqueue them into corresponding s/w waiting queues.
Arguments:
pAd Pointer to our adapter
pPacket Pointer to send packet
Return Value:
None
Note:
========================================================================
*/
NDIS_STATUS RTMPSendPacket(
IN PRTMP_ADAPTER pAd,
IN struct sk_buff *pSkb)
{
PUCHAR pSrcBufVA;
UINT AllowFragSize;
UCHAR NumberOfFrag;
UCHAR RTSRequired;
UCHAR QueIdx, UserPriority;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PQUEUE_HEADER pTxQueue;
UCHAR PsMode;
ULONG IrqFlags;
DBGPRINT(RT_DEBUG_INFO, "====> RTMPSendPacket\n");
// Prepare packet information structure for buffer descriptor
pSrcBufVA = (PVOID)pSkb->data;
// STEP 1. Check for virtual address allocation, it might fail !!!
if (pSrcBufVA == NULL)
{
// Resourece is low, system did not allocate virtual address
// return NDIS_STATUS_FAILURE directly to upper layer
return NDIS_STATUS_FAILURE;
}
//
// Check for multicast or broadcast (First byte of DA)
//
if ((*((PUCHAR) pSrcBufVA) & 0x01) != 0)
{
// For multicast & broadcast, there is no fragment allowed
NumberOfFrag = 1;
}
#if 0 //AGGREGATION_SUPPORT
else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))
{
NumberOfFrag = 1; // Aggregation overwhelms fragmentation
}
#endif
else
{
// Check for payload allowed for each fragment
AllowFragSize = (pAd->PortCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC;
// Calculate fragments required
NumberOfFrag = ((pSkb->len - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1;
// Minus 1 if the size just match to allowable fragment size
if (((pSkb->len - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0)
{
NumberOfFrag--;
}
}
// Save fragment number to Ndis packet reserved field
RTMP_SET_PACKET_FRAGMENTS(pSkb, NumberOfFrag);
// STEP 2. Check the requirement of RTS:
// If multiple fragment required, RTS is required only for the first fragment
// if the fragment size large than RTS threshold
if (NumberOfFrag > 1)
RTSRequired = (pAd->PortCfg.FragmentThreshold > pAd->PortCfg.RtsThreshold) ? 1 : 0;
else
RTSRequired = (pSkb->len > pAd->PortCfg.RtsThreshold) ? 1 : 0;
//
// Remove the following lines to avoid confusion.
// CTS requirement will not use Flag "RTSRequired", instead moveing the
// following lines to RTUSBHardTransmit(..)
//
// RTS/CTS may also be required in order to protect OFDM frame
//if ((pAd->PortCfg.TxRate >= RATE_FIRST_OFDM_RATE) &&
// OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED))
// RTSRequired = 1;
// Save RTS requirement to Ndis packet reserved field
RTMP_SET_PACKET_RTS(pSkb, RTSRequired);
RTMP_SET_PACKET_TXRATE(pSkb, pAd->PortCfg.TxRate);
//
// STEP 3. Traffic classification. outcome = <UserPriority, QueIdx>
//
UserPriority = 0;
QueIdx = QID_AC_BE;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))
{
USHORT Protocol;
UCHAR LlcSnapLen = 0, Byte0, Byte1;
do
{
// get Ethernet protocol field
Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]);
if (Protocol <= 1500)
{
// get Ethernet protocol field from LLC/SNAP
if (Sniff2BytesFromNdisBuffer(pSkb, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS)
break;
Protocol = (USHORT)((Byte0 << 8) + Byte1);
LlcSnapLen = 8;
}
// always AC_BE for non-IP packet
if (Protocol != 0x0800)
break;
// get IP header
if (Sniff2BytesFromNdisBuffer(pSkb, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS)
break;
// return AC_BE if packet is not IPv4
if ((Byte0 & 0xf0) != 0x40)
break;
UserPriority = (Byte1 & 0xe0) >> 5;
QueIdx = MapUserPriorityToAccessCategory[UserPriority];
// TODO: have to check ACM bit. apply TSPEC if ACM is ON
// TODO: downgrade UP & QueIdx before passing ACM
if (pAd->PortCfg.APEdcaParm.bACM[QueIdx])
{
UserPriority = 0;
QueIdx = QID_AC_BE;
}
} while (FALSE);
}
RTMP_SET_PACKET_UP(pSkb, UserPriority);
// Make sure SendTxWait queue resource won't be used by other threads
NdisAcquireSpinLock(&pAd->SendTxWaitQueueLock[QueIdx], IrqFlags);
pTxQueue = &pAd->SendTxWaitQueue[QueIdx];
//
// For infrastructure mode, enqueue this frame immediately to sendwaitqueue
// For Ad-hoc mode, check the DA power state, then decide which queue to enqueue
//
if (INFRA_ON(pAd))
{
// In infrastructure mode, simply enqueue the packet into Tx waiting queue.
DBGPRINT(RT_DEBUG_INFO, "Infrastructure -> Enqueue one frame\n");
// Enqueue Ndis packet to end of Tx wait queue
InsertTailQueue(pTxQueue, pSkb);
Status = NDIS_STATUS_SUCCESS;
#ifdef DBG
pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed
#endif
}
else
{
// In IBSS mode, power state of destination should be considered.
PsMode = PWR_ACTIVE; // Faked
if (PsMode == PWR_ACTIVE)
{
DBGPRINT(RT_DEBUG_INFO,"Ad-Hoc -> Enqueue one frame\n");
// Enqueue Ndis packet to end of Tx wait queue
InsertTailQueue(pTxQueue, pSkb);
Status = NDIS_STATUS_SUCCESS;
#ifdef DBG
pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed
#endif
}
}
NdisReleaseSpinLock(&pAd->SendTxWaitQueueLock[QueIdx], IrqFlags);
return (Status);
}
/*
========================================================================
Routine Description:
SendPackets handler
Arguments:
skb point to sk_buf which upper layer transmit
net_dev point to net_dev
Return Value:
None
Note:
========================================================================
*/
INT RTMPSendPackets(
IN struct sk_buff *pSkb,
IN struct net_device *net_dev)
{
PRTMP_ADAPTER pAd = net_dev->priv;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
INT Index;
DBGPRINT(RT_DEBUG_INFO, "===> RTMPSendPackets\n");
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))
{
// Drop send request since hardware is in reset state
RTUSBFreeSkbBuffer(pSkb);
return 0;
}
// Drop packets if no associations
else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd))
{
RTUSBFreeSkbBuffer(pSkb);
return 0;
}
else
{
// initial pSkb->data_len=0, we will use this variable to store data size when fragment(in TKIP)
// and pSkb->len is actual data len
pSkb->data_len = pSkb->len;
// Record that orignal packet source is from protocol layer,so that
// later on driver knows how to release this skb buffer
RTMP_SET_PACKET_SOURCE(pSkb, PKTSRC_NDIS);
pAd->RalinkCounters.PendingNdisPacketCount ++;
Status = RTMPSendPacket(pAd, pSkb);
if (Status != NDIS_STATUS_SUCCESS)
{
// Errors before enqueue stage
RELEASE_NDIS_PACKET(pAd, pSkb);
DBGPRINT(RT_DEBUG_TRACE,"<---RTUSBSendPackets not dequeue\n");
return 0;
}
}
// Dequeue one frame from SendTxWait queue and process it
// There are two place calling dequeue for TX ring.
// 1. Here, right after queueing the frame.
// 2. At the end of TxRingTxDone service routine.
if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) &&
(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) &&
(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)))
{
for (Index = 0; Index < 4; Index++)
{
if(pAd->SendTxWaitQueue[Index].Number > 0)
{
RTMPDeQueuePacket(pAd, Index);
}
}
}
// Kick bulk out
RTUSBKickBulkOut(pAd);
return 0;
}
/*
========================================================================
Routine Description:
Copy frame from waiting queue into relative ring buffer and set
appropriate ASIC register to kick hardware encryption before really
sent out to air.
Arguments:
pAd Pointer to our adapter
PNDIS_PACKET Pointer to outgoing Ndis frame
NumberOfFrag Number of fragment required
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -