diff options
Diffstat (limited to 'src/devices/bluetooth/nm-device-bt.c')
-rw-r--r-- | src/devices/bluetooth/nm-device-bt.c | 880 |
1 files changed, 522 insertions, 358 deletions
diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index b8acc90577..61a7759e11 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -10,8 +10,9 @@ #include <stdio.h> +#include "nm-core-internal.h" #include "nm-bluez-common.h" -#include "nm-bluez-device.h" +#include "nm-bluez-manager.h" #include "devices/nm-device-private.h" #include "ppp/nm-ppp-manager.h" #include "nm-setting-connection.h" @@ -35,10 +36,12 @@ _LOG_DECLARE_SELF(NMDeviceBt); /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE_BASE ( - PROP_BT_NAME, +NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceBt, + PROP_BT_BDADDR, + PROP_BT_BZ_MGR, PROP_BT_CAPABILITIES, - PROP_BT_DEVICE, + PROP_BT_DBUS_PATH, + PROP_BT_NAME, ); enum { @@ -51,24 +54,38 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { NMModemManager *modem_manager; - gboolean mm_running; + NMBluezManager *bz_mgr; - NMBluezDevice *bt_device; + char *dbus_path; char *bdaddr; char *name; - guint32 capabilities; - gboolean connected; - gboolean have_iface; + char *connect_rfcomm_iface; + + GSList *connect_modem_candidates; - char *rfcomm_iface; NMModem *modem; - guint timeout_id; - GCancellable *cancellable; + GCancellable *connect_bz_cancellable; + + gulong connect_watch_link_id; + + guint connect_watch_link_idle_id; + + guint connect_wait_modem_id; + + NMBluetoothCapabilities capabilities:6; + + NMBluetoothCapabilities connect_bt_type:6; /* BT type of the current connection */ + + NMDeviceStageState stage1_bt_state:3; + NMDeviceStageState stage1_modem_prepare_state:3; + + bool is_connected:1; + + bool mm_running:1; - guint32 bt_type; /* BT type of the current connection */ } NMDeviceBtPrivate; struct _NMDeviceBt { @@ -82,42 +99,65 @@ struct _NMDeviceBtClass { G_DEFINE_TYPE (NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) -#define NM_DEVICE_BT_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceBt, NM_IS_DEVICE_BT) - -/*****************************************************************************/ - -static gboolean modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *out_failure_reason); +#define NM_DEVICE_BT_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceBt, NM_IS_DEVICE_BT, NMDevice) /*****************************************************************************/ -guint32 nm_device_bt_get_capabilities (NMDeviceBt *self) +NMBluetoothCapabilities nm_device_bt_get_capabilities (NMDeviceBt *self) { g_return_val_if_fail (NM_IS_DEVICE_BT (self), NM_BT_CAPABILITY_NONE); return NM_DEVICE_BT_GET_PRIVATE (self)->capabilities; } -static guint32 +static NMBluetoothCapabilities get_connection_bt_type (NMConnection *connection) { NMSettingBluetooth *s_bt; const char *bt_type; s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) - return NM_BT_CAPABILITY_NONE; - bt_type = nm_setting_bluetooth_get_connection_type (s_bt); - g_assert (bt_type); - - if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)) - return NM_BT_CAPABILITY_DUN; - else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) - return NM_BT_CAPABILITY_NAP; + if (s_bt) { + bt_type = nm_setting_bluetooth_get_connection_type (s_bt); + if (bt_type) { + if (nm_streq (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)) + return NM_BT_CAPABILITY_DUN; + else if (nm_streq (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) + return NM_BT_CAPABILITY_NAP; + } + } return NM_BT_CAPABILITY_NONE; } +static gboolean +get_connection_bt_type_check (NMDeviceBt *self, + NMConnection *connection, + NMBluetoothCapabilities *out_bt_type, + GError **error) +{ + NMBluetoothCapabilities bt_type; + + bt_type = get_connection_bt_type (connection); + + NM_SET_OUT (out_bt_type, bt_type); + + if (bt_type == NM_BT_CAPABILITY_NONE) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "profile is not a PANU/DUN bluetooth type"); + return FALSE; + } + + if (!NM_FLAGS_ALL (NM_DEVICE_BT_GET_PRIVATE (self)->capabilities, bt_type)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support bluetooth type"); + return FALSE; + } + + return TRUE; +} + static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { @@ -129,17 +169,24 @@ can_auto_connect (NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - guint32 bt_type; + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + NMBluetoothCapabilities bt_type; nm_assert (!specific_object || !*specific_object); if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->can_auto_connect (device, sett_conn, NULL)) return FALSE; + if (!get_connection_bt_type_check (self, + nm_settings_connection_get_connection (sett_conn), + &bt_type, + NULL)) + return FALSE; + /* Can't auto-activate a DUN connection without ModemManager */ - bt_type = get_connection_bt_type (nm_settings_connection_get_connection (sett_conn)); - if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) + if ( bt_type == NM_BT_CAPABILITY_DUN + && priv->mm_running == FALSE) return FALSE; return TRUE; @@ -148,20 +195,16 @@ can_auto_connect (NMDevice *device, static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); NMSettingBluetooth *s_bt; const char *bdaddr; - guint32 bt_type; if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - bt_type = get_connection_bt_type (connection); - if (!NM_FLAGS_ALL (priv->capabilities, bt_type)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not support bluetooth type of profile"); + if (!get_connection_bt_type_check (self, connection, NULL, error)) return FALSE; - } s_bt = nm_connection_get_setting_bluetooth (connection); @@ -187,18 +230,15 @@ check_connection_available (NMDevice *device, const char *specific_object, GError **error) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - guint32 bt_type; + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + NMBluetoothCapabilities bt_type; - bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not support bluetooth type"); + if (!get_connection_bt_type_check (self, connection, &bt_type, error)) return FALSE; - } - /* DUN connections aren't available without ModemManager */ - if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) { + if ( bt_type == NM_BT_CAPABILITY_DUN + && !priv->mm_running) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "ModemManager missing for DUN profile"); return FALSE; @@ -214,11 +254,12 @@ complete_connection (NMDevice *device, NMConnection *const*existing_connections, GError **error) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); NMSettingBluetooth *s_bt; const char *setting_bdaddr; const char *ctype; - gboolean is_dun = FALSE, is_pan = FALSE; + gboolean is_dun = FALSE; + gboolean is_pan = FALSE; NMSettingGsm *s_gsm; NMSettingCdma *s_cdma; NMSettingSerial *s_serial; @@ -261,7 +302,10 @@ complete_connection (NMDevice *device, } /* PAN can't use any DUN-related settings */ - if (s_gsm || s_cdma || s_serial || s_ppp) { + if ( s_gsm + || s_cdma + || s_serial + || s_ppp) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, @@ -291,7 +335,8 @@ complete_connection (NMDevice *device, } /* Need at least a GSM or a CDMA setting */ - if (!s_gsm && !s_cdma) { + if ( !s_gsm + && !s_cdma) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, @@ -428,20 +473,19 @@ static void modem_auth_result (NMModem *modem, GError *error, gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); + + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); if (error) { nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - } else { - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - /* Otherwise, on success for GSM/CDMA secrets we need to schedule modem stage1 again */ - g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); - if (!modem_stage1 (NM_DEVICE_BT (device), priv->modem, &failure_reason)) - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, failure_reason); + return; } + + priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_INIT; + nm_device_activate_schedule_stage1_device_prepare (device); } static void @@ -450,45 +494,33 @@ modem_prepare_result (NMModem *modem, guint i_reason, gpointer user_data) { - NMDeviceBt *self = NM_DEVICE_BT (user_data); - NMDevice *device = NM_DEVICE (self); + NMDeviceBt *self = user_data; + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); NMDeviceStateReason reason = i_reason; NMDeviceState state; - state = nm_device_get_state (device); - g_return_if_fail (state == NM_DEVICE_STATE_CONFIG || state == NM_DEVICE_STATE_NEED_AUTH); - - if (success) { - NMActRequest *req; - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - req = nm_device_get_act_request (device); - g_return_if_fail (req); - - ret = nm_modem_act_stage2_config (modem, req, &failure_reason); - switch (ret) { - case NM_ACT_STAGE_RETURN_POSTPONE: - break; - case NM_ACT_STAGE_RETURN_SUCCESS: - nm_device_activate_schedule_stage3_ip_config_start (device); - break; - case NM_ACT_STAGE_RETURN_FAILURE: - default: - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, failure_reason); - break; - } - } else { + state = nm_device_get_state (NM_DEVICE (self)); + + g_return_if_fail (NM_IN_SET (state, NM_DEVICE_STATE_PREPARE, + NM_DEVICE_STATE_NEED_AUTH)); + + nm_assert (priv->stage1_modem_prepare_state == NM_DEVICE_STAGE_STATE_PENDING); + + if (!success) { if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT) { /* If the connect failed because the SIM PIN was wrong don't allow * the device to be auto-activated anymore, which would risk locking * the SIM if the incorrect PIN continues to be used. */ - nm_device_autoconnect_blocked_set (device, NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN); + nm_device_autoconnect_blocked_set (NM_DEVICE (self), NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN); } - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, reason); + return; } + + priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_COMPLETED; + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); } static void @@ -497,7 +529,7 @@ device_state_changed (NMDevice *device, NMDeviceState old_state, NMDeviceStateReason reason) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); if (priv->modem) nm_modem_device_state_changed (priv->modem, new_state, old_state); @@ -506,7 +538,8 @@ device_state_changed (NMDevice *device, * since the device could be both DUN and NAP capable and thus may not * change state (which rechecks available connections) when MM comes and goes. */ - if (priv->mm_running && (priv->capabilities & NM_BT_CAPABILITY_DUN)) + if ( priv->mm_running + && NM_FLAGS_HAS (priv->capabilities, NM_BT_CAPABILITY_DUN)) nm_device_recheck_available_connections (device); } @@ -528,8 +561,10 @@ modem_ip4_config_result (NMModem *modem, nm_device_ip_method_failed (device, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else - nm_device_activate_schedule_ip_config_result (device, AF_INET, NM_IP_CONFIG_CAST (config)); + return; + } + + nm_device_activate_schedule_ip_config_result (device, AF_INET, NM_IP_CONFIG_CAST (config)); } static void @@ -545,29 +580,6 @@ ip_ifindex_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) } } -static gboolean -modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *out_failure_reason) -{ - NMActRequest *req; - NMActStageReturn ret; - - req = nm_device_get_act_request (NM_DEVICE (self)); - g_return_val_if_fail (req, FALSE); - - ret = nm_modem_act_stage1_prepare (modem, req, out_failure_reason); - switch (ret) { - case NM_ACT_STAGE_RETURN_POSTPONE: - case NM_ACT_STAGE_RETURN_SUCCESS: - /* Success, wait for the 'prepare-result' signal */ - return TRUE; - case NM_ACT_STAGE_RETURN_FAILURE: - default: - break; - } - - return FALSE; -} - /*****************************************************************************/ static void @@ -577,7 +589,7 @@ modem_cleanup (NMDeviceBt *self) if (priv->modem) { g_signal_handlers_disconnect_matched (priv->modem, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); - g_clear_object (&priv->modem); + nm_clear_pointer (&priv->modem, nm_modem_unclaim); } } @@ -592,11 +604,13 @@ modem_state_cb (NMModem *modem, NMDevice *device = NM_DEVICE (user_data); NMDeviceState dev_state = nm_device_get_state (device); - if (new_state <= NM_MODEM_STATE_DISABLING && old_state > NM_MODEM_STATE_DISABLING) { + if ( new_state <= NM_MODEM_STATE_DISABLING + && old_state > NM_MODEM_STATE_DISABLING) { /* Will be called whenever something external to NM disables the * modem directly through ModemManager. */ - if (nm_device_is_activating (device) || dev_state == NM_DEVICE_STATE_ACTIVATED) { + if ( nm_device_is_activating (device) + || dev_state == NM_DEVICE_STATE_ACTIVATED) { nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_USER_REQUESTED); @@ -604,13 +618,15 @@ modem_state_cb (NMModem *modem, } } - if (new_state < NM_MODEM_STATE_CONNECTING && - old_state >= NM_MODEM_STATE_CONNECTING && - dev_state >= NM_DEVICE_STATE_NEED_AUTH && - dev_state <= NM_DEVICE_STATE_ACTIVATED) { + if ( new_state < NM_MODEM_STATE_CONNECTING + && old_state >= NM_MODEM_STATE_CONNECTING + && dev_state >= NM_DEVICE_STATE_NEED_AUTH + && dev_state <= NM_DEVICE_STATE_ACTIVATED) { /* Fail the device if the modem disconnects unexpectedly while the * device is activating/activated. */ - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); return; } } @@ -621,66 +637,56 @@ modem_removed_cb (NMModem *modem, gpointer user_data) NMDeviceBt *self = NM_DEVICE_BT (user_data); NMDeviceState state; - /* Fail the device if the modem was removed while active */ state = nm_device_get_state (NM_DEVICE (self)); - if ( state == NM_DEVICE_STATE_ACTIVATED - || nm_device_is_activating (NM_DEVICE (self))) { + if ( nm_device_is_activating (NM_DEVICE (self)) + || state == NM_DEVICE_STATE_ACTIVATED) { nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); - } else - modem_cleanup (self); + return; + } + + modem_cleanup (self); } static gboolean -component_added (NMDevice *device, GObject *component) +modem_try_claim (NMDeviceBt *self, + NMModem *modem) { - NMDeviceBt *self = NM_DEVICE_BT (device); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - NMModem *modem; + gs_free char *rfcomm_base_name = NULL; NMDeviceState state; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - if ( !component - || !NM_IS_MODEM (component)) + if (priv->modem) { + if (priv->modem == modem) + return TRUE; return FALSE; + } - modem = NM_MODEM (component); - if (!priv->rfcomm_iface) + if (nm_modem_is_claimed (modem)) return FALSE; - { - gs_free char *base = NULL; - - base = g_path_get_basename (priv->rfcomm_iface); - if (!nm_streq (base, nm_modem_get_control_port (modem))) - return FALSE; - } + if (!priv->connect_rfcomm_iface) + return FALSE; - /* Got the modem */ - nm_clear_g_source (&priv->timeout_id); - nm_clear_g_cancellable (&priv->cancellable); + rfcomm_base_name = g_path_get_basename (priv->connect_rfcomm_iface); + if (!nm_streq0 (rfcomm_base_name, nm_modem_get_control_port (modem))) + return FALSE; - /* Can only accept the modem in stage2, but since the interface matched + /* Can only accept the modem in stage1, but since the interface matched * what we were expecting, don't let anything else claim the modem either. */ state = nm_device_get_state (NM_DEVICE (self)); - if (state != NM_DEVICE_STATE_CONFIG) { - _LOGW (LOGD_BT | LOGD_MB, + if (state != NM_DEVICE_STATE_PREPARE) { + _LOGD (LOGD_BT | LOGD_MB, "modem found but device not in correct state (%d)", nm_device_get_state (NM_DEVICE (self))); - return TRUE; + return FALSE; } - _LOGI (LOGD_BT | LOGD_MB, - "Activation: (bluetooth) Stage 2 of 5 (Device Configure) modem found."); + priv->modem = nm_modem_claim (modem); + priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_INIT; - if (priv->modem) { - g_warn_if_reached (); - modem_cleanup (self); - } - - priv->modem = g_object_ref (modem); g_signal_connect (modem, NM_MODEM_PPP_STATS, G_CALLBACK (ppp_stats), self); g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), self); g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), self); @@ -689,92 +695,187 @@ component_added (NMDevice *device, GObject *component) g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self); g_signal_connect (modem, NM_MODEM_STATE_CHANGED, G_CALLBACK (modem_state_cb), self); g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); - g_signal_connect (modem, "notify::" NM_MODEM_IP_IFINDEX, G_CALLBACK (ip_ifindex_changed_cb), self); - /* Kick off the modem connection */ - if (!modem_stage1 (self, modem, &failure_reason)) - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, failure_reason); + _LOGD (LOGD_BT | LOGD_MB, + "modem found"); return TRUE; } -static gboolean -modem_find_timeout (gpointer user_data) +static void +mm_modem_added_cb (NMModemManager *manager, + NMModem *modem, + gpointer user_data) +{ + NMDeviceBt *self = user_data; + NMDeviceBtPrivate *priv; + + if (!modem_try_claim (user_data, modem)) + return; + + priv = NM_DEVICE_BT_GET_PRIVATE (self); + + if (priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_COMPLETED) + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); +} + +/*****************************************************************************/ + +void +_nm_device_bt_notify_set_connected (NMDeviceBt *self, + gboolean connected) { - NMDeviceBt *self = NM_DEVICE_BT (user_data); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - priv->timeout_id = 0; - nm_clear_g_cancellable (&priv->cancellable); + connected = !!connected; + if (priv->is_connected == connected) + return; + + priv->is_connected = connected; + if ( connected + || priv->stage1_bt_state != NM_DEVICE_STAGE_STATE_COMPLETED + || nm_device_get_state (NM_DEVICE (self)) > NM_DEVICE_STATE_ACTIVATED) { + _LOGT (LOGD_BT, "set-connected: %d", connected); + return; + } + + _LOGT (LOGD_BT, "set-connected: %d (disconnecting device...)", connected); nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND); - return FALSE; + NM_DEVICE_STATE_REASON_CARRIER); } -static void -check_connect_continue (NMDeviceBt *self) +static gboolean +connect_watch_link_idle_cb (gpointer user_data) { - NMDevice *device = NM_DEVICE (self); + NMDeviceBt *self = user_data; NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean pan = (priv->bt_type == NM_BT_CAPABILITY_NAP); - gboolean dun = (priv->bt_type == NM_BT_CAPABILITY_DUN); + int ifindex; - if (!priv->connected || !priv->have_iface) - return; + priv->connect_watch_link_idle_id = 0; + + if (nm_device_get_state (NM_DEVICE (self)) <= NM_DEVICE_STATE_ACTIVATED) { + ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); + if ( ifindex > 0 + && !nm_platform_link_get (nm_device_get_platform (NM_DEVICE (self)), ifindex)) { + _LOGT (LOGD_BT, "device disappeared"); + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BT_FAILED); + } + } + + return G_SOURCE_REMOVE; +} + +static void +connect_watch_link_cb (NMPlatform *platform, + int obj_type_i, + int ifindex, + NMPlatformLink *info, + int change_type_i, + NMDevice *self) +{ + const NMPlatformSignalChangeType change_type = change_type_i; + NMDeviceBtPrivate *priv; + + /* bluez doesn't notify us when the connection disconnects. + * Neither does NMManager (or NMDevice) tell us when the ip-ifindex goes away. + * This is horrible, and should be improved. For now, watch the link ourself... */ + + if (NM_IN_SET (change_type, NM_PLATFORM_SIGNAL_CHANGED, + NM_PLATFORM_SIGNAL_REMOVED)) { + priv = NM_DEVICE_BT_GET_PRIVATE (self); + if (priv->connect_watch_link_idle_id == 0) + priv->connect_watch_link_idle_id = g_idle_add (connect_watch_link_idle_cb, self); + } +} - _LOGI (LOGD_BT, - "Activation: (bluetooth) Stage 2 of 5 (Device Configure) successful. Will connect via %s.", - dun ? "DUN" : (pan ? "PAN" : "unknown")); +static gboolean +connect_wait_modem_timeout (gpointer user_data) +{ + NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - nm_clear_g_source (&priv->timeout_id); - nm_clear_g_cancellable (&priv->cancellable); + /* since this timeout is longer than the connect timeout, we must have already + * hit the connect-timeout first or being connected. */ + nm_assert (priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_COMPLETED); - if (pan) { - /* Bluez says we're connected now. Start IP config. */ - nm_device_activate_schedule_stage3_ip_config_start (device); - } else if (dun) { - /* Wait for ModemManager to find the modem */ - priv->timeout_id = g_timeout_add_seconds (30, modem_find_timeout, self); + priv->connect_wait_modem_id = 0; + nm_clear_g_cancellable (&priv->connect_bz_cancellable); - _LOGI (LOGD_BT | LOGD_MB, - "Activation: (bluetooth) Stage 2 of 5 (Device Configure) waiting for modem to appear."); - } else - g_assert_not_reached (); + if (priv->modem) + _LOGD (LOGD_BT, "timeout connecting modem for DUN connection"); + else + _LOGD (LOGD_BT, "timeout finding modem for DUN connection"); + + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND); + return G_SOURCE_REMOVE; } static void -bluez_connect_cb (NMBluezDevice *bt_device, - const char *device_name, - GError *error, - gpointer user_data) +connect_bz_cb (NMBluezManager *bz_mgr, + gboolean is_complete, + const char *device_name, + GError *error, + gpointer user_data) { - gs_unref_object NMDeviceBt *self = user_data; - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + NMDeviceBt *self; + NMDeviceBtPrivate *priv; + char sbuf[100]; if (nm_utils_error_is_cancelled (error, FALSE)) return; - nm_clear_g_source (&priv->timeout_id); - g_clear_object (&priv->cancellable); + self = user_data; + priv = NM_DEVICE_BT_GET_PRIVATE (self); + + nm_assert (nm_device_is_activating (NM_DEVICE (self))); + nm_assert (NM_IN_SET ((NMBluetoothCapabilities) priv->connect_bt_type, NM_BT_CAPABILITY_DUN, + NM_BT_CAPABILITY_NAP)); - if (!nm_device_is_activating (NM_DEVICE (self))) + if (!is_complete) { + nm_assert (priv->connect_bt_type == NM_BT_CAPABILITY_DUN); + nm_assert (device_name); + nm_assert (!error); + + if (!nm_streq0 (priv->connect_rfcomm_iface, device_name)) { + nm_assert (!priv->connect_rfcomm_iface); + _LOGD (LOGD_BT, "DUN is still connecting but got serial port \"%s\" to claim modem", device_name); + g_free (priv->connect_rfcomm_iface); + priv->connect_rfcomm_iface = g_strdup (device_name); + } return; + } + + g_clear_object (&priv->connect_bz_cancellable); if (!device_name) { - _LOGW (LOGD_BT, "Error connecting with bluez: %s", error->message); + _LOGW (LOGD_BT, "%s connect request failed: %s", + nm_bluetooth_capability_to_string (priv->connect_bt_type, sbuf, sizeof (sbuf)), + error->message); nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); return; } - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - g_free (priv->rfcomm_iface); - priv->rfcomm_iface = g_strdup (device_name); - } else if (priv->bt_type == NM_BT_CAPABILITY_NAP) { + _LOGD (LOGD_BT, "%s connect request successful (%s)", + nm_bluetooth_capability_to_string (priv->connect_bt_type, sbuf, sizeof (sbuf)), + device_name); + + if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { + if (!nm_streq0 (priv->connect_rfcomm_iface, device_name)) { + nm_assert_not_reached (); + g_free (priv->connect_rfcomm_iface); + priv->connect_rfcomm_iface = g_strdup (device_name); + } + } else { + nm_assert (priv->connect_bt_type == NM_BT_CAPABILITY_NAP); if (!nm_device_set_ip_iface (NM_DEVICE (self), device_name)) { _LOGW (LOGD_BT, "Error connecting with bluez: cannot find device %s", device_name); nm_device_state_changed (NM_DEVICE (self), @@ -782,107 +883,121 @@ bluez_connect_cb (NMBluezDevice *bt_device, NM_DEVICE_STATE_REASON_BT_FAILED); return; } + priv->connect_watch_link_id = g_signal_connect (nm_device_get_platform (NM_DEVICE (self)), + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK (connect_watch_link_cb), + self); } - _LOGD (LOGD_BT, "connect request successful"); - - /* Stage 3 gets scheduled when Bluez says we're connected */ - priv->have_iface = TRUE; - check_connect_continue (self); -} - -static void -bluez_connected_changed (NMBluezDevice *bt_device, - GParamSpec *pspec, - NMDevice *device) -{ - NMDeviceBt *self = NM_DEVICE_BT (device); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean connected; - NMDeviceState state; - - state = nm_device_get_state (device); - connected = nm_bluez_device_get_connected (bt_device); - if (connected) { - if (state == NM_DEVICE_STATE_CONFIG) { - _LOGD (LOGD_BT, "connected to the device"); - - priv->connected = TRUE; - check_connect_continue (self); - } - } else { - gboolean fail = FALSE; - - /* Bluez says we're disconnected from the device. Suck. */ - - if (nm_device_is_activating (device)) { - _LOGI (LOGD_BT, "Activation: (bluetooth) bluetooth link disconnected."); - fail = TRUE; - } else if (state == NM_DEVICE_STATE_ACTIVATED) { - _LOGI (LOGD_BT, "bluetooth link disconnected."); - fail = TRUE; - } - - if (fail) { - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CARRIER); - priv->connected = FALSE; - } + if (!priv->is_connected) { + /* we got the callback from NMBluezManager with succes. We actually should be + * connected and this line shouldn't be reached. */ + nm_assert_not_reached (); + _LOGE (LOGD_BT, "bluetooth is unexpectedly not in connected state"); + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BT_FAILED); + return; } -} -static gboolean -bt_connect_timeout (gpointer user_data) -{ - NMDeviceBt *self = NM_DEVICE_BT (user_data); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - - _LOGD (LOGD_BT, "initial connection timed out"); - - priv->timeout_id = 0; - nm_clear_g_cancellable (&priv->cancellable); - - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return FALSE; + priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_COMPLETED; + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); } static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) +act_stage1_prepare (NMDevice *device, + NMDeviceStateReason *out_failure_reason) { NMDeviceBt *self = NM_DEVICE_BT (device); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + gs_free_error GError *error = NULL; NMConnection *connection; connection = nm_device_get_applied_connection (device); g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - priv->bt_type = get_connection_bt_type (connection); - if (priv->bt_type == NM_BT_CAPABILITY_NONE) { - // FIXME: set a reason code + priv->connect_bt_type = get_connection_bt_type (connection); + if (priv->connect_bt_type == NM_BT_CAPABILITY_NONE) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_BT_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } - if (priv->bt_type == NM_BT_CAPABILITY_DUN && !priv->mm_running) { + if ( priv->connect_bt_type == NM_BT_CAPABILITY_DUN + && !priv->mm_running) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } - _LOGD (LOGD_BT, "requesting connection to the device"); + if (priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_PENDING) + return NM_ACT_STAGE_RETURN_POSTPONE; + else if (priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_INIT) { + gs_unref_object GCancellable *cancellable = NULL; + char sbuf[100]; + + _LOGD (LOGD_BT, "connecting to %s bluetooth device", + nm_bluetooth_capability_to_string (priv->connect_bt_type, sbuf, sizeof (sbuf))); + + cancellable = g_cancellable_new (); + + if (!nm_bluez_manager_connect (priv->bz_mgr, + priv->dbus_path, + priv->connect_bt_type, + 30000, + cancellable, + connect_bz_cb, + self, + &error)) { + _LOGD (LOGD_BT, "cannot connect to bluetooth device: %s", error->message); + *out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; + } + + priv->connect_bz_cancellable = g_steal_pointer (&cancellable); + priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_PENDING; + return NM_ACT_STAGE_RETURN_POSTPONE; + } + + if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { + if (!priv->modem) { + gs_free NMModem **modems = NULL; + guint i, n; + + if (priv->connect_wait_modem_id == 0) + priv->connect_wait_modem_id = g_timeout_add_seconds (30, connect_wait_modem_timeout, self); + + modems = nm_modem_manager_get_modems (priv->modem_manager, &n); + for (i = 0; i < n; i++) { + if (modem_try_claim (self, modems[i])) + break; + } + if (!priv->modem) + return NM_ACT_STAGE_RETURN_POSTPONE; + } + + if (priv->stage1_modem_prepare_state == NM_DEVICE_STAGE_STATE_PENDING) + return NM_ACT_STAGE_RETURN_POSTPONE; + if (priv->stage1_modem_prepare_state == NM_DEVICE_STAGE_STATE_INIT) { + priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_PENDING; + return nm_modem_act_stage1_prepare (priv->modem, + nm_device_get_act_request (NM_DEVICE (self)), + out_failure_reason); + } + } - nm_clear_g_source (&priv->timeout_id); - nm_clear_g_cancellable (&priv->cancellable); + return NM_ACT_STAGE_RETURN_SUCCESS; +} - priv->timeout_id = g_timeout_add_seconds (30, bt_connect_timeout, device); - priv->cancellable = g_cancellable_new (); +static NMActStageReturn +act_stage2_config (NMDevice *device, + NMDeviceStateReason *out_failure_reason) +{ + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - nm_bluez_device_connect_async (priv->bt_device, - priv->bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP), - priv->cancellable, - bluez_connect_cb, - g_object_ref (self)); + if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) + nm_modem_act_stage2_config (priv->modem); - return NM_ACT_STAGE_RETURN_POSTPONE; + return NM_ACT_STAGE_RETURN_SUCCESS; } static NMActStageReturn @@ -891,11 +1006,11 @@ act_stage3_ip_config_start (NMDevice *device, gpointer *out_config, NMDeviceStateReason *out_failure_reason) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); nm_assert_addr_family (addr_family); - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { + if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { if (addr_family == AF_INET) { return nm_modem_stage3_ip4_config_start (priv->modem, device, @@ -914,15 +1029,17 @@ act_stage3_ip_config_start (NMDevice *device, static void deactivate (NMDevice *device) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); - priv->have_iface = FALSE; - priv->connected = FALSE; + nm_clear_g_signal_handler (nm_device_get_platform (device), &priv->connect_watch_link_id); + nm_clear_g_source (&priv->connect_watch_link_idle_id); + priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_INIT; + nm_clear_g_source (&priv->connect_wait_modem_id); + nm_clear_g_cancellable (&priv->connect_bz_cancellable); - nm_clear_g_source (&priv->timeout_id); - nm_clear_g_cancellable (&priv->cancellable); + priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_INIT; - if (priv->bt_type == NM_BT_CAPABILITY_DUN) { + if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { if (priv->modem) { nm_modem_deactivate (priv->modem, device); @@ -936,22 +1053,53 @@ deactivate (NMDevice *device) } } - if (priv->bt_type != NM_BT_CAPABILITY_NONE) - nm_bluez_device_disconnect (priv->bt_device); - - priv->bt_type = NM_BT_CAPABILITY_NONE; + if (priv->connect_bt_type != NM_BT_CAPABILITY_NONE) { + priv->connect_bt_type = NM_BT_CAPABILITY_NONE; + nm_bluez_manager_disconnect (priv->bz_mgr, priv->dbus_path); + } - g_free (priv->rfcomm_iface); - priv->rfcomm_iface = NULL; + nm_clear_g_free (&priv->connect_rfcomm_iface); if (NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate) NM_DEVICE_CLASS (nm_device_bt_parent_class)->deactivate (device); } -static void -bluez_device_removed (NMBluezDevice *bdev, gpointer user_data) +void +_nm_device_bt_notify_removed (NMDeviceBt *self) +{ + g_signal_emit_by_name (self, NM_DEVICE_REMOVED); +} + +/*****************************************************************************/ + +gboolean +_nm_device_bt_for_same_device (NMDeviceBt *self, + const char *dbus_path, + const char *bdaddr, + const char *name, + NMBluetoothCapabilities capabilities) { - g_signal_emit_by_name (NM_DEVICE_BT (user_data), NM_DEVICE_REMOVED); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + + return nm_streq (priv->dbus_path, dbus_path) + && nm_streq (priv->bdaddr, bdaddr) + && capabilities == priv->capabilities + && (!name || nm_streq (priv->name, name)); +} + +void +_nm_device_bt_notify_set_name (NMDeviceBt *self, const char *name) +{ + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + + nm_assert (name); + + if (!nm_streq (priv->name, name)) { + _LOGT (LOGD_BT, "set-name: %s", name); + g_free (priv->name); + priv->name = g_strdup (name); + _notify (self, PROP_BT_NAME); + } } /*****************************************************************************/ @@ -1012,9 +1160,6 @@ get_property (GObject *object, guint prop_id, case PROP_BT_CAPABILITIES: g_value_set_uint (value, priv->capabilities); break; - case PROP_BT_DEVICE: - g_value_set_object (value, priv->bt_device); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1028,19 +1173,32 @@ set_property (GObject *object, guint prop_id, NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); switch (prop_id) { + case PROP_BT_BZ_MGR: + /* construct-only */ + priv->bz_mgr = g_object_ref (g_value_get_pointer (value)); + nm_assert (NM_IS_BLUEZ_MANAGER (priv->bz_mgr)); + break; + case PROP_BT_DBUS_PATH: + /* construct-only */ + priv->dbus_path = g_value_dup_string (value); + nm_assert (priv->dbus_path); + break; + case PROP_BT_BDADDR: + /* construct-only */ + priv->bdaddr = g_value_dup_string (value); + nm_assert (priv->bdaddr); + break; case PROP_BT_NAME: /* construct-only */ priv->name = g_value_dup_string (value); + nm_assert (priv->name); break; case PROP_BT_CAPABILITIES: /* construct-only */ priv->capabilities = g_value_get_uint (value); - break; - case PROP_BT_DEVICE: - /* construct-only */ - priv->bt_device = g_value_dup_object (value); - if (!priv->bt_device) - g_return_if_reached (); + nm_assert (NM_IN_SET ((NMBluetoothCapabilities) priv->capabilities, NM_BT_CAPABILITY_DUN, + NM_BT_CAPABILITY_NAP, + NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1060,7 +1218,6 @@ constructed (GObject *object) { NMDeviceBt *self = NM_DEVICE_BT (object); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - const char *my_hwaddr; G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object); @@ -1069,74 +1226,69 @@ constructed (GObject *object) nm_modem_manager_name_owner_ref (priv->modem_manager); g_signal_connect (priv->modem_manager, + NM_MODEM_MANAGER_MODEM_ADDED, + G_CALLBACK (mm_modem_added_cb), + self); + + g_signal_connect (priv->modem_manager, "notify::"NM_MODEM_MANAGER_NAME_OWNER, G_CALLBACK (mm_name_owner_changed_cb), self); - if (priv->bt_device) { - /* Watch for BT device property changes */ - g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED, - G_CALLBACK (bluez_connected_changed), - object); - g_signal_connect (priv->bt_device, NM_BLUEZ_DEVICE_REMOVED, - G_CALLBACK (bluez_device_removed), object); - } - - my_hwaddr = nm_device_get_hw_address (NM_DEVICE (object)); - if (my_hwaddr) - priv->bdaddr = g_strdup (my_hwaddr); - else - g_warn_if_reached (); - set_mm_running (self); } -NMDevice * -nm_device_bt_new (NMBluezDevice *bt_device, - const char *udi, +NMDeviceBt * +nm_device_bt_new (NMBluezManager *bz_mgr, + const char *dbus_path, const char *bdaddr, const char *name, - guint32 capabilities) + NMBluetoothCapabilities capabilities) { - g_return_val_if_fail (udi != NULL, NULL); - g_return_val_if_fail (bdaddr != NULL, NULL); - g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (NM_IS_BLUEZ_MANAGER (bz_mgr), NULL); + g_return_val_if_fail (dbus_path, NULL); + g_return_val_if_fail (bdaddr, NULL); + g_return_val_if_fail (name, NULL); g_return_val_if_fail (capabilities != NM_BT_CAPABILITY_NONE, NULL); - g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (bt_device), NULL); - - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BT, - NM_DEVICE_UDI, udi, - NM_DEVICE_IFACE, bdaddr, - NM_DEVICE_DRIVER, "bluez", - NM_DEVICE_PERM_HW_ADDRESS, bdaddr, - NM_DEVICE_BT_DEVICE, bt_device, - NM_DEVICE_BT_NAME, name, - NM_DEVICE_BT_CAPABILITIES, capabilities, - NM_DEVICE_TYPE_DESC, "Bluetooth", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BT, - NULL); + + return g_object_new (NM_TYPE_DEVICE_BT, + NM_DEVICE_UDI, dbus_path, + NM_DEVICE_IFACE, bdaddr, + NM_DEVICE_DRIVER, "bluez", + NM_DEVICE_PERM_HW_ADDRESS, bdaddr, + NM_DEVICE_BT_BDADDR, bdaddr, + NM_DEVICE_BT_BZ_MGR, bz_mgr, + NM_DEVICE_BT_CAPABILITIES, (guint) capabilities, + NM_DEVICE_BT_DBUS_PATH, dbus_path, + NM_DEVICE_BT_NAME, name, + NM_DEVICE_TYPE_DESC, "Bluetooth", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BT, + NULL); } static void dispose (GObject *object) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); + NMDeviceBt *self = NM_DEVICE_BT (object); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - nm_clear_g_source (&priv->timeout_id); - nm_clear_g_cancellable (&priv->cancellable); + nm_clear_g_signal_handler (nm_device_get_platform (NM_DEVICE (self)), &priv->connect_watch_link_id); + nm_clear_g_source (&priv->connect_watch_link_idle_id); - g_signal_handlers_disconnect_matched (priv->bt_device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); + nm_clear_g_source (&priv->connect_wait_modem_id); + nm_clear_g_cancellable (&priv->connect_bz_cancellable); if (priv->modem_manager) { - g_signal_handlers_disconnect_by_func (priv->modem_manager, G_CALLBACK (mm_name_owner_changed_cb), object); + g_signal_handlers_disconnect_by_func (priv->modem_manager, G_CALLBACK (mm_name_owner_changed_cb), self); nm_modem_manager_name_owner_unref (priv->modem_manager); g_clear_object (&priv->modem_manager); } - modem_cleanup (NM_DEVICE_BT (object)); - g_clear_object (&priv->bt_device); + modem_cleanup (self); G_OBJECT_CLASS (nm_device_bt_parent_class)->dispose (object); + + g_clear_object (&priv->bz_mgr); } static void @@ -1144,7 +1296,8 @@ finalize (GObject *object) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); - g_free (priv->rfcomm_iface); + g_free (priv->connect_rfcomm_iface); + g_free (priv->dbus_path); g_free (priv->name); g_free (priv->bdaddr); @@ -1186,17 +1339,34 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) device_class->get_generic_capabilities = get_generic_capabilities; device_class->can_auto_connect = can_auto_connect; device_class->deactivate = deactivate; + device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; device_class->is_available = is_available; - device_class->component_added = component_added; device_class->get_configured_mtu = nm_modem_get_configured_mtu; device_class->state_changed = device_state_changed; + obj_properties[PROP_BT_BZ_MGR] = + g_param_spec_pointer (NM_DEVICE_BT_BZ_MGR, "", "", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_BT_BDADDR] = + g_param_spec_string (NM_DEVICE_BT_BDADDR, "", "", + NULL, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_BT_DBUS_PATH] = + g_param_spec_string (NM_DEVICE_BT_DBUS_PATH, "", "", + NULL, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_BT_NAME] = g_param_spec_string (NM_DEVICE_BT_NAME, "", "", NULL, @@ -1209,12 +1379,6 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_BT_DEVICE] = - g_param_spec_object (NM_DEVICE_BT_DEVICE, "", "", - NM_TYPE_BLUEZ_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[PPP_STATS] = |