From: Vibhav Pant vibhavp@gmail.com
--- dlls/wlanapi/dbus.c | 168 +++++++++++++++++++++++++++++++++++ dlls/wlanapi/main.c | 42 ++++++++- dlls/wlanapi/tests/wlanapi.c | 12 +-- dlls/wlanapi/unixlib.c | 68 ++++++++++++++ dlls/wlanapi/unixlib.h | 25 ++++++ dlls/wlanapi/unixlib_priv.h | 8 ++ include/wlanapi.h | 2 + 7 files changed, 317 insertions(+), 8 deletions(-)
diff --git a/dlls/wlanapi/dbus.c b/dlls/wlanapi/dbus.c index f29ecd85bc9..b779f40902b 100644 --- a/dlls/wlanapi/dbus.c +++ b/dlls/wlanapi/dbus.c @@ -59,6 +59,8 @@ DBUS_FUNCS; #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" +#define NETWORKMANAGER_INTERFACE_SETTINGS "org.freedesktop.NetworkManager.Settings" +#define NETWORKMANAGER_INTERFACE_SETTINGS_CONNECTION "org.freedesktop.NetworkManager.Settings.Connection"
BOOL load_dbus_functions( void ) { @@ -821,6 +823,172 @@ NTSTATUS networkmanager_start_scan( void *connection, const GUID *interface, return STATUS_SUCCESS; }
+struct networkmanager_settings +{ + const char *id; + dbus_bool_t autoconnect; + const char *type; + const char *interface; +}; + +static BOOL networkmanager_settings_get_section_dict( DBusMessage *getsettings_reply, + const char *name, DBusMessageIter *dict ) +{ + DBusMessageIter iter, sections; + + p_dbus_message_iter_init( getsettings_reply, &iter ); + p_dbus_message_iter_recurse( &iter, §ions ); + while (p_dbus_message_iter_has_next( §ions )) + { + DBusMessageIter section; + const char *section_name; + + p_dbus_message_iter_recurse( §ions, §ion ); + p_dbus_message_iter_get_basic( §ion, §ion_name ); + if (!strcmp( section_name, name )) + { + p_dbus_message_iter_next( §ion ); + p_dbus_message_iter_recurse( §ion, dict ); + return TRUE; + } + p_dbus_message_iter_next( §ions ); + } + + return FALSE; +} + +static BOOL networkmanager_read_settings( DBusMessage *getsettings_reply, + struct networkmanager_settings *settings, + const char *filter_id ) +{ + DBusMessageIter dict, variant; + const char *prop_name; + + if (networkmanager_settings_get_section_dict( getsettings_reply, "connection", &dict )) + { + settings->autoconnect = 1; + + while((prop_name = dbus_next_dict_entry( &dict, &variant ))) + { + if (!strcmp( prop_name, "id" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_STRING) + p_dbus_message_iter_get_basic( &variant, &settings->id ); + else if (!strcmp( prop_name, "autoconnect" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_BOOLEAN) + p_dbus_message_iter_get_basic( &variant, &settings->autoconnect ); + else if (!strcmp( prop_name, "type" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_STRING) + p_dbus_message_iter_get_basic( &variant, &settings->type ); + else if (!strcmp( prop_name, "interface-name" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_STRING) + p_dbus_message_iter_get_basic( &variant, &settings->interface ); + } + } + if (filter_id && !(settings->id && !strcmp(settings->id, filter_id))) + return FALSE; + + return TRUE; +} + +NTSTATUS networkmanager_wifi_device_get_setting_ids( void *connection, const GUID *device, + struct list *ids) +{ + DBusMessage *request, *reply; + DBusError error; + char **object_paths; + int n_objects, i; + dbus_bool_t success; + char *device_path; + struct unix_wlan_interface_info device_info = {0}; + + 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; + if (!networkmanager_wifi_device_get_info( connection, device_path, &device_info)) + { + free( device_path ); + return STATUS_INTERNAL_ERROR; + } + free( device_path ); + + request = p_dbus_message_new_method_call( + NETWORKMANAGER_SERVICE, "/org/freedesktop/NetworkManager/Settings", + NETWORKMANAGER_INTERFACE_SETTINGS, "ListConnections" ); + 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 connections settings: %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 ListConnections 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++) + { + DBusMessage *getsettings_req, *getsettings_reply; + const char *object_path = object_paths[i]; + struct networkmanager_settings settings = {0}; + + getsettings_req = p_dbus_message_new_method_call( + NETWORKMANAGER_SERVICE, object_path, NETWORKMANAGER_INTERFACE_SETTINGS_CONNECTION, + "GetSettings" ); + if (!getsettings_req) continue; + p_dbus_error_init( &error ); + getsettings_reply = p_dbus_connection_send_with_reply_and_block( connection, getsettings_req, + dbus_timeout, &error ); + p_dbus_message_unref( getsettings_req ); + if (!getsettings_reply) + { + ERR( "Could not get settings for %s: %s: %s.\n", debugstr_a( object_path ), + debugstr_a( error.name ), debugstr_a( error.message ) ); + p_dbus_error_free( &error ); + continue; + } + p_dbus_error_free( &error ); + if (networkmanager_read_settings( getsettings_reply, &settings, NULL ) && settings.id && + settings.type && !strcmp( settings.type, "802-11-wireless" ) && + settings.interface && !strcmp ( settings.interface, device_info.description )) + { + struct wlan_profile *entry; + SIZE_T len; + + entry = malloc( sizeof( *entry ) ); + if (!entry) continue; + + len = min( strlen( settings.id ), sizeof( entry->name ) - 1 ); + memcpy( entry->name, settings.id, len ); + entry->name[len] = '\0'; + list_add_tail( ids, &entry->entry ); + } + p_dbus_message_unref( getsettings_reply ); + } + + 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 9d9ea91be9b..f5e70735c4f 100644 --- a/dlls/wlanapi/main.c +++ b/dlls/wlanapi/main.c @@ -367,9 +367,47 @@ DWORD WINAPI WlanGetNetworkBssList( HANDLE handle, const GUID *guid, const DOT11 DWORD WINAPI WlanGetProfileList( HANDLE handle, const GUID *guid, void *reserved, WLAN_PROFILE_INFO_LIST **list ) { - FIXME("(%p, %p, %p, %p) stub\n", handle, guid, reserved, list); + NTSTATUS status; + WLAN_PROFILE_INFO_LIST *ret_list; + struct wine_wlan *wlan; + struct wlan_get_profile_list_params params = {0}; + struct wlan_profile_list_move_to_profile_info_params move_params = {0}; + DWORD size;
- return ERROR_CALL_NOT_IMPLEMENTED; + TRACE( "(%p, %s, %p, %p)\n", handle, debugstr_guid( guid ), reserved, list ); + + if (!handle || !guid || reserved || !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_get_profile_list, ¶ms ); + if (status) + return RtlNtStatusToDosError( status ); + + size = offsetof( WLAN_PROFILE_INFO_LIST, ProfileInfo[params.len] ); + ret_list = WlanAllocateMemory( size ); + if (!ret_list) + { + struct wlan_profile_list_free_params free_params = {0}; + free_params.profiles = params.list; + UNIX_WLAN_CALL( wlan_profile_list_free, &free_params ); + return ERROR_NOT_ENOUGH_MEMORY; + } + + move_params.dest = ret_list->ProfileInfo; + move_params.profiles = params.list; + UNIX_WLAN_CALL( wlan_profile_list_move_to_profile_info, &move_params ); + + ret_list->dwIndex = 0; + ret_list->dwNumberOfItems = params.len; + *list = ret_list; + + return ERROR_SUCCESS; }
DWORD WINAPI WlanQueryInterface(HANDLE handle, const GUID *guid, WLAN_INTF_OPCODE opcode, diff --git a/dlls/wlanapi/tests/wlanapi.c b/dlls/wlanapi/tests/wlanapi.c index a3017518a55..0e01567b043 100644 --- a/dlls/wlanapi/tests/wlanapi.c +++ b/dlls/wlanapi/tests/wlanapi.c @@ -420,15 +420,15 @@ static void test_WlanGetProfileList( void ) trace( " Index[%ld] GUID: %s\n", i, debugstr_guid( &info->InterfaceGuid ) );
ret = WlanGetProfileList( NULL, NULL, NULL, NULL ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); + ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); ret = WlanGetProfileList( handle, NULL, NULL, &list ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); - todo_wine ok( list == bad_list, "list changed\n" ); + ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); + ok( list == bad_list, "list changed\n" ); ret = WlanGetProfileList( handle, &info->InterfaceGuid, NULL, NULL ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); + ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); ret = WlanGetProfileList( handle, &info->InterfaceGuid, &reserved, &list ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); - todo_wine ok( list == bad_list, "list changed\n" ); + ok( ret == ERROR_INVALID_PARAMETER, "Expected 87, got %ld\n", ret ); + ok( list == bad_list, "list changed\n" );
ret = WlanGetProfileList( handle, &info->InterfaceGuid, NULL, &list ); ok( ret == ERROR_SUCCESS, "Expected 0, got %ld\n", ret); diff --git a/dlls/wlanapi/unixlib.c b/dlls/wlanapi/unixlib.c index 3b101263f3c..0b38594fbe2 100644 --- a/dlls/wlanapi/unixlib.c +++ b/dlls/wlanapi/unixlib.c @@ -210,6 +210,70 @@ NTSTATUS wlan_start_scan( void *params ) return networkmanager_start_scan( (void *) args->handle, args->interface, args->ssid ); }
+NTSTATUS wlan_get_profile_list( void *params ) +{ + NTSTATUS status; + struct wlan_get_profile_list_params *args = params; + struct list *profiles; + + if (!initialized) + return STATUS_NOT_SUPPORTED; + + profiles = malloc( sizeof( *profiles )); + if (!profiles) return STATUS_NO_MEMORY; + + list_init( profiles ); + status = networkmanager_wifi_device_get_setting_ids( (void *)args->handle, args->interface, + profiles ); + if (status) + { + free( profiles ); + return status; + } + + args->list = (UINT_PTR)profiles; + args->len = list_count( profiles ); + return STATUS_SUCCESS; +} + +NTSTATUS wlan_profile_list_move_to_profile_info( void *params ) +{ + struct wlan_profile_list_move_to_profile_info_params *args = params; + struct list *profiles = (struct list *)args->profiles; + struct wlan_profile *cur, *next; + SIZE_T i = 0; + + LIST_FOR_EACH_ENTRY_SAFE( cur, next, profiles, struct wlan_profile, entry) + { + WCHAR *dst = args->dest[i].strProfileName; + + args->dest[i++].dwFlags = WLAN_PROFILE_USER; + ntdll_umbstowcs( cur->name, strlen( cur->name ) + 1, dst, + ARRAY_SIZE( args->dest[0].strProfileName ) ); + list_remove( &cur->entry ); + free( cur ); + } + + free( profiles ); + return STATUS_SUCCESS; +} + +NTSTATUS wlan_profile_list_free( void *params ) +{ + struct wlan_profile_list_free_params *args = params; + struct list *profiles = (struct list *)args->profiles; + struct wlan_profile *cur, *next; + + LIST_FOR_EACH_ENTRY_SAFE( cur, next, profiles, struct wlan_profile, entry) + { + list_remove( &cur->entry ); + free( cur ); + } + + free( profiles ); + return STATUS_SUCCESS; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { wlan_init, wlan_open_handle, @@ -225,6 +289,10 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { wlan_network_list_free,
wlan_start_scan, + + wlan_get_profile_list, + wlan_profile_list_move_to_profile_info, + wlan_profile_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 1a39149018b..56f85f99c82 100644 --- a/dlls/wlanapi/unixlib.h +++ b/dlls/wlanapi/unixlib.h @@ -97,6 +97,27 @@ struct wlan_start_scan const DOT11_SSID *ssid; };
+struct wlan_get_profile_list_params +{ + UINT_PTR handle; + const GUID *interface; + + UINT_PTR list; + SIZE_T len; +}; + +struct wlan_profile_list_move_to_profile_info_params +{ + UINT_PTR profiles; + + WLAN_PROFILE_INFO *dest; +}; + +struct wlan_profile_list_free_params +{ + UINT_PTR profiles; +}; + enum wlanpi_funcs { unix_wlan_init, @@ -115,6 +136,10 @@ enum wlanpi_funcs
unix_wlan_start_scan,
+ unix_wlan_get_profile_list, + unix_wlan_profile_list_move_to_profile_info, + unix_wlan_profile_list_free, + unix_funcs_count };
diff --git a/dlls/wlanapi/unixlib_priv.h b/dlls/wlanapi/unixlib_priv.h index da51fcdf66d..9171a5dafc5 100644 --- a/dlls/wlanapi/unixlib_priv.h +++ b/dlls/wlanapi/unixlib_priv.h @@ -53,6 +53,12 @@ struct wlan_network struct wlan_bss_info info; };
+struct wlan_profile +{ + struct list entry; + CHAR name[WLAN_MAX_NAME_LENGTH]; +}; + extern BOOL load_dbus_functions( void ); extern NTSTATUS init_dbus_connection( UINT_PTR *handle ); extern void close_dbus_connection( void *c ); @@ -66,4 +72,6 @@ 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 ); +extern NTSTATUS networkmanager_wifi_device_get_setting_ids( void *connection, const GUID *device, + struct list *ids ); #endif /* __WINE_WLANAPI_UNIXLIB_PRIV_H */ diff --git a/include/wlanapi.h b/include/wlanapi.h index 76cb79bb83e..c8864c09c70 100644 --- a/include/wlanapi.h +++ b/include/wlanapi.h @@ -285,6 +285,8 @@ typedef struct _WLAN_HOSTED_NETWORK_STATUS
#define WLAN_MAX_NAME_LENGTH 256
+#define WLAN_PROFILE_USER 0x00000002 + typedef struct _WLAN_PROFILE_INFO { WCHAR strProfileName[WLAN_MAX_NAME_LENGTH];