本文主要是介绍庖丁解牛---winpcap源码彻底解密系列的续集(7),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
DeviceIoControl对应npf.sys中的NPF_IoControl函数;
NTSTATUS NPF_IoControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PLIST_ENTRY RequestListEntry;
PINTERNAL_REQUEST pRequest;
ULONG FunctionCode;
NDIS_STATUS Status;
ULONG Information = 0;
PLIST_ENTRY PacketListEntry;
UINT i;
PUCHAR tpointer;
ULONG dim,timeout;
struct bpf_insn* NewBpfProgram;
PPACKET_OID_DATA OidData;
int *StatsBuf;
PNDIS_PACKET pPacket;
ULONG mode;
PWSTR DumpNameBuff;
PUCHAR TmpBPFProgram;
INT WriteRes;
BOOLEAN SyncWrite = FALSE;
struct bpf_insn *initprogram;
ULONG insns;
ULONG cnt;
BOOLEAN IsExtendedFilter=FALSE;
ULONG StringLength;
ULONG NeededBytes;
BOOLEAN Flag;
PUINT pStats;
ULONG StatsLength;
HANDLE hUserEvent;
PKEVENT pKernelEvent;
#ifdef _AMD64_
VOID*POINTER_32 hUserEvent32Bit;
#endif //_AMD64_
PMDL mdl;
TRACE_ENTER();
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode;
Open=IrpSp->FileObject->FsContext;
if (NPF_StartUsingOpenInstance(Open) == FALSE)
{
//
// an IRP_MJ_CLEANUP was received, just fail the request
//
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_CANCELLED;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
TRACE_MESSAGE3(PACKET_DEBUG_LOUD,
"Function code is %08lx Input size=%08lx Output size %08lx",
FunctionCode,
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
IrpSp->Parameters.DeviceIoControl.OutputBufferLength);
switch (FunctionCode){
case BIOCGSTATS: //function to get the capture stats
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCGSTATS");
StatsLength = 4*sizeof(UINT);
if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < StatsLength)
{
SET_FAILURE_BUFFER_SMALL();
break;
}
if (Irp->UserBuffer == NULL)
{
SET_FAILURE_UNSUCCESSFUL();
break;
}
//
// temp fix to a GIANT bug from LD. The CTL code has been defined as METHOD_NEITHER, so it
// might well be a dangling pointer. We need to probe and lock the address.
//
mdl = NULL;
pStats = NULL;
__try
{
mdl = IoAllocateMdl(
Irp->UserBuffer,
StatsLength,
FALSE,
TRUE,
NULL);
if (mdl == NULL)
{
SET_FAILURE_UNSUCCESSFUL();
break;
}
MmProbeAndLockPages(
mdl,
UserMode,
IoWriteAccess);
pStats = (PUINT)(Irp->UserBuffer);
}
__except(GetExceptionCode() == STATUS_ACCESS_VIOLATION)
{
pStats = NULL;
}
if (pStats == NULL)
{
if (mdl != NULL)
{
IoFreeMdl(mdl);
}
SET_FAILURE_UNSUCCESSFUL();
break;
}
pStats[3] = 0;
pStats[0] = 0;
pStats[1] = 0;
pStats[2] = 0; // Not yet supported
for(i = 0 ; i < g_NCpu ; i++)
{
pStats[3] += Open->CpuData[i].Accepted;
pStats[0] += Open->CpuData[i].Received;
pStats[1] += Open->CpuData[i].Dropped;
pStats[2] += 0; // Not yet supported
}
MmUnlockPages(mdl);
IoFreeMdl(mdl);
SET_RESULT_SUCCESS(StatsLength);
break;
case BIOCGEVNAME: //function to get the name of the event associated with the current instance
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCGEVNAME");
//
// Since 20060405, the event handling has been changed:
// we no longer use named events, instead the user level app creates an event,
// and passes it back to the kernel, that references it (ObReferenceObjectByHandle), and
// signals it.
// For the time being, we still leave this ioctl code here, and we simply fail.
//
SET_FAILURE_INVALID_REQUEST();
break;
case BIOCSENDPACKETSSYNC:
SyncWrite = TRUE;
case BIOCSENDPACKETSNOSYNC:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSENDPACKETSNOSYNC");
NdisAcquireSpinLock(&Open->WriteLock);
if(Open->WriteInProgress)
{
NdisReleaseSpinLock(&Open->WriteLock);
//
// Another write operation is currently in progress
//
SET_FAILURE_UNSUCCESSFUL();
break;
}
else
{
Open->WriteInProgress = TRUE;
}
NdisReleaseSpinLock(&Open->WriteLock);
WriteRes = NPF_BufferedWrite(Irp,
(PUCHAR)Irp->AssociatedIrp.SystemBuffer,
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
SyncWrite);
NdisAcquireSpinLock(&Open->WriteLock);
Open->WriteInProgress = FALSE;
NdisReleaseSpinLock(&Open->WriteLock);
if( WriteRes != -1)
{
SET_RESULT_SUCCESS(WriteRes);
}
else
{
SET_FAILURE_UNSUCCESSFUL();
}
break;
case BIOCSETF:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETF");
//
// Get the pointer to the new program
//
NewBpfProgram = (struct bpf_insn*)Irp->AssociatedIrp.SystemBuffer;
if(NewBpfProgram == NULL)
{
SET_FAILURE_BUFFER_SMALL();
break;
}
//
// Lock the machine. After this call we are at DISPATCH level
//
NdisAcquireSpinLock(&Open->MachineLock);
do
{
// Free the previous buffer if it was present
if(Open->bpfprogram != NULL)
{
TmpBPFProgram = Open->bpfprogram;
Open->bpfprogram = NULL;
ExFreePool(TmpBPFProgram);
}
//
// Jitted filters are supported on x86 (32bit) only
//
#ifdef _X86_
if (Open->Filter != NULL)
{
BPF_Destroy_JIT_Filter(Open->Filter);
Open->Filter = NULL;
}
#endif // _X86_
insns = (IrpSp->Parameters.DeviceIoControl.InputBufferLength)/sizeof(struct bpf_insn);
//count the number of operative instructions
for (cnt = 0 ; (cnt < insns) &&(NewBpfProgram[cnt].code != BPF_SEPARATION); cnt++);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Operative instructions=%u", cnt);
#ifdef HAVE_BUGGY_TME_SUPPORT
if ( (cnt != insns) && (insns != cnt+1) && (NewBpfProgram[cnt].code == BPF_SEPARATION))
{
TRACE_MESSAGE1(PACKET_DEBUG_LOUD,"Initialization instructions = %u",insns-cnt-1);
IsExtendedFilter = TRUE;
initprogram = &NewBpfProgram[cnt+1];
if(bpf_filter_init(initprogram,&(Open->mem_ex),&(Open->tme), &G_Start_Time)!=INIT_OK)
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error initializing NPF machine (bpf_filter_init)");
SET_FAILURE_INVALID_REQUEST();
break;
}
}
#else // HAVE_BUGGY_TME_SUPPORT
if ( cnt != insns)
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error installing the BPF filter. The filter contains TME extensions,"
" not supported on 64bit platforms.");
SET_FAILURE_INVALID_REQUEST();
break;
}
#endif // HAVE_BUGGY_TME_SUPPORT
//the NPF processor has been initialized, we have to validate the operative instructions
insns = cnt;
//NOTE: the validation code checks for TME instructions, and fails if a TME instruction is
//encountered on 64 bit machines
#ifdef HAVE_BUGGY_TME_SUPPORT
if(bpf_validate(NewBpfProgram, cnt, Open->mem_ex.size) == 0)
#else //HAVE_BUGGY_TME_SUPPORT
if(bpf_validate(NewBpfProgram, cnt) == 0)
#endif //HAVE_BUGGY_TME_SUPPORT
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error validating program");
//FIXME: the machine has been initialized(?), but the operative code is wrong.
//we have to reset the machine!
//something like: reallocate the mem_ex, and reset the tme_core
SET_FAILURE_INVALID_REQUEST();
break;
}
// Allocate the memory to contain the new filter program
// We could need the original BPF binary if we are forced to use bpf_filter_with_2_buffers()
TmpBPFProgram = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, cnt*sizeof(struct bpf_insn), '4PWA');
if (TmpBPFProgram == NULL)
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error - No memory for filter");
// no memory
SET_FAILURE_NOMEM();
break;
}
//
// At the moment the JIT compiler works on x86 (32 bit) only
//
#ifdef _X86_
// Create the new JIT filter function
if(!IsExtendedFilter)
{
if((Open->Filter = BPF_jitter(NewBpfProgram, cnt)) == NULL)
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Error jittering filter");
ExFreePool(TmpBPFProgram);
SET_FAILURE_UNSUCCESSFUL();
break;
}
}
#endif //_X86_
//copy the program in the new buffer
RtlCopyMemory(TmpBPFProgram,NewBpfProgram,cnt*sizeof(struct bpf_insn));
Open->bpfprogram = TmpBPFProgram;
SET_RESULT_SUCCESS(0);
}
while(FALSE);
//
// release the machine lock and then reset the buffer
//
NdisReleaseSpinLock(&Open->MachineLock);
NPF_ResetBufferContents(Open);
break;
case BIOCSMODE: //set the capture mode
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSMODE");
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
mode=*((PULONG)Irp->AssociatedIrp.SystemBuffer);
///kernel dump does not work at the moment//
if (mode & MODE_DUMP)
{
SET_FAILURE_INVALID_REQUEST();
break;
}
///kernel dump does not work at the moment//
if(mode == MODE_CAPT)
{
Open->mode = MODE_CAPT;
SET_RESULT_SUCCESS(0);
break;
}
else if (mode == MODE_MON)
{
//
// The MONITOR_MODE (aka TME extensions) is not supported on
// 64 bit architectures
//
#ifdef HAVE_BUGGY_TME_SUPPORT
Open->mode = MODE_MON;
SET_RESULT_SUCCESS(0);
#else // HAVE_BUGGY_TME_SUPPORT
SET_FAILURE_INVALID_REQUEST();
#endif // HAVE_BUGGY_TME_SUPPORT
break;
}
else{
if(mode & MODE_STAT){
Open->mode = MODE_STAT;
NdisAcquireSpinLock(&Open->CountersLock);
Open->Nbytes.QuadPart = 0;
Open->Npackets.QuadPart = 0;
NdisReleaseSpinLock(&Open->CountersLock);
if(Open->TimeOut.QuadPart==0)Open->TimeOut.QuadPart = -10000000;
}
if(mode & MODE_DUMP){
Open->mode |= MODE_DUMP;
// Open->MinToCopy=(Open->BufSize<2000000)?Open->BufSize/2:1000000;
}
SET_RESULT_SUCCESS(0);
break;
}
SET_FAILURE_INVALID_REQUEST();
break;
case BIOCSETDUMPFILENAME:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETDUMPFILENAME");
///kernel dump does not work at the moment//
SET_FAILURE_INVALID_REQUEST();
break;
///kernel dump does not work at the moment//
//if(Open->mode & MODE_DUMP)
//{
//
// // Close current dump file
// if(Open->DumpFileHandle != NULL)
// {
// NPF_CloseDumpFile(Open);
// Open->DumpFileHandle = NULL;
// }
//
// if(IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0){
// EXIT_FAILURE(0);
// }
//
// // Allocate the buffer that will contain the string
// DumpNameBuff=ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.DeviceIoControl.InputBufferLength, '5PWA');
// if(DumpNameBuff==NULL || Open->DumpFileName.Buffer!=NULL){
// IF_LOUD(DbgPrint("NPF: unable to allocate the dump filename: not enough memory or name already set\n");)
// EXIT_FAILURE(0);
// }
//
// // Copy the buffer
// RtlCopyBytes((PVOID)DumpNameBuff,
// Irp->AssociatedIrp.SystemBuffer,
// IrpSp->Parameters.DeviceIoControl.InputBufferLength);
//
// // Force a \0 at the end of the filename to avoid that malformed strings cause RtlInitUnicodeString to crash the system
// ((PSHORT)DumpNameBuff)[IrpSp->Parameters.DeviceIoControl.InputBufferLength/2-1]=0;
//
// // Create the unicode string
// RtlInitUnicodeString(&Open->DumpFileName, DumpNameBuff);
//
// IF_LOUD(DbgPrint("NPF: dump file name set to %ws, len=%d\n",
// Open->DumpFileName.Buffer,
// IrpSp->Parameters.DeviceIoControl.InputBufferLength);)
//
// // Try to create the file
// if ( NT_SUCCESS( NPF_OpenDumpFile(Open,&Open->DumpFileName,FALSE)) &&
// NT_SUCCESS( NPF_StartDump(Open)))
// {
// EXIT_SUCCESS(0);
// }
//}
//
//EXIT_FAILURE(0);
//
//break;
case BIOCSETDUMPLIMITS:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETDUMPLIMITS");
///kernel dump does not work at the moment//
SET_FAILURE_INVALID_REQUEST();
break;
///kernel dump does not work at the moment//
//if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < 2*sizeof(ULONG))
//{
// EXIT_FAILURE(0);
//}
//
//Open->MaxDumpBytes = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
//Open->MaxDumpPacks = *((PULONG)Irp->AssociatedIrp.SystemBuffer + 1);
//
//IF_LOUD(DbgPrint("NPF: Set dump limits to %u bytes, %u packs\n", Open->MaxDumpBytes, Open->MaxDumpPacks);)
//
//EXIT_SUCCESS(0);
//
//break;
case BIOCISDUMPENDED:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCISDUMPENDED");
///kernel dump does not work at the moment//
SET_FAILURE_INVALID_REQUEST();
break;
///kernel dump does not work at the moment//
//if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT))
//{
// EXIT_FAILURE(0);
//}
//*((UINT*)Irp->UserBuffer) = (Open->DumpLimitReached)?1:0;
//EXIT_SUCCESS(4);
//break;
case BIOCISETLOBBEH:
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(INT))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
#ifdef __NPF_NT4__
// NT4 doesn't support loopback inhibition / activation
SET_FAILURE_INVALID_REQUEST();
break;
#else //not __NPF_NT4__
//
// win2000/xp/2003/vista
//
if(*(PINT)Irp->AssociatedIrp.SystemBuffer == NPF_DISABLE_LOOPBACK)
{
Open->SkipSentPackets = TRUE;
//
// Reset the capture buffers, since they could contain loopbacked packets
//
NPF_ResetBufferContents(Open);
SET_RESULT_SUCCESS(0);
break;
}
else
if(*(PINT)Irp->AssociatedIrp.SystemBuffer == NPF_ENABLE_LOOPBACK)
{
Open->SkipSentPackets = FALSE;
SET_RESULT_SUCCESS(0);
break;
}
else
{
// Unknown operation
SET_FAILURE_INVALID_REQUEST();
break;
}
#endif // !__NPF_NT4__
break;
case BIOCSETEVENTHANDLE:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETEVENTHANDLE");
#ifdef _AMD64_
if (IoIs32bitProcess(Irp))
{
//
// validate the input
//
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof (hUserEvent32Bit))
{
SET_FAILURE_INVALID_REQUEST();
break;
}
hUserEvent32Bit = *(VOID*POINTER_32*)Irp->AssociatedIrp.SystemBuffer;
hUserEvent = hUserEvent32Bit;
}
else
#endif //_AMD64_
{
//
// validate the input
//
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof (hUserEvent))
{
SET_FAILURE_INVALID_REQUEST();
break;
}
hUserEvent = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
}
//
// NT4 doesn't seem to have EVENT_MODIFY_STATE, so on NT4 we request a wider set
// of privileges for the event handle
//
#ifdef __NPF_NT4__
Status = ObReferenceObjectByHandle(hUserEvent,
OBJECT_TYPE_ALL_ACCESS, *ExEventObjectType, Irp->RequestorMode,
(PVOID*) &pKernelEvent, NULL);
#else //__NPF_NT4__
Status = ObReferenceObjectByHandle(hUserEvent,
EVENT_MODIFY_STATE, *ExEventObjectType, Irp->RequestorMode,
(PVOID*) &pKernelEvent, NULL);
#endif //__NPF_NT4__
if (!NT_SUCCESS(Status))
{
// Status = ??? already set
Information = 0;
break;
}
//
// NT4 does not have InterlockedCompareExchangePointer
// InterlockedCompareExchange on NT4 has the same prototype of InterlockedCompareExchange
// on NT5x, so we use this one.
//
#ifdef __NPF_NT4__
if (InterlockedCompareExchange(&Open->ReadEvent, pKernelEvent, NULL) != NULL)
#else
if (InterlockedCompareExchangePointer(&Open->ReadEvent, pKernelEvent, NULL) != NULL)
#endif
{
//
// dereference the new pointer
//
ObDereferenceObject(pKernelEvent);
SET_FAILURE_INVALID_REQUEST();
break;
}
KeResetEvent(Open->ReadEvent);
SET_RESULT_SUCCESS(0);
break;
case BIOCSETBUFFERSIZE:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETBUFFERSIZE");
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
// Get the number of bytes to allocate
dim = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
if (dim / g_NCpu < sizeof(struct PacketHeader))
{
dim = 0;
}
else
{
tpointer = ExAllocatePoolWithTag(NonPagedPool, dim, '6PWA');
if (tpointer == NULL)
{
// no memory
SET_FAILURE_NOMEM();
break;
}
}
//
// acquire the locks for all the buffers
//
for (i = 0; i < g_NCpu ; i++)
{
#pragma prefast(suppress:8103, "There's no Spinlock leak here, as it's released some lines below.")
NdisAcquireSpinLock(&Open->CpuData[i].BufferLock);
}
//
// free the old buffer, if any
//
if (Open->CpuData[0].Buffer != NULL)
{
ExFreePool(Open->CpuData[0].Buffer);
}
for (i = 0 ; i < g_NCpu ; i++)
{
if (dim > 0)
Open->CpuData[i].Buffer=(PUCHAR)tpointer + (dim/g_NCpu)*i;
else
Open->CpuData[i].Buffer = NULL;
Open->CpuData[i].Free = dim/g_NCpu;
Open->CpuData[i].P = 0;
Open->CpuData[i].C = 0;
Open->CpuData[i].Accepted = 0;
Open->CpuData[i].Dropped = 0;
Open->CpuData[i].Received = 0;
}
Open->ReaderSN=0;
Open->WriterSN=0;
Open->Size = dim/g_NCpu;
//
// acquire the locks for all the buffers
//
i = g_NCpu;
do
{
i--;
#pragma prefast(suppress:8107, "There's no Spinlock leak here, as it's acquired some lines above.")
NdisReleaseSpinLock(&Open->CpuData[i].BufferLock);
}while(i != 0);
SET_RESULT_SUCCESS(0);
break;
case BIOCSRTIMEOUT: //set the timeout on the read calls
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSRTIMEOUT");
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
timeout = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
if(timeout == (ULONG)-1)
Open->TimeOut.QuadPart=(LONGLONG)IMMEDIATE;
else
{
Open->TimeOut.QuadPart = (LONGLONG)timeout;
Open->TimeOut.QuadPart *= 10000;
Open->TimeOut.QuadPart = -Open->TimeOut.QuadPart;
}
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Read timeout set to %I64d",Open->TimeOut.QuadPart);
SET_RESULT_SUCCESS(0);
break;
case BIOCSWRITEREP: //set the writes repetition number
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSWRITEREP");
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
Open->Nwrites = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
SET_RESULT_SUCCESS(0);
break;
case BIOCSMINTOCOPY: //set the minimum buffer's size to copy to the application
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSMINTOCOPY");
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}
Open->MinToCopy = (*((PULONG)Irp->AssociatedIrp.SystemBuffer))/g_NCpu; //An hack to make the NCPU-buffers behave like a larger one
SET_RESULT_SUCCESS(0);
break;
// case IOCTL_PROTOCOL_RESET:
//
// TRACE_MESSAGE(PACKET_DEBUG_LOUD, "IOCTL_PROTOCOL_RESET");
//
// IoMarkIrpPending(Irp);
// Irp->IoStatus.Status = STATUS_SUCCESS;
//
// ExInterlockedInsertTailList(&Open->ResetIrpList,&Irp->Tail.Overlay.ListEntry,&Open->RequestSpinLock);
// NdisReset(&Status,Open->AdapterHandle);
// if (Status != NDIS_STATUS_PENDING)
// {
// IF_LOUD(DbgPrint("NPF: IoControl - ResetComplete being called\n");)
// NPF_ResetComplete(Open,Status);
// }
//
// break;
case BIOCSETOID:
case BIOCQUERYOID:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "BIOCSETOID - BIOCQUERYOID");
//
// gain ownership of the Ndis Handle
//
if (NPF_StartUsingBinding(Open) == FALSE)
{
//
// MAC unbindind or unbound
//
SET_FAILURE_INVALID_REQUEST();
break;
}
// Extract a request from the list of free ones
RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList,&Open->RequestSpinLock);
if (RequestListEntry == NULL)
{
//
// Release ownership of the Ndis Handle
//
NPF_StopUsingBinding(Open);
SET_FAILURE_NOMEM();
break;
}
pRequest=CONTAINING_RECORD(RequestListEntry,INTERNAL_REQUEST,ListElement);
//
// See if it is an Ndis request
//
OidData=Irp->AssociatedIrp.SystemBuffer;
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength == IrpSp->Parameters.DeviceIoControl.OutputBufferLength)
&&
(IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA))
&&
(IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA)-1+OidData->Length)) {
TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "BIOCSETOID|BIOCQUERYOID Request: Oid=%08lx, Length=%08lx",OidData->Oid,OidData->Length);
//
// The buffer is valid
//
if (FunctionCode == BIOCSETOID){
pRequest->Request.RequestType=NdisRequestSetInformation;
pRequest->Request.DATA.SET_INFORMATION.Oid=OidData->Oid;
pRequest->Request.DATA.SET_INFORMATION.InformationBuffer=OidData->Data;
pRequest->Request.DATA.SET_INFORMATION.InformationBufferLength=OidData->Length;
}
else{
pRequest->Request.RequestType=NdisRequestQueryInformation;
pRequest->Request.DATA.QUERY_INFORMATION.Oid=OidData->Oid;
pRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer=OidData->Data;
pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength=OidData->Length;
}
NdisResetEvent(&pRequest->InternalRequestCompletedEvent);
//
// submit the request
//
NdisRequest(
&Status,
Open->AdapterHandle,
&pRequest->Request
);
} else {
//
// Release ownership of the Ndis Handle
//
NPF_StopUsingBinding(Open);
//
// buffer too small
//
SET_FAILURE_BUFFER_SMALL();
break;
}
if (Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&pRequest->InternalRequestCompletedEvent, 0);
Status = pRequest->RequestStatus;
}
//
// Release ownership of the Ndis Handle
//
NPF_StopUsingBinding(Open);
//
// Complete the request
//
if (FunctionCode == BIOCSETOID)
{
OidData->Length = pRequest->Request.DATA.SET_INFORMATION.BytesRead;
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "BIOCSETOID completed, BytesRead = %u",OidData->Length);
}
else
{
if (FunctionCode == BIOCQUERYOID)
{
OidData->Length = pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
if (Status == NDIS_STATUS_SUCCESS)
{
//
// check for the stupid bug of the Nortel driver ipsecw2k.sys v. 4.10.0.0 that doesn't set the BytesWritten correctly
// The driver is the one shipped with Nortel client Contivity VPN Client V04_65.18, and the MD5 for the buggy (unsigned) driver
// is 3c2ff8886976214959db7d7ffaefe724 *ipsecw2k.sys (there are multiple copies of this binary with the same exact version info!)
//
// The (certified) driver shipped with Nortel client Contivity VPN Client V04_65.320 doesn't seem affected by the bug.
//
if (pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten > pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength)
{
TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "Bogus return from NdisRequest (query): Bytes Written (%u) > InfoBufferLength (%u)!!",
pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten,
pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength);
Status = NDIS_STATUS_INVALID_DATA;
}
}
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "BIOCQUERYOID completed, BytesWritten = %u",OidData->Length);
}
}
ExInterlockedInsertTailList(
&Open->RequestList,
&pRequest->ListElement,
&Open->RequestSpinLock);
if (Status == NDIS_STATUS_SUCCESS)
{
SET_RESULT_SUCCESS(sizeof(PACKET_OID_DATA) - 1 + OidData->Length);
}
else
{
SET_FAILURE_INVALID_REQUEST();
}
break;
default:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Unknown IOCTL code");
SET_FAILURE_INVALID_REQUEST();
break;
}
//
// release the Open structure
//
NPF_StopUsingOpenInstance(Open);
//
// complete the IRP
//
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return Status;
}
对应该函数中的BIOCSETOID,通过 NdisRequest(
&Status,
Open->AdapterHandle,
&pRequest->Request
);
函数将请求发送给网卡;
VOID NdisRequest(
PNDIS_STATUS Status,
NDIS_HANDLE NdisBindingHandle,
PNDIS_REQUEST NdisRequest
);
Parameters
Status
[in] Pointer to a caller-supplied variable that is set on return from this function. The underlying driver determines which NDIS_STATUS_XXX is returned.
NdisBindingHandle
[in] Handle returned by the NdisOpenAdapter function that identifies the target NIC or the virtual adapter of the next-lower driver to which the caller is bound.
NdisRequest
[in] Pointer to a buffered structure specifying the operation requested with a specified OID_XXX code for either a query or a set.
Return Values
The following table shows typical return values for this function.
这篇关于庖丁解牛---winpcap源码彻底解密系列的续集(7)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!