bluetooth: refactor BlueZ handling and let NMBluezManager cache ObjectManager data

This is a complete refactoring of the bluetooth code.

Now that BlueZ 4 support was dropped, the separation of NMBluezManager
and NMBluez5Manager makes no sense. They should be merged.

At that point, notice that BlueZ 5's D-Bus API is fully centered around
D-Bus's ObjectManager interface. Using that interface, we basically only
call GetManagedObjects() once and register to InterfacesAdded,
InterfacesRemoved and PropertiesChanged signals. There is no need to
fetch individual properties ever.

Note how NMBluezDevice used to query the D-Bus properties itself by
creating a GDBusProxy. This is redundant, because when using the ObjectManager
interfaces, we have all information already.

Instead, let NMBluezManager basically become the client-side cache of
all of BlueZ's ObjectManager interface. NMBluezDevice was mostly concerned
about caching the D-Bus interface's state, tracking suitable profiles
(pan_connection), and moderate between bluez and NMDeviceBt.
These tasks don't get simpler by moving them to a seprate file. Let them
also be handled by NMBluezManager.

I mean, just look how it was previously: NMBluez5Manager registers to
ObjectManager interface and sees a device appearing. It creates a
NMBluezDevice object and registers to its "initialized" and
"notify:usable" signal. In the meantime, NMBluezDevice fetches the
relevant information from D-Bus (although it was already present in the
data provided by the ObjectManager) and eventually emits these usable
and initialized signals.
Then, NMBlue5Manager emits a "bdaddr-added" signal, for which NMBluezManager
creates the NMDeviceBt instance. NMBluezManager, NMBluez5Manager and
NMBluezDevice are strongly cooperating to the point that it is simpler
to merge them.

This is not mere refactoring. This patch aims to make everything
asynchronously and always cancellable. Also, it aims to fix races
and inconsistencies of the state.

- Registering to a NAP server now waits for the response and delays
  activation of the NMDeviceBridge accordingly.

- For NAP connections we now watch the bnep0 interface in platform, and tear
  down the device when it goes away. Bluez doesn't send us a notification
  on D-Bus in that case.

- Rework establishing a DUN connection. It no longer uses blocking
  connect() and does not block until rfcomm device appears. It's
  all async now. It also watches the rfcomm file descriptor for
  POLLERR/POLLHUP to notice disconnect.

- drop nm_device_factory_emit_component_added() and instead let
  NMDeviceBt directly register to the WWan factory's "added" signal.
This commit is contained in:
Thomas Haller 2019-08-11 10:43:53 +02:00
parent 878d4963ed
commit 4154d9618c
26 changed files with 4325 additions and 2842 deletions

View file

