1313#include <ddk/ndisguid.h>
1414#include <nci.h>
1515#include <wireguard.h>
16+ #include <hashtable.h>
1617
1718#define IPC_SUPPORTS_KERNEL_INTERFACE
1819
20+ static bool have_cached_kernel_interfaces ;
21+ static struct hashtable cached_kernel_interfaces ;
22+
1923static int kernel_get_wireguard_interfaces (struct string_list * list )
2024{
2125 HDEVINFO dev_info = SetupDiGetClassDevsExW (& GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL );
26+ bool will_have_cached_kernel_interfaces = true;
2227
2328 if (dev_info == INVALID_HANDLE_VALUE ) {
2429 errno = EACCES ;
@@ -33,6 +38,7 @@ static int kernel_get_wireguard_interfaces(struct string_list *list)
3338 HKEY key ;
3439 GUID instance_id ;
3540 char * interface_name ;
41+ struct hashtable_entry * entry ;
3642
3743 if (!SetupDiEnumDeviceInfo (dev_info , i , & dev_info_data )) {
3844 if (GetLastError () == ERROR_NO_MORE_ITEMS )
@@ -105,23 +111,74 @@ static int kernel_get_wireguard_interfaces(struct string_list *list)
105111 }
106112
107113 string_list_add (list , interface_name );
114+
115+ entry = hashtable_find_or_insert_entry (& cached_kernel_interfaces , interface_name );
108116 free (interface_name );
117+ if (!entry )
118+ goto cleanup_entry ;
119+
120+ if (SetupDiGetDeviceInstanceIdW (dev_info , & dev_info_data , NULL , 0 , & buf_len ) || GetLastError () != ERROR_INSUFFICIENT_BUFFER )
121+ goto cleanup_entry ;
122+ entry -> value = calloc (sizeof (WCHAR ), buf_len );
123+ if (!entry -> value )
124+ goto cleanup_entry ;
125+ if (!SetupDiGetDeviceInstanceIdW (dev_info , & dev_info_data , entry -> value , buf_len , & buf_len )) {
126+ free (entry -> value );
127+ entry -> value = NULL ;
128+ goto cleanup_entry ;
129+ }
130+
131+ cleanup_entry :
132+ will_have_cached_kernel_interfaces |= entry != NULL && entry -> value != NULL ;
109133cleanup_buf :
110134 free (buf );
111135cleanup_key :
112136 RegCloseKey (key );
113137skip :;
114138 }
115139 SetupDiDestroyDeviceInfoList (dev_info );
140+ have_cached_kernel_interfaces = will_have_cached_kernel_interfaces ;
116141 return 0 ;
117142}
118143
119144static HANDLE kernel_interface_handle (const char * iface )
120145{
121- HDEVINFO dev_info = SetupDiGetClassDevsExW ( & GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL ) ;
146+ HDEVINFO dev_info ;
122147 WCHAR * interfaces = NULL ;
123148 HANDLE handle ;
124149
150+ if (have_cached_kernel_interfaces ) {
151+ struct hashtable_entry * entry = hashtable_find_entry (& cached_kernel_interfaces , iface );
152+ if (entry ) {
153+ DWORD buf_len ;
154+ if (CM_Get_Device_Interface_List_SizeW (
155+ & buf_len , (GUID * )& GUID_DEVINTERFACE_NET , (DEVINSTID_W )entry -> value ,
156+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT ) != CR_SUCCESS )
157+ goto err_hash ;
158+ interfaces = calloc (buf_len , sizeof (* interfaces ));
159+ if (!interfaces )
160+ goto err_hash ;
161+ if (CM_Get_Device_Interface_ListW (
162+ (GUID * )& GUID_DEVINTERFACE_NET , (DEVINSTID_W )entry -> value , interfaces , buf_len ,
163+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT ) != CR_SUCCESS || !interfaces [0 ]) {
164+ free (interfaces );
165+ interfaces = NULL ;
166+ goto err_hash ;
167+ }
168+ handle = CreateFileW (interfaces , GENERIC_READ | GENERIC_WRITE ,
169+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE , NULL ,
170+ OPEN_EXISTING , 0 , NULL );
171+ free (interfaces );
172+ if (handle == INVALID_HANDLE_VALUE )
173+ goto err_hash ;
174+ return handle ;
175+ err_hash :
176+ errno = EACCES ;
177+ return NULL ;
178+ }
179+ }
180+
181+ dev_info = SetupDiGetClassDevsExW (& GUID_DEVCLASS_NET , NULL , NULL , DIGCF_PRESENT , NULL , NULL , NULL );
125182 if (dev_info == INVALID_HANDLE_VALUE )
126183 return NULL ;
127184
0 commit comments