This MR adds a unixlib component to wlanapi containing DBus + NetworkManager implementations for
* WlanEnumInterfaces * WlanGetAvailableNetworkList * WlanGetAvailableNetworkList * WlanGetNetworkBssList * WlanScan
-- v2: wlanapi/tests: Add unit tests for WlanScan. wlanapi: Add NetworkManager backed implementation for WlanScan. wlanapi/tests: Add unit test for test_WlanGetNetworkBssList. wlanapi: Add NetworkManager backed implementation for WlanGetNetworkBssList. wlanapi/tests: Add unit test for WlanGetAvailableNetworkList. wlanapi: Add NetworkManager backed implementation for WlanGetAvailableNetworkList.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/Makefile.in | 6 +- dlls/wlanapi/dbus.c | 101 ++++++++++++++++++++++++++++++++ dlls/wlanapi/dbus.h | 113 ++++++++++++++++++++++++++++++++++++ dlls/wlanapi/main.c | 35 +++++++++++ dlls/wlanapi/unixlib.c | 71 ++++++++++++++++++++++ dlls/wlanapi/unixlib.h | 48 +++++++++++++++ dlls/wlanapi/unixlib_priv.h | 28 +++++++++ 7 files changed, 401 insertions(+), 1 deletion(-) create mode 100644 dlls/wlanapi/dbus.c create mode 100644 dlls/wlanapi/dbus.h create mode 100644 dlls/wlanapi/unixlib.c create mode 100644 dlls/wlanapi/unixlib.h create mode 100644 dlls/wlanapi/unixlib_priv.h
diff --git a/dlls/wlanapi/Makefile.in b/dlls/wlanapi/Makefile.in index bd2bf87d4d1..92e65dabd54 100644 --- a/dlls/wlanapi/Makefile.in +++ b/dlls/wlanapi/Makefile.in @@ -1,7 +1,11 @@ MODULE = wlanapi.dll IMPORTLIB = wlanapi +UNIXLIB = wlanapi.so +UNIX_CFLAGS = $(DBUS_CFLAGS)
EXTRADLLFLAGS = -Wb,--prefer-native
SOURCES = \ - main.c + main.c \ + dbus.c \ + unixlib.c diff --git a/dlls/wlanapi/dbus.c b/dlls/wlanapi/dbus.c new file mode 100644 index 00000000000..8a6b5e5b5bb --- /dev/null +++ b/dlls/wlanapi/dbus.c @@ -0,0 +1,101 @@ +/* + * wlanapi DBus backed implementation + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <dlfcn.h> + +#ifdef SONAME_LIBDBUS_1 +#include <dbus/dbus.h> +#endif + +#include <ntstatus.h> +#define WIN32_NO_STATUS +#include <winternl.h> + +#include <wine/debug.h> + +#include "dbus.h" + +WINE_DEFAULT_DEBUG_CHANNEL( wlanapi ); + +#ifdef SONAME_LIBDBUS_1 + +#define DO_FUNC( f ) typeof( f ) (*p_##f) +DBUS_FUNCS; +#undef DO_FUNC + +BOOL load_dbus_functions( void ) +{ + void *handle = dlopen( SONAME_LIBDBUS_1, RTLD_NOW ); + + if (handle == NULL) goto failed; + +#define DO_FUNC( f ) \ + if (!(p_##f = dlsym( handle, #f ))) \ + { \ + ERR( "failed to load symbol %s: %s\n", #f, dlerror() ); \ + goto failed; \ + } + DBUS_FUNCS; +#undef DO_FUNC + p_dbus_threads_init_default(); + return TRUE; + +failed: + WARN( "failed to load DBus support: %s\n", dlerror() ); + return FALSE; +} + +NTSTATUS init_dbus_connection( UINT_PTR *handle ) +{ + DBusError error; + DBusConnection *connection; + NTSTATUS ret = STATUS_SUCCESS; + + p_dbus_error_init( &error ); + connection = p_dbus_bus_get_private( DBUS_BUS_SYSTEM, &error ); + if (connection == NULL) + { + ERR( "Failed to get system dbus connection: %s: %s.\n", debugstr_a( error.name ), + debugstr_a( error.message ) ); + ret = STATUS_NOT_SUPPORTED; + } + else + *handle = (UINT_PTR)connection; + p_dbus_error_free( &error ); + + return ret; +} + +void close_dbus_connection( void *c ) +{ + p_dbus_connection_close( c ); + p_dbus_connection_unref( c ); +} +#else /* SONAME_LIBDBUS_1 */ +BOOL load_dbus_functions( void ) { return FALSE; } +NTSTATUS init_dbus_connection( UINT_PTR *handle ) { return STATUS_NOT_SUPPORTED; } +void close_dbus_connection( void *c ) { return STATUS_NOT_SUPPORTED; } +#endif diff --git a/dlls/wlanapi/dbus.h b/dlls/wlanapi/dbus.h new file mode 100644 index 00000000000..86c5309d117 --- /dev/null +++ b/dlls/wlanapi/dbus.h @@ -0,0 +1,113 @@ +/* + * DBus declarations. + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WLANAPI_UNIXLIB_DBUS_H +#define __WINE_WLANAPI_UNIXLIB_DBUS_H + +#include "config.h" + +#ifdef SONAME_LIBDBUS_1 +#include <dbus/dbus.h> +#endif + +#ifdef SONAME_LIBDBUS_1 + +#define DBUS_FUNCS \ + DO_FUNC(dbus_bus_add_match); \ + DO_FUNC(dbus_bus_get); \ + DO_FUNC(dbus_bus_get_id); \ + DO_FUNC(dbus_bus_get_private); \ + DO_FUNC(dbus_bus_remove_match); \ + DO_FUNC(dbus_connection_add_filter); \ + DO_FUNC(dbus_connection_close); \ + DO_FUNC(dbus_connection_flush); \ + DO_FUNC(dbus_connection_free_preallocated_send); \ + DO_FUNC(dbus_connection_get_is_anonymous); \ + DO_FUNC(dbus_connection_get_is_authenticated); \ + DO_FUNC(dbus_connection_get_is_connected); \ + DO_FUNC(dbus_connection_get_server_id); \ + DO_FUNC(dbus_connection_get_unix_process_id); \ + DO_FUNC(dbus_connection_get_unix_fd); \ + DO_FUNC(dbus_connection_get_unix_user); \ + DO_FUNC(dbus_connection_preallocate_send); \ + DO_FUNC(dbus_connection_read_write_dispatch); \ + DO_FUNC(dbus_connection_remove_filter); \ + DO_FUNC(dbus_connection_ref); \ + DO_FUNC(dbus_connection_send); \ + DO_FUNC(dbus_connection_send_preallocated); \ + DO_FUNC(dbus_connection_send_with_reply); \ + DO_FUNC(dbus_connection_send_with_reply_and_block); \ + DO_FUNC(dbus_connection_try_register_object_path); \ + DO_FUNC(dbus_connection_unref); \ + DO_FUNC(dbus_connection_unregister_object_path); \ + DO_FUNC(dbus_error_free); \ + DO_FUNC(dbus_error_has_name) ; \ + DO_FUNC(dbus_error_init); \ + DO_FUNC(dbus_error_is_set); \ + DO_FUNC(dbus_free); \ + DO_FUNC(dbus_free_string_array); \ + DO_FUNC(dbus_message_append_args); \ + DO_FUNC(dbus_message_get_args); \ + DO_FUNC(dbus_message_iter_get_element_count); \ + DO_FUNC(dbus_message_get_interface); \ + DO_FUNC(dbus_message_get_member); \ + DO_FUNC(dbus_message_get_path); \ + DO_FUNC(dbus_message_get_sender); \ + DO_FUNC(dbus_message_get_serial); \ + DO_FUNC(dbus_message_get_signature); \ + DO_FUNC(dbus_message_get_type); \ + DO_FUNC(dbus_message_has_signature); \ + DO_FUNC(dbus_message_iter_has_next); \ + DO_FUNC(dbus_message_is_error); \ + DO_FUNC(dbus_message_is_method_call); \ + DO_FUNC(dbus_message_is_signal); \ + DO_FUNC(dbus_message_iter_append_basic); \ + DO_FUNC(dbus_message_iter_close_container); \ + DO_FUNC(dbus_message_iter_get_arg_type); \ + DO_FUNC(dbus_message_iter_get_element_type); \ + DO_FUNC(dbus_message_iter_get_basic); \ + DO_FUNC(dbus_message_iter_get_fixed_array); \ + DO_FUNC(dbus_message_iter_get_signature); \ + DO_FUNC(dbus_message_iter_init); \ + DO_FUNC(dbus_message_iter_init_append); \ + DO_FUNC(dbus_message_iter_next); \ + DO_FUNC(dbus_message_iter_open_container); \ + DO_FUNC(dbus_message_iter_recurse); \ + DO_FUNC(dbus_message_new_error); \ + DO_FUNC(dbus_message_new_error_printf); \ + DO_FUNC(dbus_message_new_method_return); \ + DO_FUNC(dbus_message_new_method_call); \ + DO_FUNC(dbus_message_ref); \ + DO_FUNC(dbus_message_unref); \ + DO_FUNC(dbus_pending_call_block); \ + DO_FUNC(dbus_pending_call_cancel); \ + DO_FUNC(dbus_pending_call_get_completed); \ + DO_FUNC(dbus_pending_call_set_notify); \ + DO_FUNC(dbus_pending_call_steal_reply); \ + DO_FUNC(dbus_pending_call_unref); \ + DO_FUNC(dbus_set_error_from_message); \ + DO_FUNC(dbus_threads_init_default); + +#define DO_FUNC( f ) extern typeof( f ) *p_##f +DBUS_FUNCS; +#undef DO_FUNC + +#endif /* SONAME_LIBDBUS_1 */ +#endif /* __WINE_WLANAPI_UNIXLIB_DBUS_H */ diff --git a/dlls/wlanapi/main.c b/dlls/wlanapi/main.c index c3712662232..6335088973c 100644 --- a/dlls/wlanapi/main.c +++ b/dlls/wlanapi/main.c @@ -28,12 +28,18 @@
#include <stdarg.h>
+#include <ntstatus.h> +#define WIN32_NO_STATUS + #include "windef.h" #include "winbase.h" #include "wine/debug.h" +#include "wine/unixlib.h"
#include "wlanapi.h"
+#include "unixlib.h" + WINE_DEFAULT_DEBUG_CHANNEL(wlanapi);
#define WLAN_MAGIC 0x574c414e /* WLAN */ @@ -41,6 +47,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wlanapi); static struct wine_wlan { DWORD magic, cli_version; + UINT_PTR unix_handle; } handle_table[16];
static struct wine_wlan* handle_index(HANDLE handle) @@ -98,6 +105,8 @@ DWORD WINAPI WlanEnumInterfaces(HANDLE handle, void *reserved, WLAN_INTERFACE_IN DWORD WINAPI WlanCloseHandle(HANDLE handle, void *reserved) { struct wine_wlan *wlan; + struct wlan_close_handle_params params = {0}; + NTSTATUS status;
TRACE("(%p, %p)\n", handle, reserved);
@@ -108,6 +117,11 @@ DWORD WINAPI WlanCloseHandle(HANDLE handle, void *reserved) if (!wlan) return ERROR_INVALID_HANDLE;
+ params.handle = wlan->unix_handle; + status = UNIX_WLAN_CALL( wlan_close_handle, ¶ms ); + if (status != STATUS_SUCCESS && status != STATUS_NOT_SUPPORTED) + return RtlNtStatusToDosError( status ); + wlan->magic = 0; return ERROR_SUCCESS; } @@ -115,7 +129,9 @@ DWORD WINAPI WlanCloseHandle(HANDLE handle, void *reserved) DWORD WINAPI WlanOpenHandle(DWORD client_version, void *reserved, DWORD *negotiated_version, HANDLE *handle) { struct wine_wlan *wlan; + struct wlan_open_handle_params params = {0}; HANDLE ret_handle; + NTSTATUS status;
TRACE("(%lu, %p, %p, %p)\n", client_version, reserved, negotiated_version, handle);
@@ -129,6 +145,11 @@ DWORD WINAPI WlanOpenHandle(DWORD client_version, void *reserved, DWORD *negotia if (!ret_handle) return ERROR_REMOTE_SESSION_LIMIT_EXCEEDED;
+ status = UNIX_WLAN_CALL( wlan_open_handle, ¶ms ); + if (status != STATUS_SUCCESS && status != STATUS_NOT_SUPPORTED) + return RtlNtStatusToDosError( status ); + + wlan->unix_handle = params.handle; wlan->magic = WLAN_MAGIC; wlan->cli_version = *negotiated_version = client_version; *handle = ret_handle; @@ -225,3 +246,17 @@ void *WINAPI WlanAllocateMemory(DWORD size)
return ret; } + +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, LPVOID reserved ) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( instance ); + if (__wine_init_unix_call()) return FALSE; + UNIX_WLAN_CALL( wlan_init, NULL ); + break; + } + + return TRUE; +} diff --git a/dlls/wlanapi/unixlib.c b/dlls/wlanapi/unixlib.c new file mode 100644 index 00000000000..92311ffb856 --- /dev/null +++ b/dlls/wlanapi/unixlib.c @@ -0,0 +1,71 @@ +/* + * wlanapi unixlib implementation + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <ntstatus.h> +#define WIN32_NO_STATUS +#include <winternl.h> + +#include <wine/unixlib.h> + +#include "unixlib.h" +#include "unixlib_priv.h" + +static BOOL initialized; + +NTSTATUS wlan_init( void *params ) +{ + initialized = load_dbus_functions(); + return STATUS_SUCCESS; +} + +NTSTATUS wlan_open_handle( void *params ) +{ + struct wlan_open_handle_params *args = params; + NTSTATUS status; + if (!initialized) + return STATUS_NOT_SUPPORTED; + + status = init_dbus_connection( &args->handle ); + return status; +} + +NTSTATUS wlan_close_handle( void *params ) +{ + struct wlan_close_handle_params *args = params; + if (!initialized) + return STATUS_NOT_SUPPORTED; + + close_dbus_connection( (void *)args->handle ); + return STATUS_SUCCESS; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = { + wlan_init, + wlan_open_handle, + wlan_close_handle +}; + +C_ASSERT( ARRAYSIZE( __wine_unix_call_funcs ) == unix_funcs_count ); diff --git a/dlls/wlanapi/unixlib.h b/dlls/wlanapi/unixlib.h new file mode 100644 index 00000000000..9bf2149e7c3 --- /dev/null +++ b/dlls/wlanapi/unixlib.h @@ -0,0 +1,48 @@ +/* + * Unix interface definitions + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WLANAPI_UNIXLIB_H +#define __WINE_WLANAPI_UNIXLIB_H + +#include <windef.h> + +struct wlan_open_handle_params +{ + UINT_PTR handle; +}; + +struct wlan_close_handle_params +{ + UINT_PTR handle; +}; + +enum wlanpi_funcs +{ + unix_wlan_init, + + unix_wlan_open_handle, + unix_wlan_close_handle, + + unix_funcs_count +}; + +#define UNIX_WLAN_CALL( func, params ) WINE_UNIX_CALL( unix_##func, (params) ) + +#endif /* __WINE_WLANAPI_UNIXLIB_H */ diff --git a/dlls/wlanapi/unixlib_priv.h b/dlls/wlanapi/unixlib_priv.h new file mode 100644 index 00000000000..fa813d07844 --- /dev/null +++ b/dlls/wlanapi/unixlib_priv.h @@ -0,0 +1,28 @@ +/* + * Unix private definitions + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WLANAPI_UNIXLIB_PRIV_H +#define __WINE_WLANAPI_UNIXLIB_PRIV_H + +extern BOOL load_dbus_functions( void ); +extern NTSTATUS init_dbus_connection( UINT_PTR *handle ); +extern void close_dbus_connection( void *c ); + +#endif /* __WINE_WLANAPI_UNIXLIB_PRIV_H */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/dbus.c | 290 ++++++++++++++++++++++++++++++++++++ dlls/wlanapi/main.c | 72 ++++++++- dlls/wlanapi/unixlib.c | 70 ++++++++- dlls/wlanapi/unixlib.h | 31 ++++ dlls/wlanapi/unixlib_priv.h | 7 + 5 files changed, 465 insertions(+), 5 deletions(-)
diff --git a/dlls/wlanapi/dbus.c b/dlls/wlanapi/dbus.c index 8a6b5e5b5bb..dca8156afe5 100644 --- a/dlls/wlanapi/dbus.c +++ b/dlls/wlanapi/dbus.c @@ -24,6 +24,7 @@
#include "config.h"
+#include <stdlib.h> #include <dlfcn.h>
#ifdef SONAME_LIBDBUS_1 @@ -33,9 +34,13 @@ #include <ntstatus.h> #define WIN32_NO_STATUS #include <winternl.h> +#include <wlanapi.h>
#include <wine/debug.h> +#include <wine/list.h>
+#include "unixlib.h" +#include "unixlib_priv.h" #include "dbus.h"
WINE_DEFAULT_DEBUG_CHANNEL( wlanapi ); @@ -46,6 +51,11 @@ WINE_DEFAULT_DEBUG_CHANNEL( wlanapi ); DBUS_FUNCS; #undef DO_FUNC
+#define NETWORKMANAGER_SERVICE "org.freedesktop.NetworkManager" + +#define NETWORKMANAGER_INTERFACE_MANAGER "org.freedesktop.NetworkManager" +#define NETWORKMANAGER_INTERFACE_DEVICE "org.freedesktop.NetworkManager.Device" + BOOL load_dbus_functions( void ) { void *handle = dlopen( SONAME_LIBDBUS_1, RTLD_NOW ); @@ -94,6 +104,286 @@ void close_dbus_connection( void *c ) p_dbus_connection_close( c ); p_dbus_connection_unref( c ); } + +const static int dbus_timeout = -1; + + +static NTSTATUS dbus_error_to_ntstatus( const DBusError *error ) +{ + +#define DBUS_ERROR_CASE(n, s) if(p_dbus_error_has_name( error, (n)) ) return (s) + + DBUS_ERROR_CASE( DBUS_ERROR_UNKNOWN_OBJECT, STATUS_INVALID_PARAMETER ); + DBUS_ERROR_CASE( DBUS_ERROR_NO_MEMORY, STATUS_NO_MEMORY ); + DBUS_ERROR_CASE( DBUS_ERROR_NOT_SUPPORTED, STATUS_NOT_SUPPORTED ); + DBUS_ERROR_CASE( DBUS_ERROR_ACCESS_DENIED, STATUS_ACCESS_DENIED ); + return STATUS_INTERNAL_ERROR; +#undef DBUS_ERROR_CASE +} + +#define NM_DEVICE_TYPE_WIFI 2 + +static BOOL networkmanager_device_is_wifi( void *connection, const char *object_path ) +{ + DBusMessage *request, *reply; + DBusError error; + DBusMessageIter iter, variant; + dbus_bool_t success; + BOOL is_wifi; + const char *device_iface = NETWORKMANAGER_INTERFACE_DEVICE; + const char *devicetype_prop = "DeviceType"; + + request = p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, object_path, + DBUS_INTERFACE_PROPERTIES, "Get" ); + if (!request) return FALSE; + success = p_dbus_message_append_args( request, DBUS_TYPE_STRING, &device_iface, + DBUS_TYPE_STRING, &devicetype_prop, DBUS_TYPE_INVALID ); + if (!success) + { + p_dbus_message_unref( request ); + return FALSE; + } + + p_dbus_error_init( &error ); + reply = p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + p_dbus_error_free( &error ); + return FALSE; + } + p_dbus_error_free( &error ); + p_dbus_error_init( &error ); + + p_dbus_message_iter_init( reply, &iter ); + p_dbus_message_iter_recurse( &iter, &variant ); + if (p_dbus_message_iter_get_arg_type( &variant) == DBUS_TYPE_UINT32) + { + dbus_uint32_t device_type; + + p_dbus_message_iter_get_basic( &variant, &device_type ); + is_wifi = device_type == NM_DEVICE_TYPE_WIFI; + } + else + { + ERR( "Unexpected signature for property DeviceType: %c\n", + p_dbus_message_iter_get_arg_type( &variant ) ); + is_wifi = FALSE; + } + + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); + + return is_wifi; +} + +/* NetworkManager device objects do not have any UUID-like propertiy which we could use to + deterministically derive an interface GUID for Win32. However, all device objects have + the object path prefix "/org/freedesktop/NetworkManager/Devices/" followed by a numerical + index. We use index as the last 4 bytes of this GUID to create a Win32 WLAN interface GUID. */ +const static GUID NETWORKMANAGER_DEVICE_BASE_INTERFACE_GUID = { + 0xa53634f7, 0xc1bc, 0x4d41, { 0xbc, 0x06, 0xd3, 0xf7, 0x00, 0x00, 0x00, 0x00 } }; + +static BOOL networkmanager_device_path_to_guid( const char *object_path, GUID *guid ) +{ + const static char device_prefix[] = "/org/freedesktop/NetworkManager/Devices/"; + BOOL is_device = strncmp( object_path, device_prefix, sizeof( device_prefix ) ); + UINT32 idx; + + if (!is_device) return FALSE; + idx = atoi( object_path + sizeof(device_prefix) - 1 ); + if (!idx) /* NetworkManager doesn't seem to use 0 as an index for devices. */ + { + ERR( "Could not parse index from device path %s:\n", debugstr_a( object_path )); + return FALSE; + } + + *guid = NETWORKMANAGER_DEVICE_BASE_INTERFACE_GUID; + memcpy( &guid->Data4[4], &idx, 4 ); + + return TRUE; +} + +static const char *dbus_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant ) +{ + DBusMessageIter sub; + const char *name; + + if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY) + return NULL; + + p_dbus_message_iter_recurse( iter, &sub ); + p_dbus_message_iter_next( iter ); + p_dbus_message_iter_get_basic( &sub, &name ); + p_dbus_message_iter_next( &sub ); + p_dbus_message_iter_recurse( &sub, variant ); + return name; +} + +#define NM_DEVICE_STATE_UNKNOWN 0 +#define NM_DEVICE_STATE_UNMANAGED 10 +#define NM_DEVICE_STATE_UNAVAILABLE 20 +#define NM_DEVICE_STATE_DISCONNECTED 30 +#define NM_DEVICE_STATE_PREPARE 40 +#define NM_DEVICE_STATE_CONFIG 50 +#define NM_DEVICE_STATE_NEED_AUTH 60 +#define NM_DEVICE_STATE_IP_CONFIG 70 +#define NM_DEVICE_STATE_IP_CHECK 80 +#define NM_DEVICE_STATE_SECONDARIES 90 +#define NM_DEVICE_STATE_ACTIVATED 100 +#define NM_DEVICE_STATE_DEACTIVATING 110 +#define NM_DEVICE_STATE_FAILED 120 + +static BOOL networkmanager_wifi_device_get_info( void *connection, const char *object_path, + struct unix_wlan_interface_info *info ) +{ + DBusMessage *request, *reply; + DBusError error; + DBusMessageIter dict, prop_iter, variant; + const char *prop_name; + const char *device_iface = NETWORKMANAGER_INTERFACE_DEVICE; + + if (!networkmanager_device_path_to_guid( object_path, &info->guid )) return FALSE; + request = p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, object_path, + DBUS_INTERFACE_PROPERTIES, "GetAll" ); + if (!request) return FALSE; + + p_dbus_message_append_args( request, DBUS_TYPE_STRING, &device_iface, DBUS_TYPE_INVALID ); + p_dbus_error_init( &error ); + reply = p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + ERR( "Could not get properties for %s: %s: %s.\n", debugstr_a( object_path ), error.name, + error.message ); + p_dbus_error_free( &error ); + return FALSE; + } + + p_dbus_error_free( &error ); + p_dbus_message_iter_init( reply, &dict ); + p_dbus_message_iter_recurse( &dict, &prop_iter ); + while ((prop_name = dbus_next_dict_entry( &prop_iter, &variant ))) + { + if (!strcmp( prop_name, "Interface" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_STRING) + { + const char *interface; + size_t len; + + p_dbus_message_iter_get_basic( &variant, &interface ); + len = min( strlen( interface ), sizeof( info->description ) - 1 ); + memcpy( info->description, interface, len); + info->description[len] = '\0'; + } + else if (!strcmp( prop_name, "State" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + dbus_uint32_t state; + + p_dbus_message_iter_get_basic( &variant, &state ); + switch (state) + { + case NM_DEVICE_STATE_UNKNOWN: + case NM_DEVICE_STATE_UNMANAGED: + case NM_DEVICE_STATE_UNAVAILABLE: + case NM_DEVICE_STATE_FAILED: + case NM_DEVICE_STATE_SECONDARIES: + info->state = wlan_interface_state_not_ready; + break; + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_PREPARE: + info->state = wlan_interface_state_associating; + break; + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_IP_CHECK: + info->state = wlan_interface_state_discovering; + break; + case NM_DEVICE_STATE_NEED_AUTH: + info->state = wlan_interface_state_authenticating; + break; + case NM_DEVICE_STATE_ACTIVATED: + info->state = wlan_interface_state_connected; + break; + case NM_DEVICE_STATE_DEACTIVATING: + info->state = wlan_interface_state_disconnecting; + break; + case NM_DEVICE_STATE_DISCONNECTED: + info->state = wlan_interface_state_disconnected; + break; + default: + FIXME( "Unknown NMDeviceState value %d\n", (int)state ); + info->state = wlan_interface_state_not_ready; + break; + } + } + } + p_dbus_message_unref(reply); + return TRUE; +} + +NTSTATUS networkmanager_get_wifi_devices( void *connection, struct list *devices ) +{ + DBusMessage *request, *reply; + char **object_paths = NULL; + int n_objects, i; + dbus_bool_t success; + DBusError error; + + request = + p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, "/org/freedesktop/NetworkManager", + NETWORKMANAGER_INTERFACE_MANAGER, "GetDevices" ); + if (!request) return STATUS_NO_MEMORY; + + p_dbus_error_init( &error ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + NTSTATUS ret = dbus_error_to_ntstatus( &error ); + ERR( "Could not get list of network devices: %s: %s.\n", debugstr_a( error.name ), + debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + return ret; + } + + p_dbus_error_free( &error ); + p_dbus_error_init( &error ); + success = p_dbus_message_get_args( reply, &error, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, + &object_paths, &n_objects, DBUS_TYPE_INVALID ); + if (!success) + { + NTSTATUS ret = dbus_error_to_ntstatus( &error ); + ERR( "Could not read object paths from GetDevices reply: %s: %s.\n", + debugstr_a( error.name ), debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); + return ret; + } + + p_dbus_error_free( &error ); + for (i = 0; i < n_objects; i++) + { + const char *object_path = object_paths[i]; + struct unix_wlan_interface_info info = {0}; + + if (networkmanager_device_is_wifi( connection, object_path ) && + networkmanager_device_path_to_guid( object_path, &info.guid ) && + networkmanager_wifi_device_get_info( connection, object_path, &info )) + { + struct wlan_interface *entry = malloc( sizeof(*entry) ); + if (!entry) continue; + entry->info = info; + list_add_head( devices, &entry->entry ); + } + } + + p_dbus_free_string_array( object_paths ); + p_dbus_message_unref( reply ); + return STATUS_SUCCESS; +} + #else /* SONAME_LIBDBUS_1 */ BOOL load_dbus_functions( void ) { return FALSE; } NTSTATUS init_dbus_connection( UINT_PTR *handle ) { return STATUS_NOT_SUPPORTED; } diff --git a/dlls/wlanapi/main.c b/dlls/wlanapi/main.c index 6335088973c..8c47b7244d0 100644 --- a/dlls/wlanapi/main.c +++ b/dlls/wlanapi/main.c @@ -27,12 +27,14 @@ */
#include <stdarg.h> +#include <stdlib.h>
#include <ntstatus.h> #define WIN32_NO_STATUS
#include "windef.h" #include "winbase.h" + #include "wine/debug.h" #include "wine/unixlib.h"
@@ -79,9 +81,12 @@ static HANDLE handle_new(struct wine_wlan **entry) DWORD WINAPI WlanEnumInterfaces(HANDLE handle, void *reserved, WLAN_INTERFACE_INFO_LIST **interface_list) { struct wine_wlan *wlan; + struct wlan_get_interfaces_params args = {0}; + SIZE_T count, list_size; WLAN_INTERFACE_INFO_LIST *ret_list; + NTSTATUS status;
- FIXME("(%p, %p, %p) semi-stub\n", handle, reserved, interface_list); + TRACE( "(%p, %p, %p)\n", handle, reserved, interface_list );
if (!handle || reserved || !interface_list) return ERROR_INVALID_PARAMETER; @@ -90,12 +95,71 @@ DWORD WINAPI WlanEnumInterfaces(HANDLE handle, void *reserved, WLAN_INTERFACE_IN if (!wlan) return ERROR_INVALID_HANDLE;
- ret_list = WlanAllocateMemory(sizeof(WLAN_INTERFACE_INFO_LIST)); + args.handle = wlan->unix_handle; + status = UNIX_WLAN_CALL( wlan_get_interfaces, &args ); + if (status == STATUS_NOT_SUPPORTED) + { + count = -1; + } + else if (status != STATUS_SUCCESS) + { + ERR( "Could not get list of interfaces from host: %lx.\n", status ); + return RtlNtStatusToDosError( status ); + } + else + count = args.len; + + list_size = offsetof(WLAN_INTERFACE_INFO_LIST, InterfaceInfo[count > 1 ? count : 1]); + ret_list = WlanAllocateMemory(list_size); if (!ret_list) + { + if (count != -1) + { + struct wlan_free_interfaces_params free_args = {0}; + + free_args.interfaces = args.interfaces; + UNIX_WLAN_CALL( wlan_free_interfaces, &free_args ); + } return ERROR_NOT_ENOUGH_MEMORY; + }
- memset(&ret_list->InterfaceInfo[0], 0, sizeof(WLAN_INTERFACE_INFO)); - ret_list->dwNumberOfItems = 0; + memset( ret_list, 0, list_size ); + if (count != -1) + { + struct wlan_copy_and_free_interfaces_params copy_args = {0}; + struct unix_wlan_interface_info *unix_ifaces = NULL; + SIZE_T i; + + unix_ifaces = malloc( sizeof( *unix_ifaces ) * count ); + if (!unix_ifaces) + { + struct wlan_free_interfaces_params free_args = {0}; + + free_args.interfaces = args.interfaces; + UNIX_WLAN_CALL( wlan_free_interfaces, &free_args ); + WlanFreeMemory( ret_list ); + return ERROR_NOT_ENOUGH_MEMORY; + } + + copy_args.info = unix_ifaces; + copy_args.interfaces = args.interfaces; + UNIX_WLAN_CALL( wlan_copy_and_free_interfaces, ©_args ); + + for (i = 0; i < count; i++) + { + const size_t desc_max = + sizeof( ret_list->InterfaceInfo[i].strInterfaceDescription ) / sizeof( WCHAR ); + + ret_list->InterfaceInfo[i].InterfaceGuid = unix_ifaces[i].guid; + ret_list->InterfaceInfo[i].isState = unix_ifaces[i].state; + + mbstowcs( ret_list->InterfaceInfo[i].strInterfaceDescription, + unix_ifaces[i].description, desc_max ); + ret_list->InterfaceInfo[i].strInterfaceDescription[desc_max - 1] = '\0'; + } + free( unix_ifaces ); + } + ret_list->dwNumberOfItems = count != -1 ? count : 0; ret_list->dwIndex = 0; /* unused in this function */ *interface_list = ret_list;
diff --git a/dlls/wlanapi/unixlib.c b/dlls/wlanapi/unixlib.c index 92311ffb856..8888f620ed0 100644 --- a/dlls/wlanapi/unixlib.c +++ b/dlls/wlanapi/unixlib.c @@ -24,10 +24,14 @@
#include "config.h"
+#include <stdlib.h> + #include <ntstatus.h> #define WIN32_NO_STATUS #include <winternl.h> +#include <wlanapi.h>
+#include <wine/list.h> #include <wine/unixlib.h>
#include "unixlib.h" @@ -62,10 +66,74 @@ NTSTATUS wlan_close_handle( void *params ) return STATUS_SUCCESS; }
+NTSTATUS wlan_get_interfaces( void *params ) +{ + struct wlan_get_interfaces_params *args = params; + struct list *ifaces; + NTSTATUS status; + + if (!initialized) + return STATUS_NOT_SUPPORTED; + + ifaces = malloc( sizeof( *ifaces ) ); + if (!ifaces) return STATUS_NO_MEMORY; + + list_init( ifaces ); + status = networkmanager_get_wifi_devices( (void *)args->handle, ifaces ); + if (status != STATUS_SUCCESS) + { + free( ifaces ); + return status; + } + + args->interfaces = (UINT_PTR)ifaces; + args->len = list_count( ifaces ); + return STATUS_SUCCESS; +} + +NTSTATUS wlan_copy_and_free_interfaces( void *params ) +{ + struct wlan_copy_and_free_interfaces_params *args = params; + struct wlan_interface *ifaces = (struct wlan_interface *)args->interfaces; + struct wlan_interface *cur, *next; + SIZE_T i = 0; + + LIST_FOR_EACH_ENTRY_SAFE(cur, next, &ifaces->entry, struct wlan_interface, entry) + { + args->info[i++] = cur->info; + list_remove( &cur->entry ); + free( cur ); + } + + free( ifaces ); + return STATUS_SUCCESS; +} + +NTSTATUS wlan_free_interfaces( void *params ) +{ + struct wlan_free_interfaces_params *args = params; + struct wlan_interface *ifaces = (struct wlan_interface *)args->interfaces; + struct wlan_interface *cur, *next; + + LIST_FOR_EACH_ENTRY_SAFE(cur, next, &ifaces->entry, struct wlan_interface, entry) + { + list_remove( &cur->entry ); + free( cur ); + } + + free( ifaces ); + return STATUS_SUCCESS; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { wlan_init, wlan_open_handle, - wlan_close_handle + wlan_close_handle, + + wlan_get_interfaces, + wlan_copy_and_free_interfaces, + + wlan_free_interfaces, };
C_ASSERT( ARRAYSIZE( __wine_unix_call_funcs ) == unix_funcs_count ); diff --git a/dlls/wlanapi/unixlib.h b/dlls/wlanapi/unixlib.h index 9bf2149e7c3..0f9f41ffb3d 100644 --- a/dlls/wlanapi/unixlib.h +++ b/dlls/wlanapi/unixlib.h @@ -33,6 +33,33 @@ struct wlan_close_handle_params UINT_PTR handle; };
+struct wlan_get_interfaces_params +{ + UINT_PTR handle; + + UINT_PTR interfaces; + SIZE_T len; +}; + +struct unix_wlan_interface_info +{ + GUID guid; + CHAR description[256]; + WLAN_INTERFACE_STATE state; +}; + +struct wlan_copy_and_free_interfaces_params +{ + UINT_PTR interfaces; + + struct unix_wlan_interface_info *info; +}; + +struct wlan_free_interfaces_params +{ + UINT_PTR interfaces; +}; + enum wlanpi_funcs { unix_wlan_init, @@ -40,6 +67,10 @@ enum wlanpi_funcs unix_wlan_open_handle, unix_wlan_close_handle,
+ unix_wlan_get_interfaces, + unix_wlan_copy_and_free_interfaces, + unix_wlan_free_interfaces, + unix_funcs_count };
diff --git a/dlls/wlanapi/unixlib_priv.h b/dlls/wlanapi/unixlib_priv.h index fa813d07844..9b6982f0e46 100644 --- a/dlls/wlanapi/unixlib_priv.h +++ b/dlls/wlanapi/unixlib_priv.h @@ -21,8 +21,15 @@ #ifndef __WINE_WLANAPI_UNIXLIB_PRIV_H #define __WINE_WLANAPI_UNIXLIB_PRIV_H
+struct wlan_interface +{ + struct list entry; + struct unix_wlan_interface_info info; +}; + extern BOOL load_dbus_functions( void ); extern NTSTATUS init_dbus_connection( UINT_PTR *handle ); extern void close_dbus_connection( void *c ); +extern NTSTATUS networkmanager_get_wifi_devices( void *connection, struct list *devices );
#endif /* __WINE_WLANAPI_UNIXLIB_PRIV_H */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/dbus.c | 464 +++++++++++++++++++++++++++++++++++- dlls/wlanapi/main.c | 42 +++- dlls/wlanapi/unixlib.c | 64 ++++- dlls/wlanapi/unixlib.h | 25 ++ dlls/wlanapi/unixlib_priv.h | 31 ++- include/windot11.h | 2 + include/wlanapi.h | 7 + 7 files changed, 627 insertions(+), 8 deletions(-)
diff --git a/dlls/wlanapi/dbus.c b/dlls/wlanapi/dbus.c index dca8156afe5..f0e3ea124e2 100644 --- a/dlls/wlanapi/dbus.c +++ b/dlls/wlanapi/dbus.c @@ -55,6 +55,9 @@ DBUS_FUNCS;
#define NETWORKMANAGER_INTERFACE_MANAGER "org.freedesktop.NetworkManager" #define NETWORKMANAGER_INTERFACE_DEVICE "org.freedesktop.NetworkManager.Device" +#define NETWORKMANAGER_INTERFACE_DEVICE_WIRELESS "org.freedesktop.NetworkManager.Device.Wireless" +#define NETWORKMANAGER_INTERFACE_ACCESS_POINT "org.freedesktop.NetworkManager.AccessPoint" +#define NETWORKMANAGER_INTERFACE_CONNECTION_ACTIVE "org.freedesktop.NetworkManager.Connection.Active"
BOOL load_dbus_functions( void ) { @@ -183,15 +186,46 @@ static BOOL networkmanager_device_is_wifi( void *connection, const char *object_ index. We use index as the last 4 bytes of this GUID to create a Win32 WLAN interface GUID. */ const static GUID NETWORKMANAGER_DEVICE_BASE_INTERFACE_GUID = { 0xa53634f7, 0xc1bc, 0x4d41, { 0xbc, 0x06, 0xd3, 0xf7, 0x00, 0x00, 0x00, 0x00 } }; +#define NETWORKMANAGER_DEVICE_PATH_PREFIX "/org/freedesktop/NetworkManager/Devices/" + +static BOOL networkmanager_valid_device_guid( const GUID *guid ) +{ + return !memcmp( &NETWORKMANAGER_DEVICE_BASE_INTERFACE_GUID, guid, offsetof( GUID, Data4[4] ) ); +} + +static __WINE_MALLOC char *networkmanager_device_guid_to_path( const GUID *guid ) +{ + char *path; + UINT32 idx = *(UINT32 *)&guid->Data4[4]; + size_t orig_size = sizeof( NETWORKMANAGER_DEVICE_PATH_PREFIX ) + 3; + size_t size; + + path = malloc( orig_size ); + if (!path) return NULL; + + size = snprintf( path, orig_size, NETWORKMANAGER_DEVICE_PATH_PREFIX "%u", idx ); + if (size >= orig_size) + { + char *ptr = realloc( path, size ); + if (!ptr) + { + free( path ); + return NULL; + } + path = ptr; + snprintf( path, size, NETWORKMANAGER_DEVICE_PATH_PREFIX "%u", idx ); + } + + return path; +}
static BOOL networkmanager_device_path_to_guid( const char *object_path, GUID *guid ) { - const static char device_prefix[] = "/org/freedesktop/NetworkManager/Devices/"; - BOOL is_device = strncmp( object_path, device_prefix, sizeof( device_prefix ) ); + BOOL is_device = strncmp( object_path, NETWORKMANAGER_DEVICE_PATH_PREFIX, sizeof( NETWORKMANAGER_DEVICE_PATH_PREFIX ) ); UINT32 idx;
if (!is_device) return FALSE; - idx = atoi( object_path + sizeof(device_prefix) - 1 ); + idx = atoi( object_path + sizeof( NETWORKMANAGER_DEVICE_PATH_PREFIX ) - 1 ); if (!idx) /* NetworkManager doesn't seem to use 0 as an index for devices. */ { ERR( "Could not parse index from device path %s:\n", debugstr_a( object_path )); @@ -384,8 +418,432 @@ NTSTATUS networkmanager_get_wifi_devices( void *connection, struct list *devices return STATUS_SUCCESS; }
+static void parse_mac_address( const char *addr_str, BYTE dest[6] ) +{ + int addr[6], i; + + sscanf( addr_str, "%x:%x:%x:%x:%x:%x", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], + &addr[5] ); + for (i = 0 ; i < 6; i++) + dest[i] = addr[i]; +} + +static BOOL networkmanager_get_access_point_info( void *connection, const char *object_path, + struct wlan_bss_info *network ) +{ + DBusMessage *request, *reply; + DBusMessageIter dict, prop_iter, variant; + DBusError error; + dbus_bool_t success; + const char *prop_name; + const char *iface_accesspoint = NETWORKMANAGER_INTERFACE_ACCESS_POINT; + + TRACE( "(%p, %s, %p)\n", connection, debugstr_a( object_path ), network ); + request = p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, object_path, + DBUS_INTERFACE_PROPERTIES, "GetAll" ); + if (!request) return FALSE; + success = p_dbus_message_append_args( request, DBUS_TYPE_STRING, &iface_accesspoint, + DBUS_TYPE_INVALID ); + if (!success) + { + p_dbus_message_unref( request ); + return FALSE; + } + + p_dbus_error_init( &error ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + ERR( "Could not get proerties for access point %s: %s: %s.\n", debugstr_a( object_path ), + debugstr_a( error.name ), debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + return FALSE; + } + + + p_dbus_error_free( &error ); + p_dbus_message_iter_init( reply, &dict ); + p_dbus_message_iter_recurse( &dict, &prop_iter ); + while ((prop_name = dbus_next_dict_entry( &prop_iter, &variant ))) + { + if (!strcmp( prop_name, "Flags" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + p_dbus_message_iter_get_basic( &variant, &network->flags ); + } + else if (!strcmp( prop_name, "WpaFlags" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + p_dbus_message_iter_get_basic( &variant, &network->wpa_flags ); + } + else if (!strcmp( prop_name, "RsnFlags" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + p_dbus_message_iter_get_basic( &variant, &network->rsn_flags ); + } + else if (!strcmp( prop_name, "Ssid" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY && + p_dbus_message_iter_get_element_type( &variant ) == DBUS_TYPE_BYTE) + { + DBusMessageIter iter; + const char *ssid; + int len; + + p_dbus_message_iter_recurse( &variant, &iter ); + p_dbus_message_iter_get_fixed_array( &iter, &ssid, &len ); + if (len > sizeof( network->ssid )) + WARN( "SSID %s for %s is too long\n", debugstr_a( object_path ), + debugstr_an( ssid, len ) ); + + memcpy( network->ssid, ssid, min( len, sizeof( network->ssid ) ) ); + network->ssid_len = min( len, sizeof( network->ssid ) ); + } + else if (!strcmp( prop_name, "Frequency" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + p_dbus_message_iter_get_basic( &variant, &network->frequency ); + } + else if (!strcmp( prop_name, "HwAddress") && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_STRING) + { + const char *addr_str; + + p_dbus_message_iter_get_basic( &variant, &addr_str ); + if (strlen( addr_str ) != 17) + ERR( "Unexpected HwAddress %s for %s\n", debugstr_a( addr_str ), + debugstr_a( object_path ) ); + + parse_mac_address( addr_str, network->hw_address ); + } + else if (!strcmp( prop_name, "Mode" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + p_dbus_message_iter_get_basic( &variant, &network->mode ); + } + else if (!strcmp( prop_name, "MaxBitrate") && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + p_dbus_message_iter_get_basic( &variant, &network->max_bitrate ); + } + else if (!strcmp( prop_name, "Bandwidth" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_UINT32) + { + p_dbus_message_iter_get_basic( &variant, &network->bandwidth ); + } + else if (!strcmp( prop_name, "Strength" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_BYTE) + { + p_dbus_message_iter_get_basic( &variant, &network->strength ); + } + else if (!strcmp( prop_name, "LastSeen") && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_INT32) + { + p_dbus_message_iter_get_basic( &variant, &network->last_seen ); + } + + } + + p_dbus_message_unref( reply ); + return TRUE; +} + +static char *__WINE_MALLOC networkmanager_device_get_active_ap( void *connection, + const char *device_path ) +{ + DBusMessage *request, *reply; + DBusMessageIter iter, variant; + DBusError error; + const char *str; + char *dup; + const char *device_iface = NETWORKMANAGER_INTERFACE_DEVICE, + *conn_active_iface = NETWORKMANAGER_INTERFACE_CONNECTION_ACTIVE; + const char *activeconn_prop = "ActiveConnection", *specobj_prop = "SpecificObject"; + dbus_bool_t success; + + request = p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, device_path, + DBUS_INTERFACE_PROPERTIES, + "Get" ); + if (!request) return NULL; + success = p_dbus_message_append_args( request, DBUS_TYPE_STRING, &device_iface, + DBUS_TYPE_STRING, &activeconn_prop, DBUS_TYPE_INVALID ); + if (!success) + { + p_dbus_message_unref( request ); + return NULL; + } + + p_dbus_error_init( &error ); + reply = p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + p_dbus_error_free( &error ); + return NULL; + } + p_dbus_error_free( &error ); + + p_dbus_message_iter_init( reply, &iter ); + p_dbus_message_iter_recurse( &iter, &variant ); + if (p_dbus_message_iter_get_arg_type( &variant ) != DBUS_TYPE_OBJECT_PATH) + { + ERR( "Unexpected signature for property ActiveConnection: %c\n", + p_dbus_message_iter_get_arg_type( &variant ) ); + return NULL; + } + p_dbus_message_iter_get_basic( &variant, &str ); + + request = p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, str, + DBUS_INTERFACE_PROPERTIES, "Get" ); + p_dbus_message_unref( reply ); + + if (!request) return NULL; + success = p_dbus_message_append_args( request, DBUS_TYPE_STRING, &conn_active_iface, + DBUS_TYPE_STRING, &specobj_prop, DBUS_TYPE_INVALID ); + if (!success) + { + p_dbus_message_unref( request ); + return NULL; + } + + p_dbus_error_init( &error ); + reply = p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + ERR( "Could not get properties for %s: %s: %s.\n", debugstr_a( device_path ), error.name, + error.message ); + p_dbus_error_free( &error ); + return NULL; + } + p_dbus_error_free( &error ); + p_dbus_message_iter_init( reply, &iter ); + p_dbus_message_iter_recurse( &iter, &variant ); + if ( p_dbus_message_iter_get_arg_type( &variant ) != DBUS_TYPE_OBJECT_PATH ) + { + ERR( "Unexpected signature for property SpecificObject: %c\n", + p_dbus_message_iter_get_arg_type( &variant ) ); + return NULL; + } + + p_dbus_message_iter_get_basic( &variant, &str ); + dup = strdup( str ); + p_dbus_message_unref( reply ); + + return dup; +} + +NTSTATUS networkmanager_get_access_points( void *connection, const GUID *device, struct list *access_points ) +{ + DBusMessage *request, *reply; + DBusError error; + dbus_bool_t success; + char *device_path, *active_ap = NULL; + char **object_paths; + int n_objects, i; + + TRACE( "(%p, %s, %p)\n", connection, debugstr_guid( device ), access_points ); + + if (!networkmanager_valid_device_guid( device )) return STATUS_INVALID_PARAMETER; + device_path = networkmanager_device_guid_to_path( device ); + if (!device_path) return STATUS_NO_MEMORY; + + request = p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, device_path, + NETWORKMANAGER_INTERFACE_DEVICE_WIRELESS, + "GetAllAccessPoints" ); + active_ap = networkmanager_device_get_active_ap( connection, device_path ); + + free( device_path ); + if (!request) + { + free( active_ap ); + return STATUS_NO_MEMORY; + } + + p_dbus_error_init( &error ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + NTSTATUS ret = dbus_error_to_ntstatus( &error ); + ERR( "Could not get list of access points: %s: %s.\n", debugstr_a( error.name ), + debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + free( active_ap ); + return ret; + } + + p_dbus_error_free( &error ); + p_dbus_error_init( &error ); + success = p_dbus_message_get_args( reply, &error, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, + &object_paths, &n_objects, DBUS_TYPE_INVALID ); + if (!success) + { + NTSTATUS ret = dbus_error_to_ntstatus( &error ); + ERR( "Could not read object paths from GetDevices reply: %s: %s.\n", + debugstr_a( error.name ), debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); + free( active_ap ); + return ret; + } + + p_dbus_error_free( &error ); + for (i = 0; i < n_objects; i++) + { + const char *object_path = object_paths[i]; + struct wlan_bss_info info = {0}; + + if (networkmanager_get_access_point_info( connection, object_path, &info )) + { + struct wlan_network *network = calloc( 1, sizeof( *network ) ); + + if (!network) continue; + network->info = info; + network->info.connected = active_ap && !strcmp( active_ap, object_path ); + list_add_tail( access_points, &network->entry ); + } + } + + free( active_ap ); + p_dbus_free_string_array( object_paths ); + p_dbus_message_unref( reply ); + return STATUS_SUCCESS; +} + #else /* SONAME_LIBDBUS_1 */ BOOL load_dbus_functions( void ) { return FALSE; } NTSTATUS init_dbus_connection( UINT_PTR *handle ) { return STATUS_NOT_SUPPORTED; } void close_dbus_connection( void *c ) { return STATUS_NOT_SUPPORTED; } +NTSTATUS networkmanager_get_wifi_devices( void *connection, struct list *devices ) +{ + return STATUS_NOT_SUPPORTED; +} +NTSTATUS networkmanager_get_access_points( void *connection, GUID device, + struct list *access_points ) +{ + return STATUS_NOT_SUPPORTED; +} #endif + +#define NM_802_11_MODE_UNKNOWN 0 +#define NM_802_11_MODE_ADHOC 1 +#define NM_802_11_MODE_INFRA 2 +#define NM_802_11_MODE_AP 3 +#define NM_802_11_MODE_MESH 4 + +#define NM_802_11_AP_FLAGS_NONE 0x00000000 +#define NM_802_11_AP_FLAGS_PRIVACY 0x00000001 +#define NM_802_11_AP_FLAGS_WPS 0x00000002 +#define NM_802_11_AP_FLAGS_WPS_PBC 0x00000004 +#define NM_802_11_AP_FLAGS_WPS_PIN 0x00000008 + +#define NM_802_11_AP_SEC_NONE 0x00000000 +#define NM_802_11_AP_SEC_PAIR_WEP40 0x00000001 +#define NM_802_11_AP_SEC_PAIR_WEP104 0x00000002 +#define NM_802_11_AP_SEC_PAIR_TKIP 0x00000004 +#define NM_802_11_AP_SEC_PAIR_CCMP 0x00000008 +#define NM_802_11_AP_SEC_GROUP_WEP40 0x00000010 +#define NM_802_11_AP_SEC_GROUP_WEP104 0x00000020 +#define NM_802_11_AP_SEC_GROUP_TKIP 0x00000040 +#define NM_802_11_AP_SEC_GROUP_CCMP 0x00000080 +#define NM_802_11_AP_SEC_KEY_MGMT_PSK 0x00000100 +#define NM_802_11_AP_SEC_KEY_MGMT_802_1X 0x00000200 +#define NM_802_11_AP_SEC_KEY_MGMT_SAE 0x00000400 +#define NM_802_11_AP_SEC_KEY_MGMT_OWE 0x00000800 +#define NM_802_11_AP_SEC_KEY_MGMT_OWE_TM 0x00001000 +#define NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192 0x00002000 + +void wlan_bss_info_to_WLAN_AVAILABLE_NETWORK( const struct wlan_bss_info *info, + WLAN_AVAILABLE_NETWORK *dest ) +{ + memset( dest, 0, sizeof( *dest ) ); + + memcpy( dest->dot11Ssid.ucSSID, info->ssid, sizeof( info->ssid ) ); + dest->dot11Ssid.uSSIDLength = info->ssid_len; + dest->dot11BssType = info->mode == NM_802_11_MODE_INFRA ? dot11_BSS_type_infrastructure + : dot11_BSS_type_independent; + dest->uNumberOfBssids = 1; + dest->bNetworkConnectable = TRUE; + dest->uNumberOfPhyTypes = 1; + /* Use dot11_phy_type_any for now, as NetworkManager AccessPoints object do not have an equivalent + * property. */ + dest->dot11PhyTypes[0] = dot11_phy_type_any; + dest->bMorePhyTypes = FALSE; + dest->wlanSignalQuality = info->strength; + dest->bSecurityEnabled = !(info->flags & NM_802_11_AP_FLAGS_PRIVACY); + + if (info->rsn_flags) + { + if (info->rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + { + dest->dot11DefaultAuthAlgorithm = DOT11_AUTH_ALGO_RSNA; + if (info->rsn_flags & NM_802_11_AP_SEC_GROUP_TKIP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_TKIP; + else if (info->rsn_flags & NM_802_11_AP_SEC_PAIR_CCMP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_CCMP; + else if (info->rsn_flags & (NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP)) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_RSN_USE_GROUP; + } + if (info->rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192) + { + dest->dot11DefaultAuthAlgorithm = DOT11_AUTH_ALGO_WPA3_ENT_192; + if (info->rsn_flags & NM_802_11_AP_SEC_GROUP_TKIP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_TKIP; + else if (info->rsn_flags & NM_802_11_AP_SEC_PAIR_CCMP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_CCMP; + else if (info->rsn_flags & (NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP)) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_RSN_USE_GROUP; + } + if (info->rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) + { + dest->dot11DefaultAuthAlgorithm = DOT11_AUTH_ALGO_WPA3_SAE; + dest->dot11DefaultCipherAlgorithm = info->rsn_flags & NM_802_11_AP_SEC_PAIR_TKIP + ? DOT11_CIPHER_ALGO_TKIP + : DOT11_CIPHER_ALGO_CCMP; + } + if (info->rsn_flags & (NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) + { + dest->dot11DefaultAuthAlgorithm = DOT11_AUTH_ALGO_OWE; + dest->dot11DefaultCipherAlgorithm = info->rsn_flags & NM_802_11_AP_SEC_PAIR_TKIP + ? DOT11_CIPHER_ALGO_TKIP + : DOT11_CIPHER_ALGO_CCMP; + } + } + else if (info->wpa_flags) + { + if (info->wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + { + dest->dot11DefaultAuthAlgorithm = DOT11_AUTH_ALGO_WPA; + if (info->wpa_flags & NM_802_11_AP_SEC_GROUP_TKIP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_TKIP; + else if (info->wpa_flags & NM_802_11_AP_SEC_PAIR_CCMP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_CCMP; + else if (info->wpa_flags & (NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP)) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_WPA_USE_GROUP; + } + if (info->wpa_flags & (NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104)) + { + dest->dot11DefaultAuthAlgorithm = DOT11_AUTH_ALGO_80211_SHARED_KEY; + dest->dot11DefaultCipherAlgorithm = + info->wpa_flags & ( NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_GROUP_WEP40 ) + ? DOT11_CIPHER_ALGO_WEP40 + : DOT11_CIPHER_ALGO_WEP104; + } + if (info->wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + { + dest->dot11DefaultAuthAlgorithm = DOT11_AUTH_ALGO_WPA_PSK; + if (info->wpa_flags & NM_802_11_AP_SEC_GROUP_TKIP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_TKIP; + else if (info->wpa_flags & NM_802_11_AP_SEC_PAIR_CCMP) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_CCMP; + else if (info->wpa_flags & (NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP)) + dest->dot11DefaultCipherAlgorithm = DOT11_CIPHER_ALGO_WPA_USE_GROUP; + } + } + + if (info->connected) + dest->dwFlags |= WLAN_AVAILABLE_NETWORK_CONNECTED; +} diff --git a/dlls/wlanapi/main.c b/dlls/wlanapi/main.c index 8c47b7244d0..f27ce1fba80 100644 --- a/dlls/wlanapi/main.c +++ b/dlls/wlanapi/main.c @@ -243,10 +243,46 @@ DWORD WINAPI WlanRegisterNotification(HANDLE handle, DWORD notify_source, BOOL i DWORD WINAPI WlanGetAvailableNetworkList(HANDLE handle, const GUID *guid, DWORD flags, void *reserved, WLAN_AVAILABLE_NETWORK_LIST **network_list) { - FIXME("(%p, %s, 0x%lx, %p, %p) stub\n", - handle, wine_dbgstr_guid(guid), flags, reserved, network_list); + struct wine_wlan *wlan; + struct wlan_network_list_get_params params = {0}; + struct wlan_network_list_move_to_avail_network_params move_params = {0}; + WLAN_AVAILABLE_NETWORK_LIST *ret_list; + NTSTATUS status;
- return ERROR_CALL_NOT_IMPLEMENTED; + TRACE( "(%p, %s, 0x%lx, %p, %p)\n", handle, wine_dbgstr_guid( guid ), flags, reserved, + network_list ); + + if (!handle || !guid || reserved || !network_list) + return ERROR_INVALID_PARAMETER; + + wlan = handle_index( handle ); + if (!wlan) + return ERROR_INVALID_HANDLE; + + params.handle = wlan->unix_handle; + params.interface = guid; + status = UNIX_WLAN_CALL( wlan_network_list_get, ¶ms ); + if (status != STATUS_SUCCESS) + return RtlNtStatusToDosError( status ); + + ret_list = WlanAllocateMemory( offsetof( WLAN_AVAILABLE_NETWORK_LIST, Network[params.len] ) ); + if (!ret_list) + { + struct wlan_network_list_free_params free_params = {0}; + free_params.networks = params.networks; + UNIX_WLAN_CALL( wlan_network_list_free, &free_params ); + return ERROR_NOT_ENOUGH_MEMORY; + } + + move_params.networks = params.networks; + move_params.dest = ret_list->Network; + UNIX_WLAN_CALL( wlan_network_list_move_to_avail_network, &move_params ); + + ret_list->dwNumberOfItems = params.len; + ret_list->dwIndex = 0; + *network_list = ret_list; + + return ERROR_SUCCESS; }
DWORD WINAPI WlanQueryInterface(HANDLE handle, const GUID *guid, WLAN_INTF_OPCODE opcode, diff --git a/dlls/wlanapi/unixlib.c b/dlls/wlanapi/unixlib.c index 8888f620ed0..3b64c55730c 100644 --- a/dlls/wlanapi/unixlib.c +++ b/dlls/wlanapi/unixlib.c @@ -125,6 +125,65 @@ NTSTATUS wlan_free_interfaces( void *params ) return STATUS_SUCCESS; }
+NTSTATUS wlan_network_list_get( void *params ) +{ + NTSTATUS status; + struct wlan_network_list_get_params *args = params; + struct list *networks; + + if (!initialized) + return STATUS_NOT_SUPPORTED; + + networks = malloc( sizeof( *networks )); + if (!networks) return STATUS_NO_MEMORY; + + list_init( networks ); + status = networkmanager_get_access_points( (void *)args->handle, args->interface, networks ); + if (status != STATUS_SUCCESS) + { + free( networks ); + return status; + } + + args->networks = (UINT_PTR)networks; + args->len = list_count( networks ); + return STATUS_SUCCESS; +} + +NTSTATUS wlan_network_list_move_to_avail_network( void *params ) +{ + struct wlan_network_list_move_to_avail_network_params *args = params; + struct wlan_network *networks = (struct wlan_network *)args->networks; + struct wlan_network *cur, *next; + SIZE_T i = 0; + + LIST_FOR_EACH_ENTRY_SAFE( cur, next, &networks->entry, struct wlan_network, entry) + { + wlan_bss_info_to_WLAN_AVAILABLE_NETWORK( &cur->info, &args->dest[i++] ); + list_remove( &cur->entry ); + free( cur ); + } + + free( networks ); + return STATUS_SUCCESS; +} + +NTSTATUS wlan_network_list_free( void *params ) +{ + struct wlan_network_list_free_params *args = params; + struct wlan_network *networks = (struct wlan_network *)args->networks; + struct wlan_network *cur, *next; + + LIST_FOR_EACH_ENTRY_SAFE(cur, next, &networks->entry, struct wlan_network, entry) + { + list_remove( &cur->entry ); + free( cur ); + } + + free( networks ); + return STATUS_SUCCESS; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { wlan_init, wlan_open_handle, @@ -132,8 +191,11 @@ const unixlib_entry_t __wine_unix_call_funcs[] = {
wlan_get_interfaces, wlan_copy_and_free_interfaces, - wlan_free_interfaces, + + wlan_network_list_get, + wlan_network_list_move_to_avail_network, + wlan_network_list_free, };
C_ASSERT( ARRAYSIZE( __wine_unix_call_funcs ) == unix_funcs_count ); diff --git a/dlls/wlanapi/unixlib.h b/dlls/wlanapi/unixlib.h index 0f9f41ffb3d..06c961c5e36 100644 --- a/dlls/wlanapi/unixlib.h +++ b/dlls/wlanapi/unixlib.h @@ -60,6 +60,27 @@ struct wlan_free_interfaces_params UINT_PTR interfaces; };
+struct wlan_network_list_get_params +{ + UINT_PTR handle; + const GUID *interface; + + UINT_PTR networks; + SIZE_T len; +}; + +struct wlan_network_list_move_to_avail_network_params +{ + UINT_PTR networks; + + WLAN_AVAILABLE_NETWORK *dest; +}; + +struct wlan_network_list_free_params +{ + UINT_PTR networks; +}; + enum wlanpi_funcs { unix_wlan_init, @@ -71,6 +92,10 @@ enum wlanpi_funcs unix_wlan_copy_and_free_interfaces, unix_wlan_free_interfaces,
+ unix_wlan_network_list_get, + unix_wlan_network_list_move_to_avail_network, + unix_wlan_network_list_free, + unix_funcs_count };
diff --git a/dlls/wlanapi/unixlib_priv.h b/dlls/wlanapi/unixlib_priv.h index 9b6982f0e46..3868218250f 100644 --- a/dlls/wlanapi/unixlib_priv.h +++ b/dlls/wlanapi/unixlib_priv.h @@ -21,15 +21,44 @@ #ifndef __WINE_WLANAPI_UNIXLIB_PRIV_H #define __WINE_WLANAPI_UNIXLIB_PRIV_H
+struct wlan_bss_info +{ + UINT32 flags; + UINT32 wpa_flags; + UINT32 rsn_flags; + + USHORT ssid_len; + BYTE ssid[32]; + + UINT32 frequency; + BYTE hw_address[6]; + UINT32 mode; + UINT32 max_bitrate; + UINT32 bandwidth; + UINT8 strength; + INT32 last_seen; + + BOOL connected; +}; + struct wlan_interface { struct list entry; struct unix_wlan_interface_info info; };
+struct wlan_network +{ + struct list entry; + struct wlan_bss_info info; +}; + extern BOOL load_dbus_functions( void ); extern NTSTATUS init_dbus_connection( UINT_PTR *handle ); extern void close_dbus_connection( void *c ); extern NTSTATUS networkmanager_get_wifi_devices( void *connection, struct list *devices ); - +extern NTSTATUS networkmanager_get_access_points( void *connection, const GUID *device, + struct list *access_points ); +extern void wlan_bss_info_to_WLAN_AVAILABLE_NETWORK( const struct wlan_bss_info *info, + WLAN_AVAILABLE_NETWORK *dest ); #endif /* __WINE_WLANAPI_UNIXLIB_PRIV_H */ diff --git a/include/windot11.h b/include/windot11.h index 39effeb93ec..36b962be804 100644 --- a/include/windot11.h +++ b/include/windot11.h @@ -38,4 +38,6 @@ typedef enum _DOT11_PHY_TYPE typedef UCHAR DOT11_MAC_ADDRESS[6]; typedef DOT11_MAC_ADDRESS *PDOT11_MAC_ADDRESS;
+#define DOT11_RATE_SET_MAX_LENGTH 126 + #endif /* _WINDOT11_H */ diff --git a/include/wlanapi.h b/include/wlanapi.h index 5150ff09f47..0db5c5e8899 100644 --- a/include/wlanapi.h +++ b/include/wlanapi.h @@ -89,6 +89,11 @@ typedef enum _DOT11_AUTH_ALGORITHM DOT11_AUTH_ALGO_WPA_NONE = 0x05, DOT11_AUTH_ALGO_RSNA = 0x06, DOT11_AUTH_ALGO_RSNA_PSK = 0x07, + DOT11_AUTH_ALGO_WPA3 = 8, + DOT11_AUTH_ALGO_WPA3_ENT_192 = 8, + DOT11_AUTH_ALGO_WPA3_SAE = 9, + DOT11_AUTH_ALGO_OWE = 10, + DOT11_AUTH_ALGO_WPA3_ENT = 11, DOT11_AUTH_ALGO_IHV_START = 0x80000000, DOT11_AUTH_ALGO_IHV_END = 0xFFFFFFFF } DOT11_AUTH_ALGORITHM, *PDOT11_AUTH_ALGORITHM; @@ -109,6 +114,8 @@ typedef enum _DOT11_CIPHER_ALGORITHM
#define WLAN_MAX_PHY_TYPE_NUMBER 8
+#define WLAN_AVAILABLE_NETWORK_CONNECTED 0x1 + typedef struct _WLAN_AVAILABLE_NETWORK { WCHAR strProfileName[256];
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/tests/wlanapi.c | 82 ++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)
diff --git a/dlls/wlanapi/tests/wlanapi.c b/dlls/wlanapi/tests/wlanapi.c index 5c26e6d8ba0..647a0a8ea10 100644 --- a/dlls/wlanapi/tests/wlanapi.c +++ b/dlls/wlanapi/tests/wlanapi.c @@ -182,6 +182,87 @@ static void test_WlanEnumInterfaces(void) ok(ret == 0, "Expected 0, got %ld\n", ret); }
+static void test_WlanGetAvailableNetworkList( void ) +{ + HANDLE handle; + DWORD neg_version, i, ret, reserved = 0xdeadbeef; + WLAN_INTERFACE_INFO_LIST *ifaces; + + ret = WlanOpenHandle(1, NULL, &neg_version, &handle); + ok(ret == 0, "Expected 0, got %ld\n", ret); + + ret = WlanEnumInterfaces( handle, NULL, &ifaces ); + ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret); + if (!ifaces || !ifaces->dwNumberOfItems) + { + skip( "No wireless interfaces\n" ); + WlanCloseHandle( handle, NULL ); + WlanFreeMemory( ifaces ); + return; + } + + trace("Wireless interfaces: %ld\n", ifaces->dwNumberOfItems); + for (i = 0; i < ifaces->dwNumberOfItems;i ++) + { + WLAN_INTERFACE_INFO *info; + WLAN_AVAILABLE_NETWORK_LIST *bad_list = (WLAN_AVAILABLE_NETWORK_LIST *)0xdeadbeef, + *list = bad_list; + DWORD j; + + info = &ifaces->InterfaceInfo[i]; + trace( " Index[%ld] GUID: %s\n", i, debugstr_guid( &info->InterfaceGuid ) ); + + /* invalid parameters */ + ret = WlanGetAvailableNetworkList( NULL, NULL, 0, NULL, &list ); + ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); + ok( list == bad_list, "list changed\n" ); + ret = WlanGetAvailableNetworkList( handle, &info->InterfaceGuid, 0, &reserved, &list ); + ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); + ok( list == bad_list, "list changed\n" ); + ret = WlanGetAvailableNetworkList( handle, NULL, 0, NULL, &list ); + ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); + ok( list == bad_list, "list changed\n" ); + + /* valid parameters */ + ret = WlanGetAvailableNetworkList( handle, &info->InterfaceGuid, 0, NULL, &list ); + ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret); + if (!list || !list->dwNumberOfItems) + { + skip( "No wireless networks\n" ); + WlanFreeMemory( list ); + continue; + } + + for (j = 0; j < list->dwNumberOfItems; j++) + { + WLAN_AVAILABLE_NETWORK *network = &list->Network[j]; + + ok( network->dot11Ssid.uSSIDLength <= sizeof( network->dot11Ssid.ucSSID ), + "Unexpected length for uSSID, should be <= 32: %ld\n", + network->dot11Ssid.uSSIDLength ); + + trace( + " Index[%ld] SSID: %s\n", j, + debugstr_an( (char *)network->dot11Ssid.ucSSID, network->dot11Ssid.uSSIDLength ) ); + if (network->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) + { + trace(" connected\n"); + } + else + { + trace(" not connected\n"); + } + trace( " Signal Quality: %ld\n", network->wlanSignalQuality ); + } + + WlanFreeMemory( list ); + } + + WlanFreeMemory( ifaces ); + ret = WlanCloseHandle( handle, NULL ); + ok( ret == 0, "Expected 0, got %ld\n", ret ); +} + START_TEST(wlanapi) { HANDLE handle; @@ -198,4 +279,5 @@ START_TEST(wlanapi) test_WlanOpenHandle(); test_WlanAllocateFreeMemory(); test_WlanEnumInterfaces(); + test_WlanGetAvailableNetworkList(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/dbus.c | 29 +++++++++++++++-- dlls/wlanapi/main.c | 64 +++++++++++++++++++++++++++++++++++++ dlls/wlanapi/unixlib.c | 22 ++++++++++++- dlls/wlanapi/unixlib.h | 10 ++++++ dlls/wlanapi/unixlib_priv.h | 7 ++-- dlls/wlanapi/wlanapi.spec | 2 +- include/wlanapi.h | 34 ++++++++++++++++++++ 7 files changed, 162 insertions(+), 6 deletions(-)
diff --git a/dlls/wlanapi/dbus.c b/dlls/wlanapi/dbus.c index f0e3ea124e2..a9b13295d54 100644 --- a/dlls/wlanapi/dbus.c +++ b/dlls/wlanapi/dbus.c @@ -634,7 +634,9 @@ static char *__WINE_MALLOC networkmanager_device_get_active_ap( void *connection return dup; }
-NTSTATUS networkmanager_get_access_points( void *connection, const GUID *device, struct list *access_points ) +NTSTATUS networkmanager_get_access_points( void *connection, const GUID *device, + const DOT11_SSID *ssid, BOOL security, + struct list *access_points ) { DBusMessage *request, *reply; DBusError error; @@ -698,8 +700,15 @@ NTSTATUS networkmanager_get_access_points( void *connection, const GUID *device,
if (networkmanager_get_access_point_info( connection, object_path, &info )) { - struct wlan_network *network = calloc( 1, sizeof( *network ) ); + struct wlan_network *network; + + if (ssid && !(info.ssid_len == ssid->uSSIDLength && + !memcmp( info.ssid, ssid->ucSSID, sizeof( info.ssid ) ))) + continue; + if (security && !(info.flags & 1)) /* NM_802_11_AP_FLAGS_PRIVACY */ + continue;
+ network = calloc( 1, sizeof( *network ) ); if (!network) continue; network->info = info; network->info.connected = active_ap && !strcmp( active_ap, object_path ); @@ -847,3 +856,19 @@ void wlan_bss_info_to_WLAN_AVAILABLE_NETWORK( const struct wlan_bss_info *info, if (info->connected) dest->dwFlags |= WLAN_AVAILABLE_NETWORK_CONNECTED; } + +void wlan_bss_info_to_WLAN_BSS_ENTRY( const struct wlan_bss_info *info, WLAN_BSS_ENTRY *dest ) +{ + memset( dest, 0, sizeof( *dest )); + + FIXME( "(%p, %p) semi-stub\n", info, dest ); + memcpy( dest->dot11Ssid.ucSSID, info->ssid, sizeof( info->ssid ) ); + dest->dot11Ssid.uSSIDLength = info->ssid_len; + + memcpy( dest->dot11Bssid, info->hw_address, sizeof( info->hw_address ) ); + dest->dot11BssType = info->mode == NM_802_11_MODE_INFRA ? dot11_BSS_type_infrastructure + : dot11_BSS_type_independent; + dest->uLinkQuality = info->strength; + dest->bInRegDomain = TRUE; + dest->usBeaconPeriod = 1; +} diff --git a/dlls/wlanapi/main.c b/dlls/wlanapi/main.c index f27ce1fba80..e46646eddf9 100644 --- a/dlls/wlanapi/main.c +++ b/dlls/wlanapi/main.c @@ -285,6 +285,70 @@ DWORD WINAPI WlanGetAvailableNetworkList(HANDLE handle, const GUID *guid, DWORD return ERROR_SUCCESS; }
+DWORD WINAPI WlanGetNetworkBssList( HANDLE handle, const GUID *guid, const DOT11_SSID *ssid, + DOT11_BSS_TYPE bss_type, BOOL security, void *reserved, + WLAN_BSS_LIST **bss_list ) +{ + struct wine_wlan *wlan; + struct wlan_network_list_get_params params = {0}; + struct wlan_network_list_move_to_bss_entry_params move_params = {0}; + WLAN_BSS_LIST *ret_list; + NTSTATUS status; + DWORD size; + + TRACE( "(%p, %p, %p, %d, %d, %p, %p)\n", handle, guid, ssid, bss_type, security, reserved, + bss_list ); + + if (!handle || !guid || reserved || !bss_list) + return ERROR_INVALID_PARAMETER; + if (ssid) + { + if (ssid->uSSIDLength > sizeof(ssid->ucSSID)) + return ERROR_INVALID_PARAMETER; + switch (bss_type) + { + case dot11_BSS_type_infrastructure: + case dot11_BSS_type_independent: + case dot11_BSS_type_any: + break; + default: + return ERROR_INVALID_PARAMETER; + } + } + + wlan = handle_index( handle ); + if (!wlan) + return ERROR_INVALID_HANDLE; + + params.handle = wlan->unix_handle; + params.interface = guid; + params.ssid_filter = ssid; + params.security = ssid && security; + status = UNIX_WLAN_CALL( wlan_network_list_get, ¶ms ); + if (status != STATUS_SUCCESS) + return RtlNtStatusToDosError( status ); + + size = offsetof( WLAN_BSS_LIST, wlanBssEntries[params.len] ); + ret_list = WlanAllocateMemory( size ); + if (!ret_list) + { + struct wlan_network_list_free_params free_params = {0}; + free_params.networks = params.networks; + UNIX_WLAN_CALL( wlan_network_list_free, &free_params ); + return ERROR_NOT_ENOUGH_MEMORY; + } + + move_params.networks = params.networks; + move_params.dest = ret_list->wlanBssEntries; + UNIX_WLAN_CALL( wlan_network_list_move_to_bss_entry, &move_params ); + + ret_list->dwTotalSize = size; + ret_list->dwNumberOfItems = params.len; + *bss_list = ret_list; + + return ERROR_SUCCESS; +} + DWORD WINAPI WlanQueryInterface(HANDLE handle, const GUID *guid, WLAN_INTF_OPCODE opcode, void *reserved, DWORD *data_size, void **data, WLAN_OPCODE_VALUE_TYPE *opcode_type) { diff --git a/dlls/wlanapi/unixlib.c b/dlls/wlanapi/unixlib.c index 3b64c55730c..02f5d077100 100644 --- a/dlls/wlanapi/unixlib.c +++ b/dlls/wlanapi/unixlib.c @@ -138,7 +138,8 @@ NTSTATUS wlan_network_list_get( void *params ) if (!networks) return STATUS_NO_MEMORY;
list_init( networks ); - status = networkmanager_get_access_points( (void *)args->handle, args->interface, networks ); + status = networkmanager_get_access_points( (void *)args->handle, args->interface, + args->ssid_filter, args->security, networks ); if (status != STATUS_SUCCESS) { free( networks ); @@ -168,6 +169,24 @@ NTSTATUS wlan_network_list_move_to_avail_network( void *params ) return STATUS_SUCCESS; }
+NTSTATUS wlan_network_list_move_to_bss_entry( void *params ) +{ + struct wlan_network_list_move_to_bss_entry_params *args = params; + struct wlan_network *networks = (struct wlan_network *)args->networks; + struct wlan_network *cur, *next; + SIZE_T i = 0; + + LIST_FOR_EACH_ENTRY_SAFE( cur, next, &networks->entry, struct wlan_network, entry) + { + wlan_bss_info_to_WLAN_BSS_ENTRY( &cur->info, &args->dest[i++] ); + list_remove( &cur->entry ); + free( cur ); + } + + free( networks ); + return STATUS_SUCCESS; +} + NTSTATUS wlan_network_list_free( void *params ) { struct wlan_network_list_free_params *args = params; @@ -195,6 +214,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = {
wlan_network_list_get, wlan_network_list_move_to_avail_network, + wlan_network_list_move_to_bss_entry, wlan_network_list_free, };
diff --git a/dlls/wlanapi/unixlib.h b/dlls/wlanapi/unixlib.h index 06c961c5e36..2776c515e96 100644 --- a/dlls/wlanapi/unixlib.h +++ b/dlls/wlanapi/unixlib.h @@ -64,6 +64,8 @@ struct wlan_network_list_get_params { UINT_PTR handle; const GUID *interface; + const DOT11_SSID *ssid_filter; + BOOL security;
UINT_PTR networks; SIZE_T len; @@ -76,6 +78,13 @@ struct wlan_network_list_move_to_avail_network_params WLAN_AVAILABLE_NETWORK *dest; };
+struct wlan_network_list_move_to_bss_entry_params +{ + UINT_PTR networks; + + WLAN_BSS_ENTRY *dest; +}; + struct wlan_network_list_free_params { UINT_PTR networks; @@ -94,6 +103,7 @@ enum wlanpi_funcs
unix_wlan_network_list_get, unix_wlan_network_list_move_to_avail_network, + unix_wlan_network_list_move_to_bss_entry, unix_wlan_network_list_free,
unix_funcs_count diff --git a/dlls/wlanapi/unixlib_priv.h b/dlls/wlanapi/unixlib_priv.h index 3868218250f..89f0a034d97 100644 --- a/dlls/wlanapi/unixlib_priv.h +++ b/dlls/wlanapi/unixlib_priv.h @@ -58,7 +58,10 @@ extern NTSTATUS init_dbus_connection( UINT_PTR *handle ); extern void close_dbus_connection( void *c ); extern NTSTATUS networkmanager_get_wifi_devices( void *connection, struct list *devices ); extern NTSTATUS networkmanager_get_access_points( void *connection, const GUID *device, - struct list *access_points ); + const DOT11_SSID *ssid, BOOL security, + struct list *access_points ); extern void wlan_bss_info_to_WLAN_AVAILABLE_NETWORK( const struct wlan_bss_info *info, - WLAN_AVAILABLE_NETWORK *dest ); + WLAN_AVAILABLE_NETWORK *dest ); +extern void wlan_bss_info_to_WLAN_BSS_ENTRY( const struct wlan_bss_info *info, + WLAN_BSS_ENTRY *dest ); #endif /* __WINE_WLANAPI_UNIXLIB_PRIV_H */ diff --git a/dlls/wlanapi/wlanapi.spec b/dlls/wlanapi/wlanapi.spec index 45d83c80b0f..6b47812d017 100644 --- a/dlls/wlanapi/wlanapi.spec +++ b/dlls/wlanapi/wlanapi.spec @@ -9,7 +9,7 @@ @ stdcall WlanGetAvailableNetworkList(ptr ptr long ptr ptr) @ stub WlanGetFilterList @ stub WlanGetInterfaceCapability -@ stub WlanGetNetworkBssList +@ stdcall WlanGetNetworkBssList(ptr ptr ptr long long ptr ptr) @ stub WlanGetProfile @ stub WlanGetProfileCustomUserData @ stub WlanGetProfileList diff --git a/include/wlanapi.h b/include/wlanapi.h index 0db5c5e8899..a050752d541 100644 --- a/include/wlanapi.h +++ b/include/wlanapi.h @@ -135,6 +135,38 @@ typedef struct _WLAN_AVAILABLE_NETWORK DWORD dwReserved; } WLAN_AVAILABLE_NETWORK, *PWLAN_AVAILABLE_NETWORK;
+typedef struct _WLAN_RATE_SET { + ULONG uRateSetLength; + USHORT usRateSet[DOT11_RATE_SET_MAX_LENGTH]; +} WLAN_RATE_SET, *PWLAN_RATE_SET; + +typedef struct _WLAN_BSS_ENTRY +{ + DOT11_SSID dot11Ssid; + ULONG uPhyId; + DOT11_MAC_ADDRESS dot11Bssid; + DOT11_BSS_TYPE dot11BssType; + DOT11_PHY_TYPE dot11BssPhyType; + LONG lRssi; + ULONG uLinkQuality; + BOOLEAN bInRegDomain; + USHORT usBeaconPeriod; + ULONGLONG ullTimestamp; + ULONGLONG ullHostTimestamp; + USHORT usCapabilityInformation; + ULONG ulChCenterFrequency; + WLAN_RATE_SET wlanRateSet; + ULONG ulIeOffset; + ULONG ulIeSize; +} WLAN_BSS_ENTRY, *PWLAN_BSS_ENTRY; + +typedef struct _WLAN_BSS_LIST +{ + DWORD dwTotalSize; + DWORD dwNumberOfItems; + WLAN_BSS_ENTRY wlanBssEntries[1]; +} WLAN_BSS_LIST, *PWLAN_BSS_LIST; + typedef enum _WLAN_INTF_OPCODE { wlan_intf_opcode_autoconf_start = 0x000000000, @@ -260,5 +292,7 @@ DWORD WINAPI WlanScan(HANDLE, const GUID *, const DOT11_SSID *, const WLAN_RAW_D DWORD WINAPI WlanRegisterNotification(HANDLE, DWORD, BOOL, WLAN_NOTIFICATION_CALLBACK, void *, void *, DWORD *); DWORD WINAPI WlanGetAvailableNetworkList(HANDLE, const GUID *, DWORD, void *, WLAN_AVAILABLE_NETWORK_LIST **); DWORD WINAPI WlanQueryInterface(HANDLE, const GUID *, WLAN_INTF_OPCODE, void *, DWORD *, void **, WLAN_OPCODE_VALUE_TYPE *); +DWORD WINAPI WlanGetNetworkBssList( HANDLE, const GUID *, const DOT11_SSID *, DOT11_BSS_TYPE, BOOL, + void *, WLAN_BSS_LIST ** );
#endif /* _WLAN_WLANAPI_H */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/tests/wlanapi.c | 76 ++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
diff --git a/dlls/wlanapi/tests/wlanapi.c b/dlls/wlanapi/tests/wlanapi.c index 647a0a8ea10..a404848ef20 100644 --- a/dlls/wlanapi/tests/wlanapi.c +++ b/dlls/wlanapi/tests/wlanapi.c @@ -263,6 +263,81 @@ static void test_WlanGetAvailableNetworkList( void ) ok( ret == 0, "Expected 0, got %ld\n", ret ); }
+static void test_WlanGetNetworkBssList( void ) +{ + HANDLE handle; + DWORD neg_version, i, ret, reserved = 0xdeadbeef; + WLAN_INTERFACE_INFO_LIST *ifaces; + + ret = WlanOpenHandle(1, NULL, &neg_version, &handle); + ok(ret == 0, "Expected 0, got %ld\n", ret); + + ret = WlanEnumInterfaces( handle, NULL, &ifaces ); + ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret); + if (!ifaces || !ifaces->dwNumberOfItems) + { + skip( "No wireless interfaces\n" ); + WlanCloseHandle( handle, NULL ); + WlanFreeMemory( ifaces ); + return; + } + + trace("Wireless interfaces: %ld\n", ifaces->dwNumberOfItems); + + for (i = 0; i < ifaces->dwNumberOfItems; i++) + { + WLAN_INTERFACE_INFO *info; + WLAN_BSS_LIST *bad_list = (WLAN_BSS_LIST *)0xdeadbeef, *list = bad_list; + DWORD j; + + info = &ifaces->InterfaceInfo[i]; + trace( " Index[%ld] GUID: %s\n", i, debugstr_guid( &info->InterfaceGuid ) ); + + /* invalid parameters */ + ret = WlanGetNetworkBssList( NULL, NULL, NULL, 0, FALSE, NULL, NULL ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + ok( list == bad_list, "list changed\n" ); + ret = WlanGetNetworkBssList( handle, &info->InterfaceGuid, NULL, 0, FALSE, NULL, NULL ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + ok( list == bad_list, "list changed\n" ); + ret = WlanGetNetworkBssList( handle, &info->InterfaceGuid, NULL, 0, FALSE, NULL, NULL ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + ok( list == bad_list, "list changed\n" ); + ret = WlanGetNetworkBssList( handle, &info->InterfaceGuid, NULL, 0, FALSE, &reserved, &list ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + ok( list == bad_list, "list changed\n" ); + + /* valid paramters */ + ret = WlanGetNetworkBssList( handle, &info->InterfaceGuid, NULL, 0, FALSE, NULL, &list ); + ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret); + if (!list || !list->dwNumberOfItems) + { + skip( "No wireless networks\n" ); + WlanFreeMemory( list ); + continue; + } + + for (j = 0; j < list->dwNumberOfItems; j++) + { + WLAN_BSS_ENTRY *entry = &list->wlanBssEntries[j]; + + ok( entry->dot11Ssid.uSSIDLength <= sizeof( entry->dot11Ssid.ucSSID ), + "Unexpected length for uSSID, should be <= 32: %ld\n", + entry->dot11Ssid.uSSIDLength ); + + trace( + " Index[%ld] SSID: %s\n", j, + debugstr_an( (char *)entry->dot11Ssid.ucSSID, entry->dot11Ssid.uSSIDLength ) ); + } + + WlanFreeMemory( list ); + } + + WlanFreeMemory( ifaces ); + ret = WlanCloseHandle( handle, NULL ); + ok( ret == 0, "Expected 0, got %ld\n", ret ); +} + START_TEST(wlanapi) { HANDLE handle; @@ -280,4 +355,5 @@ START_TEST(wlanapi) test_WlanAllocateFreeMemory(); test_WlanEnumInterfaces(); test_WlanGetAvailableNetworkList(); + test_WlanGetNetworkBssList(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/dbus.c | 100 ++++++++++++++++++++++++++++++++++++ dlls/wlanapi/dbus.h | 2 + dlls/wlanapi/main.c | 25 +++++++-- dlls/wlanapi/unixlib.c | 9 ++++ dlls/wlanapi/unixlib.h | 9 ++++ dlls/wlanapi/unixlib_priv.h | 2 + 6 files changed, 144 insertions(+), 3 deletions(-)
diff --git a/dlls/wlanapi/dbus.c b/dlls/wlanapi/dbus.c index a9b13295d54..ee3d63c9fa0 100644 --- a/dlls/wlanapi/dbus.c +++ b/dlls/wlanapi/dbus.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "dbus/dbus-protocol.h" #if 0 #pragma makedep unix #endif @@ -26,6 +27,7 @@
#include <stdlib.h> #include <dlfcn.h> +#include <assert.h>
#ifdef SONAME_LIBDBUS_1 #include <dbus/dbus.h> @@ -722,6 +724,104 @@ NTSTATUS networkmanager_get_access_points( void *connection, const GUID *device, return STATUS_SUCCESS; }
+static BOOL networkmanager_requestscan_call_set_ssid( DBusMessageIter *dict, const DOT11_SSID *ssid ) +{ + DBusMessageIter entry, variant = DBUS_MESSAGE_ITER_INIT_CLOSED, + ssids = DBUS_MESSAGE_ITER_INIT_CLOSED, + ssid_bytes = DBUS_MESSAGE_ITER_INIT_CLOSED; + const char *ssids_key = "ssids"; + unsigned char ssid_copy[32]; + INT i; + dbus_bool_t success; + + memcpy( ssid_copy, ssid->ucSSID, sizeof( ssid->ucSSID ) ); + + success = p_dbus_message_iter_open_container( dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry ); + if (!success) return FALSE; + + success = p_dbus_message_iter_append_basic( &entry, DBUS_TYPE_STRING, &ssids_key ); + if (!success) goto failed; + success = p_dbus_message_iter_open_container( &entry, DBUS_TYPE_VARIANT, "aay", &variant ); + if (!success) goto failed; + + success = p_dbus_message_iter_open_container( &variant, DBUS_TYPE_ARRAY, "ay", &ssids ); + if (!success) goto failed; + success = p_dbus_message_iter_open_container( &ssids, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, + &ssid_bytes ); + if (!success) goto failed; + for (i = 0; i < ssid->uSSIDLength; i++) + { + success = p_dbus_message_iter_append_basic( &ssid_bytes, DBUS_TYPE_BYTE, &ssid_copy[i] ); + if (!success) goto failed; + } + + p_dbus_message_iter_close_container( &ssids, &ssid_bytes ); + p_dbus_message_iter_close_container( &variant, &ssids ); + p_dbus_message_iter_close_container( &entry, &variant ); + p_dbus_message_iter_close_container( dict, &entry ); + return TRUE; + + failed: + p_dbus_message_iter_abandon_container_if_open( &ssids, &ssid_bytes ); + p_dbus_message_iter_abandon_container_if_open( &variant, &ssids ); + p_dbus_message_iter_abandon_container_if_open( &entry, &variant ); + p_dbus_message_iter_abandon_container_if_open( dict, &entry ); + return FALSE; +} + +NTSTATUS networkmanager_start_scan( void *connection, const GUID *interface, + const DOT11_SSID *ssid ) +{ + DBusMessage *request, *reply; + DBusMessageIter iter, options; + DBusError error; + dbus_bool_t success; + char *device_path; + + TRACE( "(%p, %p, %p)\n", connection, debugstr_guid( interface ), ssid ); + + if (!networkmanager_valid_device_guid( interface )) return STATUS_INVALID_PARAMETER; + device_path = networkmanager_device_guid_to_path( interface ); + if (!device_path) return STATUS_NO_MEMORY; + + request = + p_dbus_message_new_method_call( NETWORKMANAGER_SERVICE, device_path, + NETWORKMANAGER_INTERFACE_DEVICE_WIRELESS, "RequestScan" ); + free( device_path ); + if (!request) return STATUS_NO_MEMORY; + + p_dbus_message_iter_init_append( request, &iter ); + success = p_dbus_message_iter_open_container( &iter, DBUS_TYPE_ARRAY, "{sv}", &options ); + if (!success) + { + p_dbus_message_unref( request ); + return STATUS_NO_MEMORY; + } + + if (ssid) + { + assert( ssid->uSSIDLength <= sizeof( ssid->ucSSID ) ); + networkmanager_requestscan_call_set_ssid( &options, ssid ); + } + p_dbus_message_iter_close_container( &iter, &options ); + + p_dbus_error_init( &error ); + reply = + p_dbus_connection_send_with_reply_and_block( connection, request, dbus_timeout, &error ); + p_dbus_message_unref( request ); + if (!reply) + { + NTSTATUS ret = dbus_error_to_ntstatus( &error ); + ERR( "Error calling RequestScan on interface %s: %s: %s.\n", debugstr_guid( interface ), + debugstr_a( error.name ), debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + return ret; + } + p_dbus_message_unref( reply ); + + return STATUS_SUCCESS; +} + #else /* SONAME_LIBDBUS_1 */ BOOL load_dbus_functions( void ) { return FALSE; } NTSTATUS init_dbus_connection( UINT_PTR *handle ) { return STATUS_NOT_SUPPORTED; } diff --git a/dlls/wlanapi/dbus.h b/dlls/wlanapi/dbus.h index 86c5309d117..a8c914222a6 100644 --- a/dlls/wlanapi/dbus.h +++ b/dlls/wlanapi/dbus.h @@ -78,7 +78,9 @@ DO_FUNC(dbus_message_is_error); \ DO_FUNC(dbus_message_is_method_call); \ DO_FUNC(dbus_message_is_signal); \ + DO_FUNC(dbus_message_iter_abandon_container_if_open); \ DO_FUNC(dbus_message_iter_append_basic); \ + DO_FUNC(dbus_message_iter_append_fixed_array); \ DO_FUNC(dbus_message_iter_close_container); \ DO_FUNC(dbus_message_iter_get_arg_type); \ DO_FUNC(dbus_message_iter_get_element_type); \ diff --git a/dlls/wlanapi/main.c b/dlls/wlanapi/main.c index e46646eddf9..de5eb229726 100644 --- a/dlls/wlanapi/main.c +++ b/dlls/wlanapi/main.c @@ -1,5 +1,6 @@ /* * Copyright 2010 Ričardas Barkauskas + * Copyright 2024 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -224,10 +225,28 @@ DWORD WINAPI WlanOpenHandle(DWORD client_version, void *reserved, DWORD *negotia DWORD WINAPI WlanScan(HANDLE handle, const GUID *guid, const DOT11_SSID *ssid, const WLAN_RAW_DATA *raw, void *reserved) { - FIXME("(%p, %s, %p, %p, %p) stub\n", - handle, wine_dbgstr_guid(guid), ssid, raw, reserved); + struct wine_wlan *wlan; + struct wlan_start_scan params = {0}; + NTSTATUS status;
- return ERROR_CALL_NOT_IMPLEMENTED; + TRACE( "(%p, %s, %p, %p, %p)\n", handle, wine_dbgstr_guid( guid ), ssid, raw, reserved ); + + if (!handle || !guid || reserved) + return ERROR_INVALID_PARAMETER; + + if (ssid && ssid->uSSIDLength > sizeof( ssid->ucSSID )) + return ERROR_INVALID_PARAMETER; + + wlan = handle_index( handle ); + if (!wlan) + return ERROR_INVALID_HANDLE; + + params.handle = wlan->unix_handle; + params.interface = guid; + params.ssid = ssid; + status = UNIX_WLAN_CALL( wlan_start_scan, ¶ms ); + + return RtlNtStatusToDosError( status ); }
DWORD WINAPI WlanRegisterNotification(HANDLE handle, DWORD notify_source, BOOL ignore_dup, diff --git a/dlls/wlanapi/unixlib.c b/dlls/wlanapi/unixlib.c index 02f5d077100..3b101263f3c 100644 --- a/dlls/wlanapi/unixlib.c +++ b/dlls/wlanapi/unixlib.c @@ -203,6 +203,13 @@ NTSTATUS wlan_network_list_free( void *params ) return STATUS_SUCCESS; }
+NTSTATUS wlan_start_scan( void *params ) +{ + struct wlan_start_scan *args = params; + + return networkmanager_start_scan( (void *) args->handle, args->interface, args->ssid ); +} + const unixlib_entry_t __wine_unix_call_funcs[] = { wlan_init, wlan_open_handle, @@ -216,6 +223,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { wlan_network_list_move_to_avail_network, wlan_network_list_move_to_bss_entry, wlan_network_list_free, + + wlan_start_scan, };
C_ASSERT( ARRAYSIZE( __wine_unix_call_funcs ) == unix_funcs_count ); diff --git a/dlls/wlanapi/unixlib.h b/dlls/wlanapi/unixlib.h index 2776c515e96..1a39149018b 100644 --- a/dlls/wlanapi/unixlib.h +++ b/dlls/wlanapi/unixlib.h @@ -90,6 +90,13 @@ struct wlan_network_list_free_params UINT_PTR networks; };
+struct wlan_start_scan +{ + UINT_PTR handle; + const GUID *interface; + const DOT11_SSID *ssid; +}; + enum wlanpi_funcs { unix_wlan_init, @@ -106,6 +113,8 @@ enum wlanpi_funcs unix_wlan_network_list_move_to_bss_entry, unix_wlan_network_list_free,
+ unix_wlan_start_scan, + unix_funcs_count };
diff --git a/dlls/wlanapi/unixlib_priv.h b/dlls/wlanapi/unixlib_priv.h index 89f0a034d97..da51fcdf66d 100644 --- a/dlls/wlanapi/unixlib_priv.h +++ b/dlls/wlanapi/unixlib_priv.h @@ -64,4 +64,6 @@ extern void wlan_bss_info_to_WLAN_AVAILABLE_NETWORK( const struct wlan_bss_info WLAN_AVAILABLE_NETWORK *dest ); extern void wlan_bss_info_to_WLAN_BSS_ENTRY( const struct wlan_bss_info *info, WLAN_BSS_ENTRY *dest ); +extern NTSTATUS networkmanager_start_scan( void *connection, const GUID *interface, + const DOT11_SSID *ssid ); #endif /* __WINE_WLANAPI_UNIXLIB_PRIV_H */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/tests/wlanapi.c | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/dlls/wlanapi/tests/wlanapi.c b/dlls/wlanapi/tests/wlanapi.c index a404848ef20..937af71ea75 100644 --- a/dlls/wlanapi/tests/wlanapi.c +++ b/dlls/wlanapi/tests/wlanapi.c @@ -338,6 +338,57 @@ static void test_WlanGetNetworkBssList( void ) ok( ret == 0, "Expected 0, got %ld\n", ret ); }
+static void test_WlanStartScan( void ) +{ + HANDLE handle; + DWORD neg_version, i, ret, reserved = 0xdeadbeef; + WLAN_INTERFACE_INFO_LIST *ifaces; + + ret = WlanOpenHandle(1, NULL, &neg_version, &handle); + ok(ret == 0, "Expected 0, got %ld\n", ret); + + ret = WlanEnumInterfaces( handle, NULL, &ifaces ); + ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret); + if (!ifaces || !ifaces->dwNumberOfItems) + { + skip( "No wireless interfaces\n" ); + WlanCloseHandle( handle, NULL ); + WlanFreeMemory( ifaces ); + return; + } + + trace("Wireless interfaces: %ld\n", ifaces->dwNumberOfItems); + for (i = 0; i < ifaces->dwNumberOfItems; i++) + { + WLAN_INTERFACE_INFO *info; + DOT11_SSID invalid_ssid = {.uSSIDLength = 60}, + ssid = {.uSSIDLength = 4, .ucSSID = {'t', 'e', 's', 't'}}; + + info = &ifaces->InterfaceInfo[i]; + trace( " Index[%ld] GUID: %s\n", i, debugstr_guid( &info->InterfaceGuid ) ); + + /* invalid parameters */ + ret = WlanScan( NULL, NULL, NULL, NULL, NULL ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + ret = WlanScan( handle, NULL, NULL, NULL, NULL ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + ret = WlanScan( handle, &info->InterfaceGuid, &invalid_ssid, NULL, NULL ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + ret = WlanScan ( handle, &info->InterfaceGuid, &ssid, NULL, &reserved ); + ok (ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret); + + /* valid parameters */ + ret = WlanScan( handle, &info->InterfaceGuid, NULL, NULL, NULL ); + ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret ); + ret = WlanScan( handle, &info->InterfaceGuid, &ssid, NULL, NULL ); + ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret ); + } + + WlanFreeMemory( ifaces ); + ret = WlanCloseHandle( handle, NULL ); + ok( ret == 0, "Expected 0, got %ld\n", ret ); +} + START_TEST(wlanapi) { HANDLE handle; @@ -354,6 +405,7 @@ START_TEST(wlanapi) test_WlanOpenHandle(); test_WlanAllocateFreeMemory(); test_WlanEnumInterfaces(); + test_WlanStartScan(); test_WlanGetAvailableNetworkList(); test_WlanGetNetworkBssList(); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=148442
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/wlanapi/dbus.c:18 error: patch failed: dlls/wlanapi/dbus.h:78 error: patch failed: dlls/wlanapi/main.c:1 error: patch failed: dlls/wlanapi/unixlib.c:203 error: patch failed: dlls/wlanapi/unixlib.h:90 error: patch failed: dlls/wlanapi/unixlib_priv.h:64 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/wlanapi/dbus.c:18 error: patch failed: dlls/wlanapi/dbus.h:78 error: patch failed: dlls/wlanapi/main.c:1 error: patch failed: dlls/wlanapi/unixlib.c:203 error: patch failed: dlls/wlanapi/unixlib.h:90 error: patch failed: dlls/wlanapi/unixlib_priv.h:64 Task: Patch failed to apply
=== debian11b (build log) ===
error: patch failed: dlls/wlanapi/dbus.c:18 error: patch failed: dlls/wlanapi/dbus.h:78 error: patch failed: dlls/wlanapi/main.c:1 error: patch failed: dlls/wlanapi/unixlib.c:203 error: patch failed: dlls/wlanapi/unixlib.h:90 error: patch failed: dlls/wlanapi/unixlib_priv.h:64 Task: Patch failed to apply