@ -3441,11 +3441,8 @@ $(src_devices_bluetooth_libnm_bluetooth_utils_la_OBJECTS): $(libnm_core_lib_h_pu
core_plugins += src/devices/bluetooth/libnm-device-plugin-bluetooth.la
src_devices_bluetooth_libnm_device_plugin_bluetooth_la_SOURCES = \
src/devices/bluetooth/nm-bluez-device.c \
src/devices/bluetooth/nm-bluez-device.h \
src/devices/bluetooth/nm-bluez-manager.c \
src/devices/bluetooth/nm-bluez5-manager.c \
src/devices/bluetooth/nm-bluez5-manager.h \
src/devices/bluetooth/nm-bluez-manager.h \
src/devices/bluetooth/nm-device-bt.c \
src/devices/bluetooth/nm-device-bt.h \
$(NULL)

View file

@ -131,6 +131,10 @@ _nm_setting_secret_flags_valid (NMSettingSecretFlags flags)
/*****************************************************************************/
const char *nm_bluetooth_capability_to_string (NMBluetoothCapabilities capabilities, char *buf, gsize len);
/*****************************************************************************/
typedef enum { /*< skip >*/
NM_SETTING_PARSE_FLAGS_NONE = 0,
NM_SETTING_PARSE_FLAGS_STRICT = 1LL << 0,

View file

@ -5812,6 +5812,14 @@ nm_utils_version (void)
/*****************************************************************************/
NM_UTILS_FLAGS2STR_DEFINE (nm_bluetooth_capability_to_string, NMBluetoothCapabilities,
NM_UTILS_FLAGS2STR (NM_BT_CAPABILITY_NONE, "NONE"),
NM_UTILS_FLAGS2STR (NM_BT_CAPABILITY_DUN, "DUN"),
NM_UTILS_FLAGS2STR (NM_BT_CAPABILITY_NAP, "NAP"),
)
/*****************************************************************************/
/**
* nm_utils_base64secret_decode:
* @base64_key: the (possibly invalid) base64 encode key.

View file

@ -148,7 +148,7 @@ src/dhcp/nm-dhcp-dhclient-utils.c
src/dhcp/nm-dhcp-manager.c
src/dns/nm-dns-manager.c
src/devices/adsl/nm-device-adsl.c
src/devices/bluetooth/nm-bluez-device.c
src/devices/bluetooth/nm-bluez-manager.c
src/devices/bluetooth/nm-device-bt.c
src/devices/nm-device-6lowpan.c
src/devices/nm-device-bond.c

View file

@ -1,7 +1,5 @@
sources = files(
'nm-bluez-device.c',
'nm-bluez-manager.c',
'nm-bluez5-manager.c',
'nm-bt-error.c',
'nm-device-bt.c',
)

File diff suppressed because it is too large Load diff

View file

@ -1,70 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/* NetworkManager -- Network link manager
*
* Copyright (C) 2009 - 2014 Red Hat, Inc.
*/
#ifndef __NETWORKMANAGER_BLUEZ_DEVICE_H__
#define __NETWORKMANAGER_BLUEZ_DEVICE_H__
#include "nm-connection.h"
#define NM_TYPE_BLUEZ_DEVICE (nm_bluez_device_get_type ())
#define NM_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDevice))
#define NM_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass))
#define NM_IS_BLUEZ_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_DEVICE))
#define NM_IS_BLUEZ_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ_DEVICE))
#define NM_BLUEZ_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass))
/* Properties */
#define NM_BLUEZ_DEVICE_PATH "path"
#define NM_BLUEZ_DEVICE_ADDRESS "address"
#define NM_BLUEZ_DEVICE_NAME "name"
#define NM_BLUEZ_DEVICE_CAPABILITIES "capabilities"
#define NM_BLUEZ_DEVICE_USABLE "usable"
#define NM_BLUEZ_DEVICE_CONNECTED "connected"
/* Signals */
#define NM_BLUEZ_DEVICE_INITIALIZED "initialized"
#define NM_BLUEZ_DEVICE_REMOVED "removed"
typedef struct _NMBluezDevice NMBluezDevice;
typedef struct _NMBluezDeviceClass NMBluezDeviceClass;
GType nm_bluez_device_get_type (void);
NMBluezDevice *nm_bluez_device_new (GDBusConnection *dbus_connection,
const char *path,
NMSettings *settings);
const char *nm_bluez_device_get_path (NMBluezDevice *self);
gboolean nm_bluez_device_get_initialized (NMBluezDevice *self);
gboolean nm_bluez_device_get_usable (NMBluezDevice *self);
const char *nm_bluez_device_get_address (NMBluezDevice *self);
const char *nm_bluez_device_get_name (NMBluezDevice *self);
guint32 nm_bluez_device_get_capabilities (NMBluezDevice *self);
gboolean nm_bluez_device_get_connected (NMBluezDevice *self);
typedef void (*NMBluezDeviceConnectCallback) (NMBluezDevice *self,
const char *device,
GError *error,
gpointer user_data);
void
nm_bluez_device_connect_async (NMBluezDevice *self,
NMBluetoothCapabilities connection_bt_type,
GCancellable *cancellable,
NMBluezDeviceConnectCallback callback,
gpointer callback_user_data);
void
nm_bluez_device_disconnect (NMBluezDevice *self);
#endif /* __NETWORKMANAGER_BLUEZ_DEVICE_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (C) 2009 - 2019 Red Hat, Inc.
*/
#ifndef __NM_BLUEZ_MANAGER_H__
#define __NM_BLUEZ_MANAGER_H__
#define NM_TYPE_BLUEZ_MANAGER (nm_bluez_manager_get_type ())
#define NM_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager))
#define NM_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass))
#define NM_IS_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ_MANAGER))
#define NM_IS_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ_MANAGER))
#define NM_BLUEZ_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass))
typedef struct _NMBluezManager NMBluezManager;
typedef struct _NMBluezManagerClass NMBluezManagerClass;
GType nm_bluez_manager_get_type (void);
typedef void (*NMBluezManagerConnectCb) (NMBluezManager *self,
gboolean is_completed /* or else is early notification with DUN path */,
const char *device_name,
GError *error,
gpointer user_data);
gboolean nm_bluez_manager_connect (NMBluezManager *self,
const char *object_path,
NMBluetoothCapabilities connection_bt_type,
int timeout_msec,
GCancellable *cancellable,
NMBluezManagerConnectCb callback,
gpointer callback_user_data,
GError **error);
void nm_bluez_manager_disconnect (NMBluezManager *self,
const char *object_path);
#endif /* __NM_BLUEZ_MANAGER_H__ */

File diff suppressed because it is too large Load diff

View file

@ -4,27 +4,36 @@
* Copyright (C) 2014 Red Hat, Inc.
*/
#ifndef _NM_BLUEZ5_UTILS_H_
#define _NM_BLUEZ5_UTILS_H_
#ifndef __NM_BLUEZ5_DUN_H__
#define __NM_BLUEZ5_DUN_H__
typedef struct _NMBluez5DunContext NMBluez5DunContext;
typedef void (*NMBluez5DunFunc) (NMBluez5DunContext *context,
const char *rfcomm_dev,
GError *error,
gpointer user_data);
#if WITH_BLUEZ5_DUN
NMBluez5DunContext *nm_bluez5_dun_new (const char *adapter,
const char *remote);
typedef void (*NMBluez5DunConnectCb) (NMBluez5DunContext *context,
const char *rfcomm_dev,
GError *error,
gpointer user_data);
void nm_bluez5_dun_connect (NMBluez5DunContext *context,
NMBluez5DunFunc callback,
gpointer user_data);
typedef void (*NMBluez5DunNotifyTtyHangupCb) (NMBluez5DunContext *context,
gpointer user_data);
/* Clean up connection resources */
void nm_bluez5_dun_cleanup (NMBluez5DunContext *context);
gboolean nm_bluez5_dun_connect (const char *adapter,
const char *remote,
GCancellable *cancellable,
NMBluez5DunConnectCb callback,
gpointer callback_user_data,
NMBluez5DunNotifyTtyHangupCb notify_tty_hangup_cb,
gpointer notify_tty_hangup_user_data,
GError **error);
/* Clean up and dispose all resources */
void nm_bluez5_dun_free (NMBluez5DunContext *context);
void nm_bluez5_dun_disconnect (NMBluez5DunContext *context);
#endif /* _NM_BLUEZ5_UTILS_H_ */
const char *nm_bluez5_dun_context_get_adapter (const NMBluez5DunContext *context);
const char *nm_bluez5_dun_context_get_remote (const NMBluez5DunContext *context);
const char *nm_bluez5_dun_context_get_rfcomm_dev (const NMBluez5DunContext *context);
#endif /* WITH_BLUEZ5_DUN */
#endif /* __NM_BLUEZ5_DUN_H__ */

View file

@ -1,585 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/* NetworkManager -- Network link manager
*
* Copyright (C) 2007 - 2008 Novell, Inc.
* Copyright (C) 2007 - 2017 Red Hat, Inc.
* Copyright (C) 2013 Intel Corporation.
*/
#include "nm-default.h"
#include "nm-bluez5-manager.h"
#include <signal.h>
#include <stdlib.h>
#include "nm-core-internal.h"
#include "nm-std-aux/nm-dbus-compat.h"
#include "c-list/src/c-list.h"
#include "nm-bluez-device.h"
#include "nm-bluez-common.h"
#include "devices/nm-device-bridge.h"
#include "settings/nm-settings.h"
/*****************************************************************************/
enum {
BDADDR_ADDED,
NETWORK_SERVER_ADDED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
NMSettings *settings;
GDBusProxy *proxy;
GHashTable *devices;
CList network_servers;
} NMBluez5ManagerPrivate;
struct _NMBluez5Manager {
GObject parent;
NMBtVTableNetworkServer network_server_vtable;
NMBluez5ManagerPrivate _priv;
};
struct _NMBluez5ManagerClass {
GObjectClass parent;
};
G_DEFINE_TYPE (NMBluez5Manager, nm_bluez5_manager, G_TYPE_OBJECT)
#define NM_BLUEZ5_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMBluez5Manager, NM_IS_BLUEZ5_MANAGER)
#define NM_BLUEZ5_MANAGER_GET_NETWORK_SERVER_VTABLE(self) (&(self)->network_server_vtable)
#define NETWORK_SERVER_VTABLE_GET_NM_BLUEZ5_MANAGER(vtable) \
NM_BLUEZ5_MANAGER(((char *)(vtable)) - offsetof (struct _NMBluez5Manager, network_server_vtable))
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_BT
#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bluez5", __VA_ARGS__)
/*****************************************************************************/
static void device_initialized (NMBluezDevice *device, gboolean success, NMBluez5Manager *self);
static void device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluez5Manager *self);
/*****************************************************************************/
typedef struct {
char *path;
char *addr;
NMDevice *device;
CList lst_ns;
} NetworkServer;
static NetworkServer *
_find_network_server (NMBluez5Manager *self, const char *path, NMDevice *device)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NetworkServer *network_server;
nm_assert (path || NM_IS_DEVICE (device));
c_list_for_each_entry (network_server, &priv->network_servers, lst_ns) {
if (path && !nm_streq (network_server->path, path))
continue;
if (device && network_server->device != device)
continue;
return network_server;
}
return NULL;
}
static NetworkServer *
_find_network_server_for_addr (NMBluez5Manager *self, const char *addr)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NetworkServer *network_server;
c_list_for_each_entry (network_server, &priv->network_servers, lst_ns) {
/* The address lookups need a server not assigned to a device
* and tolerate an empty address as a wildcard for "any". */
if ( !network_server->device
&& (!addr || nm_streq (network_server->addr, addr)))
return network_server;
}
return NULL;
}
static void
_network_server_unregister (NMBluez5Manager *self, NetworkServer *network_server)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
if (!network_server->device) {
/* Not connected. */
return;
}
_LOGI ("NAP: unregistering %s from %s",
nm_device_get_iface (network_server->device),
network_server->addr);
g_dbus_connection_call (g_dbus_proxy_get_connection (priv->proxy),
NM_BLUEZ_SERVICE,
network_server->path,
NM_BLUEZ5_NETWORK_SERVER_INTERFACE,
"Unregister",
g_variant_new ("(s)", BLUETOOTH_CONNECT_NAP),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, NULL, NULL);
g_clear_object (&network_server->device);
}
static void
_network_server_free (NMBluez5Manager *self, NetworkServer *network_server)
{
_network_server_unregister (self, network_server);
c_list_unlink_stale (&network_server->lst_ns);
g_free (network_server->path);
g_free (network_server->addr);
g_slice_free (NetworkServer, network_server);
}
static gboolean
network_server_is_available (const NMBtVTableNetworkServer *vtable,
const char *addr)
{
NMBluez5Manager *self = NETWORK_SERVER_VTABLE_GET_NM_BLUEZ5_MANAGER (vtable);
return !!_find_network_server_for_addr (self, addr);
}
static gboolean
network_server_register_bridge (const NMBtVTableNetworkServer *vtable,
const char *addr,
NMDevice *device)
{
NMBluez5Manager *self = NETWORK_SERVER_VTABLE_GET_NM_BLUEZ5_MANAGER (vtable);
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NetworkServer *network_server = _find_network_server_for_addr (self, addr);
nm_assert (NM_IS_DEVICE (device));
nm_assert (!_find_network_server (self, NULL, device));
if (!network_server) {
/* The device checked that a network server is available, before
* starting the activation, but for some reason it no longer is.
* Indicate that the activation should not proceed. */
_LOGI ("NAP: %s is not available for %s", addr, nm_device_get_iface (device));
return FALSE;
}
_LOGI ("NAP: registering %s on %s", nm_device_get_iface (device), network_server->addr);
g_dbus_connection_call (g_dbus_proxy_get_connection (priv->proxy),
NM_BLUEZ_SERVICE,
network_server->path,
NM_BLUEZ5_NETWORK_SERVER_INTERFACE,
"Register",
g_variant_new ("(ss)", BLUETOOTH_CONNECT_NAP, nm_device_get_iface (device)),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, NULL, NULL);
network_server->device = g_object_ref (device);
return TRUE;
}
static gboolean
network_server_unregister_bridge (const NMBtVTableNetworkServer *vtable,
NMDevice *device)
{
NMBluez5Manager *self = NETWORK_SERVER_VTABLE_GET_NM_BLUEZ5_MANAGER (vtable);
NetworkServer *network_server = _find_network_server (self, NULL, device);
if (network_server)
_network_server_unregister (self, network_server);
return TRUE;
}
static void
network_server_removed (GDBusProxy *proxy, const char *path, NMBluez5Manager *self)
{
NetworkServer *network_server;
network_server = _find_network_server (self, path, NULL);
if (!network_server)
return;
if (network_server->device) {
nm_device_queue_state (network_server->device, NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_BT_FAILED);
}
_LOGI ("NAP: removed interface %s", network_server->addr);
_network_server_free (self, network_server);
}
static void
network_server_added (GDBusProxy *proxy, const char *path, const char *addr, NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NetworkServer *network_server;
/* If BlueZ messes up and announces a single network server twice,
* make sure we get rid of the older instance first. */
network_server_removed (proxy, path, self);
network_server = g_slice_new0 (NetworkServer);
network_server->path = g_strdup (path);
network_server->addr = g_strdup (addr);
c_list_link_before (&priv->network_servers, &network_server->lst_ns);
_LOGI ("NAP: added interface %s", addr);
g_signal_emit (self, signals[NETWORK_SERVER_ADDED], 0);
}
/*****************************************************************************/
static void
emit_bdaddr_added (NMBluez5Manager *self, NMBluezDevice *device)
{
g_signal_emit (self, signals[BDADDR_ADDED], 0,
device,
nm_bluez_device_get_address (device),
nm_bluez_device_get_name (device),
nm_bluez_device_get_path (device),
nm_bluez_device_get_capabilities (device));
}
void
nm_bluez5_manager_query_devices (NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NMBluezDevice *device;
GHashTableIter iter;
g_hash_table_iter_init (&iter, priv->devices);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) {
if (nm_bluez_device_get_usable (device))
emit_bdaddr_added (self, device);
}
}
static void
remove_device (NMBluez5Manager *self, NMBluezDevice *device)
{
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_initialized), self);
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_usable), self);
if (nm_bluez_device_get_usable (device))
g_signal_emit_by_name (device, NM_BLUEZ_DEVICE_REMOVED);
}
static void
remove_all_devices (NMBluez5Manager *self)
{
GHashTableIter iter;
NMBluezDevice *device;
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
g_hash_table_iter_init (&iter, priv->devices);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) {
g_hash_table_iter_steal (&iter);
remove_device (self, device);
g_object_unref (device);
}
}
static void
device_usable (NMBluezDevice *device, GParamSpec *pspec, NMBluez5Manager *self)
{
gboolean usable = nm_bluez_device_get_usable (device);
_LOGD ("(%s): bluez device now %s",
nm_bluez_device_get_path (device),
usable ? "usable" : "unusable");
if (usable) {
_LOGD ("(%s): bluez device address %s",
nm_bluez_device_get_path (device),
nm_bluez_device_get_address (device));
emit_bdaddr_added (self, device);
} else
g_signal_emit_by_name (device, NM_BLUEZ_DEVICE_REMOVED);
}
static void
device_initialized (NMBluezDevice *device, gboolean success, NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
_LOGD ("(%s): bluez device %s",
nm_bluez_device_get_path (device),
success ? "initialized" : "failed to initialize");
if (!success)
g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device));
}
static void
device_added (GDBusProxy *proxy, const char *path, NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NMBluezDevice *device;
device = nm_bluez_device_new (g_dbus_proxy_get_connection (proxy), path, priv->settings);
g_signal_connect (device, NM_BLUEZ_DEVICE_INITIALIZED, G_CALLBACK (device_initialized), self);
g_signal_connect (device, "notify::" NM_BLUEZ_DEVICE_USABLE, G_CALLBACK (device_usable), self);
g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device);
_LOGD ("(%s): new bluez device found", path);
}
static void
device_removed (GDBusProxy *proxy, const char *path, NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NMBluezDevice *device;
_LOGD ("(%s): bluez device removed", path);
device = g_hash_table_lookup (priv->devices, path);
if (device) {
g_hash_table_steal (priv->devices, nm_bluez_device_get_path (device));
remove_device (NM_BLUEZ5_MANAGER (self), device);
g_object_unref (device);
}
}
static void
object_manager_interfaces_added (GDBusProxy *proxy,
const char *path,
GVariant *dict,
NMBluez5Manager *self)
{
if (g_variant_lookup (dict, NM_BLUEZ5_DEVICE_INTERFACE, "a{sv}", NULL))
device_added (proxy, path, self);
if (g_variant_lookup (dict, NM_BLUEZ5_NETWORK_SERVER_INTERFACE, "a{sv}", NULL)) {
gs_unref_variant GVariant *adapter = g_variant_lookup_value (dict, NM_BLUEZ5_ADAPTER_INTERFACE, G_VARIANT_TYPE_DICTIONARY);
const char *address;
if ( adapter
&& g_variant_lookup (adapter, "Address", "&s", &address))
network_server_added (proxy, path, address, self);
}
}
static void
object_manager_interfaces_removed (GDBusProxy *proxy,
const char *path,
const char **ifaces,
NMBluez5Manager *self)
{
if (ifaces && g_strv_contains (ifaces, NM_BLUEZ5_DEVICE_INTERFACE))
device_removed (proxy, path, self);
if (ifaces && g_strv_contains (ifaces, NM_BLUEZ5_NETWORK_SERVER_INTERFACE))
network_server_removed (proxy, path, self);
}
static void
get_managed_objects_cb (GDBusProxy *proxy,
GAsyncResult *res,
NMBluez5Manager *self)
{
gs_unref_variant GVariant *variant0 = NULL;
GVariant *variant, *ifaces;
GVariantIter i;
GError *error = NULL;
const char *path;
variant = _nm_dbus_proxy_call_finish (proxy, res,
G_VARIANT_TYPE ("(a{oa{sa{sv}}})"),
&error);
if (!variant) {
if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
_LOGW ("Couldn't get managed objects: not running Bluez5?");
else {
g_dbus_error_strip_remote_error (error);
_LOGW ("Couldn't get managed objects: %s", error->message);
}
g_clear_error (&error);
return;
}
variant0 = g_variant_get_child_value (variant, 0);
g_variant_iter_init (&i, variant0);
while ((g_variant_iter_next (&i, "{&o*}", &path, &ifaces))) {
object_manager_interfaces_added (proxy, path, ifaces, self);
g_variant_unref (ifaces);
}
g_variant_unref (variant);
}
static void name_owner_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data);
static void
on_proxy_acquired (GObject *object,
GAsyncResult *res,
NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
GError *error = NULL;
priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
if (!priv->proxy) {
_LOGW ("Couldn't acquire object manager proxy: %s", error->message);
g_clear_error (&error);
return;
}
g_signal_connect (priv->proxy, "notify::g-name-owner",
G_CALLBACK (name_owner_changed_cb), self);
/* Get already managed devices. */
g_dbus_proxy_call (priv->proxy, "GetManagedObjects",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
(GAsyncReadyCallback) get_managed_objects_cb,
self);
_nm_dbus_signal_connect (priv->proxy, "InterfacesAdded", G_VARIANT_TYPE ("(oa{sa{sv}})"),
G_CALLBACK (object_manager_interfaces_added), self);
_nm_dbus_signal_connect (priv->proxy, "InterfacesRemoved", G_VARIANT_TYPE ("(oas)"),
G_CALLBACK (object_manager_interfaces_removed), self);
}
static void
bluez_connect (NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
g_return_if_fail (priv->proxy == NULL);
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
NM_BLUEZ_SERVICE,
NM_BLUEZ_MANAGER_PATH,
DBUS_INTERFACE_OBJECT_MANAGER,
NULL,
(GAsyncReadyCallback) on_proxy_acquired,
self);
}
static void
name_owner_changed_cb (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
NMBluez5Manager *self = NM_BLUEZ5_MANAGER (user_data);
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
char *owner;
if (priv->devices) {
owner = g_dbus_proxy_get_name_owner (priv->proxy);
if (!owner)
remove_all_devices (self);
g_free (owner);
}
}
/*****************************************************************************/
static void
nm_bluez5_manager_init (NMBluez5Manager *self)
{
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
NMBtVTableNetworkServer *network_server_vtable = NM_BLUEZ5_MANAGER_GET_NETWORK_SERVER_VTABLE (self);
bluez_connect (self);
priv->devices = g_hash_table_new_full (nm_str_hash, g_str_equal,
NULL, g_object_unref);
c_list_init (&priv->network_servers);
nm_assert (!nm_bt_vtable_network_server);
network_server_vtable->is_available = network_server_is_available;
network_server_vtable->register_bridge = network_server_register_bridge;
network_server_vtable->unregister_bridge = network_server_unregister_bridge;
nm_bt_vtable_network_server = network_server_vtable;
}
NMBluez5Manager *
nm_bluez5_manager_new (NMSettings *settings)
{
NMBluez5Manager *instance = NULL;
g_return_val_if_fail (NM_IS_SETTINGS (settings), NULL);
instance = g_object_new (NM_TYPE_BLUEZ5_MANAGER, NULL);
NM_BLUEZ5_MANAGER_GET_PRIVATE (instance)->settings = g_object_ref (settings);
return instance;
}
static void
dispose (GObject *object)
{
NMBluez5Manager *self = NM_BLUEZ5_MANAGER (object);
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
CList *iter, *safe;
c_list_for_each_safe (iter, safe, &priv->network_servers)
_network_server_free (self, c_list_entry (iter, NetworkServer, lst_ns));
if (priv->proxy) {
g_signal_handlers_disconnect_by_func (priv->proxy, G_CALLBACK (name_owner_changed_cb), self);
g_clear_object (&priv->proxy);
}
g_hash_table_remove_all (priv->devices);
G_OBJECT_CLASS (nm_bluez5_manager_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
NMBluez5Manager *self = NM_BLUEZ5_MANAGER (object);
NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self);
g_hash_table_destroy (priv->devices);
G_OBJECT_CLASS (nm_bluez5_manager_parent_class)->finalize (object);
g_object_unref (priv->settings);
}
static void
nm_bluez5_manager_class_init (NMBluez5ManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = dispose;
object_class->finalize = finalize;
signals[BDADDR_ADDED] =
g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 5, G_TYPE_OBJECT, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
signals[NETWORK_SERVER_ADDED] =
g_signal_new (NM_BLUEZ_MANAGER_NETWORK_SERVER_ADDED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
}

View file

@ -1,27 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/* NetworkManager -- Network link manager
*
* Copyright (C) 2007 - 2008 Novell, Inc.
* Copyright (C) 2007 - 2013 Red Hat, Inc.
*/
#ifndef __NETWORKMANAGER_BLUEZ5_MANAGER_H__
#define __NETWORKMANAGER_BLUEZ5_MANAGER_H__
#define NM_TYPE_BLUEZ5_MANAGER (nm_bluez5_manager_get_type ())
#define NM_BLUEZ5_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ5_MANAGER, NMBluez5Manager))
#define NM_BLUEZ5_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerClass))
#define NM_IS_BLUEZ5_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BLUEZ5_MANAGER))
#define NM_IS_BLUEZ5_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_BLUEZ5_MANAGER))
#define NM_BLUEZ5_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ5_MANAGER, NMBluez5ManagerClass))
typedef struct _NMBluez5Manager NMBluez5Manager;
typedef struct _NMBluez5ManagerClass NMBluez5ManagerClass;
GType nm_bluez5_manager_get_type (void);
NMBluez5Manager *nm_bluez5_manager_new (NMSettings *settings);
void nm_bluez5_manager_query_devices (NMBluez5Manager *manager);
#endif /* __NETWORKMANAGER_BLUEZ5_MANAGER_H__ */

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,6 @@
#define __NETWORKMANAGER_DEVICE_BT_H__
#include "devices/nm-device.h"
#include "nm-bluez-device.h"
#define NM_TYPE_DEVICE_BT (nm_device_bt_get_type ())
#define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BT, NMDeviceBt))
@ -17,9 +16,11 @@
#define NM_IS_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_BT))
#define NM_DEVICE_BT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_BT, NMDeviceBtClass))
#define NM_DEVICE_BT_NAME "name"
#define NM_DEVICE_BT_BDADDR "bt-bdaddr"
#define NM_DEVICE_BT_BZ_MGR "bt-bz-mgr"
#define NM_DEVICE_BT_CAPABILITIES "bt-capabilities"
#define NM_DEVICE_BT_DEVICE "bt-device"
#define NM_DEVICE_BT_DBUS_PATH "bt-dbus-path"
#define NM_DEVICE_BT_NAME "bt-name"
#define NM_DEVICE_BT_PPP_STATS "ppp-stats"
@ -28,13 +29,21 @@ typedef struct _NMDeviceBtClass NMDeviceBtClass;
GType nm_device_bt_get_type (void);
NMDevice *nm_device_bt_new (NMBluezDevice *bt_device,
const char *udi,
const char *bdaddr,
const char *name,
guint32 capabilities);
struct _NMBluezManager;
guint32 nm_device_bt_get_capabilities (NMDeviceBt *device);
NMDeviceBt *nm_device_bt_new (struct _NMBluezManager *bz_mgr,
const char *dbus_path,
const char *bdaddr,
const char *name,
NMBluetoothCapabilities capabilities);
gboolean _nm_device_bt_for_same_device (NMDeviceBt *device,
const char *dbus_path,
const char *bdaddr,
const char *name,
NMBluetoothCapabilities capabilities);
NMBluetoothCapabilities nm_device_bt_get_capabilities (NMDeviceBt *device);
struct _NMModem;
@ -42,4 +51,11 @@ gboolean nm_device_bt_modem_added (NMDeviceBt *device,
struct _NMModem *modem,
const char *driver);
void _nm_device_bt_notify_removed (NMDeviceBt *self);
void _nm_device_bt_notify_set_name (NMDeviceBt *self, const char *name);
void _nm_device_bt_notify_set_connected (NMDeviceBt *self,
gboolean connected);
#endif /* __NETWORKMANAGER_DEVICE_BT_H__ */

View file

@ -2,35 +2,219 @@
#include "nm-default.h"
#include <glib-unix.h>
#include "devices/bluetooth/nm-bluez5-dun.h"
#include "nm-test-utils-core.h"
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_BT
#define _NMLOG(level, ...) \
nm_log ((level), _NMLOG_DOMAIN, \
NULL, NULL, \
"bt%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
NM_PRINT_FMT_QUOTED (gl.argv_cmd, "[", gl.argv_cmd, "]", "") \
_NM_UTILS_MACRO_REST (__VA_ARGS__))
/*****************************************************************************/
struct {
int argc;
const char *const*argv;
const char *argv_cmd;
GMainLoop *loop;
} gl;
typedef struct _MainCmdInfo {
const char *name;
int (*main_func) (const struct _MainCmdInfo *main_cmd_info);
} MainCmdInfo;
/*****************************************************************************/
#if WITH_BLUEZ5_DUN
typedef struct {
NMBluez5DunContext *dun_context;
GCancellable *cancellable;
guint timeout_id;
guint sig_term_id;
guint sig_int_id;
} DunConnectData;
static void
_dun_connect_cb (NMBluez5DunContext *context,
const char *rfcomm_dev,
GError *error,
gpointer user_data)
{
DunConnectData *dun_connect_data = user_data;
g_assert (dun_connect_data);
g_assert (!dun_connect_data->dun_context);
g_assert ((!!error) != (!!rfcomm_dev));
if (rfcomm_dev && !context) {
_LOGI ("dun-connect notifies path \"%s\". Wait longer...", rfcomm_dev);
return;
}
if (rfcomm_dev) {
g_assert (context);
_LOGI ("dun-connect completed with path \"%s\"", rfcomm_dev);
} else {
g_assert (!context);
_LOGI ("dun-connect failed with error: %s", error->message);
}
dun_connect_data->dun_context = context;
g_main_loop_quit (gl.loop);
}
static void
_dun_notify_tty_hangup_cb (NMBluez5DunContext *context,
gpointer user_data)
{
_LOGI ("dun-connect: notified TTY hangup");
}
static gboolean
_timeout_cb (gpointer user_data)
{
DunConnectData *dun_connect_data = user_data;
_LOGI ("timeout");
dun_connect_data->timeout_id = 0;
if (dun_connect_data->cancellable)
g_cancellable_cancel (dun_connect_data->cancellable);
return G_SOURCE_REMOVE;
}
static gboolean
_sig_xxx_cb (DunConnectData *dun_connect_data, int sigid)
{
_LOGI ("signal %s received", sigid == SIGTERM ? "SIGTERM" : "SIGINT");
g_main_loop_quit (gl.loop);
return G_SOURCE_CONTINUE;
}
static gboolean
_sig_term_cb (gpointer user_data)
{
return _sig_xxx_cb (user_data, SIGTERM);
}
static gboolean
_sig_int_cb (gpointer user_data)
{
return _sig_xxx_cb (user_data, SIGINT);
}
#endif
static int
do_dun_connect (const MainCmdInfo *main_cmd_info)
{
#if WITH_BLUEZ5_DUN
gs_unref_object GCancellable *cancellable = NULL;
gs_free_error GError *error = NULL;
const char *adapter;
const char *remote;
DunConnectData dun_connect_data = { };
if (gl.argc < 4) {
_LOGE ("missing arguments \"adapter\" and \"remote\"");
return -1;
}
adapter = gl.argv[2];
remote = gl.argv[3];
cancellable = g_cancellable_new ();
dun_connect_data.cancellable = cancellable;
if (!nm_bluez5_dun_connect (adapter,
remote,
cancellable,
_dun_connect_cb,
&dun_connect_data,
_dun_notify_tty_hangup_cb,
&dun_connect_data,
&error)) {
_LOGE ("connect failed to start: %s", error->message);
return -1;
}
dun_connect_data.timeout_id = g_timeout_add (60000, _timeout_cb, &dun_connect_data);
g_main_loop_run (gl.loop);
nm_clear_g_source (&dun_connect_data.timeout_id);
if (dun_connect_data.dun_context) {
dun_connect_data.sig_term_id = g_unix_signal_add (SIGTERM, _sig_term_cb, &dun_connect_data);
dun_connect_data.sig_int_id = g_unix_signal_add (SIGINT, _sig_int_cb, &dun_connect_data);
g_main_loop_run (gl.loop);
nm_clear_g_source (&dun_connect_data.sig_term_id);
nm_clear_g_source (&dun_connect_data.sig_int_id);
nm_bluez5_dun_disconnect (g_steal_pointer (&dun_connect_data.dun_context));
}
return 0;
#else
_LOGE ("compiled without bluetooth DUN support");
return 1;
#endif
}
/*****************************************************************************/
NMTST_DEFINE ();
int
main (int argc, char **argv)
{
NMBluez5DunContext *dun_context;
GMainLoop *loop;
static const MainCmdInfo main_cmd_infos[] = {
{ .name = "dun-connect", .main_func = do_dun_connect, },
};
int exit_code = 0;
guint i;
if (!g_getenv ("G_MESSAGES_DEBUG"))
g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
nmtst_init_with_logging (&argc, &argv, "DEBUG", "ALL");
nm_log_info (LOGD_BT, "bluetooth test util start");
nm_logging_init (NULL, TRUE);
dun_context = nm_bluez5_dun_new ("aa:bb:cc:dd:ee:ff",
"aa:bb:cc:dd:ee:fa");
gl.argv = (const char *const*) argv;
gl.argc = argc;
gl.loop = g_main_loop_new (NULL, FALSE);
loop = g_main_loop_new (NULL, FALSE);
_LOGI ("bluetooth test util start");
g_main_loop_unref (loop);
gl.argv_cmd = argc >= 2 ? argv[1] : NULL;
nm_bluez5_dun_free (dun_context);
for (i = 0; i < G_N_ELEMENTS (main_cmd_infos); i++) {
if (nm_streq0 (main_cmd_infos[i].name, gl.argv_cmd)) {
_LOGD ("start \"%s\"", gl.argv_cmd);
exit_code = main_cmd_infos[i].main_func (&main_cmd_infos[i]);
_LOGD ("completed with %d", exit_code);
break;
}
}
if (gl.argv_cmd && i >= G_N_ELEMENTS (main_cmd_infos)) {
nm_log_err (LOGD_BT, "invalid command \"%s\"", gl.argv_cmd);
exit_code = -1;
}
return EXIT_SUCCESS;
nm_clear_pointer (&gl.loop, g_main_loop_unref);
return exit_code;
}

View file

@ -23,7 +23,9 @@ _LOG_DECLARE_SELF(NMDeviceBridge);
struct _NMDeviceBridge {
NMDevice parent;
GCancellable *bt_cancellable;
bool vlan_configured:1;
bool bt_registered:1;
};
struct _NMDeviceBridgeClass {
@ -51,6 +53,7 @@ check_connection_available (NMDevice *device,
const char *specific_object,
GError **error)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
NMSettingBluetooth *s_bt;
if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_available (device, connection, flags, specific_object, error))
@ -67,13 +70,18 @@ check_connection_available (NMDevice *device,
}
bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt);
if (!nm_bt_vtable_network_server->is_available (nm_bt_vtable_network_server, bdaddr)) {
if (!nm_bt_vtable_network_server->is_available (nm_bt_vtable_network_server,
bdaddr,
( self->bt_cancellable
|| self->bt_registered)
? device
: NULL)) {
if (bdaddr)
nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"not suitable NAP device \"%s\" available", bdaddr);
"no suitable NAP device \"%s\" available", bdaddr);
else
nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"not suitable NAP device available");
"no suitable NAP device available");
return FALSE;
}
}
@ -505,9 +513,53 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
return NM_ACT_STAGE_RETURN_SUCCESS;
}
static void
_bt_register_bridge_cb (GError *error,
gpointer user_data)
{
NMDeviceBridge *self;
if (nm_utils_error_is_cancelled (error, FALSE))
return;
self = user_data;
g_clear_object (&self->bt_cancellable);
if (error) {
_LOGD (LOGD_DEVICE, "bluetooth NAP server failed to register bridge: %s", error->message);
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_BT_FAILED);
return;
}
nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self));
}
void
_nm_device_bridge_notify_unregister_bt_nap (NMDevice *device,
const char *reason)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
_LOGD (LOGD_DEVICE, "bluetooth NAP server unregistered from bridge: %s%s",
reason,
self->bt_registered ? "" : " (was no longer registered)");
nm_clear_g_cancellable (&self->bt_cancellable);
if (self->bt_registered) {
self->bt_registered = FALSE;
nm_device_state_changed (device,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_BT_FAILED);
}
}
static NMActStageReturn
act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
NMConnection *connection;
NMSettingBluetooth *s_bt;
@ -515,14 +567,32 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
s_bt = _nm_connection_get_setting_bluetooth_for_nap (connection);
if (s_bt) {
if ( !nm_bt_vtable_network_server
|| !nm_bt_vtable_network_server->register_bridge (nm_bt_vtable_network_server,
nm_setting_bluetooth_get_bdaddr (s_bt),
device)) {
/* The HCI we could use is no longer present. */
*out_failure_reason = NM_DEVICE_STATE_REASON_REMOVED;
gs_free_error GError *error = NULL;
if (!nm_bt_vtable_network_server) {
_LOGD (LOGD_DEVICE, "bluetooth NAP server failed because bluetooth plugin not available");
*out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED;
return NM_ACT_STAGE_RETURN_FAILURE;
}
if (self->bt_cancellable)
return NM_ACT_STAGE_RETURN_POSTPONE;
self->bt_cancellable = g_cancellable_new ();
if (!nm_bt_vtable_network_server->register_bridge (nm_bt_vtable_network_server,
nm_setting_bluetooth_get_bdaddr (s_bt),
device,
self->bt_cancellable,
_bt_register_bridge_cb,
device,
&error)) {
_LOGD (LOGD_DEVICE, "bluetooth NAP server failed to register bridge: %s", error->message);
*out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED;
return NM_ACT_STAGE_RETURN_FAILURE;
}
self->bt_registered = TRUE;
return NM_ACT_STAGE_RETURN_POSTPONE;
}
return NM_ACT_STAGE_RETURN_SUCCESS;
@ -533,11 +603,15 @@ deactivate (NMDevice *device)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
_LOGD (LOGD_DEVICE, "deactivate bridge%s",
self->bt_registered ? " (registered as NAP bluetooth device)" : "");
self->vlan_configured = FALSE;
if (nm_bt_vtable_network_server) {
/* always call unregister. It does nothing if the device
* isn't registered as a hotspot bridge. */
nm_clear_g_cancellable (&self->bt_cancellable);
if (self->bt_registered) {
self->bt_registered = FALSE;
nm_bt_vtable_network_server->unregister_bridge (nm_bt_vtable_network_server,
device);
}

View file

@ -23,4 +23,7 @@ GType nm_device_bridge_get_type (void);
extern const NMBtVTableNetworkServer *nm_bt_vtable_network_server;
void _nm_device_bridge_notify_unregister_bt_nap (NMDevice *device,
const char *reason);
#endif /* __NETWORKMANAGER_DEVICE_BRIDGE_H__ */

View file

@ -23,7 +23,6 @@
enum {
DEVICE_ADDED,
COMPONENT_ADDED,
LAST_SIGNAL
};
@ -33,17 +32,6 @@ G_DEFINE_ABSTRACT_TYPE (NMDeviceFactory, nm_device_factory, G_TYPE_OBJECT)
/*****************************************************************************/
gboolean
nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component)
{
gboolean consumed = FALSE;
g_return_val_if_fail (NM_IS_DEVICE_FACTORY (factory), FALSE);
g_signal_emit (factory, signals[COMPONENT_ADDED], 0, component, &consumed);
return consumed;
}
static void
nm_device_factory_get_supported_types (NMDeviceFactory *factory,
const NMLinkType **out_link_types,
@ -182,16 +170,8 @@ nm_device_factory_class_init (NMDeviceFactoryClass *klass)
signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMDeviceFactoryClass, device_added),
NULL, NULL, NULL,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1, NM_TYPE_DEVICE);
signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMDeviceFactoryClass, component_added),
g_signal_accumulator_true_handled, NULL, NULL,
G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT);
}
/*****************************************************************************/

