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 | 10 +- 7 files changed, 629 insertions(+), 9 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..5bd7c969b8c 100644 --- a/include/wlanapi.h +++ b/include/wlanapi.h @@ -89,9 +89,15 @@ 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; +} DOT11_AUTH_ALGORITHM, + *PDOT11_AUTH_ALGORITHM;
typedef enum _DOT11_CIPHER_ALGORITHM { @@ -109,6 +115,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];