summaryrefslogtreecommitdiff
path: root/src/tapctl/tap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tapctl/tap.c')
-rw-r--r--src/tapctl/tap.c242
1 files changed, 84 insertions, 158 deletions
diff --git a/src/tapctl/tap.c b/src/tapctl/tap.c
index 7cb3ded..dd4a10a 100644
--- a/src/tapctl/tap.c
+++ b/src/tapctl/tap.c
@@ -33,18 +33,69 @@
#include <setupapi.h>
#include <stdio.h>
#include <tchar.h>
+#include <newdev.h>
#ifdef _MSC_VER
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "setupapi.lib")
+#pragma comment(lib, "newdev.lib")
#endif
+
const static GUID GUID_DEVCLASS_NET = { 0x4d36e972L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
const static TCHAR szAdapterRegKeyPathTemplate[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Network\\%") TEXT(PRIsLPOLESTR) TEXT("\\%") TEXT(PRIsLPOLESTR) TEXT("\\Connection");
#define ADAPTER_REGKEY_PATH_MAX (_countof(TEXT("SYSTEM\\CurrentControlSet\\Control\\Network\\")) - 1 + 38 + _countof(TEXT("\\")) - 1 + 38 + _countof(TEXT("\\Connection")))
+/**
+ * Dynamically load a library and find a function in it
+ *
+ * @param libname Name of the library to load
+ * @param funcname Name of the function to find
+ * @param m Pointer to a module. On return this is set to the
+ * the handle to the loaded library. The caller must
+ * free it by calling FreeLibrary() if not NULL.
+ *
+ * @return Pointer to the function
+ * NULL on error -- use GetLastError() to find the error code.
+ *
+ **/
+static void *
+find_function(const WCHAR *libname, const char *funcname, HMODULE *m)
+{
+ WCHAR libpath[MAX_PATH];
+ void *fptr = NULL;
+
+ /* Make sure the dll is loaded from the system32 folder */
+ if (!GetSystemDirectoryW(libpath, _countof(libpath)))
+ {
+ return NULL;
+ }
+
+ size_t len = _countof(libpath) - wcslen(libpath) - 1;
+ if (len < wcslen(libname) + 1)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return NULL;
+ }
+ wcsncat(libpath, L"\\", len);
+ wcsncat(libpath, libname, len-1);
+
+ *m = LoadLibraryW(libpath);
+ if (*m == NULL)
+ {
+ return NULL;
+ }
+ fptr = GetProcAddress(*m, funcname);
+ if (!fptr)
+ {
+ FreeLibrary(*m);
+ *m = NULL;
+ return NULL;
+ }
+ return fptr;
+}
/**
* Returns length of string of strings
@@ -678,6 +729,7 @@ tap_create_adapter(
_Out_ LPGUID pguidAdapter)
{
DWORD dwResult;
+ HMODULE libnewdev = NULL;
if (szHwId == NULL
|| pbRebootRequired == NULL
@@ -746,129 +798,7 @@ tap_create_adapter(
goto cleanup_hDevInfoList;
}
- /* Search for the driver. */
- if (!SetupDiBuildDriverInfoList(
- hDevInfoList,
- &devinfo_data,
- SPDIT_CLASSDRIVER))
- {
- dwResult = GetLastError();
- msg(M_NONFATAL, "%s: SetupDiBuildDriverInfoList failed", __FUNCTION__);
- goto cleanup_hDevInfoList;
- }
- DWORDLONG dwlDriverVersion = 0;
- DWORD drvinfo_detail_data_size = sizeof(SP_DRVINFO_DETAIL_DATA) + 0x100;
- SP_DRVINFO_DETAIL_DATA *drvinfo_detail_data = (SP_DRVINFO_DETAIL_DATA *)malloc(drvinfo_detail_data_size);
- if (drvinfo_detail_data == NULL)
- {
- msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, drvinfo_detail_data_size);
- dwResult = ERROR_OUTOFMEMORY; goto cleanup_DriverInfoList;
- }
-
- for (DWORD dwIndex = 0;; dwIndex++)
- {
- /* Get a driver from the list. */
- SP_DRVINFO_DATA drvinfo_data = { .cbSize = sizeof(SP_DRVINFO_DATA) };
- if (!SetupDiEnumDriverInfo(
- hDevInfoList,
- &devinfo_data,
- SPDIT_CLASSDRIVER,
- dwIndex,
- &drvinfo_data))
- {
- if (GetLastError() == ERROR_NO_MORE_ITEMS)
- {
- break;
- }
- else
- {
- /* Something is wrong with this driver. Skip it. */
- msg(M_WARN | M_ERRNO, "%s: SetupDiEnumDriverInfo(%u) failed", __FUNCTION__, dwIndex);
- continue;
- }
- }
-
- /* Get driver info details. */
- DWORD dwSize;
- drvinfo_detail_data->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
- if (!SetupDiGetDriverInfoDetail(
- hDevInfoList,
- &devinfo_data,
- &drvinfo_data,
- drvinfo_detail_data,
- drvinfo_detail_data_size,
- &dwSize))
- {
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
- {
- /* (Re)allocate buffer. */
- if (drvinfo_detail_data)
- {
- free(drvinfo_detail_data);
- }
-
- drvinfo_detail_data_size = dwSize;
- drvinfo_detail_data = (SP_DRVINFO_DETAIL_DATA *)malloc(drvinfo_detail_data_size);
- if (drvinfo_detail_data == NULL)
- {
- msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, drvinfo_detail_data_size);
- dwResult = ERROR_OUTOFMEMORY; goto cleanup_DriverInfoList;
- }
-
- /* Re-get driver info details. */
- drvinfo_detail_data->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
- if (!SetupDiGetDriverInfoDetail(
- hDevInfoList,
- &devinfo_data,
- &drvinfo_data,
- drvinfo_detail_data,
- drvinfo_detail_data_size,
- &dwSize))
- {
- /* Something is wrong with this driver. Skip it. */
- continue;
- }
- }
- else
- {
- /* Something is wrong with this driver. Skip it. */
- msg(M_WARN | M_ERRNO, "%s: SetupDiGetDriverInfoDetail(\"%hs\") failed", __FUNCTION__, drvinfo_data.Description);
- continue;
- }
- }
-
- /* Check the driver version and hardware ID. */
- if (dwlDriverVersion < drvinfo_data.DriverVersion
- && drvinfo_detail_data->HardwareID
- && _tcszistr(drvinfo_detail_data->HardwareID, szHwId))
- {
- /* Newer version and matching hardware ID found. Select the driver. */
- if (!SetupDiSetSelectedDriver(
- hDevInfoList,
- &devinfo_data,
- &drvinfo_data))
- {
- /* Something is wrong with this driver. Skip it. */
- msg(M_WARN | M_ERRNO, "%s: SetupDiSetSelectedDriver(\"%hs\") failed", __FUNCTION__, drvinfo_data.Description);
- continue;
- }
-
- dwlDriverVersion = drvinfo_data.DriverVersion;
- }
- }
- if (drvinfo_detail_data)
- {
- free(drvinfo_detail_data);
- }
-
- if (dwlDriverVersion == 0)
- {
- dwResult = ERROR_NOT_FOUND;
- msg(M_NONFATAL, "%s: No driver for device \"%" PRIsLPTSTR "\" installed.", __FUNCTION__, szHwId);
- goto cleanup_DriverInfoList;
- }
-
- /* Call appropriate class installer. */
+ /* Register the device instance with the PnP Manager */
if (!SetupDiCallClassInstaller(
DIF_REGISTERDEVICE,
hDevInfoList,
@@ -876,43 +806,38 @@ tap_create_adapter(
{
dwResult = GetLastError();
msg(M_NONFATAL, "%s: SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed", __FUNCTION__);
- goto cleanup_DriverInfoList;
+ goto cleanup_hDevInfoList;
}
- /* Register device co-installers if any. */
- if (!SetupDiCallClassInstaller(
- DIF_REGISTER_COINSTALLERS,
- hDevInfoList,
- &devinfo_data))
- {
- dwResult = GetLastError();
- msg(M_WARN | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed", __FUNCTION__);
- }
+ /* Install the device using DiInstallDevice()
+ * We instruct the system to use the best driver in the driver store
+ * by setting the drvinfo argument of DiInstallDevice as NULL. This
+ * assumes a driver is already installed in the driver store.
+ */
+#ifdef HAVE_DIINSTALLDEVICE
+ if (!DiInstallDevice(hwndParent, hDevInfoList, &devinfo_data, NULL, 0, pbRebootRequired))
+#else
+ /* mingw does not resolve DiInstallDevice, so load it at run time. */
+ typedef BOOL (WINAPI *DiInstallDeviceFn) (HWND, HDEVINFO, SP_DEVINFO_DATA *,
+ SP_DRVINFO_DATA *, DWORD, BOOL *);
+ DiInstallDeviceFn installfn
+ = find_function (L"newdev.dll", "DiInstallDevice", &libnewdev);
- /* Install adapters if any. */
- if (!SetupDiCallClassInstaller(
- DIF_INSTALLINTERFACES,
- hDevInfoList,
- &devinfo_data))
+ if (!installfn)
{
dwResult = GetLastError();
- msg(M_WARN | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed", __FUNCTION__);
+ msg(M_NONFATAL | M_ERRNO, "%s: Failed to locate DiInstallDevice()", __FUNCTION__);
+ goto cleanup_hDevInfoList;
}
- /* Install the device. */
- if (!SetupDiCallClassInstaller(
- DIF_INSTALLDEVICE,
- hDevInfoList,
- &devinfo_data))
+ if (!installfn(hwndParent, hDevInfoList, &devinfo_data, NULL, 0, pbRebootRequired))
+#endif
{
dwResult = GetLastError();
- msg(M_NONFATAL | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed", __FUNCTION__);
+ msg(M_NONFATAL | M_ERRNO, "%s: DiInstallDevice failed", __FUNCTION__);
goto cleanup_remove_device;
}
- /* Check if a system reboot is required. (Ignore errors) */
- check_reboot(hDevInfoList, &devinfo_data, pbRebootRequired);
-
/* Get network adapter ID from registry. Retry for max 30sec. */
dwResult = get_net_adapter_guid(hDevInfoList, &devinfo_data, 30, pguidAdapter);
@@ -958,13 +883,11 @@ cleanup_remove_device:
}
}
-cleanup_DriverInfoList:
- SetupDiDestroyDriverInfoList(
- hDevInfoList,
- &devinfo_data,
- SPDIT_CLASSDRIVER);
-
cleanup_hDevInfoList:
+ if (libnewdev)
+ {
+ FreeLibrary(libnewdev);
+ }
SetupDiDestroyDeviceInfoList(hDevInfoList);
return dwResult;
}
@@ -1140,9 +1063,12 @@ ExecCommand(const WCHAR* cmdline)
DWORD
tap_set_adapter_name(
_In_ LPCGUID pguidAdapter,
- _In_ LPCTSTR szName)
+ _In_ LPCTSTR szName,
+ _In_ BOOL bSilent)
{
DWORD dwResult;
+ int msg_flag = bSilent ? M_WARN : M_NONFATAL;
+ msg_flag |= M_ERRNO;
if (pguidAdapter == NULL || szName == NULL)
{
@@ -1176,7 +1102,7 @@ tap_set_adapter_name(
if (dwResult != ERROR_SUCCESS)
{
SetLastError(dwResult); /* MSDN does not mention RegOpenKeyEx() to set GetLastError(). But we do have an error code. Set last error manually. */
- msg(M_NONFATAL | M_ERRNO, "%s: RegOpenKeyEx(HKLM, \"%" PRIsLPTSTR "\") failed", __FUNCTION__, szRegKey);
+ msg(msg_flag, "%s: RegOpenKeyEx(HKLM, \"%" PRIsLPTSTR "\") failed", __FUNCTION__, szRegKey);
goto cleanup_szAdapterId;
}
@@ -1185,7 +1111,7 @@ tap_set_adapter_name(
if (dwResult != ERROR_SUCCESS)
{
SetLastError(dwResult);
- msg(M_NONFATAL | M_ERRNO, "%s: Error reading adapter name", __FUNCTION__);
+ msg(msg_flag, "%s: Error reading adapter name", __FUNCTION__);
goto cleanup_hKey;
}
@@ -1203,7 +1129,7 @@ tap_set_adapter_name(
if (dwResult != ERROR_SUCCESS)
{
SetLastError(dwResult);
- msg(M_NONFATAL | M_ERRNO, "%s: Error renaming adapter", __FUNCTION__);
+ msg(msg_flag, "%s: Error renaming adapter", __FUNCTION__);
goto cleanup_hKey;
}