aboutsummaryrefslogtreecommitdiffstats
path: root/api/driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'api/driver.c')
-rw-r--r--api/driver.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/api/driver.c b/api/driver.c
new file mode 100644
index 0000000..b6bf11c
--- /dev/null
+++ b/api/driver.c
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "pch.h"
+
+/**
+ * Retrieves driver information detail for a device information set or a particular device information element in the
+ * device information set.
+ *
+ * @param DevInfo A handle to the device information set that contains a device information element that
+ * represents the device for which to retrieve driver information.
+ *
+ * @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo.
+ *
+ * @param DrvInfoData A pointer to a structure that specifies the driver information element that represents the
+ * driver for which to retrieve details.
+ *
+ * @param DrvInfoDetailData A pointer to a structure that receives detailed information about the specified driver.
+ * Must be released with HeapFree(GetProcessHeap(), 0, *DrvInfoDetailData) after use.
+ *
+ * @return non-zero on success; zero otherwise - use GetLastError().
+ */
+_Return_type_success_(return != NULL) SP_DRVINFO_DETAIL_DATA_W *DriverGetDrvInfoDetail(
+ _In_ HDEVINFO DevInfo,
+ _In_opt_ SP_DEVINFO_DATA *DevInfoData,
+ _In_ SP_DRVINFO_DATA_W *DrvInfoData)
+{
+ HANDLE Heap = GetProcessHeap();
+ DWORD Size = sizeof(SP_DRVINFO_DETAIL_DATA_W) + 0x100;
+ DWORD Result;
+ for (;;)
+ {
+ SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = HeapAlloc(Heap, 0, Size);
+ if (!DrvInfoDetailData)
+ {
+ Result = ERROR_OUTOFMEMORY;
+ goto out;
+ }
+ DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
+ if (SetupDiGetDriverInfoDetailW(DevInfo, DevInfoData, DrvInfoData, DrvInfoDetailData, Size, &Size))
+ return DrvInfoDetailData;
+ Result = GetLastError();
+ HeapFree(Heap, 0, DrvInfoDetailData);
+ if (Result != ERROR_INSUFFICIENT_BUFFER)
+ {
+ WINTUN_LOGGER_ERROR(L"Failed", Result);
+ goto out;
+ }
+ }
+out:
+ SetLastError(Result);
+ return NULL;
+}
+
+/**
+ * Checks if the device (i.e. network adapter) is using Wintun driver.
+ *
+ * @param DevInfo A handle to the device information set that contains a device information element that
+ * represents the device.
+ *
+ * @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo.
+ *
+ * @return non-zero when using Wintun driver; zero when not or error - use GetLastError().
+ */
+BOOL
+DriverIsWintunAdapter(_In_ HDEVINFO DevInfo, _In_opt_ SP_DEVINFO_DATA *DevInfoData)
+{
+ BOOL Found = FALSE;
+ if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER))
+ {
+ WINTUN_LOGGER_LAST_ERROR(L"Failed to build list of drivers");
+ return FALSE;
+ }
+ HANDLE Heap = GetProcessHeap();
+ for (DWORD EnumIndex = 0; !Found; ++EnumIndex)
+ {
+ SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
+ if (!SetupDiEnumDriverInfoW(DevInfo, DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+ SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = DriverGetDrvInfoDetail(DevInfo, DevInfoData, &DrvInfoData);
+ if (!DrvInfoDetailData)
+ continue;
+ Found = !_wcsicmp(DrvInfoDetailData->HardwareID, L"wintun");
+ HeapFree(Heap, 0, DrvInfoDetailData);
+ }
+ SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER);
+ SetLastError(ERROR_SUCCESS);
+ return Found;
+}
+
+/**
+ * Returns a handle to the adapter device object.
+ *
+ * @param InstanceId Adapter device instance ID.
+ *
+ * @return device handle on success; INVALID_HANDLE_VALUE otherwise - use GetLastError().
+ */
+_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE
+ DriverGetAdapterDeviceObject(_In_opt_z_ const WCHAR *InstanceId)
+{
+ HANDLE Heap = GetProcessHeap();
+ ULONG InterfacesLen;
+ HANDLE Handle = INVALID_HANDLE_VALUE;
+ DWORD Result = CM_Get_Device_Interface_List_SizeW(
+ &InterfacesLen, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+ if (Result != CR_SUCCESS)
+ {
+ WINTUN_LOGGER(WINTUN_LOG_ERR, L"Failed to get device associated device instances size");
+ SetLastError(ERROR_GEN_FAILURE);
+ return INVALID_HANDLE_VALUE;
+ }
+ WCHAR *Interfaces = HeapAlloc(Heap, 0, InterfacesLen * sizeof(WCHAR));
+ if (!Interfaces)
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return INVALID_HANDLE_VALUE;
+ }
+ Result = CM_Get_Device_Interface_ListW(
+ (GUID *)&GUID_DEVINTERFACE_NET,
+ (DEVINSTID_W)InstanceId,
+ Interfaces,
+ InterfacesLen,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+ if (Result != CR_SUCCESS)
+ {
+ WINTUN_LOGGER(WINTUN_LOG_ERR, L"Failed to get device associated device instances");
+ Result = ERROR_GEN_FAILURE;
+ goto cleanupBuf;
+ }
+ Handle = CreateFileW(
+ Interfaces,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ Result = Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : WINTUN_LOGGER_LAST_ERROR(L"Failed to connect to device");
+cleanupBuf:
+ HeapFree(Heap, 0, Interfaces);
+ SetLastError(Result);
+ return Handle;
+}