Commit 4154d961 authored by Thomas Haller's avatar Thomas Haller

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.
parent 878d4963
......@@ -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)
......
......@@ -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,
......
......@@ -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.
......
......@@ -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
......
sources = files(
'nm-bluez-device.c',
'nm-bluez-manager.c',
'nm-bluez5-manager.c',
'nm-bt-error.c',
'nm-device-bt.c',
)
......
This diff is collapsed.
// 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__ */
This source diff could not be displayed because it is too large. You can view the blob instead.
// 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__ */
This diff is collapsed.
......@@ -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__ */
This diff is collapsed.
// 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__ */
This diff is collapsed.
......@@ -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__ */
......@@ -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);
gl.argv = (const char *const*) argv;
gl.argc = argc;
gl.loop = g_main_loop_new (NULL, FALSE);
dun_context = nm_bluez5_dun_new ("aa:bb:cc:dd:ee:ff",
"aa:bb:cc:dd:ee:fa");
_LOGI ("bluetooth test util start");
loop = g_main_loop_new (NULL, FALSE);
gl.argv_cmd = argc >= 2 ? argv[1] : NULL;
g_main_loop_unref (loop);
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;
}
nm_bluez5_dun_free (dun_context);
nm_clear_pointer (&gl.loop, g_main_loop_unref);
return EXIT_SUCCESS;
return exit_code;
}
......@@ -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);
}
......
......@@ -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__ */
......@@ -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;