mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 07:10:07 +01:00
wifi/iwd: merge branch 'balrog-kun:iwd-p2p'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1017
This commit is contained in:
commit
2395bedd63
12 changed files with 1894 additions and 33 deletions
|
|
@ -3935,6 +3935,8 @@ if WITH_IWD
|
|||
src_core_devices_wifi_libnm_wifi_base_la_SOURCES += \
|
||||
src/core/devices/wifi/nm-device-iwd.c \
|
||||
src/core/devices/wifi/nm-device-iwd.h \
|
||||
src/core/devices/wifi/nm-device-iwd-p2p.c \
|
||||
src/core/devices/wifi/nm-device-iwd-p2p.h \
|
||||
src/core/devices/wifi/nm-iwd-manager.c \
|
||||
src/core/devices/wifi/nm-iwd-manager.h \
|
||||
$(NULL)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ iwd_sources = files()
|
|||
if enable_iwd
|
||||
iwd_sources += files(
|
||||
'nm-device-iwd.c',
|
||||
'nm-device-iwd-p2p.c',
|
||||
'nm-iwd-manager.c',
|
||||
)
|
||||
endif
|
||||
|
|
|
|||
1262
src/core/devices/wifi/nm-device-iwd-p2p.c
Normal file
1262
src/core/devices/wifi/nm-device-iwd-p2p.c
Normal file
File diff suppressed because it is too large
Load diff
36
src/core/devices/wifi/nm-device-iwd-p2p.h
Normal file
36
src/core/devices/wifi/nm-device-iwd-p2p.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __NM_DEVICE_IWD_P2P_H__
|
||||
#define __NM_DEVICE_IWD_P2P_H__
|
||||
|
||||
#include "devices/nm-device.h"
|
||||
#include "nm-device-wifi-p2p.h"
|
||||
|
||||
#define NM_TYPE_DEVICE_IWD_P2P (nm_device_iwd_p2p_get_type())
|
||||
#define NM_DEVICE_IWD_P2P(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2P))
|
||||
#define NM_DEVICE_IWD_P2P_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2PClass))
|
||||
#define NM_IS_DEVICE_IWD_P2P(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IWD_P2P))
|
||||
#define NM_IS_DEVICE_IWD_P2P_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_IWD_P2P))
|
||||
#define NM_DEVICE_IWD_P2P_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2PClass))
|
||||
|
||||
#define NM_DEVICE_IWD_P2P_PEERS NM_DEVICE_WIFI_P2P_PEERS
|
||||
#define NM_DEVICE_IWD_P2P_GROUPS NM_DEVICE_WIFI_P2P_GROUPS
|
||||
|
||||
typedef struct _NMDeviceIwdP2P NMDeviceIwdP2P;
|
||||
typedef struct _NMDeviceIwdP2PClass NMDeviceIwdP2PClass;
|
||||
|
||||
GType nm_device_iwd_p2p_get_type(void);
|
||||
|
||||
NMDeviceIwdP2P *nm_device_iwd_p2p_new(GDBusObject *object);
|
||||
|
||||
void nm_device_iwd_p2p_remove(NMDeviceIwdP2P *p2p);
|
||||
|
||||
void nm_device_iwd_p2p_peer_add_remove(NMDeviceIwdP2P *p2p, GDBusObject *peer_obj, bool add);
|
||||
|
||||
#endif /* __NM_DEVICE_IWD_P2P_H__ */
|
||||
|
|
@ -168,7 +168,7 @@ check_connection_peer_joined(NMDeviceWifiP2P *device)
|
|||
return FALSE;
|
||||
|
||||
/* NOTE: We currently only support connections to a specific peer */
|
||||
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, conn);
|
||||
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, conn, FALSE);
|
||||
if (!peer)
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
|||
NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
|
||||
g_return_val_if_fail(s_wifi_p2p, NM_ACT_STAGE_RETURN_FAILURE);
|
||||
|
||||
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
|
||||
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
|
||||
if (!peer) {
|
||||
/* Set up a timeout on the find attempt and run a find for the same period of time */
|
||||
if (priv->find_peer_timeout_id == 0) {
|
||||
|
|
@ -436,7 +436,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
|||
NM_IS_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)));
|
||||
|
||||
/* The prepare stage ensures that the peer has been found */
|
||||
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
|
||||
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
|
||||
if (!peer) {
|
||||
NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
|
|
@ -521,7 +521,8 @@ peer_add_remove(NMDeviceWifiP2P *self,
|
|||
connection = nm_device_get_applied_connection(device);
|
||||
nm_assert(NM_IS_CONNECTION(connection));
|
||||
|
||||
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
|
||||
peer =
|
||||
nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
|
||||
if (peer) {
|
||||
/* A peer for the connection was found, cancel the timeout and go to configure state. */
|
||||
nm_clear_g_source(&priv->find_peer_timeout_id);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "libnm-core-intern/nm-core-internal.h"
|
||||
#include "nm-manager.h"
|
||||
#include "nm-device-iwd.h"
|
||||
#include "nm-device-iwd-p2p.h"
|
||||
#include "nm-wifi-utils.h"
|
||||
#include "libnm-glib-aux/nm-uuid.h"
|
||||
#include "libnm-glib-aux/nm-random-utils.h"
|
||||
|
|
@ -25,6 +26,14 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
enum {
|
||||
P2P_DEVICE_ADDED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
NMIwdNetworkSecurity security;
|
||||
|
|
@ -49,6 +58,10 @@ typedef struct {
|
|||
NMDeviceIwd *last_agent_call_device;
|
||||
char *last_state_dir;
|
||||
char *warned_state_dir;
|
||||
bool netconfig_enabled;
|
||||
GHashTable *p2p_devices;
|
||||
NMIwdWfdInfo wfd_info;
|
||||
guint wfd_use_count;
|
||||
} NMIwdManagerPrivate;
|
||||
|
||||
struct _NMIwdManager {
|
||||
|
|
@ -419,6 +432,66 @@ set_device_dbus_object(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *objec
|
|||
nm_device_iwd_set_dbus_object(NM_DEVICE_IWD(device), object);
|
||||
}
|
||||
|
||||
static void
|
||||
add_p2p_device(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *object)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
const char *path = g_dbus_object_get_object_path(object);
|
||||
NMDeviceIwdP2P *p2p;
|
||||
gs_unref_object GDBusInterface *wiphy = NULL;
|
||||
const char *phy_name;
|
||||
|
||||
if (g_hash_table_contains(priv->p2p_devices, path))
|
||||
return;
|
||||
|
||||
wiphy = g_dbus_object_get_interface(object, NM_IWD_WIPHY_INTERFACE);
|
||||
if (!wiphy)
|
||||
return;
|
||||
|
||||
phy_name = get_property_string_or_null(G_DBUS_PROXY(wiphy), "Name");
|
||||
if (!phy_name) {
|
||||
_LOGE("Name not cached for phy at %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
p2p = nm_device_iwd_p2p_new(object);
|
||||
if (!p2p) {
|
||||
_LOGE("Can't create NMDeviceIwdP2P for phy at %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
g_hash_table_insert(priv->p2p_devices, g_strdup(path), p2p);
|
||||
g_signal_emit(self, signals[P2P_DEVICE_ADDED], 0, p2p, phy_name);
|
||||
|
||||
/* There should be no peer objects before the device object appeared so don't
|
||||
* try to look for them and notify the new device. */
|
||||
}
|
||||
|
||||
static void
|
||||
remove_p2p_device(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *object)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
const char *path = g_dbus_object_get_object_path(object);
|
||||
NMDeviceIwdP2P *p2p = g_hash_table_lookup(priv->p2p_devices, path);
|
||||
|
||||
if (!p2p)
|
||||
return;
|
||||
|
||||
g_hash_table_remove(priv->p2p_devices, path);
|
||||
}
|
||||
|
||||
static NMDeviceIwdP2P *
|
||||
get_p2p_device_from_peer(NMIwdManager *self, GDBusProxy *proxy)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
const char *device_path = get_property_string_or_null(proxy, "Device");
|
||||
|
||||
if (!device_path)
|
||||
return NULL;
|
||||
|
||||
return g_hash_table_lookup(priv->p2p_devices, device_path);
|
||||
}
|
||||
|
||||
static void
|
||||
known_network_update_cb(GObject *source, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
|
|
@ -998,6 +1071,22 @@ interface_added(GDBusObjectManager *object_manager,
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq(iface_name, NM_IWD_P2P_INTERFACE)) {
|
||||
add_p2p_device(self, proxy, object);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq(iface_name, NM_IWD_P2P_PEER_INTERFACE)) {
|
||||
NMDeviceIwdP2P *p2p = get_p2p_device_from_peer(self, proxy);
|
||||
|
||||
/* This is more conveniently done with a direct call than a signal because
|
||||
* this way we only notify the interested NMDeviceIwdP2P. */
|
||||
if (p2p)
|
||||
nm_device_iwd_p2p_peer_add_remove(p2p, object, TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1051,6 +1140,20 @@ interface_removed(GDBusObjectManager *object_manager,
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq(iface_name, NM_IWD_P2P_INTERFACE)) {
|
||||
remove_p2p_device(self, proxy, object);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq(iface_name, NM_IWD_P2P_PEER_INTERFACE)) {
|
||||
NMDeviceIwdP2P *p2p = get_p2p_device_from_peer(self, proxy);
|
||||
|
||||
if (p2p)
|
||||
nm_device_iwd_p2p_peer_add_remove(p2p, object, FALSE);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1469,6 +1572,15 @@ get_daemon_info_cb(GObject *source, GAsyncResult *res, gpointer user_data)
|
|||
|
||||
nm_clear_g_free(&priv->last_state_dir);
|
||||
priv->last_state_dir = g_variant_dup_string(value, NULL);
|
||||
} else if (nm_streq(key, "NetworkConfigurationEnabled")) {
|
||||
if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
|
||||
_LOGE("Daemon.GetInfo property %s is typed '%s' instead of 'b'",
|
||||
key,
|
||||
g_variant_get_type_string(value));
|
||||
goto next;
|
||||
}
|
||||
|
||||
priv->netconfig_enabled = g_variant_get_boolean(value);
|
||||
}
|
||||
|
||||
next:
|
||||
|
|
@ -1543,6 +1655,8 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data)
|
|||
if (priv->agent_id)
|
||||
register_agent(self);
|
||||
|
||||
priv->netconfig_enabled = false; /* Assume false until GetInfo() results come in */
|
||||
|
||||
daemon = g_dbus_object_manager_get_interface(object_manager,
|
||||
"/net/connman/iwd", /* IWD 1.15+ */
|
||||
NM_IWD_DAEMON_INTERFACE);
|
||||
|
|
@ -1639,6 +1753,121 @@ nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const ch
|
|||
return interface ? G_DBUS_PROXY(interface) : NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_iwd_manager_get_netconfig_enabled(NMIwdManager *self)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
|
||||
return priv->netconfig_enabled;
|
||||
}
|
||||
|
||||
/* IWD's net.connman.iwd.p2p.ServiceManager.RegisterDisplayService() is global so
|
||||
* two local Wi-Fi P2P devices can't be connected to (or even scanning for) WFD
|
||||
* peers using different WFD IE contents, e.g. one as a sink and one as a source.
|
||||
* If one device is connected to a peer without a WFD service, another can try
|
||||
* to establish a WFD connection to a peer since this won't disturb the first
|
||||
* connection. Similarly if one device is connected to a peer with WFD, another
|
||||
* can make a connection to a non-WFD peer (if that exists...) because a non-WFD
|
||||
* peer will simply ignore the WFD IEs, but it cannot connect to or search for a
|
||||
* peer that's WFD capable without passing our own WFD IEs, i.e. if the new
|
||||
* NMSettingsConnection has no WFD IEs and we're already in a WFD connection on
|
||||
* another device, we can't activate that new connection. We expose methods
|
||||
* for the NMDeviceIwdP2P's to register/unregister the service and one to check
|
||||
* if there's already an incompatible connection active.
|
||||
*/
|
||||
gboolean
|
||||
nm_iwd_manager_check_wfd_info_compatible(NMIwdManager *self, const NMIwdWfdInfo *wfd_info)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
|
||||
if (priv->wfd_use_count == 0)
|
||||
return TRUE;
|
||||
|
||||
return nm_wifi_utils_wfd_info_eq(&priv->wfd_info, wfd_info);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_iwd_manager_register_wfd(NMIwdManager *self, const NMIwdWfdInfo *wfd_info)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
gs_unref_object GDBusInterface *service_manager = NULL;
|
||||
GVariantBuilder builder;
|
||||
|
||||
nm_assert(nm_iwd_manager_check_wfd_info_compatible(self, wfd_info));
|
||||
|
||||
if (!priv->object_manager)
|
||||
return FALSE;
|
||||
|
||||
service_manager = g_dbus_object_manager_get_interface(priv->object_manager,
|
||||
"/net/connman/iwd",
|
||||
NM_IWD_P2P_SERVICE_MANAGER_INTERFACE);
|
||||
if (!service_manager) {
|
||||
_LOGE("IWD P2P service manager not found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_builder_add(&builder, "{sv}", "Source", g_variant_new_boolean(wfd_info->source));
|
||||
g_variant_builder_add(&builder, "{sv}", "Sink", g_variant_new_boolean(wfd_info->sink));
|
||||
|
||||
if (wfd_info->source)
|
||||
g_variant_builder_add(&builder, "{sv}", "Port", g_variant_new_uint16(wfd_info->port));
|
||||
|
||||
if (wfd_info->sink && wfd_info->has_audio)
|
||||
g_variant_builder_add(&builder, "{sv}", "HasAudio", g_variant_new_boolean(TRUE));
|
||||
|
||||
if (wfd_info->has_uibc)
|
||||
g_variant_builder_add(&builder, "{sv}", "HasUIBC", g_variant_new_boolean(TRUE));
|
||||
|
||||
if (wfd_info->has_cp)
|
||||
g_variant_builder_add(&builder,
|
||||
"{sv}",
|
||||
"HasContentProtection",
|
||||
g_variant_new_boolean(TRUE));
|
||||
|
||||
g_dbus_proxy_call(G_DBUS_PROXY(service_manager),
|
||||
"RegisterDisplayService",
|
||||
g_variant_new("(a{sv})", &builder),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
memcpy(&priv->wfd_info, wfd_info, sizeof(priv->wfd_info));
|
||||
priv->wfd_use_count++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_iwd_manager_unregister_wfd(NMIwdManager *self)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
gs_unref_object GDBusInterface *service_manager = NULL;
|
||||
|
||||
nm_assert(priv->wfd_use_count > 0);
|
||||
|
||||
priv->wfd_use_count--;
|
||||
|
||||
if (!priv->object_manager)
|
||||
return;
|
||||
|
||||
service_manager = g_dbus_object_manager_get_interface(priv->object_manager,
|
||||
"/net/connman/iwd",
|
||||
NM_IWD_P2P_SERVICE_MANAGER_INTERFACE);
|
||||
if (!service_manager)
|
||||
return;
|
||||
|
||||
g_dbus_proxy_call(G_DBUS_PROXY(service_manager),
|
||||
"UnregisterDisplayService",
|
||||
g_variant_new("()"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NM_DEFINE_SINGLETON_GETTER(NMIwdManager, nm_iwd_manager_get, NM_TYPE_IWD_MANAGER);
|
||||
|
|
@ -1685,6 +1914,8 @@ nm_iwd_manager_init(NMIwdManager *self)
|
|||
g_free,
|
||||
(GDestroyNotify) known_network_data_free);
|
||||
|
||||
priv->p2p_devices = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
|
||||
prepare_object_manager(self);
|
||||
}
|
||||
|
||||
|
|
@ -1718,6 +1949,8 @@ dispose(GObject *object)
|
|||
nm_clear_g_free(&priv->last_state_dir);
|
||||
nm_clear_g_free(&priv->warned_state_dir);
|
||||
|
||||
g_hash_table_unref(nm_steal_pointer(&priv->p2p_devices));
|
||||
|
||||
G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
|
|
@ -1727,4 +1960,16 @@ nm_iwd_manager_class_init(NMIwdManagerClass *klass)
|
|||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = dispose;
|
||||
|
||||
signals[P2P_DEVICE_ADDED] = g_signal_new(NM_IWD_MANAGER_P2P_DEVICE_ADDED,
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE,
|
||||
2,
|
||||
NM_TYPE_DEVICE,
|
||||
G_TYPE_STRING);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,18 +13,22 @@
|
|||
#define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM
|
||||
#define NM_IWD_SERVICE "net.connman.iwd"
|
||||
|
||||
#define NM_IWD_DAEMON_INTERFACE "net.connman.iwd.Daemon"
|
||||
#define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager"
|
||||
#define NM_IWD_WIPHY_INTERFACE "net.connman.iwd.Adapter"
|
||||
#define NM_IWD_DEVICE_INTERFACE "net.connman.iwd.Device"
|
||||
#define NM_IWD_NETWORK_INTERFACE "net.connman.iwd.Network"
|
||||
#define NM_IWD_AGENT_INTERFACE "net.connman.iwd.Agent"
|
||||
#define NM_IWD_WSC_INTERFACE "net.connman.iwd.WiFiSimpleConfiguration"
|
||||
#define NM_IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork"
|
||||
#define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent"
|
||||
#define NM_IWD_AP_INTERFACE "net.connman.iwd.AccessPoint"
|
||||
#define NM_IWD_ADHOC_INTERFACE "net.connman.iwd.AdHoc"
|
||||
#define NM_IWD_STATION_INTERFACE "net.connman.iwd.Station"
|
||||
#define NM_IWD_DAEMON_INTERFACE "net.connman.iwd.Daemon"
|
||||
#define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager"
|
||||
#define NM_IWD_WIPHY_INTERFACE "net.connman.iwd.Adapter"
|
||||
#define NM_IWD_DEVICE_INTERFACE "net.connman.iwd.Device"
|
||||
#define NM_IWD_NETWORK_INTERFACE "net.connman.iwd.Network"
|
||||
#define NM_IWD_AGENT_INTERFACE "net.connman.iwd.Agent"
|
||||
#define NM_IWD_WSC_INTERFACE "net.connman.iwd.SimpleConfiguration"
|
||||
#define NM_IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork"
|
||||
#define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent"
|
||||
#define NM_IWD_AP_INTERFACE "net.connman.iwd.AccessPoint"
|
||||
#define NM_IWD_ADHOC_INTERFACE "net.connman.iwd.AdHoc"
|
||||
#define NM_IWD_STATION_INTERFACE "net.connman.iwd.Station"
|
||||
#define NM_IWD_P2P_INTERFACE "net.connman.iwd.p2p.Device"
|
||||
#define NM_IWD_P2P_PEER_INTERFACE "net.connman.iwd.p2p.Peer"
|
||||
#define NM_IWD_P2P_SERVICE_MANAGER_INTERFACE "net.connman.iwd.p2p.ServiceManager"
|
||||
#define NM_IWD_P2P_WFD_INTERFACE "net.connman.iwd.p2p.Display"
|
||||
|
||||
#define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type())
|
||||
#define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IWD_MANAGER, NMIwdManager))
|
||||
|
|
@ -35,6 +39,8 @@
|
|||
#define NM_IWD_MANAGER_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_IWD_MANAGER, NMIwdManagerClass))
|
||||
|
||||
#define NM_IWD_MANAGER_P2P_DEVICE_ADDED "p2p-device-added"
|
||||
|
||||
typedef struct _NMIwdManager NMIwdManager;
|
||||
typedef struct _NMIwdManagerClass NMIwdManagerClass;
|
||||
|
||||
|
|
@ -51,4 +57,10 @@ NMSettingsConnection *nm_iwd_manager_get_ap_mirror_connection(NMIwdManager *self
|
|||
GDBusProxy *
|
||||
nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const char *name);
|
||||
|
||||
gboolean nm_iwd_manager_get_netconfig_enabled(NMIwdManager *self);
|
||||
|
||||
gboolean nm_iwd_manager_check_wfd_info_compatible(NMIwdManager *self, const NMIwdWfdInfo *wfd_info);
|
||||
gboolean nm_iwd_manager_register_wfd(NMIwdManager *self, const NMIwdWfdInfo *wfd_info);
|
||||
void nm_iwd_manager_unregister_wfd(NMIwdManager *self);
|
||||
|
||||
#endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include "nm-device-wifi-p2p.h"
|
||||
#include "nm-device-olpc-mesh.h"
|
||||
#include "nm-device-iwd.h"
|
||||
#include "nm-device-iwd-p2p.h"
|
||||
#include "nm-iwd-manager.h"
|
||||
#include "settings/nm-settings-connection.h"
|
||||
#include "libnm-platform/nm-platform.h"
|
||||
#include "nm-config.h"
|
||||
|
|
@ -67,6 +69,19 @@ p2p_device_created(NMDeviceWifi *device, NMDeviceWifiP2P *p2p_device, NMDeviceFa
|
|||
g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, p2p_device);
|
||||
}
|
||||
|
||||
#if WITH_IWD
|
||||
static void
|
||||
iwd_p2p_device_added(NMIwdManager *iwd,
|
||||
NMDeviceIwdP2P *p2p_device,
|
||||
const char *phy_name,
|
||||
NMDeviceFactory *self)
|
||||
{
|
||||
nm_log_info(LOGD_PLATFORM | LOGD_WIFI, "Wi-Fi P2P device added on %s", phy_name);
|
||||
|
||||
g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, p2p_device);
|
||||
}
|
||||
#endif
|
||||
|
||||
static NMDevice *
|
||||
create_device(NMDeviceFactory *factory,
|
||||
const char *iface,
|
||||
|
|
@ -76,6 +91,7 @@ create_device(NMDeviceFactory *factory,
|
|||
{
|
||||
gs_free char *backend_free = NULL;
|
||||
const char *backend;
|
||||
_NM80211Mode mode;
|
||||
|
||||
g_return_val_if_fail(iface != NULL, NULL);
|
||||
g_return_val_if_fail(plink != NULL, NULL);
|
||||
|
|
@ -85,6 +101,20 @@ create_device(NMDeviceFactory *factory,
|
|||
if (plink->type != NM_LINK_TYPE_WIFI)
|
||||
return nm_device_olpc_mesh_new(iface);
|
||||
|
||||
/* Ignore monitor-mode and other unhandled interface types.
|
||||
* FIXME: keep TYPE_MONITOR devices in UNAVAILABLE state and manage
|
||||
* them if/when they change to a handled type.
|
||||
*/
|
||||
mode = nm_platform_wifi_get_mode(NM_PLATFORM_GET, plink->ifindex);
|
||||
if (!NM_IN_SET(mode,
|
||||
_NM_802_11_MODE_INFRA,
|
||||
_NM_802_11_MODE_ADHOC,
|
||||
_NM_802_11_MODE_AP,
|
||||
_NM_802_11_MODE_MESH)) {
|
||||
*out_ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
backend = nm_config_data_get_device_config_by_pllink(NM_CONFIG_GET_DATA,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND,
|
||||
plink,
|
||||
|
|
@ -103,7 +133,6 @@ create_device(NMDeviceFactory *factory,
|
|||
if (!g_ascii_strcasecmp(backend, "wpa_supplicant")) {
|
||||
NMDevice *device;
|
||||
_NMDeviceWifiCapabilities capabilities;
|
||||
_NM80211Mode mode;
|
||||
|
||||
if (!nm_platform_wifi_get_capabilities(NM_PLATFORM_GET, plink->ifindex, &capabilities)) {
|
||||
nm_log_warn(LOGD_PLATFORM | LOGD_WIFI,
|
||||
|
|
@ -113,16 +142,6 @@ create_device(NMDeviceFactory *factory,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Ignore monitor-mode and other unhandled interface types.
|
||||
* FIXME: keep TYPE_MONITOR devices in UNAVAILABLE state and manage
|
||||
* them if/when they change to a handled type.
|
||||
*/
|
||||
mode = nm_platform_wifi_get_mode(NM_PLATFORM_GET, plink->ifindex);
|
||||
if (mode == _NM_802_11_MODE_UNKNOWN) {
|
||||
*out_ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device = nm_device_wifi_new(iface, capabilities);
|
||||
|
||||
g_signal_connect_object(device,
|
||||
|
|
@ -134,8 +153,23 @@ create_device(NMDeviceFactory *factory,
|
|||
return device;
|
||||
}
|
||||
#if WITH_IWD
|
||||
else if (!g_ascii_strcasecmp(backend, "iwd"))
|
||||
else if (!g_ascii_strcasecmp(backend, "iwd")) {
|
||||
NMIwdManager *iwd = nm_iwd_manager_get();
|
||||
|
||||
if (!g_signal_handler_find(iwd,
|
||||
G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
G_CALLBACK(iwd_p2p_device_added),
|
||||
factory))
|
||||
g_signal_connect(iwd,
|
||||
NM_IWD_MANAGER_P2P_DEVICE_ADDED,
|
||||
G_CALLBACK(iwd_p2p_device_added),
|
||||
factory);
|
||||
|
||||
return nm_device_iwd_new(iface);
|
||||
}
|
||||
#endif
|
||||
|
||||
nm_log_warn(LOGD_PLATFORM | LOGD_WIFI,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "nm-setting-wireless.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-wifi-utils.h"
|
||||
#include "nm-iwd-manager.h"
|
||||
#include "libnm-platform/nm-platform.h"
|
||||
#include "supplicant/nm-supplicant-types.h"
|
||||
|
||||
|
|
@ -100,14 +101,16 @@ nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head)
|
|||
}
|
||||
|
||||
NMWifiP2PPeer *
|
||||
nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head, NMConnection *connection)
|
||||
nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head,
|
||||
NMConnection *connection,
|
||||
gboolean check_wfd)
|
||||
{
|
||||
NMWifiP2PPeer *peer;
|
||||
|
||||
g_return_val_if_fail(connection, NULL);
|
||||
|
||||
c_list_for_each_entry (peer, peers_lst_head, peers_lst) {
|
||||
if (nm_wifi_p2p_peer_check_compatible(peer, connection))
|
||||
if (nm_wifi_p2p_peer_check_compatible(peer, connection, check_wfd))
|
||||
return peer;
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -419,6 +422,90 @@ nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer *peer, const NMSupplicantP
|
|||
return changed;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_wifi_p2p_peer_update_from_iwd_object(NMWifiP2PPeer *peer, GDBusObject *obj)
|
||||
{
|
||||
NMWifiP2PPeerPrivate *priv;
|
||||
gboolean changed = FALSE;
|
||||
nm_auto_ref_string NMRefString *peer_path = NULL;
|
||||
gs_unref_object GDBusProxy *peer_proxy = NULL;
|
||||
gs_unref_object GDBusProxy *wfd_proxy = NULL;
|
||||
GVariant *value;
|
||||
gs_unref_bytes GBytes *wfd_ies = NULL;
|
||||
|
||||
g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE);
|
||||
|
||||
peer_proxy = G_DBUS_PROXY(g_dbus_object_get_interface(obj, NM_IWD_P2P_PEER_INTERFACE));
|
||||
wfd_proxy = G_DBUS_PROXY(g_dbus_object_get_interface(obj, NM_IWD_P2P_WFD_INTERFACE));
|
||||
g_return_val_if_fail(peer_proxy, FALSE);
|
||||
|
||||
peer_path = nm_ref_string_new(g_dbus_object_get_object_path(obj));
|
||||
priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer);
|
||||
nm_assert(!priv->supplicant_path || priv->supplicant_path == peer_path);
|
||||
|
||||
g_object_freeze_notify(G_OBJECT(peer));
|
||||
|
||||
if (!priv->supplicant_path) {
|
||||
priv->supplicant_path = g_steal_pointer(&peer_path);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(peer_proxy, "Name");
|
||||
if (value && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING))
|
||||
changed |= nm_wifi_p2p_peer_set_name(peer, g_variant_get_string(value, NULL));
|
||||
else
|
||||
changed |= nm_wifi_p2p_peer_set_name(peer, "");
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(peer_proxy, "Address");
|
||||
if (value && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING))
|
||||
changed |= nm_wifi_p2p_peer_set_address(peer, g_variant_get_string(value, NULL));
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
if (wfd_proxy) {
|
||||
NMIwdWfdInfo wfd = {};
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(wfd_proxy, "Source");
|
||||
wfd.source = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
|
||||
&& g_variant_get_boolean(value);
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(wfd_proxy, "Sink");
|
||||
wfd.sink = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
|
||||
&& g_variant_get_boolean(value);
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(wfd_proxy, "Port");
|
||||
wfd.port = (value && g_variant_is_of_type(value, G_VARIANT_TYPE_UINT16))
|
||||
? g_variant_get_uint16(value)
|
||||
: 0;
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(wfd_proxy, "HasAudio");
|
||||
wfd.has_audio = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
|
||||
&& g_variant_get_boolean(value);
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(wfd_proxy, "HasUIBC");
|
||||
wfd.has_uibc = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
|
||||
&& g_variant_get_boolean(value);
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
value = g_dbus_proxy_get_cached_property(wfd_proxy, "HasContentProtection");
|
||||
wfd.has_cp = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
|
||||
&& g_variant_get_boolean(value);
|
||||
nm_g_variant_unref(value);
|
||||
|
||||
wfd_ies = nm_wifi_utils_build_wfd_ies(&wfd);
|
||||
}
|
||||
|
||||
changed |= nm_wifi_p2p_peer_set_wfd_ies(peer, wfd_ies);
|
||||
|
||||
g_object_thaw_notify(G_OBJECT(peer));
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_len, gint32 now_s)
|
||||
{
|
||||
|
|
@ -458,7 +545,7 @@ nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_l
|
|||
}
|
||||
|
||||
gboolean
|
||||
nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection)
|
||||
nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection, gboolean check_wfd)
|
||||
{
|
||||
NMWifiP2PPeerPrivate *priv;
|
||||
NMSettingWifiP2P *s_wifi_p2p;
|
||||
|
|
@ -478,6 +565,10 @@ nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection)
|
|||
if (hwaddr && (!priv->address || !nm_utils_hwaddr_matches(hwaddr, -1, priv->address, -1)))
|
||||
return FALSE;
|
||||
|
||||
if (check_wfd && nm_setting_wifi_p2p_get_wfd_ies(s_wifi_p2p)
|
||||
&& !nm_wifi_p2p_peer_get_wfd_ies(self))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -559,6 +650,17 @@ nm_wifi_p2p_peer_new_from_properties(const NMSupplicantPeerInfo *peer_info)
|
|||
return peer;
|
||||
}
|
||||
|
||||
NMWifiP2PPeer *
|
||||
nm_wifi_p2p_peer_new_from_iwd_object(GDBusObject *obj)
|
||||
{
|
||||
NMWifiP2PPeer *peer;
|
||||
|
||||
/* TODO: Set the flags here */
|
||||
peer = g_object_new(NM_TYPE_WIFI_P2P_PEER, NULL);
|
||||
nm_wifi_p2p_peer_update_from_iwd_object(peer, obj);
|
||||
return peer;
|
||||
}
|
||||
|
||||
static void
|
||||
finalize(GObject *object)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,11 +45,15 @@ struct _NMSupplicantPeerInfo;
|
|||
GType nm_wifi_p2p_peer_get_type(void);
|
||||
|
||||
NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_properties(const struct _NMSupplicantPeerInfo *peer_info);
|
||||
NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_iwd_object(GDBusObject *obj);
|
||||
|
||||
gboolean nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer *peer,
|
||||
const struct _NMSupplicantPeerInfo *peer_info);
|
||||
gboolean nm_wifi_p2p_peer_update_from_iwd_object(NMWifiP2PPeer *peer, GDBusObject *obj);
|
||||
|
||||
gboolean nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection);
|
||||
gboolean nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self,
|
||||
NMConnection *connection,
|
||||
gboolean check_wfd);
|
||||
|
||||
const char *nm_wifi_p2p_peer_get_supplicant_path(NMWifiP2PPeer *peer);
|
||||
|
||||
|
|
@ -81,7 +85,8 @@ nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_l
|
|||
const char **nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head);
|
||||
|
||||
NMWifiP2PPeer *nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head,
|
||||
NMConnection *connection);
|
||||
NMConnection *connection,
|
||||
gboolean check_wfd);
|
||||
|
||||
NMWifiP2PPeer *nm_wifi_p2p_peers_find_by_supplicant_path(const CList *peers_lst_head,
|
||||
const char *path);
|
||||
|
|
|
|||
|
|
@ -1800,3 +1800,151 @@ nm_wifi_utils_connection_to_iwd_config(NMConnection *connection,
|
|||
|
||||
return g_steal_pointer(&file);
|
||||
}
|
||||
|
||||
/* Wi-Fi Display Technical Specification v2.1.0 Table 27 */
|
||||
enum wfd_subelem_type {
|
||||
WFD_SUBELEM_WFD_DEVICE_INFORMATION = 0,
|
||||
WFD_SUBELEM_ASSOCIATED_BSSID = 1,
|
||||
WFD_SUBELEM_COUPLED_SINK_INFORMATION = 6,
|
||||
WFD_SUBELEM_EXTENDED_CAPABILITY = 7,
|
||||
WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
|
||||
WFD_SUBELEM_SESION_INFORMATION = 9,
|
||||
WFD_SUBELEM_ALTERNATIVE_MAC_ADDRESS = 10,
|
||||
WFD_SUBELEM_R2_DEVICE_INFORMATION = 11,
|
||||
};
|
||||
|
||||
bool
|
||||
nm_wifi_utils_parse_wfd_ies(GBytes *ies, NMIwdWfdInfo *out_wfd)
|
||||
{
|
||||
size_t len;
|
||||
const uint8_t *data = g_bytes_get_data(ies, &len);
|
||||
const uint8_t *dev_info = NULL;
|
||||
uint16_t dev_info_len = 0;
|
||||
uint16_t dev_info_flags;
|
||||
const uint8_t *ext_capability = NULL;
|
||||
uint16_t ext_capability_len = 0;
|
||||
|
||||
/* The single WFD IEs array provided by the client is supposed to be sent to
|
||||
* the peer in the different frame types that may include the WFD IE: Probe
|
||||
* Request/Response, Beacon, (Re)Association Request/Response, GO
|
||||
* Negotiation Request/Response/Confirm and Provision Discovery
|
||||
* Request/Response.
|
||||
*
|
||||
* It's going to be a subset of the elements allowed in all those frames.
|
||||
* Validate that it contains at least a valid WFD Device Information (with
|
||||
* the Session Available bit true) and that the sequence of subelements is
|
||||
* valid.
|
||||
*/
|
||||
while (len) {
|
||||
uint8_t subelem_id;
|
||||
uint16_t subelem_len;
|
||||
|
||||
/* Does the subelement header fit */
|
||||
if (len < 3)
|
||||
return FALSE;
|
||||
|
||||
subelem_id = data[0];
|
||||
subelem_len = (data[1] << 8) | data[2];
|
||||
data += 3;
|
||||
len -= 3;
|
||||
|
||||
if (subelem_len > len)
|
||||
return FALSE;
|
||||
|
||||
if (subelem_id == WFD_SUBELEM_WFD_DEVICE_INFORMATION) {
|
||||
/* Is there a duplicate WFD Device Information */
|
||||
if (dev_info)
|
||||
return FALSE;
|
||||
|
||||
dev_info = data;
|
||||
dev_info_len = subelem_len;
|
||||
}
|
||||
|
||||
if (subelem_id == WFD_SUBELEM_EXTENDED_CAPABILITY) {
|
||||
/* Is there a duplicate WFD Extended Capability */
|
||||
if (ext_capability)
|
||||
return FALSE;
|
||||
|
||||
ext_capability = data;
|
||||
ext_capability_len = subelem_len;
|
||||
}
|
||||
|
||||
data += subelem_len;
|
||||
len -= subelem_len;
|
||||
}
|
||||
|
||||
if (!dev_info || dev_info_len != 6)
|
||||
return FALSE;
|
||||
|
||||
dev_info_flags = (dev_info[0] << 8) | dev_info[1];
|
||||
|
||||
/* Secondary sink not supported */
|
||||
if ((dev_info_flags & 3) == 2)
|
||||
return FALSE;
|
||||
|
||||
/* Must be available for WFD Session */
|
||||
if (((dev_info_flags >> 4) & 3) != 1)
|
||||
return FALSE;
|
||||
|
||||
/* TDLS persistent group re-invocation not supported */
|
||||
if ((dev_info_flags >> 13) & 1)
|
||||
return FALSE;
|
||||
|
||||
/* All other flags indicate support but not a requirement for something
|
||||
* so not preserving them in the IEs IWD eventually sends doesn't break
|
||||
* basic functionality.
|
||||
*/
|
||||
|
||||
if (ext_capability && ext_capability_len != 2)
|
||||
return FALSE;
|
||||
|
||||
if (!out_wfd)
|
||||
return TRUE;
|
||||
|
||||
out_wfd->source = NM_IN_SET(dev_info_flags & 3, 0, 3);
|
||||
out_wfd->sink = NM_IN_SET(dev_info_flags & 3, 1, 3);
|
||||
out_wfd->port = (dev_info[2] << 8) | dev_info[3];
|
||||
out_wfd->has_audio =
|
||||
out_wfd->sink ? ((dev_info_flags >> 10) & 1) == 0 : (((dev_info_flags >> 11) & 1) == 1);
|
||||
out_wfd->has_uibc = ext_capability && (ext_capability[1] & 1) == 1;
|
||||
out_wfd->has_cp = ((dev_info_flags >> 8) & 1) == 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
nm_wifi_utils_build_wfd_ies(const NMIwdWfdInfo *wfd)
|
||||
{
|
||||
uint8_t data[64];
|
||||
uint8_t *ptr = data;
|
||||
|
||||
*ptr++ = WFD_SUBELEM_WFD_DEVICE_INFORMATION;
|
||||
*ptr++ = 0; /* WFD Subelement length */
|
||||
*ptr++ = 6;
|
||||
*ptr++ = 0; /* WFD Device Information bitmap: */
|
||||
*ptr++ = (wfd->source ? (wfd->sink ? 3 : 0) : 1) | 0x10 | /* WFD Session Available */
|
||||
(wfd->has_cp ? 0x100 : 0) | (wfd->has_audio ? 0 : 0x400);
|
||||
*ptr++ = wfd->port >> 8;
|
||||
*ptr++ = wfd->port & 255;
|
||||
*ptr++ = 0; /* WFD Device Maximum throughput */
|
||||
*ptr++ = 10;
|
||||
|
||||
if (wfd->has_uibc) {
|
||||
*ptr++ = WFD_SUBELEM_EXTENDED_CAPABILITY;
|
||||
*ptr++ = 0; /* WFD Subelement length */
|
||||
*ptr++ = 2;
|
||||
*ptr++ = 0x00; /* WFD Extended Capability Bitmap: */
|
||||
*ptr++ = 0x10; /* UIBC Support */
|
||||
}
|
||||
|
||||
return g_bytes_new(data, ptr - data);
|
||||
}
|
||||
|
||||
bool
|
||||
nm_wifi_utils_wfd_info_eq(const NMIwdWfdInfo *a, const NMIwdWfdInfo *b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return a == b;
|
||||
|
||||
return a->source == b->source && a->sink == b->sink && a->port == b->port
|
||||
&& a->has_audio == b->has_audio && a->has_uibc == b->has_uibc && a->has_cp == b->has_cp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,15 @@ typedef enum {
|
|||
NM_IWD_NETWORK_SECURITY_8021X,
|
||||
} NMIwdNetworkSecurity;
|
||||
|
||||
typedef struct {
|
||||
bool source;
|
||||
bool sink;
|
||||
uint16_t port;
|
||||
bool has_audio;
|
||||
bool has_uibc;
|
||||
bool has_cp;
|
||||
} NMIwdWfdInfo;
|
||||
|
||||
gboolean nm_wifi_utils_complete_connection(GBytes *ssid,
|
||||
const char *bssid,
|
||||
_NM80211Mode mode,
|
||||
|
|
@ -43,4 +52,8 @@ char *nm_wifi_utils_get_iwd_config_filename(const char *ssid,
|
|||
GKeyFile *
|
||||
nm_wifi_utils_connection_to_iwd_config(NMConnection *conn, char **out_filename, GError **error);
|
||||
|
||||
bool nm_wifi_utils_parse_wfd_ies(GBytes *ies, NMIwdWfdInfo *out_wfd);
|
||||
GBytes *nm_wifi_utils_build_wfd_ies(const NMIwdWfdInfo *wfd);
|
||||
bool nm_wifi_utils_wfd_info_eq(const NMIwdWfdInfo *a, const NMIwdWfdInfo *b);
|
||||
|
||||
#endif /* __NM_WIFI_UTILS_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue