/* * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include "stdarg.h" #include "ntddk.h" #include "ntiologc.h" #include "ndis.h" #include "ntddpack.h" #include "debug.h" #include "packet.h" #include "win_bpf.h" #include "win_bpf_filter_init.h" #if DBG // Declare the global debug flag for this driver. ULONG PacketDebugFlag = PACKET_DEBUG_LOUD; #endif PDEVICE_EXTENSION GlobalDeviceExtension; // // Global strings // NDIS_STRING NPF_Prefix = NDIS_STRING_CONST("SEE_"); NDIS_STRING devicePrefix = NDIS_STRING_CONST("\\Device\\"); NDIS_STRING symbolicLinkPrefix = NDIS_STRING_CONST("\\DosDevices\\"); NDIS_STRING tcpLinkageKeyName = NDIS_STRING_CONST("\\Registry\\Machine\\System" L"\\CurrentControlSet\\Services\\Tcpip\\Linkage"); NDIS_STRING AdapterListKey = NDIS_STRING_CONST("\\Registry\\Machine\\System" L"\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"); NDIS_STRING bindValueName = NDIS_STRING_CONST("Bind"); /// Global variable that points to the names of the bound adapters WCHAR* bindP = NULL; extern struct time_conv G_Start_Time; // from openclos.c extern NDIS_SPIN_LOCK Opened_Instances_Lock; ULONG NCpu = 1; ULONG TimestampMode; UINT g_SendPacketFlags = 0; // Crush now void Crush(UINT a, UINT b, UINT c, UINT d) { KeBugCheckEx(0x3f000000 + a, (ULONG_PTR)a, (ULONG_PTR)b, (ULONG_PTR)c, (ULONG_PTR)d); } // // Packet Driver's entry routine. // NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar; PDEVICE_OBJECT DeviceObject = NULL; PDEVICE_EXTENSION DeviceExtension = NULL; NTSTATUS Status = STATUS_SUCCESS; NTSTATUS ErrorCode = STATUS_SUCCESS; NDIS_STRING ProtoName = NDIS_STRING_CONST("PacketDriver"); ULONG DevicesCreated=0; NDIS_HANDLE NdisProtocolHandle; WCHAR* bindT; PKEY_VALUE_PARTIAL_INFORMATION tcpBindingsP; UNICODE_STRING macName; ULONG OsMajorVersion, OsMinorVersion; PsGetVersion(&OsMajorVersion, &OsMinorVersion, NULL, NULL); // // Define the correct flag to skip the loopback packets, according to the OS // if((OsMajorVersion == 5) && (OsMinorVersion == 0)) { // Windows 2000 wants both NDIS_FLAGS_DONT_LOOPBACK and NDIS_FLAGS_SKIP_LOOPBACK g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK | NDIS_FLAGS_SKIP_LOOPBACK_W2K; } else { // Windows XP, 2003 and following want only NDIS_FLAGS_DONT_LOOPBACK g_SendPacketFlags = NDIS_FLAGS_DONT_LOOPBACK; } if (((OsMajorVersion == 6) && (OsMinorVersion >= 1)) || (OsMajorVersion >= 7)) { // Use KeQueryActiveProcessors to get the number of CPUs in Windows 7 or later KAFFINITY cpus = KeQueryActiveProcessors(); NCpu = 0; while (cpus) { if (cpus % 2) { NCpu++; } cpus = cpus / 2; } } else { // Use NdisSystemProcessorCount in Windows Vista or earlier NCpu = NdisSystemProcessorCount(); } ReadTimeStampModeFromRegistry(RegistryPath); IF_LOUD(DbgPrint("%ws",RegistryPath->Buffer);) IF_LOUD(DbgPrint("\n\nPacket: DriverEntry\n");) RtlZeroMemory(&ProtocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); #ifdef NDIS50 ProtocolChar.MajorNdisVersion = 5; #else ProtocolChar.MajorNdisVersion = 3; #endif ProtocolChar.MinorNdisVersion = 0; ProtocolChar.Reserved = 0; ProtocolChar.OpenAdapterCompleteHandler = NPF_OpenAdapterComplete; ProtocolChar.CloseAdapterCompleteHandler = NPF_CloseAdapterComplete; ProtocolChar.SendCompleteHandler = NPF_SendComplete; ProtocolChar.TransferDataCompleteHandler = NPF_TransferDataComplete; ProtocolChar.ResetCompleteHandler = NPF_ResetComplete; ProtocolChar.RequestCompleteHandler = NPF_RequestComplete; ProtocolChar.ReceiveHandler = NPF_tap; ProtocolChar.ReceiveCompleteHandler = NPF_ReceiveComplete; ProtocolChar.StatusHandler = NPF_Status; ProtocolChar.StatusCompleteHandler = NPF_StatusComplete; #ifdef NDIS50 ProtocolChar.BindAdapterHandler = NPF_BindAdapter; ProtocolChar.UnbindAdapterHandler = NPF_UnbindAdapter; ProtocolChar.PnPEventHandler = NPF_PowerChange; ProtocolChar.ReceivePacketHandler = NULL; #endif ProtocolChar.Name = ProtoName; NdisRegisterProtocol( &Status, &NdisProtocolHandle, &ProtocolChar, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); if (Status != NDIS_STATUS_SUCCESS) { IF_LOUD(DbgPrint("NPF: Failed to register protocol with NDIS\n");) return Status; } NdisAllocateSpinLock(&Opened_Instances_Lock); // Set up the device driver entry points. DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_Open; DriverObject->MajorFunction[IRP_MJ_CLOSE] = NPF_Close; DriverObject->MajorFunction[IRP_MJ_READ] = NPF_Read; DriverObject->MajorFunction[IRP_MJ_WRITE] = NPF_Write; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NPF_IoControl; DriverObject->DriverUnload = NPF_Unload; bindP = getAdaptersList(); if (bindP == NULL) { IF_LOUD(DbgPrint("Adapters not found in the registry, try to copy the bindings of TCP-IP.\n");) tcpBindingsP = getTcpBindings(); if (tcpBindingsP == NULL) { IF_LOUD(DbgPrint("TCP-IP not found, quitting.\n");) goto RegistryError; } bindP = (WCHAR*)tcpBindingsP; bindT = (WCHAR*)(tcpBindingsP->Data); } else { bindT = bindP; } for (; *bindT != UNICODE_NULL; bindT += (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR)) { RtlInitUnicodeString(&macName, bindT); createDevice(DriverObject, &macName, NdisProtocolHandle); } return STATUS_SUCCESS; RegistryError: NdisDeregisterProtocol( &Status, NdisProtocolHandle ); Status=STATUS_UNSUCCESSFUL; return(Status); } //------------------------------------------------------------------- PWCHAR getAdaptersList(void) { PKEY_VALUE_PARTIAL_INFORMATION result = NULL; OBJECT_ATTRIBUTES objAttrs; NTSTATUS status; HANDLE keyHandle; UINT BufPos=0; UINT BufLen=4096; PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen, '0PWA'); if (DeviceNames == NULL) { IF_LOUD(DbgPrint("Unable the allocate the buffer for the list of the network adapters\n");) return NULL; } InitializeObjectAttributes(&objAttrs, &AdapterListKey, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs); if (!NT_SUCCESS(status)) { IF_LOUD(DbgPrint("\n\nStatus of %x opening %ws\n", status, tcpLinkageKeyName.Buffer);) } else { //OK ULONG resultLength; CHAR AdapInfo[1024]; UINT i=0; KEY_VALUE_PARTIAL_INFORMATION valueInfo; IF_LOUD(DbgPrint("getAdaptersList: scanning the list of the adapters in the registry, DeviceNames=%x\n",DeviceNames);) // Scan the list of the devices while((status=ZwEnumerateKey(keyHandle,i,KeyBasicInformation,AdapInfo,sizeof(AdapInfo),&resultLength))==STATUS_SUCCESS) { WCHAR ExportKeyName [512]; PWCHAR ExportKeyPrefix = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"; UINT ExportKeyPrefixSize = sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"); PWCHAR LinkageKeyPrefix = L"\\Linkage"; UINT LinkageKeyPrefixSize = sizeof(L"\\Linkage"); NDIS_STRING FinalExportKey = NDIS_STRING_CONST("Export"); PKEY_BASIC_INFORMATION tInfo= (PKEY_BASIC_INFORMATION)AdapInfo; UNICODE_STRING AdapterKeyName; HANDLE ExportKeyHandle; RtlCopyMemory(ExportKeyName, ExportKeyPrefix, ExportKeyPrefixSize); RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize, tInfo->Name, tInfo->NameLength+2); RtlCopyMemory((PCHAR)ExportKeyName+ExportKeyPrefixSize+tInfo->NameLength, LinkageKeyPrefix, LinkageKeyPrefixSize); IF_LOUD(DbgPrint("Key name=%ws\n", ExportKeyName);) RtlInitUnicodeString(&AdapterKeyName, ExportKeyName); InitializeObjectAttributes(&objAttrs, &AdapterKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); status=ZwOpenKey(&ExportKeyHandle,KEY_READ,&objAttrs); if (!NT_SUCCESS(status)) { IF_LOUD(DbgPrint("OpenKey Failed, %d!\n",status);) i++; continue; } status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey, KeyValuePartialInformation, &valueInfo, sizeof(valueInfo), &resultLength); if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) { IF_LOUD(DbgPrint("\n\nStatus of %x querying key value for size\n", status);) } else { // We know how big it needs to be. ULONG valueInfoLength = valueInfo.DataLength + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]); PKEY_VALUE_PARTIAL_INFORMATION valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePoolWithTag(PagedPool, valueInfoLength, '1PWA'); if (valueInfoP != NULL) { status = ZwQueryValueKey(ExportKeyHandle, &FinalExportKey, KeyValuePartialInformation, valueInfoP, valueInfoLength, &resultLength); if (!NT_SUCCESS(status)) { IF_LOUD(DbgPrint("Status of %x querying key value\n", status);) } else{ IF_LOUD(DbgPrint("Device %d = %ws\n", i, valueInfoP->Data);) if( BufPos + valueInfoP->DataLength > BufLen ) { // double the buffer size PWCHAR DeviceNames2 = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen << 1, '0PWA'); if( DeviceNames2 ) { RtlCopyMemory((PCHAR)DeviceNames2, (PCHAR)DeviceNames, BufLen); BufLen <<= 1; ExFreePool(DeviceNames); DeviceNames = DeviceNames2; } } if( BufPos + valueInfoP->DataLength < BufLen ) { RtlCopyMemory((PCHAR)DeviceNames+BufPos, valueInfoP->Data, valueInfoP->DataLength); BufPos+=valueInfoP->DataLength-2; } } ExFreePool(valueInfoP); } else { IF_LOUD(DbgPrint("Error Allocating the buffer for the device name\n");) } } // terminate the buffer DeviceNames[BufPos/2]=0; DeviceNames[BufPos/2+1]=0; ZwClose (ExportKeyHandle); i++; } ZwClose (keyHandle); } if(BufPos==0){ ExFreePool(DeviceNames); return NULL; } return DeviceNames; } //------------------------------------------------------------------- PKEY_VALUE_PARTIAL_INFORMATION getTcpBindings(void) { PKEY_VALUE_PARTIAL_INFORMATION result = NULL; OBJECT_ATTRIBUTES objAttrs; NTSTATUS status; HANDLE keyHandle; InitializeObjectAttributes(&objAttrs, &tcpLinkageKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwOpenKey(&keyHandle, KEY_READ, &objAttrs); if (!NT_SUCCESS(status)) { IF_LOUD(DbgPrint("\n\nStatus of %x opening %ws\n", status, tcpLinkageKeyName.Buffer);) } else { ULONG resultLength; KEY_VALUE_PARTIAL_INFORMATION valueInfo; IF_LOUD(DbgPrint("\n\nOpened %ws\n", tcpLinkageKeyName.Buffer);) status = ZwQueryValueKey(keyHandle, &bindValueName, KeyValuePartialInformation, &valueInfo, sizeof(valueInfo), &resultLength); if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) { IF_LOUD(DbgPrint("\n\nStatus of %x querying key value for size\n", status);) } else { // We know how big it needs to be. ULONG valueInfoLength = valueInfo.DataLength + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]); PKEY_VALUE_PARTIAL_INFORMATION valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(PagedPool, valueInfoLength, '2PWA'); if (valueInfoP != NULL) { status = ZwQueryValueKey(keyHandle, &bindValueName, KeyValuePartialInformation, valueInfoP, valueInfoLength, &resultLength); if (!NT_SUCCESS(status)) { IF_LOUD(DbgPrint("\n\nStatus of %x querying key value\n", status);) } else if (valueInfoLength != resultLength) { IF_LOUD(DbgPrint("\n\nQuerying key value result len = %u " "but previous len = %u\n", resultLength, valueInfoLength);) } else if (valueInfoP->Type != REG_MULTI_SZ) { IF_LOUD(DbgPrint("\n\nTcpip bind value not REG_MULTI_SZ but %u\n", valueInfoP->Type);) } else { // It's OK #if DBG ULONG i; WCHAR* dataP = (WCHAR*)(&valueInfoP->Data[0]); IF_LOUD(DbgPrint("\n\nBind value:\n");) for (i = 0; *dataP != UNICODE_NULL; i++) { UNICODE_STRING macName; RtlInitUnicodeString(&macName, dataP); IF_LOUD(DbgPrint("\n\nMac %u = %ws\n", i, macName.Buffer);) dataP += (macName.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR); } #endif // DBG result = valueInfoP; } } } ZwClose(keyHandle); } return result; } //------------------------------------------------------------------- BOOLEAN createDevice(IN OUT PDRIVER_OBJECT adriverObjectP, IN PUNICODE_STRING amacNameP, NDIS_HANDLE aProtoHandle) { NTSTATUS status; PDEVICE_OBJECT devObjP; UNICODE_STRING deviceName; UNICODE_STRING deviceSymLink; IF_LOUD(DbgPrint("\n\ncreateDevice for MAC %ws\n", amacNameP->Buffer);); if (RtlCompareMemory(amacNameP->Buffer, devicePrefix.Buffer, devicePrefix.Length) < devicePrefix.Length) { return FALSE; } deviceName.Length = 0; deviceName.MaximumLength = (USHORT)(amacNameP->Length + NPF_Prefix.Length + sizeof(UNICODE_NULL)); deviceName.Buffer = ExAllocatePoolWithTag(PagedPool, deviceName.MaximumLength, '3PWA'); if (deviceName.Buffer == NULL) return FALSE; deviceSymLink.Length = 0; deviceSymLink.MaximumLength =(USHORT)(amacNameP->Length-devicePrefix.Length + symbolicLinkPrefix.Length + NPF_Prefix.Length + sizeof(UNICODE_NULL)); deviceSymLink.Buffer = ExAllocatePoolWithTag(NonPagedPool, deviceSymLink.MaximumLength, '3PWA'); if (deviceSymLink.Buffer == NULL) { ExFreePool(deviceName.Buffer); return FALSE; } RtlAppendUnicodeStringToString(&deviceName, &devicePrefix); RtlAppendUnicodeStringToString(&deviceName, &NPF_Prefix); RtlAppendUnicodeToString(&deviceName, amacNameP->Buffer + devicePrefix.Length / sizeof(WCHAR)); RtlAppendUnicodeStringToString(&deviceSymLink, &symbolicLinkPrefix); RtlAppendUnicodeStringToString(&deviceSymLink, &NPF_Prefix); RtlAppendUnicodeToString(&deviceSymLink, amacNameP->Buffer + devicePrefix.Length / sizeof(WCHAR)); IF_LOUD(DbgPrint("Creating device name: %ws\n", deviceName.Buffer);) status = IoCreateDevice(adriverObjectP, sizeof(DEVICE_EXTENSION), &deviceName, FILE_DEVICE_TRANSPORT, 0, FALSE, &devObjP); if (NT_SUCCESS(status)) { PDEVICE_EXTENSION devExtP = (PDEVICE_EXTENSION)devObjP->DeviceExtension; IF_LOUD(DbgPrint("Device created successfully\n");); devObjP->Flags |= DO_DIRECT_IO; RtlInitUnicodeString(&devExtP->AdapterName,amacNameP->Buffer); devExtP->NdisProtocolHandle=aProtoHandle; IF_LOUD(DbgPrint("Trying to create SymLink %ws\n",deviceSymLink.Buffer);); if (IoCreateSymbolicLink(&deviceSymLink,&deviceName) != STATUS_SUCCESS) { IF_LOUD(DbgPrint("\n\nError creating SymLink %ws\nn", deviceSymLink.Buffer);); ExFreePool(deviceName.Buffer); ExFreePool(deviceSymLink.Buffer); devExtP->ExportString = NULL; return FALSE; } IF_LOUD(DbgPrint("SymLink %ws successfully created.\n\n", deviceSymLink.Buffer);); devExtP->ExportString = deviceSymLink.Buffer; ExFreePool(deviceName.Buffer); return TRUE; } else { IF_LOUD(DbgPrint("\n\nIoCreateDevice status = %x\n", status);); ExFreePool(deviceName.Buffer); ExFreePool(deviceSymLink.Buffer); return FALSE; } } //------------------------------------------------------------------- VOID NPF_Unload(IN PDRIVER_OBJECT DriverObject) { PDEVICE_OBJECT DeviceObject; PDEVICE_OBJECT OldDeviceObject; PDEVICE_EXTENSION DeviceExtension; NDIS_HANDLE NdisProtocolHandle = NULL; NDIS_STATUS Status; NDIS_STRING SymLink; IF_LOUD(DbgPrint("NPF: Unload\n");); DeviceObject = DriverObject->DeviceObject; while (DeviceObject != NULL) { OldDeviceObject = DeviceObject; DeviceObject = DeviceObject->NextDevice; DeviceExtension = OldDeviceObject->DeviceExtension; NdisProtocolHandle=DeviceExtension->NdisProtocolHandle; IF_LOUD(DbgPrint("Deleting Adapter %ws, Protocol Handle=%x, Device Obj=%x (%x)\n", DeviceExtension->AdapterName.Buffer, NdisProtocolHandle, DeviceObject, OldDeviceObject);); if (DeviceExtension->ExportString) { RtlInitUnicodeString(&SymLink , DeviceExtension->ExportString); IF_LOUD(DbgPrint("Deleting SymLink at %p\n", SymLink.Buffer);); IoDeleteSymbolicLink(&SymLink); ExFreePool(DeviceExtension->ExportString); } IoDeleteDevice(OldDeviceObject); } NdisDeregisterProtocol( &Status, NdisProtocolHandle ); // Free the adapters names ExFreePool( bindP ); } #define SET_FAILURE_BUFFER_SMALL() do{\ Information = 0; \ Status = STATUS_BUFFER_TOO_SMALL; \ } while(FALSE) #define SET_RESULT_SUCCESS(__a__) do{\ Information = __a__; \ Status = STATUS_SUCCESS; \ } while(FALSE) #define SET_FAILURE_INVALID_REQUEST() do{\ Information = 0; \ Status = STATUS_INVALID_DEVICE_REQUEST; \ } while(FALSE) #define SET_FAILURE_UNSUCCESSFUL() do{\ Information = 0; \ Status = STATUS_UNSUCCESSFUL; \ } while(FALSE) #define SET_FAILURE_NOMEM() do{\ Information = 0; \ Status = STATUS_INSUFFICIENT_RESOURCES; \ } while(FALSE) //------------------------------------------------------------------- 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; UINT i; PUCHAR tpointer; ULONG dim,timeout; PUCHAR prog; PPACKET_OID_DATA OidData; ULONG mode; // PWSTR DumpNameBuff; PUCHAR TmpBPFProgram; INT WriteRes; BOOLEAN SyncWrite = FALSE; // struct bpf_insn *initprogram; ULONG insns; ULONG cnt; BOOLEAN IsExtendedFilter=FALSE; BOOLEAN Flag; PUINT pStats; ULONG Information = 0; BOOLEAN check_ok; IF_LOUD(DbgPrint("NPF: IoControl\n");) IrpSp = IoGetCurrentIrpStackLocation(Irp); FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode; Open=IrpSp->FileObject->FsContext; Irp->IoStatus.Status = STATUS_SUCCESS; IF_LOUD(DbgPrint("NPF: Function code is %08lx buff size=%08lx %08lx\n",FunctionCode,IrpSp->Parameters.DeviceIoControl.InputBufferLength,IrpSp->Parameters.DeviceIoControl.OutputBufferLength);) switch (FunctionCode){ case BIOCGSTATS: //function to get the capture stats if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 4*sizeof(UINT)){ EXIT_FAILURE(0); } check_ok = TRUE; __try { ProbeForWrite(Irp->UserBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, 1); } __except (EXCEPTION_EXECUTE_HANDLER) { check_ok = FALSE; } if (check_ok == FALSE) { EXIT_FAILURE(0); } else { pStats = (PUINT)(Irp->UserBuffer); pStats[3] = 0; pStats[0] = 0; pStats[1] = 0; pStats[2] = 0; // Not yet supported for(i = 0 ; i < 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 } EXIT_SUCCESS(4*sizeof(UINT)); } break; case BIOCGEVNAME: //function to get the name of the event associated with the current instance if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength<26){ EXIT_FAILURE(0); } check_ok = TRUE; __try { ProbeForWrite(Irp->UserBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, 1); } __except (EXCEPTION_EXECUTE_HANDLER) { check_ok = FALSE; } if (check_ok == FALSE) { EXIT_FAILURE(0); } else { RtlCopyMemory(Irp->UserBuffer,(Open->ReadEventName.Buffer)+18,26); EXIT_SUCCESS(26); } break; case BIOCSENDPACKETSSYNC: SyncWrite = TRUE; case BIOCSENDPACKETSNOSYNC: NdisAcquireSpinLock(&Open->WriteLock); if(Open->WriteInProgress) { // Another write operation is currently in progress EXIT_FAILURE(0); } 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) { EXIT_SUCCESS(WriteRes); } EXIT_FAILURE(WriteRes); break; case BIOCSETF: Open->SkipProcessing = 1; do { Flag = FALSE; for(i = 0; i < NCpu ; i++) if (Open->CpuData[i].Processing == 1) Flag = TRUE; } while(Flag); //BUSY FORM WAITING... // 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 __NPF_x86__ if (Open->Filter != NULL) { JIT_BPF_Filter *OldFilter=Open->Filter; Open->Filter=NULL; BPF_Destroy_JIT_Filter(OldFilter); } #endif // __NPF_x86__ // Get the pointer to the new program prog=(PUCHAR)Irp->AssociatedIrp.SystemBuffer; if(prog==NULL) { Open->SkipProcessing = 0; EXIT_FAILURE(0); } insns = (IrpSp->Parameters.DeviceIoControl.InputBufferLength)/sizeof(struct bpf_insn); //count the number of operative instructions for (cnt=0;(cntmem_ex),&(Open->tme), &G_Start_Time)!=INIT_OK) { IF_LOUD(DbgPrint("Error initializing NPF machine (bpf_filter_init)\n");) Open->SkipProcessing = 0; EXIT_FAILURE(0); } } #else //x86-64 and IA64 if ( cnt != insns) { IF_LOUD(DbgPrint("Error installing the BPF filter. The filter contains TME extensions," " not supported on 64bit platforms.\n");) Open->SkipProcessing = 0; EXIT_FAILURE(0); } #endif //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 if(bpf_validate((struct bpf_insn*)prog,cnt,Open->mem_ex.size)==0) { IF_LOUD(DbgPrint("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 Open->SkipProcessing = 0; EXIT_FAILURE(0); } // 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) { IF_LOUD(DbgPrint("Error - No memory for filter");) // no memory Open->SkipProcessing = 0; EXIT_FAILURE(0); } //copy the program in the new buffer RtlCopyMemory(TmpBPFProgram,prog,cnt*sizeof(struct bpf_insn)); Open->bpfprogram=TmpBPFProgram; // // At the moment the JIT compiler works on x86 (32 bit) only // #ifdef __NPF_x86__ // Create the new JIT filter function if(!IsExtendedFilter) if((Open->Filter=BPF_jitter((struct bpf_insn*)Open->bpfprogram,cnt)) == NULL) { IF_LOUD(DbgPrint("Error jittering filter");) Open->SkipProcessing = 0; EXIT_FAILURE(0); } #endif //return for (i = 0 ; i < NCpu ; i++) { Open->CpuData[i].C=0; Open->CpuData[i].P=0; Open->CpuData[i].Free = Open->Size; Open->CpuData[i].Accepted=0; Open->CpuData[i].Dropped=0; Open->CpuData[i].Received = 0; } Open->ReaderSN=0; Open->WriterSN=0; Open->SkipProcessing = 0; EXIT_SUCCESS(IrpSp->Parameters.DeviceIoControl.InputBufferLength); break; case BIOCSMODE: //set the capture mode if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { EXIT_FAILURE(0); } mode=*((PULONG)Irp->AssociatedIrp.SystemBuffer); ///////kernel dump does not work at the moment////////////////////////////////////////// if (mode & MODE_DUMP) { EXIT_FAILURE(0); } ///////kernel dump does not work at the moment////////////////////////////////////////// if(mode == MODE_CAPT) { Open->mode = MODE_CAPT; EXIT_SUCCESS(0); } else if (mode == MODE_MON) { // // The MONITOR_MODE (aka TME extensions) is not supported on // 64 bit architectures // #ifdef __NPF_x86__ Open->mode = MODE_MON; EXIT_SUCCESS(0); #else // _NPF_x86__ EXIT_FAILURE(0); #endif // __NPF_x86__ } 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; } EXIT_SUCCESS(0); } EXIT_FAILURE(0); break; case BIOCSETDUMPFILENAME: ///////kernel dump does not work at the moment////////////////////////////////////////// EXIT_FAILURE(0); ///////kernel dump does not work at the moment////////////////////////////////////////// // // Remove the following #if 0 to enable the kernel dump again // #if 0 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; #endif // #if 0 case BIOCSETDUMPLIMITS: ///////kernel dump does not work at the moment////////////////////////////////////////// EXIT_FAILURE(0); ///////kernel dump does not work at the moment////////////////////////////////////////// // // Remove the following #if 0 to enable the kernel dump again // #if 0 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; #endif // #if 0 case BIOCISDUMPENDED: ///////kernel dump does not work at the moment////////////////////////////////////////// EXIT_FAILURE(0); ///////kernel dump does not work at the moment////////////////////////////////////////// // // Remove the following #if 0 to enable the kernel dump again // #if 0 if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT)) { EXIT_FAILURE(0); } *((UINT*)Irp->UserBuffer) = (Open->DumpLimitReached)?1:0; EXIT_SUCCESS(4); break; #endif // #if 0 case BIOCSETBUFFERSIZE: if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { EXIT_FAILURE(0); } // Get the number of bytes to allocate dim = *((PULONG)Irp->AssociatedIrp.SystemBuffer); Open->SkipProcessing = 1; do { Flag = FALSE; for(i=0;iCpuData[i].Processing == 1) Flag = TRUE; } while(Flag); //BUSY FORM WAITING... if (dim / NCpu < sizeof(struct PacketHeader)) dim = 0; else { tpointer = ExAllocatePoolWithTag(NonPagedPool, dim, '6PWA'); if (tpointer==NULL) { // no memory Open->SkipProcessing = 0; EXIT_FAILURE(0); } } if (Open->CpuData[0].Buffer != NULL) ExFreePool(Open->CpuData[0].Buffer); for (i = 0 ; i < NCpu ; i++) { if (dim > 0) Open->CpuData[i].Buffer=(PUCHAR)tpointer + (dim/NCpu)*i; else Open->CpuData[i].Buffer = NULL; Open->CpuData[i].Free = dim/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/NCpu; Open->SkipProcessing = 0; EXIT_SUCCESS(dim); break; case BIOCSRTIMEOUT: //set the timeout on the read calls if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { EXIT_FAILURE(0); } 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; } IF_LOUD(DbgPrint("NPF: read timeout set to %d:%d\n",Open->TimeOut.HighPart,Open->TimeOut.LowPart);) EXIT_SUCCESS(timeout); break; case BIOCSWRITEREP: //set the writes repetition number if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { EXIT_FAILURE(0); } Open->Nwrites = *((PULONG)Irp->AssociatedIrp.SystemBuffer); EXIT_SUCCESS(Open->Nwrites); break; case BIOCSMINTOCOPY: //set the minimum buffer's size to copy to the application if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { EXIT_FAILURE(0); } Open->MinToCopy = (*((PULONG)Irp->AssociatedIrp.SystemBuffer))/NCpu; //An hack to make the NCPU-buffers behave like a larger one EXIT_SUCCESS(Open->MinToCopy); break; case IOCTL_PROTOCOL_RESET: IF_LOUD(DbgPrint("NPF: IoControl - Reset request\n");) 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: // Extract a request from the list of free ones RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList,&Open->RequestSpinLock); if (RequestListEntry == NULL) { EXIT_FAILURE(0); } pRequest=CONTAINING_RECORD(RequestListEntry,INTERNAL_REQUEST,ListElement); pRequest->Irp = Irp; pRequest->Internal = FALSE; // // See if it is an Ndis request // OidData=Irp->AssociatedIrp.SystemBuffer; if (((FunctionCode == BIOCSETOID) || (FunctionCode == BIOCQUERYOID)) && (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)) { IF_LOUD(DbgPrint("NPF: IoControl: Request: Oid=%08lx, Length=%08lx\n",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(&Open->IOEvent); // // submit the request // NdisRequest( &Status, Open->AdapterHandle, &pRequest->Request ); } else { // // buffer too small // Status=NDIS_STATUS_FAILURE; pRequest->Request.DATA.SET_INFORMATION.BytesRead=0; pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten=0; } if (Status != NDIS_STATUS_PENDING) { IF_LOUD(DbgPrint("NPF: Calling RequestCompleteHandler\n");) NPF_RequestComplete(Open, &pRequest->Request, Status); return Status; } NdisWaitEvent(&Open->IOEvent, 5000); return(Open->IOStatus); 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 == 1) { 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 == 2) { Open->SkipSentPackets = FALSE; SET_RESULT_SUCCESS(0); break; } else { // Unknown operation SET_FAILURE_INVALID_REQUEST(); break; } #endif // !__NPF_NT4__ break; default: EXIT_FAILURE(0); } if (FunctionCode == BIOCISETLOBBEH) { Irp->IoStatus.Information = Information; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return Status; } //------------------------------------------------------------------- VOID NPF_RequestComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status ) { POPEN_INSTANCE Open; PIO_STACK_LOCATION IrpSp; PIRP Irp; PINTERNAL_REQUEST pRequest; UINT FunctionCode; // KIRQL OldIrq; PPACKET_OID_DATA OidData; IF_LOUD(DbgPrint("NPF: RequestComplete\n");) Open= (POPEN_INSTANCE)ProtocolBindingContext; pRequest=CONTAINING_RECORD(NdisRequest,INTERNAL_REQUEST,Request); Irp=pRequest->Irp; if(pRequest->Internal == TRUE){ // Put the request in the list of the free ones ExInterlockedInsertTailList(&Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock); if(Status != NDIS_STATUS_SUCCESS) Open->MaxFrameSize = 1600; // Assume Ethernet // We always return success, because the adapter has been already opened Irp->IoStatus.Status = NDIS_STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return; } IrpSp = IoGetCurrentIrpStackLocation(Irp); FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode; OidData=Irp->AssociatedIrp.SystemBuffer; if (FunctionCode == BIOCSETOID) { OidData->Length=pRequest->Request.DATA.SET_INFORMATION.BytesRead; } else { if (FunctionCode == BIOCQUERYOID) { OidData->Length=pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten; IF_LOUD(DbgPrint("RequestComplete: BytesWritten=%d\n",pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten);) } } Irp->IoStatus.Information=IrpSp->Parameters.DeviceIoControl.InputBufferLength; IF_LOUD(DbgPrint("RequestComplete: BytesReturned=%d\n",IrpSp->Parameters.DeviceIoControl.InputBufferLength);) ExInterlockedInsertTailList( &Open->RequestList, &pRequest->ListElement, &Open->RequestSpinLock); Irp->IoStatus.Status = Status; Open->IOStatus = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // Unlock the caller NdisSetEvent(&Open->IOEvent); return; } //------------------------------------------------------------------- VOID NPF_Status( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN PVOID StatusBuffer, IN UINT StatusBufferSize ) { IF_LOUD(DbgPrint("NPF: Status Indication\n");) return; } //------------------------------------------------------------------- VOID NPF_StatusComplete( IN NDIS_HANDLE ProtocolBindingContext ) { IF_LOUD(DbgPrint("NPF: StatusIndicationComplete\n");) return; } //------------------------------------------------------------------- NTSTATUS NPF_ReadRegistry( IN PWSTR *MacDriverName, IN PWSTR *PacketDriverName, IN PUNICODE_STRING RegistryPath ) { NTSTATUS Status; RTL_QUERY_REGISTRY_TABLE ParamTable[4]; PWSTR Bind = L"Bind"; PWSTR Export = L"Export"; PWSTR Parameters = L"Parameters"; PWSTR Linkage = L"Linkage"; PWCHAR Path; Path=ExAllocatePoolWithTag(PagedPool, RegistryPath->Length+sizeof(WCHAR), '7PWA'); if (Path == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory( Path, RegistryPath->Length+sizeof(WCHAR) ); RtlCopyMemory( Path, RegistryPath->Buffer, RegistryPath->Length ); IF_LOUD(DbgPrint("NPF: Reg path is %ws\n",RegistryPath->Buffer);) RtlZeroMemory( ParamTable, sizeof(ParamTable) ); // // change to the linkage key // ParamTable[0].QueryRoutine = NULL; ParamTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; ParamTable[0].Name = Linkage; // // Get the name of the mac driver we should bind to // ParamTable[1].QueryRoutine = NPF_QueryRegistryRoutine; ParamTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; ParamTable[1].Name = Bind; ParamTable[1].EntryContext = (PVOID)MacDriverName; ParamTable[1].DefaultType = REG_MULTI_SZ; // // Get the name that we should use for the driver object // ParamTable[2].QueryRoutine = NPF_QueryRegistryRoutine; ParamTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; ParamTable[2].Name = Export; ParamTable[2].EntryContext = (PVOID)PacketDriverName; ParamTable[2].DefaultType = REG_MULTI_SZ; Status=RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, Path, ParamTable, NULL, NULL ); ExFreePool(Path); return Status; } //------------------------------------------------------------------- NTSTATUS NPF_QueryRegistryRoutine( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) { PUCHAR Buffer; IF_LOUD(DbgPrint("Perf: QueryRegistryRoutine\n");) if (ValueType != REG_MULTI_SZ) { return STATUS_OBJECT_NAME_NOT_FOUND; } Buffer=ExAllocatePoolWithTag(NonPagedPool, ValueLength, '8PWA'); if (Buffer==NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory( Buffer, ValueData, ValueLength ); *((PUCHAR *)EntryContext)=Buffer; return STATUS_SUCCESS; }