📄 send.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 + -