View file

@ -23,7 +23,6 @@
#define NM_IS_DEVICE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_FACTORY))
#define NM_DEVICE_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactoryClass))
#define NM_DEVICE_FACTORY_COMPONENT_ADDED "component-added"
#define NM_DEVICE_FACTORY_DEVICE_ADDED "device-added"
typedef struct {
@ -118,36 +117,6 @@ typedef struct {
NMConnection *connection,
gboolean *out_ignore);
/* Signals */
/**
* device_added:
* @factory: the #NMDeviceFactory
* @device: the new #NMDevice subclass
*
* The factory emits this signal if it finds a new device by itself.
*/
void (*device_added) (NMDeviceFactory *factory, NMDevice *device);
/**
* component_added:
* @factory: the #NMDeviceFactory
* @component: a new component which existing devices may wish to claim
*
* The factory emits this signal when an appearance of some component
* native to it could be interesting to some of the already existing devices.
* The devices then indicate if they took interest in claiming the component.
*
* For example, the WWAN factory may indicate that a new modem is available,
* which an existing Bluetooth device may wish to claim. It emits a signal
* passing the modem instance around to see if any device claims it.
* If no device claims the component, the plugin is allowed to create a new
* #NMDevice instance for that component and emit the "device-added" signal.
*
* Returns: %TRUE if the component was claimed by a device, %FALSE if not
*/
gboolean (*component_added) (NMDeviceFactory *factory, GObject *component);
} NMDeviceFactoryClass;
GType nm_device_factory_get_type (void);
@ -189,10 +158,6 @@ NMDevice * nm_device_factory_create_device (NMDeviceFactory *factory,
gboolean *out_ignore,
GError **error);
/* For use by implementations */
gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory,
GObject *component);
#define NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(...) \
{ static NMLinkType const _link_types_declared[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; _link_types = _link_types_declared; }
#define NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(...) \

View file

@ -4785,42 +4785,24 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
return TRUE;
}
/**
* nm_device_notify_component_added():
* @self: the #NMDevice
* @component: the component being added by a plugin
*
* Called by the manager to notify the device that a new component has
* been found. The device implementation should return %TRUE if it
* wishes to claim the component, or %FALSE if it cannot.
*
* Returns: %TRUE to claim the component, %FALSE if the component cannot be
* claimed.
*/
gboolean
nm_device_notify_component_added (NMDevice *self, GObject *component)
void
nm_device_notify_availability_maybe_changed (NMDevice *self)
{
NMDeviceClass *klass;
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
klass = NM_DEVICE_GET_CLASS (self);
if (priv->state == NM_DEVICE_STATE_DISCONNECTED) {
/* A device could have stayed disconnected because it would
* want to register with a network server that now become
* available. */
nm_device_recheck_available_connections (self);
if (g_hash_table_size (priv->available_connections) > 0)
nm_device_emit_recheck_auto_activate (self);
}
if (priv->state != NM_DEVICE_STATE_DISCONNECTED)
return;
if (klass->component_added)
return klass->component_added (self, component);
return FALSE;
/* A device could have stayed disconnected because it would
* want to register with a network server that now become
* available. */
nm_device_recheck_available_connections (self);
if (g_hash_table_size (priv->available_connections) > 0)
nm_device_emit_recheck_auto_activate (self);
}
/**

View file

@ -416,23 +416,6 @@ typedef struct _NMDeviceClass {
int new_ifindex,
NMDevice *new_parent);
/**
* component_added:
* @self: the #NMDevice
* @component: the component (device, modem, etc) which was added
*
* Notifies @self that a new component that a device might be interested
* in was detected by some device factory. It may include an object of
* %GObject subclass to help the devices decide whether it claims that
* particular object itself and the emitting factory should not.
*
* Returns: %TRUE if the component was claimed exclusively and no further
* devices should be notified of the new component. %FALSE to indicate
* that the component was not exclusively claimed and other devices should
* be notified.
*/
gboolean (* component_added) (NMDevice *self, GObject *component);
gboolean (* owns_iface) (NMDevice *self, const char *iface);
NMConnection * (* new_default_connection) (NMDevice *self);
@ -809,7 +792,7 @@ gboolean nm_device_check_connection_available (NMDevice *device,
const char *specific_object,
GError **error);
gboolean nm_device_notify_component_added (NMDevice *device, GObject *component);
void nm_device_notify_availability_maybe_changed (NMDevice *self);
gboolean nm_device_owns_iface (NMDevice *device, const char *iface);
@ -869,12 +852,22 @@ void nm_device_check_connectivity_cancel (NMDeviceConnectivityHandle *handle);
NMConnectivityState nm_device_get_connectivity_state (NMDevice *self, int addr_family);
typedef struct _NMBtVTableNetworkServer NMBtVTableNetworkServer;
typedef void (*NMBtVTableRegisterCallback) (GError *error,
gpointer user_data);
struct _NMBtVTableNetworkServer {
gboolean (*is_available) (const NMBtVTableNetworkServer *vtable,
const char *addr);
const char *addr,
NMDevice *device_accept_busy);
gboolean (*register_bridge) (const NMBtVTableNetworkServer *vtable,
const char *addr,
NMDevice *device);
NMDevice *device,
GCancellable *cancellable,
NMBtVTableRegisterCallback callback,
gpointer callback_user_data,
GError **error);
gboolean (*unregister_bridge) (const NMBtVTableNetworkServer *vtable,
NMDevice *device);
};

