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

📄 send.cpp

📁 一个无线网卡的驱动程序,基于win2
💻 CPP
字号:
//////////////////////////////////////////////////////////////////////////

//    Copyright @2003 Peng He,Information Science Insititute,XiDian University

//    MyNdis_Wdm example
//Abstract:
//    Send.c   将上层协议驱动程序发出的数据包发送给底层USB设备
//Environment:
//    kernel mode only

//    Version history:
//
///////////////////////////////////////////////////////////////////////////


#include <ndis.h>
#include <ntdef.h>
#include <windef.h>

#include "stdarg.h"
#include "stdio.h"
#include "debug.h"

#include "usbdi.h"
#include "usbdlib.h"

#include "common.h"
#include "Usb_wirlessadapter.h"



/*****************************************************************************
// SendPacket
//
// 数据包发送处理例程,将数据包发送至USB设备,并产生irp,用以操作发送队列
//
//
*****************************************************************************/

NTSTATUS
SendPacket(
           IN PUSB_DEVICE   Adapter,        
           IN PVOID         pPacketToSend,                // 指向要发送包的指针
           IN UINT         Flags,                        // 包的标志位
           IN CONTEXT_TYPE Type                         // 包类型
           );
{
	PIRP                PIrp;                 // 定义I/O请求包
	UINT                BytesToWrite =0;      
    NTSTATUS            status;
	BOOLEAN             fConvertedPacket;
	ULONG   size;
	PURB  Urb=NULL;                          // 初始Urb指针为空
	PDEVICE_OBJECT     urbTargetDev;
    PIO_STACK_LOCATION  nextStack;
    PMDL    mdl = NULL;                      // 定义驻留缓冲区
	PUSB_CONTEXT  pCur, thisContext;         // 定义指向USB_CONTEXT结构体的指针

	ASSERT(KeGetCurrentIrql()==PASSIVE_LEVEL);

	thisContext=(PUSB_CONTEXT)GetFreeContext(Adapter);
	  
	if ( NULL == thisContext )
    {
        
		status = STATUS_UNSUCCESSFUL;
        
		goto release;
    }


	thisContext->Packet= pPacketToSend;  // 指向要发送的包
	thisContext->Type = Type;            // 确定包类型

	urb=thisContext->Urb;               // 确定URB结构体指针

	NdisZeroMemory(urb,Adapter->UrbLen); // 对URB结构体清零

	if (CONTEXT_NDIS_PACKET == Type)
	{ 
		ASSERT(NULL!=pPacketToSend);  // 判断发送包的包描述符指针是否为空

		//
		// 获得整个包的信息
		//

		NdisQueryPacket( (PNDIS_PACKET)pPacketToSend, NULL, NULL, NULL, &BytesToWrite);
		
		BytesToWrite += USB_PACKET_LENGTH;  // 包长加2

		thisContext->BufLen=BytesToWrite;  // 将包的数据内容附给thisContext结构体中的BufLen变量

		
        NdisZeroMemory(                    // 清空thisContext结构体中定义的缓冲区
                    thisContext->Buffer,
                    thisContext->BufLen
                    );


		//
		// 将NDIS类型的网络数据包转变为USB设备可传输的贞结构,并将它考贝到定义好的缓冲区中,同时向USB设备传递irp
		//
        //
		    
		fConvertedPacket = NdisToUsbPacket(
                                    Adapter,
                                    pPacketToSend,
                                    (PUCHAR)thisContext->Buffer,
                                  	MAX_PACKET_SIZE+USB_PACKET_LENGTH
                                    );

		if (fConvertedPacket==FALSE)
		{
			status=STATUS_UNSUCCESSFUL;

			goto release;
		}

	}

	else if ( CONTEXT_TERMINATOR == Type)
	{
		//
		// 发送一个0长度的包作为终止包的标志
		//

		BytesToWrite=0;
	
	}


	thisContext->BufLen=BytesToWrite; 

	//
	// 产生Urb,并且向USB设备发送irp请求
	//

    urbTargetDev=Adapter->pUsbDevObj;  // 绑定USB设备对象

	//
	// 向UsbHub发送irp
	//

	pIrp = IoAllocateIrp( (CCHAR)(Device->pUsbDevObj->StackSize +1), FALSE );  // 用IoAllocateIrp来创建Irp其StackSize均要+1
    
	if (NULL==PIrp)
	{
		status=STATUS_UNSUCCESSFUL;

		goto release;
	}

	// 
	// 为USBD创建URB结构
	//

    urb->UrbBulkOrInterruptTransfer.Hdr.Length =
        (USHORT) sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
    urb->UrbBulkOrInterruptTransfer.Hdr.Function =
                URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
    urb->UrbBulkOrInterruptTransfer.PipeHandle =
               Adapter->BulkOutPipeHandle;
    urb->UrbBulkOrInterruptTransfer.TransferFlags =
        USBD_TRANSFER_DIRECTION_OUT ;
    // short packet is not treated as an error.
    urb->UrbBulkOrInterruptTransfer.TransferFlags |=
        USBD_SHORT_TRANSFER_OK;
    urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
    urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
    urb->UrbBulkOrInterruptTransfer.TransferBuffer = thisContext1->Buffer;
    urb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int) BytesToWrite;


	//
	// 调用USB类驱动程序,完成操作
	//

	 nextStack = IoGetNextIrpStackLocation(pIrp);

	 ASSERT(nextStack != NULL);

	 // 
	 // 设置I/O栈单元参数,确定其完成的操作,发出URB
	 //

	 
     nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
     nextStack->Parameters.Others.Argument1 = urb;
     nextStack->Parameters.DeviceIoControl.IoControlCode =IOCTL_INTERNAL_USB_SUBMIT_URB;

     //
	 // 注册一个IoCompletion例程,当下一层驱动程序已经完成对给定IRP的请求操作时调用它
	 //

    IoSetCompletionRoutine(
                pIrp,                      // 指向驱动程序想追踪的irp
                UsbIoCompleteWrite,        // 指定驱动程序提供的IoCompletion例程的入口,在下一层驱动程序完成信息包时调用它
                DEV_TO_CONTEXT(thisContext),  // 指向驱动程序决定的传递到IoCompletion例程的上下文
                TRUE,                      // 如果IRP在I/O状态块中用STATUS_SUCCESS完成,则确定是否调用完成例程
                TRUE,                      // 如果IRP在I/O状态块中用STATUS_XXX完成,则确定是否调用完成例程
                TRUE);                     // 如果IRP在I/O状态块中用STATUS_CANCELLED完成,则确定是否调用完成例程

	//
	// 传递一个IRP到下一层驱动程序
	//
	 
     UsbIncIoCount( Adapter );

	 status=IoCallDriver(
		           urbTargetDev,  // 指向下一层驱动程序的设备对象,该对象为请求I/O操作描述目标设备
				   PIrp);         // 指向IRP

	 //
	 // 当USB设备收到一个写请求的IRP时,此层的驱动程序会返回STATUS_PENDING状态
	 //
    
	 ASSERT(status == STATUS_PENDING);

    
    if ( BytesToWrite && ( BytesToWrite % 64 == 0))
    {   // ((PUSB_INFO) Device->pUsbInfo)->UsbInterface->Pipes[1].MaximumPacketSize ) == 0) {

        SendPacket(	Adapter, NULL, 0, CONTEXT_TERMINATOR );
    }

