?? rtusb_data.c
字號(hào):
/*
***************************************************************************
* Ralink Tech Inc.
* 4F, No. 2 Technology 5th Rd.
* Science-based Industrial Park
* Hsin-chu, Taiwan, R.O.C.
*
* (c) Copyright 2002-2004, 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:
rtusb_data.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
Name Date Modification logs
Jan Lee 2005-06-01 Release
*/
#include "rt_config.h"
static UCHAR PlcpSignal[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
static UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
static UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8};
static UCHAR EAPOL[] = {0x88, 0x8e};
static UCHAR IPX[] = {0x81, 0x37};
static UCHAR APPLE_TALK[] = {0x80, 0xf3};
UCHAR ARP[]={0x08, 0x06};
////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
// RTUSBSendPackets
//
// DESCRIPTION
// VNETMultipleSend handler is called by NDIS to transmit packets
// through the adapter. If there are packets in the Q and the device
// can accept the Tx requests initiate a transmission and queue the
// rest of the packets (if any...). If we can not transmit or the
// station is not ready we imediatelly complete the request
//
// INPUT
// MiniportAdapterContext Context registered with the wrapper
// (Ptr to to the Adapter object)
// PacketArray Array of Ptrs to NDIS_PACKET structs
// NumberOfPackets Number of packets in PacketArray
//
// OUTPUT
// -
//
////////////////////////////////////////////////////////////////////////////
int RTUSBSendPackets(struct sk_buff *skb, struct net_device *net_dev)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PRT2570ADAPTER pAdapter = net_dev->priv;
skb->data_len = skb->len;
if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF) ||
RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS))
{
RTUSBFreeSkbBuffer(skb);
return 0;
}
// Drop packets if no associations
else if (!INFRA_ON(pAdapter) && !ADHOC_ON(pAdapter))
{
RTUSBFreeSkbBuffer(skb);
return 0;
}
else
{
Status = RTUSBSendPacket(pAdapter, skb);
if (Status != NDIS_STATUS_SUCCESS)
{
// Errors before enqueue stage
RTUSBFreeSkbBuffer(skb);
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(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) &&
(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) &&
(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)))
{
//RTMPDeQueuePacket(pAdapter, &pAdapter->TxSwQueue0);
// Call dequeue without selected queue, let the subroutine select the right priority
// Tx software queue
RTUSBDeQueuePacket(pAdapter);
}
// Kick bulk out
RTUSBKickBulkOut(pAdapter);
return 0;
}
NDIS_STATUS RTUSBSendPacket(
IN PRT2570ADAPTER pAdapter,
IN struct sk_buff *skb)
{
PVOID pVirtualAddress;
PQUEUE_HEADER pTxQueue;
ULONG Priority;
UCHAR NumberOfFrag;
UCHAR RTSRequired;
UINT AllowFragSize;
UCHAR AccessCategory;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
UCHAR PsMode;
// Init priority value
Priority = 0;
AccessCategory = 0;
if (skb)
{
Priority = skb->priority;
// 802.11e/d4.4 June, 2003
if (Priority <=2)
AccessCategory = 0;
else if (Priority == 3)
AccessCategory = 1;
else if (Priority <= 5)
AccessCategory = 2;
else
AccessCategory = 3;
DBGPRINT(RT_DEBUG_INFO, "Priority = %d, AC = %d\n", Priority, AccessCategory);
}
// For TKIP, MIC value is treated as payload, it might be fragmented through
// different MPDUs.
if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled)
{
skb->data_len += 8;
}
pVirtualAddress = (PVOID)skb->data;
// Check for virtual address allocation, it might fail !!!
if (pVirtualAddress == NULL)
{
DBGPRINT(RT_DEBUG_TRACE,"<---RTUSBSendPacket NULL pVirtualAddress\n");
// Resourece is low, system did not allocation virtual address
// return NDIS_STATUS_FAILURE directly to upper layer
return (Status);
}
//
// Check for multicast or broadcast (First byte of DA)
//
if ((*((PUCHAR) pVirtualAddress) & 0x01) != 0)
{
// For multicast & broadcast, there is no fragment allowed
NumberOfFrag = 1;
}
else
{
// Check for payload allowed for each fragment
AllowFragSize = (pAdapter->PortCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC;
// Calculate fragments required
NumberOfFrag = ((skb->data_len - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1;
// Minus 1 if the size just match to allowable fragment size
if (((skb->data_len - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0)
{
NumberOfFrag--;
}
}
// Check for requirement of RTS
if (NumberOfFrag > 1)
{
// If multiple fragment required, RTS is required only for the first fragment
// if the fragment size large than RTS threshold
RTSRequired = (pAdapter->PortCfg.FragmentThreshold > pAdapter->PortCfg.RtsThreshold) ? 1 : 0;
}
else
{
RTSRequired = (skb->data_len > pAdapter->PortCfg.RtsThreshold) ? 1 : 0;
}
// RTS/CTS may also be required in order to protect OFDM frame
if ((pAdapter->PortCfg.TxRate >= RATE_FIRST_OFDM_RATE) && pAdapter->PortCfg.BGProtectionInUsed)
RTSRequired = 1;
//DBGPRINT(RT_DEBUG_TEMP, "Number of fragments :%d , include RTS :%d\n", NumberOfFrag, NumberOfFrag + RTSRequired);
// Save framnet number to Ndis packet reserved field
RTMP_SET_PACKET_FRAGMENTS(skb, NumberOfFrag);
// Save RTS requirement to Ndis packet reserved field
RTMP_SET_PACKET_RTS(skb, RTSRequired);
// Make sure SendTxWait queue resource won't be used by other threads
NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);
pTxQueue = &pAdapter->SendTxWaitQueue;
if (INFRA_ON(pAdapter))
{
if(pTxQueue->Number > MAX_PACKETS_IN_QUEUE)
{
DBGPRINT(RT_DEBUG_WARN, "pTxQueue is full!!!\n\n");
pAdapter->bNetDeviceStopQueue = TRUE;
netif_stop_queue(pAdapter->net);
}
// 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, skb);
Status = NDIS_STATUS_SUCCESS;
}
else
{
if(pTxQueue->Number > MAX_PACKETS_IN_QUEUE)
{
DBGPRINT(RT_DEBUG_WARN, "pTxQueue is full!!!\n");
pAdapter->bNetDeviceStopQueue = TRUE;
netif_stop_queue(pAdapter->net);
}
// In IBSS mode, power state of destination should be considered.
PsMode = PWR_ACTIVE; // Faked
if (PsMode == PWR_ACTIVE)
{
// Enqueue Ndis packet to end of Tx wait queue
InsertTailQueue(pTxQueue, skb);
Status = NDIS_STATUS_SUCCESS;
}
}
NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);
return Status;
}
VOID RTUSBDeQueuePacket(
IN PRT2570ADAPTER pAdapter)
{
UCHAR FragmentRequired;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
struct sk_buff *skb;
PQUEUE_HEADER pQueue;
UCHAR Count = 0;
// Make sure SendTxWait queue resource won't be used by other threads
NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);
// Select Queue
pQueue = &pAdapter->SendTxWaitQueue;
// Check queue before dequeue
while ((pQueue->Head != NULL) && (Count < MAX_TX_PROCESS))
{
// Reset is in progress, stop immediately
if ( RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS))
{
break;
}
// Dequeue the first entry from head of queue list
skb = (struct sk_buff *)RemoveHeadQueue(pQueue);
// RTS or CTS-to-self for B/G protection mode has been set already.
// There is no need to re-do it here.
// Total fragment required = number of fragment + RST if required
FragmentRequired = RTMP_GET_PACKET_FRAGMENTS(skb) + RTMP_GET_PACKET_RTS(skb);
if (RTUSBFreeDescriptorRequest(pAdapter, TX_RING, FragmentRequired) == NDIS_STATUS_SUCCESS)
{
// Avaliable ring descriptors are enough for this frame
// Call hard transmit
// Nitro mode / Normal mode selection
NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);
if (pAdapter->PortCfg.EnableTxBurst == 1)
Status = RTUSBHardEncrypt(pAdapter, skb, FragmentRequired, TRUE);
else
Status = RTUSBHardEncrypt(pAdapter, skb, FragmentRequired, FALSE);
//
// Acquire the resource again, snice we may need to process it in this while-loop.
//
NdisAcquireSpinLock(&pAdapter->SendTxWaitQueueLock);
if (Status == NDIS_STATUS_FAILURE)
{
// Packet failed due to various Ndis Packet error
RTUSBFreeSkbBuffer(skb);
break;
}
else if (Status == NDIS_STATUS_RESOURCES)
{
// Not enough free tx ring, it might happen due to free descriptor inquery might be not correct
// It also might change to NDIS_STATUS_FAILURE to simply drop the frame
// Put the frame back into head of queue
InsertHeadQueue(pQueue, skb);
break;
}
Count++;
}
else
{
InsertHeadQueue(pQueue, skb);
break;
}
}
NdisReleaseSpinLock(&pAdapter->SendTxWaitQueueLock);
return;
}
NDIS_STATUS RTUSBFreeDescriptorRequest(
IN PRT2570ADAPTER pAdapter,
IN UCHAR RingType,
IN UCHAR NumberRequired)
{
UCHAR FreeNumber = 0;
UINT Index;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
switch (RingType)
{
case TX_RING:
Index = pAdapter->NextTxIndex;
do
{
PTX_CONTEXT pTxD = &pAdapter->TxContext[Index];
// While Owner bit is NIC, obviously ASIC still need it.
// If valid bit is TRUE, indicate that TxDone has not process yet
// We should not use it until TxDone finish cleanup job
if (pTxD->InUse == FALSE)
{
// This one is free
FreeNumber++;
}
else
{
break;
}
Index = (Index + 1) % TX_RING_SIZE;
} while (FreeNumber < NumberRequired); // Quit here ! Free number is enough !
if (FreeNumber >= NumberRequired)
{
Status = NDIS_STATUS_SUCCESS;
}
break;
case PRIO_RING:
Index = pAdapter->NextMLMEIndex;
do
{
PTX_CONTEXT pTxD = &pAdapter->MLMEContext[Index];
// While Owner bit is NIC, obviously ASIC still need it.
// If valid bit is TRUE, indicate that TxDone has not process yet
// We should not use it until TxDone finish cleanup job
if (pTxD->InUse == FALSE)
{
// This one is free
FreeNumber++;
}
else
{
break;
}
Index = (Index + 1) % PRIO_RING_SIZE;
} while (FreeNumber < NumberRequired); // Quit here ! Free number is enough !
if (FreeNumber >= NumberRequired)
{
Status = NDIS_STATUS_SUCCESS;
}
break;
default:
break;
}
return (Status);
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -