aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2026-05-04 23:33:13 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2026-05-07 14:24:51 +0200
commit765f429ac12b1d39b22df4e8beb3a0558a9d9e82 (patch)
treea7d4e7372d9b3e67a611d6fa9b20a204bf813741
parentversion: bump (diff)
downloadwireguard-nt-jd/cm_register_notification.tar.xz
wireguard-nt-jd/cm_register_notification.zip
api: use CM_Register_Notification instead of DevCreateObjectQueryjd/cm_register_notification
CM_Register_Notification uses lower level WNF notifications, rather than the more convoluted registry-based watching. Hopefully this addresses certain races with incoming events. See comments in link. This didn't work. Link: https://github.com/WireGuard/wintun/pull/7 Suggested-by: Aaron Klotz <aaron@tailscale.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--api/adapter.c105
-rw-r--r--api/api.vcxproj2
2 files changed, 35 insertions, 72 deletions
diff --git a/api/adapter.c b/api/adapter.c
index 14b1ab6..5ab3385 100644
--- a/api/adapter.c
+++ b/api/adapter.c
@@ -15,7 +15,6 @@
#include <wchar.h>
#include <initguid.h> /* Keep these at the bottom in this order, so that we only generate extra GUIDs for devpkey. The other keys we'll get from uuid.lib like usual. */
#include <devpkey.h>
-#include <devquery.h>
#include <swdevice.h>
#include "adapter.h"
@@ -391,34 +390,17 @@ AdapterGetDeviceObjectFileName(LPCWSTR InstanceId)
return Interfaces;
}
-typedef struct _WAIT_FOR_INTERFACE_CTX
-{
- HANDLE Event;
- DWORD LastError;
-} WAIT_FOR_INTERFACE_CTX;
-
-static VOID WINAPI
+static DWORD CALLBACK
WaitForInterfaceCallback(
- _In_ HDEVQUERY DevQuery,
- _Inout_ PVOID Context,
- _In_ const DEV_QUERY_RESULT_ACTION_DATA *ActionData)
+ _In_ HCMNOTIFICATION Notification,
+ _In_opt_ PVOID Context,
+ _In_ CM_NOTIFY_ACTION Action,
+ _In_reads_bytes_(EventDataSize) PCM_NOTIFY_EVENT_DATA EventData,
+ _In_ DWORD EventDataSize)
{
- WAIT_FOR_INTERFACE_CTX *Ctx = Context;
- DWORD Ret = ERROR_SUCCESS;
- switch (ActionData->Action)
- {
- case DevQueryResultStateChange:
- if (ActionData->Data.State != DevQueryStateAborted)
- return;
- Ret = ERROR_DEVICE_NOT_AVAILABLE;
- case DevQueryResultAdd:
- case DevQueryResultUpdate:
- break;
- default:
- return;
- }
- Ctx->LastError = Ret;
- SetEvent(Ctx->Event);
+ if (Action == CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED)
+ SetEvent((HANDLE)Context);
+ return ERROR_SUCCESS;
}
_Must_inspect_result_
@@ -426,65 +408,46 @@ static _Return_type_success_(return != FALSE)
BOOL
WaitForInterface(_In_ WCHAR *InstanceId)
{
- DWORD LastError = ERROR_SUCCESS;
- static const DEVPROP_BOOLEAN DevPropTrue = DEVPROP_TRUE;
- const DEVPROP_FILTER_EXPRESSION Filters[] = { { .Operator = DEVPROP_OPERATOR_EQUALS_IGNORE_CASE,
- .Property.CompKey.Key = DEVPKEY_Device_InstanceId,
- .Property.CompKey.Store = DEVPROP_STORE_SYSTEM,
- .Property.Type = DEVPROP_TYPE_STRING,
- .Property.Buffer = InstanceId,
- .Property.BufferSize =
- (ULONG)((wcslen(InstanceId) + 1) * sizeof(InstanceId[0])) },
- { .Operator = DEVPROP_OPERATOR_EQUALS,
- .Property.CompKey.Key = DEVPKEY_DeviceInterface_Enabled,
- .Property.CompKey.Store = DEVPROP_STORE_SYSTEM,
- .Property.Type = DEVPROP_TYPE_BOOLEAN,
- .Property.Buffer = (PVOID)&DevPropTrue,
- .Property.BufferSize = sizeof(DevPropTrue) },
- { .Operator = DEVPROP_OPERATOR_EQUALS,
- .Property.CompKey.Key = DEVPKEY_DeviceInterface_ClassGuid,
- .Property.CompKey.Store = DEVPROP_STORE_SYSTEM,
- .Property.Type = DEVPROP_TYPE_GUID,
- .Property.Buffer = (PVOID)&GUID_DEVINTERFACE_NET,
- .Property.BufferSize = sizeof(GUID_DEVINTERFACE_NET) } };
- WAIT_FOR_INTERFACE_CTX Ctx = { .Event = CreateEventW(NULL, FALSE, FALSE, NULL) };
- if (!Ctx.Event)
+ DWORD LastError;
+ CM_NOTIFY_FILTER Filter = { .cbSize = sizeof(Filter), .FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE };
+ if (wcsncpy_s(Filter.u.DeviceInstance.InstanceId, _countof(Filter.u.DeviceInstance.InstanceId), InstanceId, _TRUNCATE) == STRUNCATE)
+ {
+ LastError = LOG_ERROR(ERROR_BUFFER_OVERFLOW, L"Instance ID too long: %s", InstanceId);
+ goto cleanup;
+ }
+ HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
+ if (!Event)
{
LastError = LOG_LAST_ERROR(L"Failed to create event");
goto cleanup;
}
- HDEVQUERY Query;
- HRESULT HRet = DevCreateObjectQuery(
- DevObjectTypeDeviceInterface,
- DevQueryFlagUpdateResults,
- 0,
- NULL,
- _countof(Filters),
- Filters,
- WaitForInterfaceCallback,
- &Ctx,
- &Query);
- if (FAILED(HRet))
+ HCMNOTIFICATION Notification;
+ LastError = CM_MapCrToWin32Err(
+ CM_Register_Notification(&Filter, Event, WaitForInterfaceCallback, &Notification),
+ ERROR_GEN_FAILURE);
+ if (LastError != ERROR_SUCCESS)
{
- LastError = LOG_ERROR(HRet, L"Failed to create device query");
+ LastError = LOG_ERROR(LastError, L"Failed to register for instance arrival notification");
goto cleanupEvent;
}
- LastError = WaitForSingleObject(Ctx.Event, 15000);
+ LPWSTR Existing = AdapterGetDeviceObjectFileName(InstanceId);
+ if (Existing)
+ {
+ Free(Existing);
+ goto cleanupNotification;
+ }
+ LastError = WaitForSingleObject(Event, 15000);
if (LastError != WAIT_OBJECT_0)
{
if (LastError == WAIT_FAILED)
LastError = LOG_LAST_ERROR(L"Failed to wait for device query");
else
LastError = LOG_ERROR(LastError, L"Timed out waiting for device query");
- goto cleanupQuery;
}
- LastError = Ctx.LastError;
- if (LastError != ERROR_SUCCESS)
- LastError = LOG_ERROR(LastError, L"Failed to get enabled device");
-cleanupQuery:
- DevCloseObjectQuery(Query);
+cleanupNotification:
+ CM_Unregister_Notification(Notification);
cleanupEvent:
- CloseHandle(Ctx.Event);
+ CloseHandle(Event);
cleanup:
return RET_ERROR(TRUE, LastError);
}
diff --git a/api/api.vcxproj b/api/api.vcxproj
index 0520b78..fd7c8e5 100644
--- a/api/api.vcxproj
+++ b/api/api.vcxproj
@@ -34,7 +34,7 @@
<PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
- <DelayLoadDLLs>advapi32.dll;api-ms-win-devices-query-l1-1-0.dll;api-ms-win-devices-swdevice-l1-1-0.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shlwapi.dll;version.dll</DelayLoadDLLs>
+ <DelayLoadDLLs>advapi32.dll;api-ms-win-devices-swdevice-l1-1-0.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shlwapi.dll;version.dll</DelayLoadDLLs>
<DelayLoadDLLs Condition="'$(Platform)'!='ARM64'">shell32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<AdditionalDependencies>Cfgmgr32.lib;Iphlpapi.lib;onecore.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;swdevice.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>