From d22bbaaa17fb1ad220b5f617bebad8a4583e025a Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 16 Oct 2014 13:50:40 +0200 Subject: [PATCH] bluetooth: Restore DUN support (rh #1055628) --- ...dns2.patch => 0000-explain-dns1-dns2.patch | 0 ...-local-admin-sessions-to-control-the.patch | 14 +- 0002-bluez-split-out-errors.patch | 171 ++++ ...ack-adapter-address-in-NMBluezDevice.patch | 147 ++++ ...-bluez-re-add-DUN-support-for-Bluez5.patch | 810 ++++++++++++++++++ NetworkManager.spec | 31 +- 6 files changed, 1160 insertions(+), 13 deletions(-) rename 0001-explain-dns1-dns2.patch => 0000-explain-dns1-dns2.patch (100%) rename non-local-session-polkit.patch => 0001-policy-allow-non-local-admin-sessions-to-control-the.patch (61%) create mode 100644 0002-bluez-split-out-errors.patch create mode 100644 0003-bluez-track-adapter-address-in-NMBluezDevice.patch create mode 100644 0004-bluez-re-add-DUN-support-for-Bluez5.patch diff --git a/0001-explain-dns1-dns2.patch b/0000-explain-dns1-dns2.patch similarity index 100% rename from 0001-explain-dns1-dns2.patch rename to 0000-explain-dns1-dns2.patch diff --git a/non-local-session-polkit.patch b/0001-policy-allow-non-local-admin-sessions-to-control-the.patch similarity index 61% rename from non-local-session-polkit.patch rename to 0001-policy-allow-non-local-admin-sessions-to-control-the.patch index 401a9a5..5086775 100644 --- a/non-local-session-polkit.patch +++ b/0001-policy-allow-non-local-admin-sessions-to-control-the.patch @@ -1,14 +1,16 @@ -From f044ff186b433ef3debab7651adc06115809afc6 Mon Sep 17 00:00:00 2001 +From 2a10b58fad810aca1a041cd37b00241ace9be0c7 Mon Sep 17 00:00:00 2001 From: Marius Vollmer -Date: Mon, 6 Oct 2014 11:16:03 +0300 -Subject: [PATCH] policy: allow non-local admin sessions to control the network (rh #1145646) +Date: Mon, 13 Oct 2014 15:58:46 -0500 +Subject: [PATCH 1/4] policy: allow non-local admin sessions to control the + network (rh #1145646) +(cherry picked from commit 4f950ee5692e57bbc9737720adfd7ad6788dabb7) --- - policy/org.freedesktop.NetworkManager.policy.in.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + policy/org.freedesktop.NetworkManager.policy.in.in | 1 + + 1 file changed, 1 insertion(+) diff --git a/policy/org.freedesktop.NetworkManager.policy.in.in b/policy/org.freedesktop.NetworkManager.policy.in.in -index cb22999..e103cd9 100644 +index cb22999..daefd80 100644 --- a/policy/org.freedesktop.NetworkManager.policy.in.in +++ b/policy/org.freedesktop.NetworkManager.policy.in.in @@ -58,6 +58,7 @@ diff --git a/0002-bluez-split-out-errors.patch b/0002-bluez-split-out-errors.patch new file mode 100644 index 0000000..6d3d438 --- /dev/null +++ b/0002-bluez-split-out-errors.patch @@ -0,0 +1,171 @@ +From 616d032c62f0d02be7ec29ff012c45c284f397a8 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Mon, 16 Jun 2014 11:04:06 -0500 +Subject: [PATCH 2/4] bluez: split out errors + +We'll use them from more places than nm nm-bt-device.c in the future. + +(cherry picked from commit 5254ac456ecd2f5ef76b0a1937f52b75e319f204) +--- + src/devices/bluetooth/Makefile.am | 4 +++- + src/devices/bluetooth/nm-bt-error.c | 33 +++++++++++++++++++++++++++++++++ + src/devices/bluetooth/nm-bt-error.h | 35 +++++++++++++++++++++++++++++++++++ + src/devices/bluetooth/nm-device-bt.c | 13 ++----------- + src/devices/bluetooth/nm-device-bt.h | 6 ------ + 5 files changed, 73 insertions(+), 18 deletions(-) + create mode 100644 src/devices/bluetooth/nm-bt-error.c + create mode 100644 src/devices/bluetooth/nm-bt-error.h + +diff --git a/src/devices/bluetooth/Makefile.am b/src/devices/bluetooth/Makefile.am +index 639a1ad..4342d4b 100644 +--- a/src/devices/bluetooth/Makefile.am ++++ b/src/devices/bluetooth/Makefile.am +@@ -24,7 +24,7 @@ AM_CPPFLAGS = \ + GLIB_GENERATED = nm-bt-enum-types.h nm-bt-enum-types.c + GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM + GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM +-nm_bt_enum_types_sources = $(srcdir)/nm-device-bt.h ++nm_bt_enum_types_sources = $(srcdir)/nm-bt-error.h + + nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml + dbus-binding-tool --prefix=nm_device_bt --mode=glib-server --output=$@ $< +@@ -47,6 +47,8 @@ libnm_device_plugin_bluetooth_la_SOURCES = \ + nm-bluez4-manager.h \ + nm-bluez5-manager.c \ + nm-bluez5-manager.h \ ++ nm-bt-error.h \ ++ nm-bt-error.c \ + \ + nm-device-bt.c \ + nm-device-bt.h \ +diff --git a/src/devices/bluetooth/nm-bt-error.c b/src/devices/bluetooth/nm-bt-error.c +new file mode 100644 +index 0000000..d014a10 +--- /dev/null ++++ b/src/devices/bluetooth/nm-bt-error.c +@@ -0,0 +1,33 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* NetworkManager -- Network link manager ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Copyright (C) 2014 Red Hat, Inc. ++ */ ++ ++#include ++#include "nm-bt-error.h" ++ ++GQuark ++nm_bt_error_quark (void) ++{ ++ static GQuark quark = 0; ++ if (!quark) ++ quark = g_quark_from_static_string ("nm-bt-error"); ++ return quark; ++} ++ ++ +diff --git a/src/devices/bluetooth/nm-bt-error.h b/src/devices/bluetooth/nm-bt-error.h +new file mode 100644 +index 0000000..fa3a957 +--- /dev/null ++++ b/src/devices/bluetooth/nm-bt-error.h +@@ -0,0 +1,35 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* NetworkManager -- Network link manager ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Copyright (C) 2014 Red Hat, Inc. ++ */ ++ ++#ifndef _NM_BLUEZ5_ERROR_H_ ++#define _NM_BLUEZ5_ERROR_H_ ++ ++typedef enum { ++ NM_BT_ERROR_CONNECTION_NOT_BT = 0, /*< nick=ConnectionNotBt >*/ ++ NM_BT_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ ++ NM_BT_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ ++ NM_BT_ERROR_DUN_CONNECT_FAILED, /*< nick=DunConnectFailed >*/ ++} NMBtError; ++ ++#define NM_BT_ERROR (nm_bt_error_quark ()) ++GQuark nm_bt_error_quark (void); ++ ++#endif /* _NM_BT_ERROR_H_ */ ++ +diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c +index 6e1a399..ca3deb2 100644 +--- a/src/devices/bluetooth/nm-device-bt.c ++++ b/src/devices/bluetooth/nm-device-bt.c +@@ -46,6 +46,8 @@ + #include "NetworkManagerUtils.h" + #include "nm-bt-enum-types.h" + #include "nm-utils.h" ++#include "nm-bt-error.h" ++#include "nm-bt-enum-types.h" + + #define MM_OLD_DBUS_SERVICE "org.freedesktop.ModemManager" + #define MM_NEW_DBUS_SERVICE "org.freedesktop.ModemManager1" +@@ -94,17 +96,6 @@ enum { + static guint signals[LAST_SIGNAL] = { 0 }; + + +-#define NM_BT_ERROR (nm_bt_error_quark ()) +- +-static GQuark +-nm_bt_error_quark (void) +-{ +- static GQuark quark = 0; +- if (!quark) +- quark = g_quark_from_static_string ("nm-bt-error"); +- return quark; +-} +- + guint32 nm_device_bt_get_capabilities (NMDeviceBt *self) + { + g_return_val_if_fail (NM_IS_DEVICE_BT (self), NM_BT_CAPABILITY_NONE); +diff --git a/src/devices/bluetooth/nm-device-bt.h b/src/devices/bluetooth/nm-device-bt.h +index 83732bc..ac5b115 100644 +--- a/src/devices/bluetooth/nm-device-bt.h ++++ b/src/devices/bluetooth/nm-device-bt.h +@@ -34,12 +34,6 @@ G_BEGIN_DECLS + #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)) + +-typedef enum { +- NM_BT_ERROR_CONNECTION_NOT_BT = 0, /*< nick=ConnectionNotBt >*/ +- NM_BT_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ +- NM_BT_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ +-} NMBtError; +- + #define NM_DEVICE_BT_NAME "name" + #define NM_DEVICE_BT_CAPABILITIES "bt-capabilities" + #define NM_DEVICE_BT_DEVICE "bt-device" +-- +1.9.3 + diff --git a/0003-bluez-track-adapter-address-in-NMBluezDevice.patch b/0003-bluez-track-adapter-address-in-NMBluezDevice.patch new file mode 100644 index 0000000..a50219f --- /dev/null +++ b/0003-bluez-track-adapter-address-in-NMBluezDevice.patch @@ -0,0 +1,147 @@ +From d59bd3c9b57e55b20fd4d2e4781a8da123546f4d Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Mon, 16 Jun 2014 10:20:29 -0500 +Subject: [PATCH 3/4] bluez: track adapter address in NMBluezDevice + +We'll need it for bluez5 DUN support. + +[lkundrak@v3.sk: Turn the addresses to strings from guint8[ETH_ALEN], as that +is what rest of NetworkManager uses for MAC addresses and what Bluez utility +functions expect as well.] + +(cherry picked from commit 384ec8606488e67433753eb52440b4846a3090e7) +--- + src/devices/bluetooth/nm-bluez-device.c | 29 ++++++++++++++++++++++++++--- + src/devices/bluetooth/nm-bluez-device.h | 5 ++++- + src/devices/bluetooth/nm-bluez4-adapter.c | 2 +- + src/devices/bluetooth/nm-bluez5-manager.c | 2 +- + 4 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c +index 4c448a3..edebb75 100644 +--- a/src/devices/bluetooth/nm-bluez-device.c ++++ b/src/devices/bluetooth/nm-bluez-device.c +@@ -55,6 +55,7 @@ typedef struct { + gboolean usable; + NMBluetoothCapabilities connection_bt_type; + ++ char *adapter_address; + char *address; + guint8 bin_address[ETH_ALEN]; + char *name; +@@ -270,7 +271,7 @@ check_emit_usable (NMBluezDevice *self) + new_usable = (priv->initialized && priv->capabilities && priv->name && + ((priv->bluez_version == 4) || + (priv->bluez_version == 5 && priv->adapter5 && priv->adapter_powered) ) && +- priv->dbus_connection && priv->address); ++ priv->dbus_connection && priv->address && priv->adapter_address); + + if (!new_usable) + goto END; +@@ -558,6 +559,18 @@ nm_bluez_device_connect_finish (NMBluezDevice *self, + + /***********************************************************/ + ++static void ++set_adapter_address (NMBluezDevice *self, const char *address) ++{ ++ NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); ++ ++ g_return_if_fail (address); ++ ++ if (priv->adapter_address) ++ g_free (priv->adapter_address); ++ priv->adapter_address = g_strdup (address); ++} ++ + static guint32 + convert_uuids_to_capabilities (const char **strings, int bluez_version) + { +@@ -752,6 +765,10 @@ adapter5_on_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) + if (v) + g_variant_unref (v); + ++ v = g_dbus_proxy_get_cached_property (priv->adapter5, "Address"); ++ if (VARIANT_IS_OF_TYPE_STRING (v)) ++ set_adapter_address (self, g_variant_get_string (v, NULL)); ++ + priv->initialized = TRUE; + g_signal_emit (self, signals[INITIALIZED], 0, TRUE); + +@@ -957,7 +974,10 @@ on_bus_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) + /********************************************************************/ + + NMBluezDevice * +-nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez_version) ++nm_bluez_device_new (const char *path, ++ const char *adapter_address, ++ NMConnectionProvider *provider, ++ int bluez_version) + { + NMBluezDevice *self; + NMBluezDevicePrivate *priv; +@@ -978,8 +998,10 @@ nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez + priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + + priv->bluez_version = bluez_version; +- + priv->provider = provider; ++ g_return_val_if_fail (bluez_version == 5 || (bluez_version == 4 && adapter_address), NULL); ++ if (adapter_address) ++ set_adapter_address (self, adapter_address); + + g_signal_connect (priv->provider, + NM_CP_SIGNAL_CONNECTION_ADDED, +@@ -1073,6 +1095,7 @@ finalize (GObject *object) + nm_log_dbg (LOGD_BT, "bluez[%s]: finalize NMBluezDevice", priv->path); + + g_free (priv->path); ++ g_free (priv->adapter_address); + g_free (priv->address); + g_free (priv->name); + g_free (priv->bt_iface); +diff --git a/src/devices/bluetooth/nm-bluez-device.h b/src/devices/bluetooth/nm-bluez-device.h +index 0bf7d89..25891a0 100644 +--- a/src/devices/bluetooth/nm-bluez-device.h ++++ b/src/devices/bluetooth/nm-bluez-device.h +@@ -62,7 +62,10 @@ typedef struct { + + GType nm_bluez_device_get_type (void); + +-NMBluezDevice *nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez_version); ++NMBluezDevice *nm_bluez_device_new (const char *path, ++ const char *adapter_address, ++ NMConnectionProvider *provider, ++ int bluez_version); + + const char *nm_bluez_device_get_path (NMBluezDevice *self); + +diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c +index ad1786f..9c57d97 100644 +--- a/src/devices/bluetooth/nm-bluez4-adapter.c ++++ b/src/devices/bluetooth/nm-bluez4-adapter.c +@@ -162,7 +162,7 @@ device_created (DBusGProxy *proxy, const char *path, gpointer user_data) + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + NMBluezDevice *device; + +- device = nm_bluez_device_new (path, priv->provider, 4); ++ device = nm_bluez_device_new (path, priv->address, priv->provider, 4); + g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self); + g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); + g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device); +diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c +index 63006b3..8653c28 100644 +--- a/src/devices/bluetooth/nm-bluez5-manager.c ++++ b/src/devices/bluetooth/nm-bluez5-manager.c +@@ -143,7 +143,7 @@ device_added (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) + NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); + NMBluezDevice *device; + +- device = nm_bluez_device_new (path, priv->provider, 5); ++ device = nm_bluez_device_new (path, NULL, priv->provider, 5); + g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self); + g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); + g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device); +-- +1.9.3 + diff --git a/0004-bluez-re-add-DUN-support-for-Bluez5.patch b/0004-bluez-re-add-DUN-support-for-Bluez5.patch new file mode 100644 index 0000000..7797781 --- /dev/null +++ b/0004-bluez-re-add-DUN-support-for-Bluez5.patch @@ -0,0 +1,810 @@ +From 2ca59ef657b1f2a584807adea923589e5a4470a1 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Wed, 1 Oct 2014 10:59:13 +0200 +Subject: [PATCH 4/4] bluez: re-add DUN support for Bluez5 + +This adds service discovery via SDP and RFCOMM tty management to +NetworkManager, as it was dropped from Bluez. + +Based on work by Dan Williams . +The SDP discovery is based on code from Bluez project. + +(cherry picked from commit f1c9595311f52d8b79e8d2032e006005613a8fb1) +--- +[lkundrak@v3.sk: contrib/fedora/rpm/NetworkManager.spec hunk removed for RPM] + + configure.ac | 14 ++ + contrib/fedora/rpm/NetworkManager.spec | 3 + + src/devices/bluetooth/Makefile.am | 10 + + src/devices/bluetooth/nm-bluez-device.c | 134 +++++++---- + src/devices/bluetooth/nm-bluez5-dun.c | 409 ++++++++++++++++++++++++++++++++ + src/devices/bluetooth/nm-bluez5-dun.h | 46 ++++ + 6 files changed, 573 insertions(+), 43 deletions(-) + create mode 100644 src/devices/bluetooth/nm-bluez5-dun.c + create mode 100644 src/devices/bluetooth/nm-bluez5-dun.h + +diff --git a/configure.ac b/configure.ac +index d4437a6..d1ba66a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -586,6 +586,20 @@ else + fi + AM_CONDITIONAL(WITH_MODEM_MANAGER_1, test "${with_modem_manager_1}" = "yes") + ++# Bluez5 DUN support ++PKG_CHECK_MODULES(BLUEZ5, [bluez >= 5], [have_bluez5=yes],[have_bluez5=no]) ++AC_ARG_ENABLE(bluez5-dun, AS_HELP_STRING([--enable-bluez5-dun], [enable Bluez5 DUN support]), ++ [enable_bluez5_dun=${enableval}], [enable_bluez5_dun=${have_bluez5}]) ++if (test "${enable_bluez5_dun}" = "yes"); then ++ if test x"$have_bluez5" = x"no"; then ++ AC_MSG_ERROR(Bluez 5.x development headers are required) ++ fi ++ AC_DEFINE(WITH_BLUEZ5_DUN, 1, [Define if you have Bluez 5 libraries]) ++else ++ AC_DEFINE(HAVE_BLUEZ5_DUN, 0, [Define if you have Bluez 5 libraries]) ++fi ++AM_CONDITIONAL(WITH_BLUEZ5_DUN, test "${enable_bluez5_dun}" = "yes") ++ + # DHCP client support + AC_ARG_WITH([dhclient], AS_HELP_STRING([--with-dhclient=yes|no|path], [Enable dhclient 4.x support])) + AC_ARG_WITH([dhcpcd], AS_HELP_STRING([--with-dhcpcd=yes|no|path], [Enable dhcpcd 4.x support])) +diff --git a/src/devices/bluetooth/Makefile.am b/src/devices/bluetooth/Makefile.am +index 4342d4b..7840a21 100644 +--- a/src/devices/bluetooth/Makefile.am ++++ b/src/devices/bluetooth/Makefile.am +@@ -64,6 +64,16 @@ libnm_device_plugin_bluetooth_la_LIBADD = \ + $(DBUS_LIBS) \ + $(GUDEV_LIBS) + ++if WITH_BLUEZ5_DUN ++AM_CPPFLAGS += $(BLUEZ5_CFLAGS) ++ ++libnm_device_plugin_bluetooth_la_SOURCES += \ ++ nm-bluez5-dun.c \ ++ nm-bluez5-dun.h ++ ++libnm_device_plugin_bluetooth_la_LIBADD += $(BLUEZ5_LIBS) ++endif ++ + CLEANFILES = $(BUILT_SOURCES) + EXTRA_DIST = $(SYMBOL_VIS_FILE) + +diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c +index edebb75..5ca370a 100644 +--- a/src/devices/bluetooth/nm-bluez-device.c ++++ b/src/devices/bluetooth/nm-bluez-device.c +@@ -34,7 +34,8 @@ + #include "nm-logging.h" + #include "nm-utils.h" + #include "nm-settings-connection.h" +- ++#include "nm-bluez5-dun.h" ++#include "NetworkManagerUtils.h" + + G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT) + +@@ -62,7 +63,8 @@ typedef struct { + guint32 capabilities; + gboolean connected; + +- char *bt_iface; ++ char *b4_iface; ++ NMBluez5DunContext *b5_dun_context; + + NMConnectionProvider *provider; + GSList *connections; +@@ -157,9 +159,12 @@ nm_bluez_device_get_capabilities (NMBluezDevice *self) + gboolean + nm_bluez_device_get_connected (NMBluezDevice *self) + { ++ NMBluezDevicePrivate *priv; ++ + g_return_val_if_fail (NM_IS_BLUEZ_DEVICE (self), FALSE); + +- return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->connected; ++ priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); ++ return priv->connected; + } + + static void +@@ -265,8 +270,7 @@ check_emit_usable (NMBluezDevice *self) + gboolean new_usable; + + /* only expect the supported capabilities set. */ +- g_assert (priv->bluez_version != 4 || ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP | NM_BT_CAPABILITY_DUN)) == NM_BT_CAPABILITY_NONE )); +- g_assert (priv->bluez_version != 5 || ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP )) == NM_BT_CAPABILITY_NONE )); ++ g_assert ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP | NM_BT_CAPABILITY_DUN)) == NM_BT_CAPABILITY_NONE ); + + new_usable = (priv->initialized && priv->capabilities && priv->name && + ((priv->bluez_version == 4) || +@@ -421,26 +425,33 @@ nm_bluez_device_disconnect (NMBluezDevice *self) + { + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GVariant *args = NULL; +- const char *dbus_iface; ++ const char *dbus_iface = NULL; + + g_return_if_fail (priv->dbus_connection); + +- if (priv->bluez_version == 5) { +- g_return_if_fail (priv->connection_bt_type == NM_BT_CAPABILITY_NAP); +- dbus_iface = BLUEZ5_NETWORK_INTERFACE; +- } else if (priv->bluez_version == 4 && priv->connection_bt_type == NM_BT_CAPABILITY_DUN) { +- /* Can't pass a NULL interface name through dbus to bluez, so just +- * ignore the disconnect if the interface isn't known. +- */ +- if (!priv->bt_iface) +- return; +- +- args = g_variant_new ("(s)", priv->bt_iface), +- dbus_iface = BLUEZ4_SERIAL_INTERFACE; +- } else { +- g_return_if_fail (priv->bluez_version == 4 && priv->connection_bt_type == NM_BT_CAPABILITY_NAP); +- dbus_iface = BLUEZ4_NETWORK_INTERFACE; +- } ++ if (priv->connection_bt_type == NM_BT_CAPABILITY_DUN) { ++ if (priv->bluez_version == 4) { ++ /* Can't pass a NULL interface name through dbus to bluez, so just ++ * ignore the disconnect if the interface isn't known. ++ */ ++ if (!priv->b4_iface) ++ goto out; ++ args = g_variant_new ("(s)", priv->b4_iface), ++ dbus_iface = BLUEZ4_SERIAL_INTERFACE; ++ } else if (priv->bluez_version == 5) { ++ nm_bluez5_dun_cleanup (priv->b5_dun_context); ++ priv->connected = FALSE; ++ goto out; ++ } ++ } else if (priv->connection_bt_type == NM_BT_CAPABILITY_NAP) { ++ if (priv->bluez_version == 4) ++ dbus_iface = BLUEZ4_NETWORK_INTERFACE; ++ else if (priv->bluez_version == 5) ++ dbus_iface = BLUEZ5_NETWORK_INTERFACE; ++ else ++ g_assert_not_reached (); ++ } else ++ g_assert_not_reached (); + + g_dbus_connection_call (priv->dbus_connection, + BLUEZ_SERVICE, +@@ -455,6 +466,8 @@ nm_bluez_device_disconnect (NMBluezDevice *self) + (GAsyncReadyCallback) bluez_disconnect_cb, + g_object_ref (self)); + ++out: ++ g_clear_pointer (&priv->b4_iface, g_free); + priv->connection_bt_type = NM_BT_CAPABILITY_NONE; + } + +@@ -481,7 +494,7 @@ bluez_connect_cb (GDBusConnection *dbus_connection, + g_simple_async_result_set_op_res_gpointer (result, + g_strdup (device), + g_free); +- priv->bt_iface = device; ++ priv->b4_iface = device; + g_variant_unref (variant); + } + +@@ -490,6 +503,26 @@ bluez_connect_cb (GDBusConnection *dbus_connection, + g_object_unref (result_object); + } + ++static void ++bluez5_dun_connect_cb (NMBluez5DunContext *context, ++ const char *device, ++ GError *error, ++ gpointer user_data) ++{ ++ GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); ++ ++ if (error) { ++ g_simple_async_result_take_error (result, error); ++ } else { ++ g_simple_async_result_set_op_res_gpointer (result, ++ g_strdup (device), ++ g_free); ++ } ++ ++ g_simple_async_result_complete (result); ++ g_object_unref (result); ++} ++ + void + nm_bluez_device_connect_async (NMBluezDevice *self, + NMBluetoothCapabilities connection_bt_type, +@@ -498,26 +531,35 @@ nm_bluez_device_connect_async (NMBluezDevice *self, + { + GSimpleAsyncResult *simple; + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); +- const char *dbus_iface; +- const char *connect_type = BLUETOOTH_CONNECT_NAP; ++ const char *dbus_iface = NULL; ++ const char *connect_type = NULL; + + g_return_if_fail (priv->capabilities & connection_bt_type & (NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP)); + +- if (priv->bluez_version == 5) { +- g_return_if_fail (connection_bt_type == NM_BT_CAPABILITY_NAP); +- dbus_iface = BLUEZ5_NETWORK_INTERFACE; +- } else if (priv->bluez_version == 4 && connection_bt_type == NM_BT_CAPABILITY_DUN) { +- dbus_iface = BLUEZ4_SERIAL_INTERFACE; +- connect_type = BLUETOOTH_CONNECT_DUN; +- } else { +- g_return_if_fail (priv->bluez_version == 4 && connection_bt_type == NM_BT_CAPABILITY_NAP); +- dbus_iface = BLUEZ4_NETWORK_INTERFACE; +- } +- + simple = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + nm_bluez_device_connect_async); ++ priv->connection_bt_type = connection_bt_type; ++ ++ if (connection_bt_type == NM_BT_CAPABILITY_NAP) { ++ connect_type = BLUETOOTH_CONNECT_NAP; ++ if (priv->bluez_version == 4) ++ dbus_iface = BLUEZ4_NETWORK_INTERFACE; ++ else if (priv->bluez_version == 5) ++ dbus_iface = BLUEZ5_NETWORK_INTERFACE; ++ } else if (connection_bt_type == NM_BT_CAPABILITY_DUN) { ++ connect_type = BLUETOOTH_CONNECT_DUN; ++ if (priv->bluez_version == 4) ++ dbus_iface = BLUEZ4_SERIAL_INTERFACE; ++ else if (priv->bluez_version == 5) { ++ if (priv->b5_dun_context == NULL) ++ priv->b5_dun_context = nm_bluez5_dun_new (priv->adapter_address, priv->address); ++ nm_bluez5_dun_connect (priv->b5_dun_context, bluez5_dun_connect_cb, simple); ++ return; ++ } ++ } else ++ g_assert_not_reached (); + + g_dbus_connection_call (priv->dbus_connection, + BLUEZ_SERVICE, +@@ -531,8 +573,6 @@ nm_bluez_device_connect_async (NMBluezDevice *self, + NULL, + (GAsyncReadyCallback) bluez_connect_cb, + simple); +- +- priv->connection_bt_type = connection_bt_type; + } + + const char * +@@ -540,6 +580,7 @@ nm_bluez_device_connect_finish (NMBluezDevice *self, + GAsyncResult *result, + GError **error) + { ++ NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + GSimpleAsyncResult *simple; + const char *device; + +@@ -554,6 +595,9 @@ nm_bluez_device_connect_finish (NMBluezDevice *self, + return NULL; + + device = (const char *) g_simple_async_result_get_op_res_gpointer (simple); ++ if (device && priv->bluez_version == 5) ++ priv->connected = TRUE; ++ + return device; + } + +@@ -572,7 +616,7 @@ set_adapter_address (NMBluezDevice *self, const char *address) + } + + static guint32 +-convert_uuids_to_capabilities (const char **strings, int bluez_version) ++convert_uuids_to_capabilities (const char **strings) + { + const char **iter; + guint32 capabilities = 0; +@@ -584,8 +628,7 @@ convert_uuids_to_capabilities (const char **strings, int bluez_version) + if (parts && parts[0]) { + switch (g_ascii_strtoull (parts[0], NULL, 16)) { + case 0x1103: +- if (bluez_version == 4) +- capabilities |= NM_BT_CAPABILITY_DUN; ++ capabilities |= NM_BT_CAPABILITY_DUN; + break; + case 0x1116: + capabilities |= NM_BT_CAPABILITY_NAP; +@@ -606,7 +649,7 @@ _set_property_capabilities (NMBluezDevice *self, const char **uuids) + guint32 uint_val; + NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + +- uint_val = convert_uuids_to_capabilities (uuids, priv->bluez_version); ++ uint_val = convert_uuids_to_capabilities (uuids); + if (priv->capabilities != uint_val) { + if (priv->capabilities) { + /* changing (relevant) capabilities is not supported and ignored -- except setting initially */ +@@ -1067,6 +1110,11 @@ dispose (GObject *object) + g_clear_object (&priv->pan_connection_original); + } + ++ if (priv->b5_dun_context) { ++ nm_bluez5_dun_free (priv->b5_dun_context); ++ priv->b5_dun_context = NULL; ++ } ++ + g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_added, self); + g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_removed, self); + g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self); +@@ -1098,7 +1146,7 @@ finalize (GObject *object) + g_free (priv->adapter_address); + g_free (priv->address); + g_free (priv->name); +- g_free (priv->bt_iface); ++ g_free (priv->b4_iface); + + if (priv->proxy) + g_signal_handlers_disconnect_by_data (priv->proxy, object); +diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c +new file mode 100644 +index 0000000..dcd3d73 +--- /dev/null ++++ b/src/devices/bluetooth/nm-bluez5-dun.c +@@ -0,0 +1,409 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* NetworkManager -- Network link manager ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Copyright (C) 2014 Red Hat, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "nm-bluez5-dun.h" ++#include "nm-bt-error.h" ++#include "nm-logging.h" ++#include "NetworkManagerUtils.h" ++ ++typedef struct _NMBluez5DunContext { ++ bdaddr_t src; ++ bdaddr_t dst; ++ char *src_str; ++ char *dst_str; ++ int rfcomm_channel; ++ int rfcomm_fd; ++ int rfcomm_tty_fd; ++ int rfcomm_id; ++ NMBluez5DunFunc callback; ++ gpointer user_data; ++ sdp_session_t *sdp_session; ++ guint sdp_watch_id; ++} NMBluez5DunContext; ++ ++static void ++dun_connect (NMBluez5DunContext *context) ++{ ++ struct sockaddr_rc sa; ++ int devid, try = 30; ++ char tty[100]; ++ const int ttylen = sizeof (tty) - 1; ++ GError *error = NULL; ++ ++ struct rfcomm_dev_req req = { ++ .flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP), ++ .dev_id = -1, ++ .channel = context->rfcomm_channel ++ }; ++ ++ context->rfcomm_fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); ++ if (context->rfcomm_fd < 0) { ++ int errsv = errno; ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Failed to create RFCOMM socket: (%d) %s", ++ errsv, strerror (errsv)); ++ goto done; ++ } ++ ++ /* Connect to the remote device */ ++ sa.rc_family = AF_BLUETOOTH; ++ sa.rc_channel = 0; ++ memcpy (&sa.rc_bdaddr, &context->src, ETH_ALEN); ++ if (bind (context->rfcomm_fd, (struct sockaddr *) &sa, sizeof(sa))) { ++ int errsv = errno; ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Failed to bind socket: (%d) %s", ++ errsv, strerror (errsv)); ++ goto done; ++ } ++ ++ sa.rc_channel = context->rfcomm_channel; ++ memcpy (&sa.rc_bdaddr, &context->dst, ETH_ALEN); ++ if (connect (context->rfcomm_fd, (struct sockaddr *) &sa, sizeof (sa)) ) { ++ int errsv = errno; ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Failed to connect to remote device: (%d) %s", ++ errsv, strerror (errsv)); ++ goto done; ++ } ++ ++ nm_log_dbg (LOGD_BT, "(%s): connected to %s on channel %d", ++ context->src_str, context->dst_str, context->rfcomm_channel); ++ ++ /* Create an RFCOMM kernel device for the DUN channel */ ++ memcpy (&req.src, &context->src, ETH_ALEN); ++ memcpy (&req.dst, &context->dst, ETH_ALEN); ++ devid = ioctl (context->rfcomm_fd, RFCOMMCREATEDEV, &req); ++ if (devid < 0) { ++ int errsv = errno; ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Failed to create rfcomm device: (%d) %s", ++ errsv, strerror (errsv)); ++ goto done; ++ } ++ context->rfcomm_id = devid; ++ ++ snprintf (tty, ttylen, "/dev/rfcomm%d", devid); ++ while ((context->rfcomm_tty_fd = open (tty, O_RDONLY | O_NOCTTY)) < 0 && try--) { ++ if (try) { ++ g_usleep (100 * 1000); ++ continue; ++ } ++ ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Failed to find rfcomm device: %s", ++ tty); ++ break; ++ } ++ ++done: ++ context->callback (context, tty, error, context->user_data); ++} ++ ++static void ++sdp_search_cleanup (NMBluez5DunContext *context) ++{ ++ if (context->sdp_session) { ++ sdp_close (context->sdp_session); ++ context->sdp_session = NULL; ++ } ++ ++ if (context->sdp_watch_id) { ++ g_source_remove (context->sdp_watch_id); ++ context->sdp_watch_id = 0; ++ } ++} ++ ++static void ++sdp_search_completed_cb (uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) ++{ ++ NMBluez5DunContext *context = user_data; ++ int scanned, seqlen = 0, bytesleft = size; ++ uint8_t dataType; ++ int channel = -1; ++ ++ nm_log_dbg (LOGD_BT, "(%s -> %s): SDP search finished with type=%d status=%d", ++ context->src_str, context->dst_str, status, type); ++ ++ /* SDP response received */ ++ if (status || type != SDP_SVC_SEARCH_ATTR_RSP) { ++ GError *error = g_error_new (NM_BT_ERROR, ++ NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Did not get a Service Discovery response"); ++ context->callback (context, NULL, error, context->user_data); ++ goto done; ++ } ++ ++ scanned = sdp_extract_seqtype (rsp, bytesleft, &dataType, &seqlen); ++ ++ nm_log_dbg (LOGD_BT, "(%s -> %s): SDP sequence type scanned=%d length=%d", ++ context->src_str, context->dst_str, scanned, seqlen); ++ ++ scanned = sdp_extract_seqtype (rsp, bytesleft, &dataType, &seqlen); ++ if (!scanned || !seqlen) { ++ /* Short read or unknown sequence type */ ++ GError *error = g_error_new (NM_BT_ERROR, ++ NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Improper Service Discovery response"); ++ context->callback (context, NULL, error, context->user_data); ++ goto done; ++ } ++ ++ rsp += scanned; ++ bytesleft -= scanned; ++ do { ++ sdp_record_t *rec; ++ int recsize = 0; ++ sdp_list_t *protos; ++ ++ rec = sdp_extract_pdu (rsp, bytesleft, &recsize); ++ if (!rec) ++ break; ++ ++ if (!recsize) { ++ sdp_record_free (rec); ++ break; ++ } ++ ++ if (sdp_get_access_protos (rec, &protos) == 0) { ++ /* Extract the DUN channel number */ ++ channel = sdp_get_proto_port (protos, RFCOMM_UUID); ++ sdp_list_free (protos, NULL); ++ ++ nm_log_dbg (LOGD_BT, "(%s -> %s): SDP channel=%d", ++ context->src_str, context->dst_str, channel); ++ } ++ sdp_record_free (rec); ++ ++ scanned += recsize; ++ rsp += recsize; ++ bytesleft -= recsize; ++ } while ((scanned < (ssize_t) size) && (bytesleft > 0) && (channel < 0)); ++ ++done: ++ if (channel != -1) { ++ context->rfcomm_channel = channel; ++ dun_connect (context); ++ } ++ ++ sdp_search_cleanup (context); ++} ++ ++static gboolean ++sdp_search_process_cb (GIOChannel *channel, GIOCondition condition, gpointer user_data) ++{ ++ NMBluez5DunContext *context = user_data; ++ ++ nm_log_dbg (LOGD_BT, "(%s -> %s): SDP search progressed with condition=%d", ++ context->src_str, context->dst_str, condition); ++ ++ if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { ++ GError *error = g_error_new (NM_BT_ERROR, ++ NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Service Discovery interrupted"); ++ context->callback (context, NULL, error, context->user_data); ++ sdp_search_cleanup (context); ++ return FALSE; ++ } ++ ++ if (sdp_process (context->sdp_session) < 0) { ++ nm_log_dbg (LOGD_BT, "(%s -> %s): SDP search finished", ++ context->src_str, context->dst_str); ++ ++ /* Search finished successfully. */ ++ return FALSE; ++ } ++ ++ /* Search progressed successfully. */ ++ return TRUE; ++} ++ ++static gboolean ++sdp_connect_watch (GIOChannel *channel, GIOCondition condition, gpointer user_data) ++{ ++ NMBluez5DunContext *context = user_data; ++ sdp_list_t *search, *attrs; ++ uuid_t svclass; ++ uint16_t attr; ++ int fd, err, fd_err = 0; ++ socklen_t len = sizeof (fd_err); ++ GError *error = NULL; ++ ++ context->sdp_watch_id = 0; ++ ++ fd = g_io_channel_unix_get_fd (channel); ++ if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &fd_err, &len) < 0) { ++ nm_log_dbg (LOGD_BT, "(%s -> %s): getsockopt error=%d", ++ context->src_str, context->dst_str, errno); ++ err = errno; ++ } else { ++ nm_log_dbg (LOGD_BT, "(%s -> %s): SO_ERROR error=%d", ++ context->src_str, context->dst_str, fd_err); ++ err = fd_err; ++ } ++ ++ if (err != 0) { ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Error on Service Discovery socket: (%d) %s", ++ err, strerror (err)); ++ goto done; ++ } ++ ++ if (sdp_set_notify (context->sdp_session, sdp_search_completed_cb, context) < 0) { ++ /* Should not be reached, only can fail if we passed bad sdp_session. */ ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Could not request Service Discovery notification"); ++ goto done; ++ } ++ ++ sdp_uuid16_create (&svclass, DIALUP_NET_SVCLASS_ID); ++ search = sdp_list_append (NULL, &svclass); ++ attr = SDP_ATTR_PROTO_DESC_LIST; ++ attrs = sdp_list_append (NULL, &attr); ++ ++ if (!sdp_service_search_attr_async (context->sdp_session, search, SDP_ATTR_REQ_INDIVIDUAL, attrs)) { ++ /* Set callback responsible for update the internal SDP transaction */ ++ context->sdp_watch_id = g_io_add_watch (channel, ++ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, ++ sdp_search_process_cb, ++ context); ++ } else { ++ err = sdp_get_error (context->sdp_session); ++ error = g_error_new (NM_BT_ERROR, ++ NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Error starting Service Discovery: (%d) %s", ++ err, strerror (err)); ++ } ++ ++ sdp_list_free (attrs, NULL); ++ sdp_list_free (search, NULL); ++ ++done: ++ if (error) { ++ context->callback (context, NULL, error, context->user_data); ++ sdp_search_cleanup (context); ++ } ++ ++ return G_SOURCE_REMOVE; ++} ++ ++NMBluez5DunContext * ++nm_bluez5_dun_new (const char *adapter, ++ const char *remote) ++ ++{ ++ NMBluez5DunContext *context; ++ ++ context = g_slice_new0 (NMBluez5DunContext); ++ str2ba (adapter, &context->src); ++ str2ba (remote, &context->dst); ++ context->src_str = g_strdup (adapter); ++ context->dst_str = g_strdup (remote); ++ context->rfcomm_channel = -1; ++ context->rfcomm_id = -1; ++ context->rfcomm_fd = -1; ++ return context; ++} ++ ++void ++nm_bluez5_dun_connect (NMBluez5DunContext *context, ++ NMBluez5DunFunc callback, ++ gpointer user_data) ++{ ++ GIOChannel *channel; ++ ++ context->callback = callback; ++ context->user_data = user_data; ++ ++ if (context->rfcomm_channel != -1) { ++ nm_log_dbg (LOGD_BT, "(%s): channel number on device %s cached: %d", ++ context->src_str, context->dst_str, context->rfcomm_channel); ++ dun_connect (context); ++ return; ++ } ++ ++ nm_log_dbg (LOGD_BT, "(%s): starting channel number discovery for device %s", ++ context->src_str, context->dst_str); ++ ++ context->sdp_session = sdp_connect (&context->src, &context->dst, SDP_NON_BLOCKING); ++ if (!context->sdp_session) { ++ GError *error; ++ int err = sdp_get_error (context->sdp_session); ++ ++ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, ++ "Failed to connect to the SDP server: (%d) %s", ++ err, strerror (err)); ++ context->callback (context, NULL, error, context->user_data); ++ return; ++ } ++ ++ channel = g_io_channel_unix_new (sdp_get_socket (context->sdp_session)); ++ context->sdp_watch_id = g_io_add_watch (channel, ++ G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, ++ sdp_connect_watch, ++ context); ++ g_io_channel_unref (channel); ++} ++ ++/* Only clean up connection-related stuff to allow reconnect */ ++void ++nm_bluez5_dun_cleanup (NMBluez5DunContext *context) ++{ ++ g_return_if_fail (context != NULL); ++ ++ sdp_search_cleanup (context); ++ ++ if (context->rfcomm_fd >= 0) { ++ if (context->rfcomm_id >= 0) { ++ struct rfcomm_dev_req req = { 0 }; ++ ++ req.dev_id = context->rfcomm_id; ++ ioctl (context->rfcomm_fd, RFCOMMRELEASEDEV, &req); ++ context->rfcomm_id = -1; ++ } ++ close (context->rfcomm_fd); ++ context->rfcomm_fd = -1; ++ } ++ ++ close (context->rfcomm_tty_fd); ++ context->rfcomm_tty_fd = -1; ++} ++ ++void ++nm_bluez5_dun_free (NMBluez5DunContext *context) ++{ ++ g_return_if_fail (context != NULL); ++ ++ nm_bluez5_dun_cleanup (context); ++ g_clear_pointer (&context->src_str, g_free); ++ g_clear_pointer (&context->dst_str, g_free); ++ g_slice_free (NMBluez5DunContext, context); ++} +diff --git a/src/devices/bluetooth/nm-bluez5-dun.h b/src/devices/bluetooth/nm-bluez5-dun.h +new file mode 100644 +index 0000000..7e25972 +--- /dev/null ++++ b/src/devices/bluetooth/nm-bluez5-dun.h +@@ -0,0 +1,46 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* NetworkManager -- Network link manager ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Copyright (C) 2014 Red Hat, Inc. ++ */ ++ ++#ifndef _NM_BLUEZ5_UTILS_H_ ++#define _NM_BLUEZ5_UTILS_H_ ++ ++#include ++#include ++ ++typedef struct _NMBluez5DunContext NMBluez5DunContext; ++ ++typedef void (*NMBluez5DunFunc) (NMBluez5DunContext *context, ++ const char *rfcomm_dev, ++ GError *error, ++ gpointer user_data); ++ ++NMBluez5DunContext *nm_bluez5_dun_new (const char *adapter, ++ const char *remote); ++ ++void nm_bluez5_dun_connect (NMBluez5DunContext *context, ++ NMBluez5DunFunc callback, gpointer user_data); ++ ++/* Clean up connection resources */ ++void nm_bluez5_dun_cleanup (NMBluez5DunContext *context); ++ ++/* Clean up and dispose all resources */ ++void nm_bluez5_dun_free (NMBluez5DunContext *context); ++ ++#endif /* _NM_BLUEZ5_UTILS_H_ */ +-- +1.9.3 + diff --git a/NetworkManager.spec b/NetworkManager.spec index 35d6b4f..1af5a26 100644 --- a/NetworkManager.spec +++ b/NetworkManager.spec @@ -13,7 +13,7 @@ %define snapshot .git20140704 %define git_sha 6eb82acd %define realversion 0.9.10.0 -%define release_version 7 +%define release_version 8 %define epoch_version 1 %define obsoletes_nmver 1:0.9.9.95-1 @@ -77,8 +77,15 @@ Source1: NetworkManager.conf Source2: 00-server.conf Source3: 20-connectivity-fedora.conf -Patch1: 0001-explain-dns1-dns2.patch -Patch2: non-local-session-polkit.patch +# Not upstream. +Patch0: 0000-explain-dns1-dns2.patch + +# Cherry-picks from upstream: +# http://cgit.freedesktop.org/NetworkManager/NetworkManager/log/?h=nm-0-9-10 +Patch1: 0001-policy-allow-non-local-admin-sessions-to-control-the.patch +Patch2: 0002-bluez-split-out-errors.patch +Patch3: 0003-bluez-track-adapter-address-in-NMBluezDevice.patch +Patch4: 0004-bluez-re-add-DUN-support-for-Bluez5.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -140,6 +147,9 @@ BuildRequires: libuuid-devel BuildRequires: libgudev1-devel >= 143 BuildRequires: vala-tools BuildRequires: iptables +%if 0%{?with_bluetooth} && 0%{?fedora} > 19 +BuildRequires: bluez-libs-devel +%endif %if 0%{?with_wimax} BuildRequires: wimax-devel %endif @@ -314,8 +324,11 @@ by nm-connection-editor and nm-applet in a non-graphical environment. %prep %setup -q -n NetworkManager-%{realversion} -%patch1 -p1 -b .0001.explain-dns1-dns2.orig -%patch2 -p1 -b .non-local-session-polkit.orig +%patch0 -p1 -b .explain-dns1-dns2.orig +%patch1 -p1 -b .policy-allow-non-local-admin-sessions-to-control-the.orig +%patch2 -p1 -b .bluez-split-out-errors.orig +%patch3 -p1 -b .bluez-track-adapter-address-in-NMBluezDevice.orig +%patch4 -p1 -b .bluez-re-add-DUN-support-for-Bluez5.orig %build @@ -325,8 +338,9 @@ by nm-connection-editor and nm-applet in a non-graphical environment. %{__cp} -R docs ORIG-docs %endif -#autopoint --force -#intltoolize --force +autoreconf -f -i +autopoint --force +intltoolize --force %configure \ --disable-static \ --with-dhclient=yes \ @@ -585,6 +599,9 @@ fi %endif %changelog +* Thu Oct 16 2014 Lubomir Rintel 1:0.9.10.0-8.git20140704 +- bluetooth: Restore DUN support (rh #1055628) + * Mon Oct 06 2014 Stef Walter - 1:0.9.10.0-7.git20140704 - Allow non-local users network control after PolicyKit authentication (rh #1145646)