View file

@ -1029,6 +1029,8 @@ nm_modem_act_stage1_prepare (NMModem *self,
NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
NMConnection *connection;
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE);
if (priv->act_request)
g_object_unref (priv->act_request);
priv->act_request = g_object_ref (req);
@ -1066,8 +1068,11 @@ nm_modem_act_stage1_prepare (NMModem *self,
void
nm_modem_act_stage2_config (NMModem *self)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
NMModemPrivate *priv;
g_return_if_fail (NM_IS_MODEM (self));
priv = NM_MODEM_GET_PRIVATE (self);
/* Clear secrets tries counter since secrets were successfully used
* already if we get here.
*/

View file

@ -67,10 +67,6 @@ modem_added_cb (NMModemManager *manager,
gs_unref_object NMDevice *device = NULL;
const char *driver;
/* Do nothing if the modem was consumed by some other plugin */
if (nm_device_factory_emit_component_added (NM_DEVICE_FACTORY (self), G_OBJECT (modem)))
return;
if (nm_modem_is_claimed (modem))
return;
@ -80,9 +76,10 @@ modem_added_cb (NMModemManager *manager,
* it. The rfcomm port (and thus the modem) gets created automatically
* by the Bluetooth code during the connection process.
*/
if (driver && strstr (driver, "bluetooth")) {
nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)",
nm_modem_get_control_port (modem));
if ( driver
&& strstr (driver, "bluetooth")) {
nm_log_dbg (LOGD_MB, "WWAN factory ignores bluetooth modem '%s' which should be handled by bluetooth plugin",
nm_modem_get_control_port (modem));
return;
}

View file

@ -3188,22 +3188,6 @@ factory_device_added_cb (NMDeviceFactory *factory,
}
}
static gboolean
factory_component_added_cb (NMDeviceFactory *factory,
GObject *component,
gpointer user_data)
{
NMManager *self = user_data;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDevice *device;
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
if (nm_device_notify_component_added (device, component))
return TRUE;
}
return FALSE;
}
static void
_register_device_factory (NMDeviceFactory *factory, gpointer user_data)
{
@ -3213,10 +3197,18 @@ _register_device_factory (NMDeviceFactory *factory, gpointer user_data)
NM_DEVICE_FACTORY_DEVICE_ADDED,
G_CALLBACK (factory_device_added_cb),
self);
g_signal_connect (factory,
NM_DEVICE_FACTORY_COMPONENT_ADDED,
G_CALLBACK (factory_component_added_cb),
self);
}
/*****************************************************************************/
void
nm_manager_notify_device_availibility_maybe_changed (NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDevice *device;
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst)
nm_device_notify_availability_maybe_changed (device);
}
/*****************************************************************************/

View file

@ -191,4 +191,6 @@ void nm_manager_dbus_set_property_handle (NMDBusObject *obj,
NMMetered nm_manager_get_metered (NMManager *self);
void nm_manager_notify_device_availibility_maybe_changed (NMManager *self);
#endif /* __NETWORKMANAGER_MANAGER_H__ */