庖丁解牛---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.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值