⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtusb_data.c

📁 经过修改的在uClinux2.6上正常运行的ralink rt2571芯片组的设备驱动程序.
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 ***************************************************************************
 * 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 + -