VOID otLwfEventProcessingIndicateNewNetBufferLists( _In_ PMS_FILTER pFilter, _In_ BOOLEAN DispatchLevel, _In_ PNET_BUFFER_LIST NetBufferLists ) { POTLWF_NBL_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(OTLWF_NBL_EVENT)); if (Event == NULL) { LogWarning(DRIVER_DATA_PATH, "Failed to alloc new OTLWF_NBL_EVENT"); otLwfCompleteNBLs(pFilter, DispatchLevel, NetBufferLists, STATUS_INSUFFICIENT_RESOURCES); return; } Event->NetBufferLists = NetBufferLists; // Add the event to the queue FILTER_ACQUIRE_LOCK(&pFilter->EventsLock, DispatchLevel); InsertTailList(&pFilter->NBLsHead, &Event->Link); FILTER_RELEASE_LOCK(&pFilter->EventsLock, DispatchLevel); // Set the event to indicate we have a new NBL to process KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); }
VOID otLwfEventProcessingIndicateAddressChange( _In_ PMS_FILTER pFilter, _In_ MIB_NOTIFICATION_TYPE NotificationType, _In_ PIN6_ADDR pAddr ) { LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", pFilter); NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE); POTLWF_ADDR_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(OTLWF_ADDR_EVENT)); if (Event == NULL) { LogWarning(DRIVER_DEFAULT, "Failed to alloc new OTLWF_ADDR_EVENT"); } else { Event->NotificationType = NotificationType; Event->Address = *pAddr; // Add the event to the queue NdisAcquireSpinLock(&pFilter->EventsLock); InsertTailList(&pFilter->AddressChangesHead, &Event->Link); NdisReleaseSpinLock(&pFilter->EventsLock); // Set the event to indicate we have a new address to process KeSetEvent(&pFilter->EventWorkerThreadProcessAddressChanges, 0, FALSE); } LogFuncExit(DRIVER_DEFAULT); }
NTSTATUS FilterDeleteSetting(_In_ PMS_FILTER pFilter, uint16_t aKey, int aIndex) { HANDLE regKey = NULL; OBJECT_ATTRIBUTES attributes; DECLARE_UNICODE_STRING_SIZE(Name, 20); // Convert 'aKey' to a string RtlIntegerToUnicodeString((ULONG)aKey, 16, &Name); InitializeObjectAttributes( &attributes, &Name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, pFilter->otSettingsRegKey, NULL); // Open the registry key NTSTATUS status = ZwOpenKey( ®Key, KEY_ALL_ACCESS, &attributes); if (!NT_SUCCESS(status)) { // Key doesn't exist goto error; } // If 'aIndex' is -1 then delete the whole key, otherwise delete the individual value if (aIndex == -1) { // Delete the registry key status = ZwDeleteKey(regKey); } else { UCHAR KeyInfoBuffer[128] = { 0 }; PKEY_FULL_INFORMATION pKeyInfo = (PKEY_FULL_INFORMATION)KeyInfoBuffer; ULONG KeyInfoLength = sizeof(KeyInfoBuffer); // When deleting an individual value, since order doesn't matter, we will actually // copy the last value over the one being deleted and then delete the last value; so // we maintain a contiguous list of numbered values // Query the number of values // Note: Can't use helper function because we already have the key open status = ZwQueryKey( regKey, KeyValueFullInformation, pKeyInfo, KeyInfoLength, &KeyInfoLength); if (!NT_SUCCESS(status)) { LogError(DRIVER_DEFAULT, "ZwQueryKey for %S value failed, %!STATUS!", Name.Buffer, status); goto error; } if ((ULONG)aIndex >= pKeyInfo->Values) { // Attempt to delete beyond the end of the list status = STATUS_OBJECT_NAME_NOT_FOUND; goto error; } else if (pKeyInfo->Values == 1) { // Deleting the only value on the key, go ahead and delete the entire key status = ZwDeleteKey(regKey); } else if (pKeyInfo->Values - 1 != (ULONG)aIndex) { // We aren't deleting the last value so we need to copy the last value // over this one, and then delete the last one. PKEY_VALUE_PARTIAL_INFORMATION pValueInfo = NULL; ULONG ValueInfoLength = 0; // Convert pKeyInfo->Values-1 to a string RtlIntegerToUnicodeString(pKeyInfo->Values - 1, 16, &Name); // Query the key data buffer size status = ZwQueryValueKey( regKey, &Name, KeyValuePartialInformation, pValueInfo, 0, &ValueInfoLength); NT_ASSERT(status != STATUS_SUCCESS); if (status != STATUS_BUFFER_TOO_SMALL) { LogVerbose(DRIVER_DEFAULT, "ZwQueryValueKey for %S value failed, %!STATUS!", Name.Buffer, status); goto error; } pValueInfo = FILTER_ALLOC_MEM(pFilter->FilterHandle, ValueInfoLength); if (pValueInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto error; } // Query the data buffer status = ZwQueryValueKey( regKey, &Name, KeyValuePartialInformation, pValueInfo, ValueInfoLength, &ValueInfoLength); if (!NT_SUCCESS(status)) { LogError(DRIVER_DEFAULT, "ZwQueryValueKey for %S value failed, %!STATUS!", Name.Buffer, status); goto cleanup; } // Delete the registry value status = ZwDeleteValueKey( regKey, &Name); if (!NT_SUCCESS(status)) { LogError(DRIVER_DEFAULT, "ZwDeleteValueKey for %S value failed, %!STATUS!", Name.Buffer, status); goto cleanup; } // Convert 'aIndex' to a string RtlIntegerToUnicodeString((ULONG)aIndex, 16, &Name); // Write the data to the registry key we are deleting status = ZwSetValueKey( regKey, &Name, 0, REG_BINARY, (PVOID)pValueInfo->Data, pValueInfo->DataLength); if (!NT_SUCCESS(status)) { LogError(DRIVER_DEFAULT, "ZwSetValueKey for %S value failed, %!STATUS!", Name.Buffer, status); goto cleanup; } cleanup: if (pValueInfo) FILTER_FREE_MEM(pValueInfo); } else { // Deleting the last value in the list (but not the only value) // Just delete the value directly. No need to copy any others. // Convert 'aIndex' to a string RtlIntegerToUnicodeString((ULONG)aIndex, 16, &Name); // Delete the registry value status = ZwDeleteValueKey( regKey, &Name); } } error: if (regKey) ZwClose(regKey); return status; }
NTSTATUS FilterReadSetting(_In_ PMS_FILTER pFilter, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) { HANDLE regKey = NULL; OBJECT_ATTRIBUTES attributes; DECLARE_UNICODE_STRING_SIZE(Name, 20); PKEY_VALUE_PARTIAL_INFORMATION pInfo = NULL; ULONG InfoLength = sizeof(*pInfo) + *aValueLength; // Convert 'aKey' to a string RtlIntegerToUnicodeString((ULONG)aKey, 16, &Name); InitializeObjectAttributes( &attributes, &Name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, pFilter->otSettingsRegKey, NULL); // Open the registry key NTSTATUS status = ZwOpenKey( ®Key, KEY_ALL_ACCESS, &attributes); if (!NT_SUCCESS(status)) { // Key doesn't exist goto error; } // Convert 'aIndex' to a string RtlIntegerToUnicodeString((ULONG)aIndex, 16, &Name); // Allocate buffer for query pInfo = FILTER_ALLOC_MEM(pFilter->FilterHandle, InfoLength); if (pInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto error; } // Query the data status = ZwQueryValueKey( regKey, &Name, KeyValuePartialInformation, pInfo, InfoLength, &InfoLength); if (!NT_SUCCESS(status)) { LogVerbose(DRIVER_DEFAULT, "ZwQueryValueKey for %S value failed, %!STATUS!", Name.Buffer, status); goto error; } NT_ASSERT(*aValueLength >= pInfo->DataLength); *aValueLength = (uint16_t)pInfo->DataLength; if (aValue) { memcpy(aValue, pInfo->Data, pInfo->DataLength); } error: if (pInfo) FILTER_FREE_MEM(pInfo); if (regKey) ZwClose(regKey); return status; }
// Set the event to indicate we have a new NBL to process KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); } _IRQL_requires_max_(DISPATCH_LEVEL) VOID otLwfEventProcessingIndicateNewMacFrameCommand( _In_ PMS_FILTER pFilter, _In_ BOOLEAN DispatchLevel, _In_reads_bytes_(BufferLength) const uint8_t* Buffer, _In_ uint8_t BufferLength ) { POTLWF_MAC_FRAME_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, FIELD_OFFSET(OTLWF_MAC_FRAME_EVENT, Buffer) + BufferLength); if (Event == NULL) { LogWarning(DRIVER_DATA_PATH, "Failed to alloc new OTLWF_MAC_FRAME_EVENT"); return; } Event->BufferLength = BufferLength; memcpy(Event->Buffer, Buffer, BufferLength); // Add the event to the queue FILTER_ACQUIRE_LOCK(&pFilter->EventsLock, DispatchLevel); InsertTailList(&pFilter->MacFramesHead, &Event->Link); FILTER_RELEASE_LOCK(&pFilter->EventsLock, DispatchLevel); // Set the event to indicate we have a new Mac Frame to process
_Use_decl_annotations_ NDIS_STATUS FilterAttach( NDIS_HANDLE NdisFilterHandle, NDIS_HANDLE FilterDriverContext, PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters ) /*++ Routine Description: Filter attach routine. Create filter's context, allocate NetBufferLists and NetBuffer pools and any other resources, and read configuration if needed. Arguments: NdisFilterHandle - Specify a handle identifying this instance of the filter. FilterAttach should save this handle. It is a required parameter in subsequent calls to NdisFxxx functions. FilterDriverContext - Filter driver context passed to NdisFRegisterFilterDriver. AttachParameters - attach parameters Return Value: NDIS_STATUS_SUCCESS: FilterAttach successfully allocated and initialize data structures for this filter instance. NDIS_STATUS_RESOURCES: FilterAttach failed due to insufficient resources. NDIS_STATUS_FAILURE: FilterAttach could not set up this instance of this filter and it has called NdisWriteErrorLogEntry with parameters specifying the reason for failure. N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper layer can send Irps to the filter. --*/ { PMS_FILTER pFilter = NULL; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; NTSTATUS NtStatus; NDIS_FILTER_ATTRIBUTES FilterAttributes; ULONG Size; COMPARTMENT_ID OriginalCompartmentID; OBJECT_ATTRIBUTES ObjectAttributes = {0}; const ULONG RegKeyOffset = ARRAYSIZE(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\otlwf\\Parameters\\NdisAdapters\\") - 1; DECLARE_CONST_UNICODE_STRING(RegKeyPath, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\otlwf\\Parameters\\NdisAdapters\\{00000000-0000-0000-0000-000000000000}"); RtlCopyMemory(RegKeyPath.Buffer + RegKeyOffset, AttachParameters->BaseMiniportName->Buffer + 8, sizeof(L"{00000000-0000-0000-0000-000000000000}")); LogFuncEntry(DRIVER_DEFAULT); do { ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject); if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject) { Status = NDIS_STATUS_INVALID_PARAMETER; break; } // Verify the media type is supported. This is a last resort; the // the filter should never have been bound to an unsupported miniport // to begin with. if (AttachParameters->MiniportMediaType != NdisMediumIP) { LogError(DRIVER_DEFAULT, "Unsupported media type, 0x%x.", (ULONG)AttachParameters->MiniportMediaType); Status = NDIS_STATUS_INVALID_PARAMETER; break; } Size = sizeof(MS_FILTER) + AttachParameters->BaseMiniportInstanceName->Length; pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size); if (pFilter == NULL) { LogWarning(DRIVER_DEFAULT, "Failed to allocate context structure, 0x%x bytes", Size); Status = NDIS_STATUS_RESOURCES; break; } NdisZeroMemory(pFilter, sizeof(MS_FILTER)); LogVerbose(DRIVER_DEFAULT, "Opening interface registry key %S", RegKeyPath.Buffer); InitializeObjectAttributes( &ObjectAttributes, (PUNICODE_STRING)&RegKeyPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); // Open the registry key NtStatus = ZwOpenKey(&pFilter->InterfaceRegKey, KEY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "ZwOpenKey failed to open %S, %!STATUS!", RegKeyPath.Buffer, NtStatus); Status = NDIS_STATUS_FAILURE; break; } // Format of "\DEVICE\{5BA90C49-0D7E-455B-8D3B-614F6714A212}" AttachParameters->BaseMiniportName->Buffer += 8; AttachParameters->BaseMiniportName->Length -= 8 * sizeof(WCHAR); NtStatus = RtlGUIDFromString(AttachParameters->BaseMiniportName, &pFilter->InterfaceGuid); AttachParameters->BaseMiniportName->Buffer -= 8; AttachParameters->BaseMiniportName->Length += 8 * sizeof(WCHAR); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "Failed to convert FilterModuleGuidName to a GUID, %!STATUS!", NtStatus); Status = NDIS_STATUS_FAILURE; break; } pFilter->InterfaceFriendlyName.Length = pFilter->InterfaceFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length; pFilter->InterfaceFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER)); NdisMoveMemory(pFilter->InterfaceFriendlyName.Buffer, AttachParameters->BaseMiniportInstanceName->Buffer, pFilter->InterfaceFriendlyName.Length); pFilter->InterfaceIndex = AttachParameters->BaseMiniportIfIndex; pFilter->InterfaceLuid = AttachParameters->BaseMiniportNetLuid; pFilter->InterfaceCompartmentID = UNSPECIFIED_COMPARTMENT_ID; pFilter->FilterHandle = NdisFilterHandle; NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES)); FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1; FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES); FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES; FilterAttributes.Flags = 0; NDIS_DECLARE_FILTER_MODULE_CONTEXT(MS_FILTER); Status = NdisFSetAttributes(NdisFilterHandle, pFilter, &FilterAttributes); if (Status != NDIS_STATUS_SUCCESS) { LogError(DRIVER_DEFAULT, "Failed to set attributes, %!NDIS_STATUS!", Status); break; } // Filter initially in Paused state pFilter->State = FilterPaused; // Initialize rundowns to disabled with no active references pFilter->ExternalRefs.Count = EX_RUNDOWN_ACTIVE; pFilter->cmdRundown.Count = EX_RUNDOWN_ACTIVE; // Query the compartment ID for this interface to use for the IP stack pFilter->InterfaceCompartmentID = GetInterfaceCompartmentID(&pFilter->InterfaceLuid); LogVerbose(DRIVER_DEFAULT, "Interface %!GUID! is in Compartment %u", &pFilter->InterfaceGuid, (ULONG)pFilter->InterfaceCompartmentID); // Make sure we are in the right compartment (VOID)otLwfSetCompartment(pFilter, &OriginalCompartmentID); // Register for address changed notifications NtStatus = NotifyUnicastIpAddressChange( AF_INET6, otLwfAddressChangeCallback, pFilter, FALSE, &pFilter->AddressChangeHandle ); // Revert the compartment, now that we have the table otLwfRevertCompartment(OriginalCompartmentID); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "NotifyUnicastIpAddressChange failed, %!STATUS!", NtStatus); Status = NDIS_STATUS_FAILURE; break; } // Add Filter to global list of Thread Filters NdisAcquireSpinLock(&FilterListLock); InsertTailList(&FilterModuleList, &pFilter->FilterModuleLink); NdisReleaseSpinLock(&FilterListLock); LogVerbose(DRIVER_DEFAULT, "Created Filter: %p", pFilter); } while (FALSE); // Clean up on failure if (Status != NDIS_STATUS_SUCCESS) { if (pFilter != NULL) { if (pFilter->AddressChangeHandle != NULL) { CancelMibChangeNotify2(pFilter->AddressChangeHandle); pFilter->AddressChangeHandle = NULL; } NdisFreeMemory(pFilter, 0, 0); } } LogFuncExitNDIS(DRIVER_DEFAULT, Status); return Status; }