release:

    return status;

}




/*****************************************************************************
// UsbIoCompleteWrite
//
// USB设备完成写数据功能,即将数据包发送出去
//
//
*****************************************************************************/

NTSTATUS
UsbIoCompleteWrite(
               IN PUSB_DEVICE   urbTargetDev,  // 指向完成该IRP操作的功能设备
			   IN PIRP             PIrp,          // 该功能设备要完成的IRP
               IN PVOID         Context)       // 指向驱动程序决定的传递到UsbIoCompleteWrite例程的上下文,该上下文结构在IoCallDriver调用前传递到UsbIoCompleteWrite
{
	PUSB_DEVICE         Adapter;
	PVOID               pThisContextPacket;
    NTSTATUS            status;
	BOOLEAN             found=FALSE;
	PUSB_CONTEXT        thisContext = ( PUSB_CONTEXT ) Context;
    PUSB_CONTEXT        pPrev, pCur, pNext;
	int                 len;
    CONTEXT_TYPE        ContextType;
    PIRP                ContextIrp;
    PURB                ContextUrb;
    ULONG               BufLen;

	//
	// 传递到UsbIoCompleteWrite例程的上下文结构是USB_CONTEXT结构
	//

	ASSERT( thisContext != NULL ); // 该Context结构最好不为空

	Adapter=thisContext->DeviceObject;  // 确定该例程的功能设备对象
	 
	ASSERT( Adapter != NULL );

	//
	// 确定Context结构体的各个参数
	//

	ContextType = thisContext->Type;
    ContextIrp = thisContext->Irp;
    ContextUrb = thisContext->Urb;
    BufLen = thisContext->BufLen;

	
	pThisContextPacket =  thisContext->Packet;

	//
	// 检查IRP、URB
	//

	ASSERT( ContextIrp ==  pIrp );   // 判断Context结构体内的IRP是否是该功能设备要完成的IRP

	status = pIrp->IoStatus.Status;  // 得到IRP内的状态参数

	//
	// IRP的状态参数可以是失败、成功或是清除,但不能为挂起
	//

    ASSERT( status!=STATUS_PENDING ); 

	//
	// IoCallDriver已经被调用,传递了该IRP
	//

	//
	// 在该IRP中保留URB结构体内的各个参数
	//

	pIrp->IoStatus.Information = ContextUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;

    len = (int)pIrp->IoStatus.Information; // 保留参数信息


	  if (status == STATUS_SUCCESS)
    {
        InterlockedIncrement( (PLONG) &Adapter->packetsSent );
    }
    else
    {
        InterlockedIncrement( (PLONG) &Adapter->NumDataErrors);
        InterlockedIncrement( (PLONG) &Adapter->packetsSentDropped);
    }

	//
	// 释放我们开始分配的IRP
	//

	IoFreeIrp( pIrp );

	InterlockedExchange( (PLONG) &thisContext->fInUse, FALSE );  // 给thisContext->fInUse变量附值,为FALSE

	UsbDecIoCount( Adapter ); // 跟踪挂起的IRP,其数目减1


	if (CONTEXT_NDIS_TYPE==ContextType)
	{
		//
		// 指示上一次的包发送操作已完成,并向上层协议驱动程序明确其状态
		//

		NdisMsendComplete(
			          Adapter->MiniportHandle, // 适配器环境区句柄
					  pThisContextPacket, // 上层要发送的数据包
                      status); // 传输过程的最好状态,有IRP提供



	 if (( status != STATUS_SUCCESS )  && ( status != STATUS_CANCELLED )) 
	 
	 {
        InterlockedExchange( (PLONG) &Adapter->fPendingWriteClearStall, TRUE );

        ScheduleWorkItem( Adapter,ResetPipeCallback, Adapter->BulkOutPipeHandle, 0);
	 
	 }
    return STATUS_MORE_PROCESSING_REQUIRED;
}



BOOLEAN
NdisToUsbPacket(
            PUSB_DEVICE  Adapter,
            PVOID        pPack,
            UCHAR        *usbPacketBuf,
            UINT         usbPacketBufLen
            )
{
	UINT      i;
	UINT      ndisPacketBytes;
	UINT      totalBytes;
    UINT      ndisPacketLen;
    UINT      bufLen;
	UCHAR     *bufData;
    UCHAR     nextChar;

	PNDIS_BUFFER    ndisBuf;
    PNDIS_PACKET    pPacket = (PNDIS_PACKET) pPack;

	DEBUGMSG(DBG_FUNC, ("+NdisToUsbPacket input packet:\n"));

    ndisPacketBytes = 0;
   
    totalBytes      = 0;

	//
	// 获取整个包长和它的第一个NDIS缓冲区信息
	//

	NdisQueryPacket(pPacket, NULL, NULL, &ndisBuf, &ndisPacketLen);

	//
	// 对各种包长做相应处理
	//

	if (ndisPacketLen>0)
	{
		//
		// 如果包长不为0,它至少包括地址和控制信息,我们要判断包长是否足够大?
		//

		if (ndisPacketLen<20) // IP包头

		{
            DEBUGMSG(DBG_ERR, ("Packet too short in NdisToUsbPacket (%d bytes)\n",
                    ndisPacketLen));

            return FALSE;
        }

		//
		// 同时要保证包长不能溢出到相邻的缓冲区内,也不能超过所分配的整个缓冲区大小
		//

		if (ndisPacketLen>MAX_PACKET_SIZE)
		{
		     DEBUGMSG(DBG_ERR, ("Packet too large in NdisToUsbPacket (%d=%xh bytes), \n"
                      "usbPacketBufLen=%d.",
                      ndisPacketLen, ndisPacketLen, usbPacketBufLen));

        return FALSE;
		}

		 
		if (!ndisBuf)
		 {
        
			DEBUGMSG(DBG_ERR, ("No NDIS_BUFFER in NdisToUsbPacket\n"));
        
			return FALSE;
		 }
    

		 //
		 // 获取缓冲区描述符信息
		 //

        NdisQueryBuffer(ndisBuf, (PVOID *)&bufData, &bufLen); 

		//
		//
		// 开始创建USB贞结构
		// 其格式为:
        //
        //     FIRST BYTE low byte ethernet packet length     (1)
        //     SECOND BYTE 
        //     NdisMedium packet (what we get from NDIS):
        //     Ethernet packet
        // 
		

		usbPacketBuf[0] =(UCHAR) ((ndisPacketLen) & 0x000000FF);
        // DEBUGMSG(DBG_ERR, ("usbPacketBuf[0]="d% bytes), \n",usbPacketBuf[0]);
	
        usbPacketBuf[1] =(UCHAR) (((ndisPacketLen) & 0x0000FF00)/0x100);
        //DEBUGMSG(DBG_ERR, ("usbPacketBuf[1]="d% bytes), \n",usbPacketBuf[1]);

	    totalBytes = USB_PACKET_LENGTH;  // USB_HEADER_SIZE is just two byte

       for (i=0; i<ndisPacketLen; i++)
	   {
        ASSERT(bufData);

        nextChar = *bufData++;

        usbPacketBuf[totalBytes++] = nextChar; 

        if (--bufLen==0)
        {
            NdisGetNextBuffer(ndisBuf, &ndisBuf);
            if (ndisBuf)
            {
                NdisQueryBuffer(ndisBuf, (PVOID *)&bufData, &bufLen);
            }
            else
            {
                bufData = NULL;
            }
        }

	   }

    if ((bufData!=NULL) && ndisPacketLen )
    {
        /*
         *  Packet was corrupt -- it misreported its size.
         */
        DEBUGMSG(DBG_ERR, ("Packet corrupt in NdisToUsbPacket (buffer lengths don't add up to packet length)."));
        return FALSE;
    }


    DEBUGMSG(DBG_FUNC, ("-NdisToUsbPacket converted %d-byte ndis pkt to %d-byte irda pkt to send\n", ndisPacketLen, totalBytes));

    DEBUGMSG(DBG_BUF, ("SENDING:")); 
    USB_DUMP( DBG_BUF, (usbPacketBuf,   totalBytes ) );

    return TRUE;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -