Hi guys, I’m writing a driver to limit the global network bandwith usage, after reading related DDK documents, I decide to use TDI to implement it. But I meet some strange phenomenon that I cannot explain, could someone here give me any clue to solve the problem? *Thanks in advanced*.
In my implementation, I only handle ‘ClientEventReceive / ClientEventReceiveExpedited’ call and TDI_RECEIVE event, discard ‘ClientEventChainedReceive’ and ‘ClientEventChainedReceiveExpedited’ IRP (return STATUS_ACCESS_DENIED).
The procedure of my TDI_RECEIVE handle routine is as follows:
1.insert this IRP into a private list, and fork a thread for scheduling the IRP list.
2.The scheduling thread first read MDL in IRP package(MmGetSystemAddressForMdlSafe). And I struct another IRP to read the data of the TCP device.
3.After reading the TCP device’s data, copy the data back to the mapping address(applied by MmGetSystemAddressForMdlSafe() function)
If everything is OK, the data SHOULD be the same as the TCP device, but my data is partial wrong. For example the data I received is ‘A->B->C’ though the correct sequence is ‘A->C->B’. But if I try redirecting the IRP while processing TDP_RECEIVE event, everything is perfect, the data is correct.
I’ve no idea about how does it happen…Could someone explain why my first method produces the wrong data ?
The key functions:
void InsertIrpList(PDEVICE_OBJECT pdev,PIRP pIrp,ULONG InFlags,ULONG byte)
{
KeWaitForMutexObject(&irpListMutex,Executive,KernelMode,FALSE,0);
PIO_STACK_LOCATION irpsl;
PIRPLISTENTRY p=(PIRPLISTENTRY)ExAllocatePool(NonPagedPool,sizeof(IRPLISTENTRY));
if (NULL==p)
{
return;
}
irpsl=IoGetCurrentIrpStackLocation(pIrp);
p->offset=0;
p->realbyte=0;//real read bytes
p->Buffer=MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
p->pFileObject=irpsl->FileObject;
p->pdev=pdev;//tcp device
p->byte=byte; // total to read bytes
p->pIrp=pIrp; //old irp
p->pNext=NULL;
p->InFlags=InFlags;// tdi receive flag
if (last!=0)
{
last->pNext=p;
p->pPrevious=last;
last=p;
}
else
{
last=p;
g_IrpListHead.pNext=p;
p->pPrevious=&g_IrpListHead;
}
KeReleaseMutex(&irpListMutex,FALSE);
}
ULONG RecevieTcpData(PIRPLISTENTRY pEntry,ULONG recvbyte)
{
PMDL mdl;
PIO_STACK_LOCATION nextStack;
IO_STATUS_BLOCK iostatus;
PIRP p2=IoAllocateIrp(pEntry->pdev->StackSize,FALSE);
p2->Tail.Overlay.Thread=PsGetCurrentThread();
p2->UserIosb=&iostatus;
p2->RequestorMode = KernelMode;
PVOID buffer=ExAllocatePoolWithTag(NonPagedPool,recvbyte,0x101);
RtlZeroMemory(buffer,recvbyte);
mdl=IoAllocateMdl(buffer,recvbyte,FALSE,FALSE,NULL);
KeInitializeEvent(&pEntry->uevent,NotificationEvent,FALSE);
if (mdl==NULL)
{
DbgPrint(“Error Mdl is Null\n”);
return 0;
}
__try
{
MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
}
__except(1)
{
IoFreeMdl(mdl);
DbgPrint(“Error Lock\n”);
return 0;
}
ULONG len;
//build tdi_recive irp
TdiBuildReceive(p2,pEntry->pdev,pEntry->pFileObject,MyIrpReceiveComplete,pEntry,mdl,pEntry->InFlags,recvbyte);
NTSTATUS st=IoCallDriver(pEntry->pdev,p2);
if(STATUS_PENDING==st)
{
st=KeWaitForSingleObject(&pEntry->uevent,Executive,KernelMode,FALSE,NULL);
}
//copy data
memcpy((PVOID)((ULONG)pEntry->Buffer+pEntry->offset),buffer,pEntry->ulen);
pEntry->offset+=pEntry->ulen;
ExFreePool(buffer);
return pEntry->ulen;
}
Receive thread
p1=GetIrpEntryList();
ULONG len=RecevieTcpData(p1,p1->byte);
if( buffer full ) //complete old irp
{
p1->pIrp->IoStatus.Information=p1->realbyte;
p1->pIrp->IoStatus.Status=p1->status;
IoCompleteRequest(p1->pIrp,IO_NO_INCREMENT);
}