OpenVPN
tap.c
Go to the documentation of this file.
1 /*
2  * tapctl -- Utility to manipulate TUN/TAP adapters on Windows
3  * https://community.openvpn.net/openvpn/wiki/Tapctl
4  *
5  * Copyright (C) 2018-2024 Simon Rozman <simon@rozman.si>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2
9  * as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include "tap.h"
26 #include "error.h"
27 
28 #include <windows.h>
29 #include <cfgmgr32.h>
30 #include <objbase.h>
31 #include <setupapi.h>
32 #include <stdio.h>
33 #include <tchar.h>
34 #include <newdev.h>
35 
36 #ifdef _MSC_VER
37 #pragma comment(lib, "advapi32.lib")
38 #pragma comment(lib, "ole32.lib")
39 #pragma comment(lib, "setupapi.lib")
40 #pragma comment(lib, "newdev.lib")
41 #endif
42 
43 
44 const static GUID GUID_DEVCLASS_NET = { 0x4d36e972L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
45 
46 const static TCHAR szAdapterRegKeyPathTemplate[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Network\\%") TEXT(PRIsLPOLESTR) TEXT("\\%") TEXT(PRIsLPOLESTR) TEXT("\\Connection");
47 #define ADAPTER_REGKEY_PATH_MAX (_countof(TEXT("SYSTEM\\CurrentControlSet\\Control\\Network\\")) - 1 + 38 + _countof(TEXT("\\")) - 1 + 38 + _countof(TEXT("\\Connection")))
48 
62 static void *
63 find_function(const WCHAR *libname, const char *funcname, HMODULE *m)
64 {
65  WCHAR libpath[MAX_PATH];
66  void *fptr = NULL;
67 
68  /* Make sure the dll is loaded from the system32 folder */
69  if (!GetSystemDirectoryW(libpath, _countof(libpath)))
70  {
71  return NULL;
72  }
73 
74  /* +1 for the path seperator '\' */
75  const size_t path_length = wcslen(libpath) + 1 + wcslen(libname);
76  if (path_length >= _countof(libpath))
77  {
78  SetLastError(ERROR_INSUFFICIENT_BUFFER);
79  return NULL;
80  }
81  wcscat_s(libpath, _countof(libpath), L"\\");
82  wcscat_s(libpath, _countof(libpath), libname);
83 
84  *m = LoadLibraryW(libpath);
85  if (*m == NULL)
86  {
87  return NULL;
88  }
89  fptr = GetProcAddress(*m, funcname);
90  if (!fptr)
91  {
92  FreeLibrary(*m);
93  *m = NULL;
94  return NULL;
95  }
96  return fptr;
97 }
98 
106 static inline size_t
107 _tcszlen(_In_z_ LPCTSTR szz)
108 {
109  LPCTSTR s;
110  for (s = szz; s[0]; s += _tcslen(s) + 1)
111  {
112  }
113  return s - szz;
114 }
115 
116 
127 static LPCTSTR
128 _tcszistr(_In_z_ LPCTSTR szzHay, _In_z_ LPCTSTR szNeedle)
129 {
130  for (LPCTSTR s = szzHay; s[0]; s += _tcslen(s) + 1)
131  {
132  if (_tcsicmp(s, szNeedle) == 0)
133  {
134  return s;
135  }
136  }
137 
138  return NULL;
139 }
140 
141 
158 typedef DWORD (*devop_func_t)(
159  _In_ HDEVINFO hDeviceInfoSet,
160  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
161  _Inout_ LPBOOL pbRebootRequired);
162 
163 
180 static DWORD
182  _In_ HDEVINFO hDeviceInfoSet,
183  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
184  _Inout_ LPBOOL pbRebootRequired)
185 {
186  if (pbRebootRequired == NULL)
187  {
188  return ERROR_BAD_ARGUMENTS;
189  }
190 
191  SP_DEVINSTALL_PARAMS devinstall_params = { .cbSize = sizeof(SP_DEVINSTALL_PARAMS) };
192  if (!SetupDiGetDeviceInstallParams(
193  hDeviceInfoSet,
194  pDeviceInfoData,
195  &devinstall_params))
196  {
197  DWORD dwResult = GetLastError();
198  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiGetDeviceInstallParams failed", __FUNCTION__);
199  return dwResult;
200  }
201 
202  if ((devinstall_params.Flags & (DI_NEEDREBOOT | DI_NEEDRESTART)) != 0)
203  {
204  *pbRebootRequired = TRUE;
205  }
206 
207  return ERROR_SUCCESS;
208 }
209 
210 
227 static DWORD
229  _In_ HDEVINFO hDeviceInfoSet,
230  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
231  _Inout_ LPBOOL pbRebootRequired)
232 {
233  SP_REMOVEDEVICE_PARAMS params =
234  {
235  .ClassInstallHeader =
236  {
237  .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
238  .InstallFunction = DIF_REMOVE,
239  },
240  .Scope = DI_REMOVEDEVICE_GLOBAL,
241  .HwProfile = 0,
242  };
243 
244  /* Set class installer parameters for DIF_REMOVE. */
245  if (!SetupDiSetClassInstallParams(
246  hDeviceInfoSet,
247  pDeviceInfoData,
248  &params.ClassInstallHeader,
249  sizeof(SP_REMOVEDEVICE_PARAMS)))
250  {
251  DWORD dwResult = GetLastError();
252  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiSetClassInstallParams failed", __FUNCTION__);
253  return dwResult;
254  }
255 
256  /* Call appropriate class installer. */
257  if (!SetupDiCallClassInstaller(
258  DIF_REMOVE,
259  hDeviceInfoSet,
260  pDeviceInfoData))
261  {
262  DWORD dwResult = GetLastError();
263  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_REMOVE) failed", __FUNCTION__);
264  return dwResult;
265  }
266 
267  /* Check if a system reboot is required. */
268  check_reboot(hDeviceInfoSet, pDeviceInfoData, pbRebootRequired);
269  return ERROR_SUCCESS;
270 }
271 
272 
291 static DWORD
293  _In_ HDEVINFO hDeviceInfoSet,
294  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
295  _In_ BOOL bEnable,
296  _Inout_ LPBOOL pbRebootRequired)
297 {
298  SP_PROPCHANGE_PARAMS params =
299  {
300  .ClassInstallHeader =
301  {
302  .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
303  .InstallFunction = DIF_PROPERTYCHANGE,
304  },
305  .StateChange = bEnable ? DICS_ENABLE : DICS_DISABLE,
306  .Scope = DICS_FLAG_GLOBAL,
307  .HwProfile = 0,
308  };
309 
310  /* Set class installer parameters for DIF_PROPERTYCHANGE. */
311  if (!SetupDiSetClassInstallParams(
312  hDeviceInfoSet,
313  pDeviceInfoData,
314  &params.ClassInstallHeader,
315  sizeof(SP_PROPCHANGE_PARAMS)))
316  {
317  DWORD dwResult = GetLastError();
318  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiSetClassInstallParams failed", __FUNCTION__);
319  return dwResult;
320  }
321 
322  /* Call appropriate class installer. */
323  if (!SetupDiCallClassInstaller(
324  DIF_PROPERTYCHANGE,
325  hDeviceInfoSet,
326  pDeviceInfoData))
327  {
328  DWORD dwResult = GetLastError();
329  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_PROPERTYCHANGE) failed", __FUNCTION__);
330  return dwResult;
331  }
332 
333  /* Check if a system reboot is required. */
334  check_reboot(hDeviceInfoSet, pDeviceInfoData, pbRebootRequired);
335  return ERROR_SUCCESS;
336 }
337 
338 
355 static DWORD
357  _In_ HDEVINFO hDeviceInfoSet,
358  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
359  _Inout_ LPBOOL pbRebootRequired)
360 {
361  return change_device_state(hDeviceInfoSet, pDeviceInfoData, TRUE, pbRebootRequired);
362 }
363 
364 
381 static DWORD
383  _In_ HDEVINFO hDeviceInfoSet,
384  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
385  _Inout_ LPBOOL pbRebootRequired)
386 {
387  return change_device_state(hDeviceInfoSet, pDeviceInfoData, FALSE, pbRebootRequired);
388 }
389 
390 
405 static DWORD
407  _In_ HKEY hKey,
408  _In_ LPCTSTR szName,
409  _Out_ LPTSTR *pszValue)
410 {
411  if (pszValue == NULL)
412  {
413  return ERROR_BAD_ARGUMENTS;
414  }
415 
416  DWORD dwValueType = REG_NONE, dwSize = 0;
417  DWORD dwResult = RegQueryValueEx(
418  hKey,
419  szName,
420  NULL,
421  &dwValueType,
422  NULL,
423  &dwSize);
424  if (dwResult != ERROR_SUCCESS)
425  {
426  SetLastError(dwResult); /* MSDN does not mention RegQueryValueEx() to set GetLastError(). But we do have an error code. Set last error manually. */
427  msg(M_NONFATAL | M_ERRNO, "%s: enumerating \"%" PRIsLPTSTR "\" registry value failed", __FUNCTION__, szName);
428  return dwResult;
429  }
430 
431  switch (dwValueType)
432  {
433  case REG_SZ:
434  case REG_EXPAND_SZ:
435  {
436  /* Read value. */
437  LPTSTR szValue = (LPTSTR)malloc(dwSize);
438  if (szValue == NULL)
439  {
440  msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, dwSize);
441  return ERROR_OUTOFMEMORY;
442  }
443 
444  dwResult = RegQueryValueEx(
445  hKey,
446  szName,
447  NULL,
448  NULL,
449  (LPBYTE)szValue,
450  &dwSize);
451  if (dwResult != ERROR_SUCCESS)
452  {
453  SetLastError(dwResult); /* MSDN does not mention RegQueryValueEx() to set GetLastError(). But we do have an error code. Set last error manually. */
454  msg(M_NONFATAL | M_ERRNO, "%s: reading \"%" PRIsLPTSTR "\" registry value failed", __FUNCTION__, szName);
455  free(szValue);
456  return dwResult;
457  }
458 
459  if (dwValueType == REG_EXPAND_SZ)
460  {
461  /* Expand the environment strings. */
462  DWORD
463  dwSizeExp = dwSize * 2,
464  dwCountExp =
465 #ifdef UNICODE
466  dwSizeExp / sizeof(TCHAR);
467 #else
468  dwSizeExp / sizeof(TCHAR) - 1; /* Note: ANSI version requires one extra char. */
469 #endif
470  LPTSTR szValueExp = (LPTSTR)malloc(dwSizeExp);
471  if (szValueExp == NULL)
472  {
473  free(szValue);
474  msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, dwSizeExp);
475  return ERROR_OUTOFMEMORY;
476  }
477 
478  DWORD dwCountExpResult = ExpandEnvironmentStrings(
479  szValue,
480  szValueExp, dwCountExp
481  );
482  if (dwCountExpResult == 0)
483  {
484  msg(M_NONFATAL | M_ERRNO, "%s: expanding \"%" PRIsLPTSTR "\" registry value failed", __FUNCTION__, szName);
485  free(szValueExp);
486  free(szValue);
487  return dwResult;
488  }
489  else if (dwCountExpResult <= dwCountExp)
490  {
491  /* The buffer was big enough. */
492  free(szValue);
493  *pszValue = szValueExp;
494  return ERROR_SUCCESS;
495  }
496  else
497  {
498  /* Retry with a bigger buffer. */
499  free(szValueExp);
500 #ifdef UNICODE
501  dwSizeExp = dwCountExpResult * sizeof(TCHAR);
502 #else
503  /* Note: ANSI version requires one extra char. */
504  dwSizeExp = (dwCountExpResult + 1) * sizeof(TCHAR);
505 #endif
506  dwCountExp = dwCountExpResult;
507  szValueExp = (LPTSTR)malloc(dwSizeExp);
508  if (szValueExp == NULL)
509  {
510  free(szValue);
511  msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, dwSizeExp);
512  return ERROR_OUTOFMEMORY;
513  }
514 
515  dwCountExpResult = ExpandEnvironmentStrings(
516  szValue,
517  szValueExp, dwCountExp);
518  free(szValue);
519  *pszValue = szValueExp;
520  return ERROR_SUCCESS;
521  }
522  }
523  else
524  {
525  *pszValue = szValue;
526  return ERROR_SUCCESS;
527  }
528  }
529 
530  default:
531  msg(M_NONFATAL, "%s: \"%" PRIsLPTSTR "\" registry value is not string (type %u)", __FUNCTION__, dwValueType);
532  return ERROR_UNSUPPORTED_TYPE;
533  }
534 }
535 
536 
555 static DWORD
557  _In_ HDEVINFO hDeviceInfoSet,
558  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
559  _In_ int iNumAttempts,
560  _Out_ LPGUID pguidAdapter)
561 {
562  DWORD dwResult = ERROR_BAD_ARGUMENTS;
563 
564  if (pguidAdapter == NULL || iNumAttempts < 1)
565  {
566  return ERROR_BAD_ARGUMENTS;
567  }
568 
569  /* Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class<class><id> registry key. */
570  HKEY hKey = SetupDiOpenDevRegKey(
571  hDeviceInfoSet,
572  pDeviceInfoData,
573  DICS_FLAG_GLOBAL,
574  0,
575  DIREG_DRV,
576  KEY_READ);
577  if (hKey == INVALID_HANDLE_VALUE)
578  {
579  dwResult = GetLastError();
580  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiOpenDevRegKey failed", __FUNCTION__);
581  return dwResult;
582  }
583 
584  while (iNumAttempts > 0)
585  {
586  /* Query the NetCfgInstanceId value. Using get_reg_string() right on might clutter the output with error messages while the registry is still being populated. */
587  LPTSTR szCfgGuidString = NULL;
588  dwResult = RegQueryValueEx(hKey, TEXT("NetCfgInstanceId"), NULL, NULL, NULL, NULL);
589  if (dwResult != ERROR_SUCCESS)
590  {
591  if (dwResult == ERROR_FILE_NOT_FOUND && --iNumAttempts > 0)
592  {
593  /* Wait and retry. */
594  Sleep(1000);
595  continue;
596  }
597 
598  SetLastError(dwResult); /* MSDN does not mention RegQueryValueEx() to set GetLastError(). But we do have an error code. Set last error manually. */
599  msg(M_NONFATAL | M_ERRNO, "%s: querying \"NetCfgInstanceId\" registry value failed", __FUNCTION__);
600  break;
601  }
602 
603  /* Read the NetCfgInstanceId value now. */
604  dwResult = get_reg_string(
605  hKey,
606  TEXT("NetCfgInstanceId"),
607  &szCfgGuidString);
608  if (dwResult != ERROR_SUCCESS)
609  {
610  break;
611  }
612 
613  dwResult = SUCCEEDED(CLSIDFromString(szCfgGuidString, (LPCLSID)pguidAdapter)) ? ERROR_SUCCESS : ERROR_INVALID_DATA;
614  free(szCfgGuidString);
615  break;
616  }
617 
618  RegCloseKey(hKey);
619  return dwResult;
620 }
621 
622 
644 static DWORD
646  _In_ HDEVINFO hDeviceInfoSet,
647  _In_ PSP_DEVINFO_DATA pDeviceInfoData,
648  _In_ DWORD dwProperty,
649  _Out_opt_ LPDWORD pdwPropertyRegDataType,
650  _Out_ LPVOID *ppData)
651 {
652  DWORD dwResult = ERROR_BAD_ARGUMENTS;
653 
654  if (ppData == NULL)
655  {
656  return ERROR_BAD_ARGUMENTS;
657  }
658 
659  /* Try with stack buffer first. */
660  BYTE bBufStack[128];
661  DWORD dwRequiredSize = 0;
662  if (SetupDiGetDeviceRegistryProperty(
663  hDeviceInfoSet,
664  pDeviceInfoData,
665  dwProperty,
666  pdwPropertyRegDataType,
667  bBufStack,
668  sizeof(bBufStack),
669  &dwRequiredSize))
670  {
671  /* Copy from stack. */
672  *ppData = malloc(dwRequiredSize);
673  if (*ppData == NULL)
674  {
675  msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, dwRequiredSize);
676  return ERROR_OUTOFMEMORY;
677  }
678 
679  memcpy(*ppData, bBufStack, dwRequiredSize);
680  return ERROR_SUCCESS;
681  }
682  else
683  {
684  dwResult = GetLastError();
685  if (dwResult == ERROR_INSUFFICIENT_BUFFER)
686  {
687  /* Allocate on heap and retry. */
688  *ppData = malloc(dwRequiredSize);
689  if (*ppData == NULL)
690  {
691  msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, dwRequiredSize);
692  return ERROR_OUTOFMEMORY;
693  }
694 
695  if (SetupDiGetDeviceRegistryProperty(
696  hDeviceInfoSet,
697  pDeviceInfoData,
698  dwProperty,
699  pdwPropertyRegDataType,
700  *ppData,
701  dwRequiredSize,
702  &dwRequiredSize))
703  {
704  return ERROR_SUCCESS;
705  }
706  else
707  {
708  dwResult = GetLastError();
709  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiGetDeviceRegistryProperty(%u) failed", __FUNCTION__, dwProperty);
710  return dwResult;
711  }
712  }
713  else
714  {
715  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiGetDeviceRegistryProperty(%u) failed", __FUNCTION__, dwProperty);
716  return dwResult;
717  }
718  }
719 }
720 
721 
722 DWORD
724  _In_opt_ HWND hwndParent,
725  _In_opt_ LPCTSTR szDeviceDescription,
726  _In_ LPCTSTR szHwId,
727  _Inout_ LPBOOL pbRebootRequired,
728  _Out_ LPGUID pguidAdapter)
729 {
730  DWORD dwResult;
731  HMODULE libnewdev = NULL;
732 
733  if (szHwId == NULL
734  || pbRebootRequired == NULL
735  || pguidAdapter == NULL)
736  {
737  return ERROR_BAD_ARGUMENTS;
738  }
739 
740  /* Create an empty device info set for network adapter device class. */
741  HDEVINFO hDevInfoList = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, hwndParent);
742  if (hDevInfoList == INVALID_HANDLE_VALUE)
743  {
744  dwResult = GetLastError();
745  msg(M_NONFATAL, "%s: SetupDiCreateDeviceInfoList failed", __FUNCTION__);
746  return dwResult;
747  }
748 
749  /* Get the device class name from GUID. */
750  TCHAR szClassName[MAX_CLASS_NAME_LEN];
751  if (!SetupDiClassNameFromGuid(
753  szClassName,
754  _countof(szClassName),
755  NULL))
756  {
757  dwResult = GetLastError();
758  msg(M_NONFATAL, "%s: SetupDiClassNameFromGuid failed", __FUNCTION__);
759  goto cleanup_hDevInfoList;
760  }
761 
762  /* Create a new device info element and add it to the device info set. */
763  SP_DEVINFO_DATA devinfo_data = { .cbSize = sizeof(SP_DEVINFO_DATA) };
764  if (!SetupDiCreateDeviceInfo(
765  hDevInfoList,
766  szClassName,
768  szDeviceDescription,
769  hwndParent,
770  DICD_GENERATE_ID,
771  &devinfo_data))
772  {
773  dwResult = GetLastError();
774  msg(M_NONFATAL, "%s: SetupDiCreateDeviceInfo failed", __FUNCTION__);
775  goto cleanup_hDevInfoList;
776  }
777 
778  /* Set a device information element as the selected member of a device information set. */
779  if (!SetupDiSetSelectedDevice(
780  hDevInfoList,
781  &devinfo_data))
782  {
783  dwResult = GetLastError();
784  msg(M_NONFATAL, "%s: SetupDiSetSelectedDevice failed", __FUNCTION__);
785  goto cleanup_hDevInfoList;
786  }
787 
788  /* Set Plug&Play device hardware ID property. */
789  if (!SetupDiSetDeviceRegistryProperty(
790  hDevInfoList,
791  &devinfo_data,
792  SPDRP_HARDWAREID,
793  (const BYTE *)szHwId, (DWORD)((_tcslen(szHwId) + 1) * sizeof(TCHAR))))
794  {
795  dwResult = GetLastError();
796  msg(M_NONFATAL, "%s: SetupDiSetDeviceRegistryProperty failed", __FUNCTION__);
797  goto cleanup_hDevInfoList;
798  }
799 
800  /* Register the device instance with the PnP Manager */
801  if (!SetupDiCallClassInstaller(
802  DIF_REGISTERDEVICE,
803  hDevInfoList,
804  &devinfo_data))
805  {
806  dwResult = GetLastError();
807  msg(M_NONFATAL, "%s: SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed", __FUNCTION__);
808  goto cleanup_hDevInfoList;
809  }
810 
811  /* Install the device using DiInstallDevice()
812  * We instruct the system to use the best driver in the driver store
813  * by setting the drvinfo argument of DiInstallDevice as NULL. This
814  * assumes a driver is already installed in the driver store.
815  */
816 #ifdef HAVE_DIINSTALLDEVICE
817  if (!DiInstallDevice(hwndParent, hDevInfoList, &devinfo_data, NULL, 0, pbRebootRequired))
818 #else
819  /* mingw does not resolve DiInstallDevice, so load it at run time. */
820  typedef BOOL (WINAPI *DiInstallDeviceFn)(HWND, HDEVINFO, SP_DEVINFO_DATA *,
821  SP_DRVINFO_DATA *, DWORD, BOOL *);
822  DiInstallDeviceFn installfn
823  = find_function(L"newdev.dll", "DiInstallDevice", &libnewdev);
824 
825  if (!installfn)
826  {
827  dwResult = GetLastError();
828  msg(M_NONFATAL | M_ERRNO, "%s: Failed to locate DiInstallDevice()", __FUNCTION__);
829  goto cleanup_hDevInfoList;
830  }
831 
832  if (!installfn(hwndParent, hDevInfoList, &devinfo_data, NULL, 0, pbRebootRequired))
833 #endif
834  {
835  dwResult = GetLastError();
836  msg(M_NONFATAL | M_ERRNO, "%s: DiInstallDevice failed", __FUNCTION__);
837  goto cleanup_remove_device;
838  }
839 
840  /* Get network adapter ID from registry. Retry for max 30sec. */
841  dwResult = get_net_adapter_guid(hDevInfoList, &devinfo_data, 30, pguidAdapter);
842 
843 cleanup_remove_device:
844  if (dwResult != ERROR_SUCCESS)
845  {
846  /* The adapter was installed. But, the adapter ID was unobtainable. Clean-up. */
847  SP_REMOVEDEVICE_PARAMS removedevice_params =
848  {
849  .ClassInstallHeader =
850  {
851  .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
852  .InstallFunction = DIF_REMOVE,
853  },
854  .Scope = DI_REMOVEDEVICE_GLOBAL,
855  .HwProfile = 0,
856  };
857 
858  /* Set class installer parameters for DIF_REMOVE. */
859  if (SetupDiSetClassInstallParams(
860  hDevInfoList,
861  &devinfo_data,
862  &removedevice_params.ClassInstallHeader,
863  sizeof(SP_REMOVEDEVICE_PARAMS)))
864  {
865  /* Call appropriate class installer. */
866  if (SetupDiCallClassInstaller(
867  DIF_REMOVE,
868  hDevInfoList,
869  &devinfo_data))
870  {
871  /* Check if a system reboot is required. */
872  check_reboot(hDevInfoList, &devinfo_data, pbRebootRequired);
873  }
874  else
875  {
876  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiCallClassInstaller(DIF_REMOVE) failed", __FUNCTION__);
877  }
878  }
879  else
880  {
881  msg(M_NONFATAL | M_ERRNO, "%s: SetupDiSetClassInstallParams failed", __FUNCTION__);
882  }
883  }
884 
885 cleanup_hDevInfoList:
886  if (libnewdev)
887  {
888  FreeLibrary(libnewdev);
889  }
890  SetupDiDestroyDeviceInfoList(hDevInfoList);
891  return dwResult;
892 }
893 
894 
915 static DWORD
917  _In_opt_ HWND hwndParent,
918  _In_ LPCGUID pguidAdapter,
919  _In_ devop_func_t funcOperation,
920  _Inout_ LPBOOL pbRebootRequired)
921 {
922  DWORD dwResult;
923 
924  if (pguidAdapter == NULL)
925  {
926  return ERROR_BAD_ARGUMENTS;
927  }
928 
929  /* Create a list of network devices. */
930  HDEVINFO hDevInfoList = SetupDiGetClassDevsEx(
932  NULL,
933  hwndParent,
934  DIGCF_PRESENT,
935  NULL,
936  NULL,
937  NULL);
938  if (hDevInfoList == INVALID_HANDLE_VALUE)
939  {
940  dwResult = GetLastError();
941  msg(M_NONFATAL, "%s: SetupDiGetClassDevsEx failed", __FUNCTION__);
942  return dwResult;
943  }
944 
945  /* Retrieve information associated with a device information set. */
946  SP_DEVINFO_LIST_DETAIL_DATA devinfo_list_detail_data = { .cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA) };
947  if (!SetupDiGetDeviceInfoListDetail(hDevInfoList, &devinfo_list_detail_data))
948  {
949  dwResult = GetLastError();
950  msg(M_NONFATAL, "%s: SetupDiGetDeviceInfoListDetail failed", __FUNCTION__);
951  goto cleanup_hDevInfoList;
952  }
953 
954  /* Iterate. */
955  for (DWORD dwIndex = 0;; dwIndex++)
956  {
957  /* Get the device from the list. */
958  SP_DEVINFO_DATA devinfo_data = { .cbSize = sizeof(SP_DEVINFO_DATA) };
959  if (!SetupDiEnumDeviceInfo(
960  hDevInfoList,
961  dwIndex,
962  &devinfo_data))
963  {
964  if (GetLastError() == ERROR_NO_MORE_ITEMS)
965  {
966  LPOLESTR szAdapterId = NULL;
967  StringFromIID((REFIID)pguidAdapter, &szAdapterId);
968  msg(M_NONFATAL, "%s: Adapter %" PRIsLPOLESTR " not found", __FUNCTION__, szAdapterId);
969  CoTaskMemFree(szAdapterId);
970  dwResult = ERROR_FILE_NOT_FOUND;
971  goto cleanup_hDevInfoList;
972  }
973  else
974  {
975  /* Something is wrong with this device. Skip it. */
976  msg(M_WARN | M_ERRNO, "%s: SetupDiEnumDeviceInfo(%u) failed", __FUNCTION__, dwIndex);
977  continue;
978  }
979  }
980 
981  /* Get adapter GUID. */
982  GUID guidAdapter;
983  dwResult = get_net_adapter_guid(hDevInfoList, &devinfo_data, 1, &guidAdapter);
984  if (dwResult != ERROR_SUCCESS)
985  {
986  /* Something is wrong with this device. Skip it. */
987  continue;
988  }
989 
990  /* Compare GUIDs. */
991  if (memcmp(pguidAdapter, &guidAdapter, sizeof(GUID)) == 0)
992  {
993  dwResult = funcOperation(hDevInfoList, &devinfo_data, pbRebootRequired);
994  break;
995  }
996  }
997 
998 cleanup_hDevInfoList:
999  SetupDiDestroyDeviceInfoList(hDevInfoList);
1000  return dwResult;
1001 }
1002 
1003 
1004 DWORD
1006  _In_opt_ HWND hwndParent,
1007  _In_ LPCGUID pguidAdapter,
1008  _Inout_ LPBOOL pbRebootRequired)
1009 {
1010  return execute_on_first_adapter(hwndParent, pguidAdapter, delete_device, pbRebootRequired);
1011 }
1012 
1013 
1014 DWORD
1016  _In_opt_ HWND hwndParent,
1017  _In_ LPCGUID pguidAdapter,
1018  _In_ BOOL bEnable,
1019  _Inout_ LPBOOL pbRebootRequired)
1020 {
1021  return execute_on_first_adapter(hwndParent, pguidAdapter, bEnable ? enable_device : disable_device, pbRebootRequired);
1022 }
1023 
1024 /* stripped version of ExecCommand in interactive.c */
1025 static DWORD
1026 ExecCommand(const WCHAR *cmdline)
1027 {
1028  DWORD exit_code;
1029  STARTUPINFOW si;
1030  PROCESS_INFORMATION pi;
1031  DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
1032  WCHAR *cmdline_dup = NULL;
1033 
1034  ZeroMemory(&si, sizeof(si));
1035  ZeroMemory(&pi, sizeof(pi));
1036 
1037  si.cb = sizeof(si);
1038 
1039  /* CreateProcess needs a modifiable cmdline: make a copy */
1040  cmdline_dup = _wcsdup(cmdline);
1041  if (cmdline_dup && CreateProcessW(NULL, cmdline_dup, NULL, NULL, FALSE,
1042  proc_flags, NULL, NULL, &si, &pi))
1043  {
1044  WaitForSingleObject(pi.hProcess, INFINITE);
1045  if (!GetExitCodeProcess(pi.hProcess, &exit_code))
1046  {
1047  exit_code = GetLastError();
1048  }
1049 
1050  CloseHandle(pi.hProcess);
1051  CloseHandle(pi.hThread);
1052  }
1053  else
1054  {
1055  exit_code = GetLastError();
1056  }
1057 
1058  free(cmdline_dup);
1059  return exit_code;
1060 }
1061 
1062 DWORD
1064  _In_ LPCGUID pguidAdapter,
1065  _In_ LPCTSTR szName,
1066  _In_ BOOL bSilent)
1067 {
1068  DWORD dwResult;
1069  int msg_flag = bSilent ? M_WARN : M_NONFATAL;
1070  msg_flag |= M_ERRNO;
1071 
1072  if (pguidAdapter == NULL || szName == NULL)
1073  {
1074  return ERROR_BAD_ARGUMENTS;
1075  }
1076 
1077  /* Get the device class GUID as string. */
1078  LPOLESTR szDevClassNetId = NULL;
1079  StringFromIID((REFIID)&GUID_DEVCLASS_NET, &szDevClassNetId);
1080 
1081  /* Get the adapter GUID as string. */
1082  LPOLESTR szAdapterId = NULL;
1083  StringFromIID((REFIID)pguidAdapter, &szAdapterId);
1084 
1085  /* Render registry key path. */
1086  TCHAR szRegKey[ADAPTER_REGKEY_PATH_MAX];
1087  _stprintf_s(
1088  szRegKey, _countof(szRegKey),
1090  szDevClassNetId,
1091  szAdapterId);
1092 
1093  /* Open network adapter registry key. */
1094  HKEY hKey = NULL;
1095  dwResult = RegOpenKeyEx(
1096  HKEY_LOCAL_MACHINE,
1097  szRegKey,
1098  0,
1099  KEY_QUERY_VALUE,
1100  &hKey);
1101  if (dwResult != ERROR_SUCCESS)
1102  {
1103  SetLastError(dwResult); /* MSDN does not mention RegOpenKeyEx() to set GetLastError(). But we do have an error code. Set last error manually. */
1104  msg(msg_flag, "%s: RegOpenKeyEx(HKLM, \"%" PRIsLPTSTR "\") failed", __FUNCTION__, szRegKey);
1105  goto cleanup_szAdapterId;
1106  }
1107 
1108  LPTSTR szOldName = NULL;
1109  dwResult = get_reg_string(hKey, TEXT("Name"), &szOldName);
1110  if (dwResult != ERROR_SUCCESS)
1111  {
1112  SetLastError(dwResult);
1113  msg(msg_flag, "%s: Error reading adapter name", __FUNCTION__);
1114  goto cleanup_hKey;
1115  }
1116 
1117  /* rename adapter via netsh call */
1118  const TCHAR *szFmt = TEXT("netsh interface set interface name=\"%")
1119  TEXT(PRIsLPTSTR) TEXT("\" newname=\"%") TEXT(PRIsLPTSTR) TEXT("\"");
1120  size_t ncmdline = _tcslen(szFmt) + _tcslen(szOldName) + _tcslen(szName) + 1;
1121  WCHAR *szCmdLine = malloc(ncmdline * sizeof(TCHAR));
1122  _stprintf_s(szCmdLine, ncmdline, szFmt, szOldName, szName);
1123 
1124  free(szOldName);
1125 
1126  dwResult = ExecCommand(szCmdLine);
1127  free(szCmdLine);
1128 
1129  if (dwResult != ERROR_SUCCESS)
1130  {
1131  SetLastError(dwResult);
1132  msg(msg_flag, "%s: Error renaming adapter", __FUNCTION__);
1133  goto cleanup_hKey;
1134  }
1135 
1136 cleanup_hKey:
1137  RegCloseKey(hKey);
1138 cleanup_szAdapterId:
1139  CoTaskMemFree(szAdapterId);
1140  CoTaskMemFree(szDevClassNetId);
1141  return dwResult;
1142 }
1143 
1144 
1145 DWORD
1147  _In_opt_ HWND hwndParent,
1148  _In_opt_ LPCTSTR szzHwIDs,
1149  _Out_ struct tap_adapter_node **ppAdapter)
1150 {
1151  DWORD dwResult;
1152 
1153  if (ppAdapter == NULL)
1154  {
1155  return ERROR_BAD_ARGUMENTS;
1156  }
1157 
1158  /* Create a list of network devices. */
1159  HDEVINFO hDevInfoList = SetupDiGetClassDevsEx(
1161  NULL,
1162  hwndParent,
1163  DIGCF_PRESENT,
1164  NULL,
1165  NULL,
1166  NULL);
1167  if (hDevInfoList == INVALID_HANDLE_VALUE)
1168  {
1169  dwResult = GetLastError();
1170  msg(M_NONFATAL, "%s: SetupDiGetClassDevsEx failed", __FUNCTION__);
1171  return dwResult;
1172  }
1173 
1174  /* Retrieve information associated with a device information set. */
1175  SP_DEVINFO_LIST_DETAIL_DATA devinfo_list_detail_data = { .cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA) };
1176  if (!SetupDiGetDeviceInfoListDetail(hDevInfoList, &devinfo_list_detail_data))
1177  {
1178  dwResult = GetLastError();
1179  msg(M_NONFATAL, "%s: SetupDiGetDeviceInfoListDetail failed", __FUNCTION__);
1180  goto cleanup_hDevInfoList;
1181  }
1182 
1183  /* Get the device class GUID as string. */
1184  LPOLESTR szDevClassNetId = NULL;
1185  StringFromIID((REFIID)&GUID_DEVCLASS_NET, &szDevClassNetId);
1186 
1187  /* Iterate. */
1188  *ppAdapter = NULL;
1189  struct tap_adapter_node *pAdapterTail = NULL;
1190  for (DWORD dwIndex = 0;; dwIndex++)
1191  {
1192  /* Get the device from the list. */
1193  SP_DEVINFO_DATA devinfo_data = { .cbSize = sizeof(SP_DEVINFO_DATA) };
1194  if (!SetupDiEnumDeviceInfo(
1195  hDevInfoList,
1196  dwIndex,
1197  &devinfo_data))
1198  {
1199  if (GetLastError() == ERROR_NO_MORE_ITEMS)
1200  {
1201  break;
1202  }
1203  else
1204  {
1205  /* Something is wrong with this device. Skip it. */
1206  msg(M_WARN | M_ERRNO, "%s: SetupDiEnumDeviceInfo(%u) failed", __FUNCTION__, dwIndex);
1207  continue;
1208  }
1209  }
1210 
1211  /* Get device hardware ID(s). */
1212  DWORD dwDataType = REG_NONE;
1213  LPTSTR szzDeviceHardwareIDs = NULL;
1214  dwResult = get_device_reg_property(
1215  hDevInfoList,
1216  &devinfo_data,
1217  SPDRP_HARDWAREID,
1218  &dwDataType,
1219  (LPVOID)&szzDeviceHardwareIDs);
1220  if (dwResult != ERROR_SUCCESS)
1221  {
1222  /* Something is wrong with this device. Skip it. */
1223  continue;
1224  }
1225 
1226  /* Check that hardware ID is REG_SZ/REG_MULTI_SZ, and optionally if it matches ours. */
1227  if (dwDataType == REG_SZ)
1228  {
1229  if (szzHwIDs && !_tcszistr(szzHwIDs, szzDeviceHardwareIDs))
1230  {
1231  /* This is not our device. Skip it. */
1232  goto cleanup_szzDeviceHardwareIDs;
1233  }
1234  }
1235  else if (dwDataType == REG_MULTI_SZ)
1236  {
1237  if (szzHwIDs)
1238  {
1239  for (LPTSTR s = szzDeviceHardwareIDs;; s += _tcslen(s) + 1)
1240  {
1241  if (s[0] == 0)
1242  {
1243  /* This is not our device. Skip it. */
1244  goto cleanup_szzDeviceHardwareIDs;
1245  }
1246  else if (_tcszistr(szzHwIDs, s))
1247  {
1248  /* This is our device. */
1249  break;
1250  }
1251  }
1252  }
1253  }
1254  else
1255  {
1256  /* Unexpected hardware ID format. Skip device. */
1257  goto cleanup_szzDeviceHardwareIDs;
1258  }
1259 
1260  /* Get adapter GUID. */
1261  GUID guidAdapter;
1262  dwResult = get_net_adapter_guid(hDevInfoList, &devinfo_data, 1, &guidAdapter);
1263  if (dwResult != ERROR_SUCCESS)
1264  {
1265  /* Something is wrong with this device. Skip it. */
1266  goto cleanup_szzDeviceHardwareIDs;
1267  }
1268 
1269  /* Get the adapter GUID as string. */
1270  LPOLESTR szAdapterId = NULL;
1271  StringFromIID((REFIID)&guidAdapter, &szAdapterId);
1272 
1273  /* Render registry key path. */
1274  TCHAR szRegKey[ADAPTER_REGKEY_PATH_MAX];
1275  _stprintf_s(
1276  szRegKey, _countof(szRegKey),
1278  szDevClassNetId,
1279  szAdapterId);
1280 
1281  /* Open network adapter registry key. */
1282  HKEY hKey = NULL;
1283  dwResult = RegOpenKeyEx(
1284  HKEY_LOCAL_MACHINE,
1285  szRegKey,
1286  0,
1287  KEY_READ,
1288  &hKey);
1289  if (dwResult != ERROR_SUCCESS)
1290  {
1291  SetLastError(dwResult); /* MSDN does not mention RegOpenKeyEx() to set GetLastError(). But we do have an error code. Set last error manually. */
1292  msg(M_WARN | M_ERRNO, "%s: RegOpenKeyEx(HKLM, \"%" PRIsLPTSTR "\") failed", __FUNCTION__, szRegKey);
1293  goto cleanup_szAdapterId;
1294  }
1295 
1296  /* Read adapter name. */
1297  LPTSTR szName = NULL;
1298  dwResult = get_reg_string(
1299  hKey,
1300  TEXT("Name"),
1301  &szName);
1302  if (dwResult != ERROR_SUCCESS)
1303  {
1304  SetLastError(dwResult);
1305  msg(M_WARN | M_ERRNO, "%s: Cannot determine %" PRIsLPOLESTR " adapter name", __FUNCTION__, szAdapterId);
1306  goto cleanup_hKey;
1307  }
1308 
1309  /* Append to the list. */
1310  size_t hwid_size = (_tcszlen(szzDeviceHardwareIDs) + 1) * sizeof(TCHAR);
1311  size_t name_size = (_tcslen(szName) + 1) * sizeof(TCHAR);
1312  struct tap_adapter_node *node = (struct tap_adapter_node *)malloc(sizeof(struct tap_adapter_node) + hwid_size + name_size);
1313  if (node == NULL)
1314  {
1315  msg(M_FATAL, "%s: malloc(%u) failed", __FUNCTION__, sizeof(struct tap_adapter_node) + hwid_size + name_size);
1316  dwResult = ERROR_OUTOFMEMORY; goto cleanup_szName;
1317  }
1318 
1319  memcpy(&node->guid, &guidAdapter, sizeof(GUID));
1320  node->szzHardwareIDs = (LPTSTR)(node + 1);
1321  memcpy(node->szzHardwareIDs, szzDeviceHardwareIDs, hwid_size);
1322  node->szName = (LPTSTR)((LPBYTE)node->szzHardwareIDs + hwid_size);
1323  memcpy(node->szName, szName, name_size);
1324  node->pNext = NULL;
1325  if (pAdapterTail)
1326  {
1327  pAdapterTail->pNext = node;
1328  pAdapterTail = node;
1329  }
1330  else
1331  {
1332  *ppAdapter = pAdapterTail = node;
1333  }
1334 
1335 cleanup_szName:
1336  free(szName);
1337 cleanup_hKey:
1338  RegCloseKey(hKey);
1339 cleanup_szAdapterId:
1340  CoTaskMemFree(szAdapterId);
1341 cleanup_szzDeviceHardwareIDs:
1342  free(szzDeviceHardwareIDs);
1343  }
1344 
1345  dwResult = ERROR_SUCCESS;
1346 
1347  CoTaskMemFree(szDevClassNetId);
1348 cleanup_hDevInfoList:
1349  SetupDiDestroyDeviceInfoList(hDevInfoList);
1350  return dwResult;
1351 }
1352 
1353 
1354 void
1356  _In_ struct tap_adapter_node *pAdapterList)
1357 {
1358  /* Iterate over all nodes of the list. */
1359  while (pAdapterList)
1360  {
1361  struct tap_adapter_node *node = pAdapterList;
1362  pAdapterList = pAdapterList->pNext;
1363 
1364  /* Free the adapter node. */
1365  free(node);
1366  }
1367 }
tap_adapter_node::szzHardwareIDs
LPTSTR szzHardwareIDs
Adapter GUID.
Definition: tap.h:139
tap_adapter_node::pNext
struct tap_adapter_node * pNext
Adapter name.
Definition: tap.h:142
PRIsLPTSTR
#define PRIsLPTSTR
Definition: basic.h:29
M_ERRNO
#define M_ERRNO
Definition: error.h:94
tap_adapter_node::guid
GUID guid
Definition: tap.h:138
ADAPTER_REGKEY_PATH_MAX
#define ADAPTER_REGKEY_PATH_MAX
Definition: tap.c:47
M_FATAL
#define M_FATAL
Definition: error.h:89
M_NONFATAL
#define M_NONFATAL
Definition: error.h:90
change_device_state
static DWORD change_device_state(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _In_ BOOL bEnable, _Inout_ LPBOOL pbRebootRequired)
Changes the device state.
Definition: tap.c:292
get_net_adapter_guid
static DWORD get_net_adapter_guid(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _In_ int iNumAttempts, _Out_ LPGUID pguidAdapter)
Returns network adapter ID.
Definition: tap.c:556
devop_func_t
DWORD(* devop_func_t)(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _Inout_ LPBOOL pbRebootRequired)
Function that performs a specific task on a device.
Definition: tap.c:158
GUID_DEVCLASS_NET
const static GUID GUID_DEVCLASS_NET
Definition: tap.c:44
tap_delete_adapter
DWORD tap_delete_adapter(_In_opt_ HWND hwndParent, _In_ LPCGUID pguidAdapter, _Inout_ LPBOOL pbRebootRequired)
Deletes an adapter.
Definition: tap.c:1005
_tcszistr
static LPCTSTR _tcszistr(_In_z_ LPCTSTR szzHay, _In_z_ LPCTSTR szNeedle)
Checks if string is contained in the string of strings.
Definition: tap.c:128
delete_device
static DWORD delete_device(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _Inout_ LPBOOL pbRebootRequired)
Deletes the device.
Definition: tap.c:228
tap_adapter_node::szName
LPTSTR szName
Device hardware ID(s)
Definition: tap.h:140
tap_free_adapter_list
void tap_free_adapter_list(_In_ struct tap_adapter_node *pAdapterList)
Frees a list of network adapters.
Definition: tap.c:1355
M_WARN
#define M_WARN
Definition: error.h:91
_Out_opt_
#define _Out_opt_
Definition: basic.h:60
ExecCommand
static DWORD ExecCommand(const WCHAR *cmdline)
Definition: tap.c:1026
execute_on_first_adapter
static DWORD execute_on_first_adapter(_In_opt_ HWND hwndParent, _In_ LPCGUID pguidAdapter, _In_ devop_func_t funcOperation, _Inout_ LPBOOL pbRebootRequired)
Performs a given task on an adapter.
Definition: tap.c:916
_In_
#define _In_
Definition: basic.h:42
_Out_
#define _Out_
Definition: basic.h:57
tap.h
_tcszlen
static size_t _tcszlen(_In_z_ LPCTSTR szz)
Returns length of string of strings.
Definition: tap.c:107
tap_adapter_node
Network adapter list node.
Definition: tap.h:136
disable_device
static DWORD disable_device(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _Inout_ LPBOOL pbRebootRequired)
Disables the device.
Definition: tap.c:382
PRIsLPOLESTR
#define PRIsLPOLESTR
Definition: basic.h:30
_Inout_
#define _Inout_
Definition: basic.h:51
error.h
tap_enable_adapter
DWORD tap_enable_adapter(_In_opt_ HWND hwndParent, _In_ LPCGUID pguidAdapter, _In_ BOOL bEnable, _Inout_ LPBOOL pbRebootRequired)
Enables or disables an adapter.
Definition: tap.c:1015
enable_device
static DWORD enable_device(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _Inout_ LPBOOL pbRebootRequired)
Enables the device.
Definition: tap.c:356
get_device_reg_property
static DWORD get_device_reg_property(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _In_ DWORD dwProperty, _Out_opt_ LPDWORD pdwPropertyRegDataType, _Out_ LPVOID *ppData)
Returns a specified Plug and Play device property.
Definition: tap.c:645
_In_opt_
#define _In_opt_
Definition: basic.h:45
config.h
_In_z_
#define _In_z_
Definition: basic.h:48
tap_create_adapter
DWORD tap_create_adapter(_In_opt_ HWND hwndParent, _In_opt_ LPCTSTR szDeviceDescription, _In_ LPCTSTR szHwId, _Inout_ LPBOOL pbRebootRequired, _Out_ LPGUID pguidAdapter)
Creates a TUN/TAP adapter.
Definition: tap.c:723
tap_set_adapter_name
DWORD tap_set_adapter_name(_In_ LPCGUID pguidAdapter, _In_ LPCTSTR szName, _In_ BOOL bSilent)
Sets adapter name.
Definition: tap.c:1063
szAdapterRegKeyPathTemplate
const static TCHAR szAdapterRegKeyPathTemplate[]
Definition: tap.c:46
tap_list_adapters
DWORD tap_list_adapters(_In_opt_ HWND hwndParent, _In_opt_ LPCTSTR szzHwIDs, _Out_ struct tap_adapter_node **ppAdapter)
Creates a list of existing network adapters.
Definition: tap.c:1146
get_reg_string
static DWORD get_reg_string(_In_ HKEY hKey, _In_ LPCTSTR szName, _Out_ LPTSTR *pszValue)
Reads string value from registry key.
Definition: tap.c:406
msg
#define msg(flags,...)
Definition: error.h:144
check_reboot
static DWORD check_reboot(_In_ HDEVINFO hDeviceInfoSet, _In_ PSP_DEVINFO_DATA pDeviceInfoData, _Inout_ LPBOOL pbRebootRequired)
Checks device install parameters if a system reboot is required.
Definition: tap.c:181
find_function
static void * find_function(const WCHAR *libname, const char *funcname, HMODULE *m)
Dynamically load a library and find a function in it.
Definition: tap.c:63