All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/5] Rebond support
@ 2016-08-04 13:28 Szymon Janc
  2016-08-04 13:28 ` [RFC 1/5] lib/mgmt: Add MGMT_DEV_DISCONN_AUTH_FAILURE definition Szymon Janc
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Szymon Janc @ 2016-08-04 13:28 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

Hi,

This serie adds support for asking agent for rebond consent. It makes
use of recently added 'Authentication Failed' error code on MGMT
device disconnected event.

If agent gives consent for rebond then device is unpaired and new
pairing is started without need for user to manually remove device
and discover it again.

I'm not fully happy with method name RebondConsent() so I'm open for
suggestions.

Comment are welcome.

Szymon Janc (5):
  lib/mgmt: Add MGMT_DEV_DISCONN_AUTH_FAILURE definition
  doc: Add RebondConsent method to agent API
  core/adapter: Add support for rebond consent
  plugins/policy: Disable policies on authentication failure
  client: Add support for RebondConsent request

 client/agent.c    |  22 ++++++++++
 doc/agent-api.txt |   8 ++++
 lib/mgmt.h        |   1 +
 plugins/policy.c  |  58 ++++++++++++++++++-------
 src/adapter.c     | 124 +++++++++++++++++++++++++++++++++++++++---------------
 src/agent.c       |  47 +++++++++++++++++++++
 src/agent.h       |   4 ++
 7 files changed, 215 insertions(+), 49 deletions(-)

-- 
2.7.4

On behalf of SCHILLER Medical SAS.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC 1/5] lib/mgmt: Add MGMT_DEV_DISCONN_AUTH_FAILURE definition
  2016-08-04 13:28 [RFC 0/5] Rebond support Szymon Janc
@ 2016-08-04 13:28 ` Szymon Janc
  2016-08-04 13:28 ` [RFC 2/5] doc: Add RebondConsent method to agent API Szymon Janc
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2016-08-04 13:28 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This error code was recently added to device disconnected event.
---
 lib/mgmt.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/mgmt.h b/lib/mgmt.h
index f6a976a..705be07 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -589,6 +589,7 @@ struct mgmt_ev_device_connected {
 #define MGMT_DEV_DISCONN_TIMEOUT	0x01
 #define MGMT_DEV_DISCONN_LOCAL_HOST	0x02
 #define MGMT_DEV_DISCONN_REMOTE		0x03
+#define MGMT_DEV_DISCONN_AUTH_FAILURE	0x04
 
 #define MGMT_EV_DEVICE_DISCONNECTED	0x000C
 struct mgmt_ev_device_disconnected {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 2/5] doc: Add RebondConsent method to agent API
  2016-08-04 13:28 [RFC 0/5] Rebond support Szymon Janc
  2016-08-04 13:28 ` [RFC 1/5] lib/mgmt: Add MGMT_DEV_DISCONN_AUTH_FAILURE definition Szymon Janc
@ 2016-08-04 13:28 ` Szymon Janc
  2016-08-04 13:28 ` [RFC 3/5] core/adapter: Add support for rebond consent Szymon Janc
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2016-08-04 13:28 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This method will be called when bluetoothd requires user consent for
performing re-bond operation.
---
 doc/agent-api.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index 801ccb6..16328d7 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -176,6 +176,14 @@ Methods		void Release()
 			Possible errors: org.bluez.Error.Rejected
 			                 org.bluez.Error.Canceled
 
+		void RebondConsent(object device)
+
+			This method gets called when service daemon needs to
+			authorize rebonding of remote device that lost bond
+			(replied with 'Pin or Key missing' error).
+
+			Possible errors: org.bluez.Error.Rejected
+
 		void Cancel()
 
 			This method gets called to indicate that the agent
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 3/5] core/adapter: Add support for rebond consent
  2016-08-04 13:28 [RFC 0/5] Rebond support Szymon Janc
  2016-08-04 13:28 ` [RFC 1/5] lib/mgmt: Add MGMT_DEV_DISCONN_AUTH_FAILURE definition Szymon Janc
  2016-08-04 13:28 ` [RFC 2/5] doc: Add RebondConsent method to agent API Szymon Janc
@ 2016-08-04 13:28 ` Szymon Janc
  2016-08-04 13:28 ` [RFC 4/5] plugins/policy: Disable policies on authentication failure Szymon Janc
  2016-08-04 13:28 ` [RFC 5/5] client: Add support for RebondConsent request Szymon Janc
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2016-08-04 13:28 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

If device was disconnected with authentication failed error (result of
PIN or Key missing HCI error) send a rebond consent request to agent.
If agent confirms request, unpair device and start new pairing without
need to discover device again.
---
 src/adapter.c | 124 ++++++++++++++++++++++++++++++++++++++++++----------------
 src/agent.c   |  47 ++++++++++++++++++++++
 src/agent.h   |   4 ++
 3 files changed, 141 insertions(+), 34 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 3742398..704844a 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -6643,6 +6643,69 @@ static void disconnect_notify(struct btd_device *dev, uint8_t reason)
 	}
 }
 
+static void remove_keys(struct btd_adapter *adapter,
+					struct btd_device *device, uint8_t type)
+{
+	char adapter_addr[18];
+	char device_addr[18];
+	char filename[PATH_MAX];
+	GKeyFile *key_file;
+	gsize length = 0;
+	char *str;
+
+	ba2str(btd_adapter_get_address(adapter), adapter_addr);
+	ba2str(device_get_address(device), device_addr);
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+								device_addr);
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+	if (type == BDADDR_BREDR) {
+		g_key_file_remove_group(key_file, "LinkKey", NULL);
+	} else {
+		g_key_file_remove_group(key_file, "LongTermKey", NULL);
+		g_key_file_remove_group(key_file, "LocalSignatureKey", NULL);
+		g_key_file_remove_group(key_file, "RemoteSignatureKey", NULL);
+		g_key_file_remove_group(key_file, "IdentityResolvingKey", NULL);
+	}
+
+	str = g_key_file_to_data(key_file, &length, NULL);
+	g_file_set_contents(filename, str, length, NULL);
+	g_free(str);
+
+	g_key_file_free(key_file);
+}
+
+struct rebond_consent_data {
+	struct btd_adapter *adapter;
+	bdaddr_t addr;
+	uint8_t addr_type;
+};
+
+static void rebond_consent_cb(struct agent *agent, DBusError *err,
+							void *user_data)
+{
+	struct rebond_consent_data *data = user_data;
+	struct btd_device *device;
+
+	if (err)
+		return;
+
+	device = btd_adapter_find_device(data->adapter, &data->addr,
+							data->addr_type);
+	if (device) {
+		btd_adapter_remove_bonding(data->adapter, &data->addr,
+							data->addr_type);
+
+		remove_keys(data->adapter, device, data->addr_type);
+		device_set_unpaired(device, data->addr_type);
+	}
+
+	adapter_create_bonding(data->adapter, &data->addr, data->addr_type,
+					agent_get_io_capability(agent));
+}
+
 static void dev_disconnected(struct btd_adapter *adapter,
 					const struct mgmt_addr_info *addr,
 					uint8_t reason)
@@ -6662,6 +6725,33 @@ static void dev_disconnected(struct btd_adapter *adapter,
 
 	bonding_attempt_complete(adapter, &addr->bdaddr, addr->type,
 						MGMT_STATUS_DISCONNECTED);
+
+	/* send re-bond consent only if lost bond */
+	if (reason != MGMT_DEV_DISCONN_AUTH_FAILURE)
+		return;
+
+	if (device && device_is_bonded(device, addr->type)) {
+		struct rebond_consent_data *data;
+		struct agent *agent;
+
+		info("Device %s lost bond", dst);
+
+		agent = agent_get(NULL);
+		if (!agent)
+			return;
+
+		data = new0(struct rebond_consent_data, 1);
+		data->adapter = adapter;
+		bacpy(&data->addr, &addr->bdaddr);
+		data->addr_type = addr->type;
+
+		if (agent_rebond_consent(agent, device,
+					rebond_consent_cb,
+					data, (GDestroyNotify)free) < 0)
+			free(data);
+
+		agent_unref(agent);
+	}
 }
 
 void btd_add_disconnect_cb(btd_disconnect_cb func)
@@ -7706,40 +7796,6 @@ static void connect_failed_callback(uint16_t index, uint16_t length,
 		btd_adapter_remove_device(adapter, device);
 }
 
-static void remove_keys(struct btd_adapter *adapter,
-					struct btd_device *device, uint8_t type)
-{
-	char adapter_addr[18];
-	char device_addr[18];
-	char filename[PATH_MAX];
-	GKeyFile *key_file;
-	gsize length = 0;
-	char *str;
-
-	ba2str(btd_adapter_get_address(adapter), adapter_addr);
-	ba2str(device_get_address(device), device_addr);
-
-	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
-								device_addr);
-	key_file = g_key_file_new();
-	g_key_file_load_from_file(key_file, filename, 0, NULL);
-
-	if (type == BDADDR_BREDR) {
-		g_key_file_remove_group(key_file, "LinkKey", NULL);
-	} else {
-		g_key_file_remove_group(key_file, "LongTermKey", NULL);
-		g_key_file_remove_group(key_file, "LocalSignatureKey", NULL);
-		g_key_file_remove_group(key_file, "RemoteSignatureKey", NULL);
-		g_key_file_remove_group(key_file, "IdentityResolvingKey", NULL);
-	}
-
-	str = g_key_file_to_data(key_file, &length, NULL);
-	g_file_set_contents(filename, str, length, NULL);
-	g_free(str);
-
-	g_key_file_free(key_file);
-}
-
 static void unpaired_callback(uint16_t index, uint16_t length,
 					const void *param, void *user_data)
 {
diff --git a/src/agent.c b/src/agent.c
index ff44d57..4d441b5 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -70,6 +70,7 @@ typedef enum {
 	AGENT_REQUEST_PINCODE,
 	AGENT_REQUEST_AUTHORIZE_SERVICE,
 	AGENT_REQUEST_DISPLAY_PINCODE,
+	AGENT_REQUEST_REBOND_CONSENT,
 } agent_request_type_t;
 
 struct agent {
@@ -247,6 +248,7 @@ void agent_unref(struct agent *agent)
 		case AGENT_REQUEST_AUTHORIZATION:
 		case AGENT_REQUEST_AUTHORIZE_SERVICE:
 		case AGENT_REQUEST_DISPLAY_PINCODE:
+		case AGENT_REQUEST_REBOND_CONSENT:
 		default:
 			cb = agent->request->cb;
 			cb(agent, &err, agent->request->user_data);
@@ -899,6 +901,51 @@ failed:
 	return err;
 }
 
+int agent_rebond_consent(struct agent *agent, struct btd_device *device,
+						agent_cb cb, void *user_data,
+						GDestroyNotify destroy)
+{
+	struct agent_request *req;
+	const char *dev_path = device_get_path(device);
+	int err;
+
+	if (agent->request)
+		return -EBUSY;
+
+	req = agent_request_new(agent, AGENT_REQUEST_REBOND_CONSENT, cb,
+				user_data, destroy);
+
+
+	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
+					AGENT_INTERFACE, "RebondConsent");
+	if (req->msg == NULL) {
+		error("Couldn't allocate D-Bus message");
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	dbus_message_append_args(req->msg,
+				DBUS_TYPE_OBJECT_PATH, &dev_path,
+				DBUS_TYPE_INVALID);
+
+	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
+				&req->call, REQUEST_TIMEOUT) == FALSE) {
+		error("D-Bus send failed");
+		err = -EIO;
+		goto failed;
+	}
+
+	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+
+	agent->request = req;
+
+	return 0;
+
+failed:
+	agent_request_free(req, FALSE);
+	return err;
+}
+
 uint8_t agent_get_io_capability(struct agent *agent)
 {
 	return agent->capability;
diff --git a/src/agent.h b/src/agent.h
index 1e46920..3b15453 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -65,6 +65,10 @@ int agent_display_pincode(struct agent *agent, struct btd_device *device,
 				const char *pincode, agent_cb cb,
 				void *user_data, GDestroyNotify destroy);
 
+int agent_rebond_consent(struct agent *agent, struct btd_device *device,
+						agent_cb cb, void *user_data,
+						GDestroyNotify destroy);
+
 int agent_cancel(struct agent *agent);
 
 uint8_t agent_get_io_capability(struct agent *agent);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 4/5] plugins/policy: Disable policies on authentication failure
  2016-08-04 13:28 [RFC 0/5] Rebond support Szymon Janc
                   ` (2 preceding siblings ...)
  2016-08-04 13:28 ` [RFC 3/5] core/adapter: Add support for rebond consent Szymon Janc
@ 2016-08-04 13:28 ` Szymon Janc
  2016-08-04 13:28 ` [RFC 5/5] client: Add support for RebondConsent request Szymon Janc
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2016-08-04 13:28 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

If remote device was disconnected due to authentication failure (lost
bond) there is no point in trying to reconnect.
---
 plugins/policy.c | 58 +++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 15 deletions(-)

diff --git a/plugins/policy.c b/plugins/policy.c
index 0330456..933a968 100644
--- a/plugins/policy.c
+++ b/plugins/policy.c
@@ -93,6 +93,8 @@ struct policy_data {
 	uint8_t ct_retries;
 	guint tg_timer;
 	uint8_t tg_retries;
+
+	bool auth_failure;
 };
 
 static struct reconnect_data *reconnect_find(struct btd_device *dev)
@@ -172,22 +174,34 @@ static struct policy_data *find_data(struct btd_device *dev)
 	return NULL;
 }
 
-static void policy_remove(void *user_data)
+static void policy_reset(struct policy_data *data)
 {
-	struct policy_data *data = user_data;
-
-	if (data->source_timer > 0)
+	if (data->source_timer > 0) {
 		g_source_remove(data->source_timer);
+		data->source_timer = 0;
+	}
 
-	if (data->sink_timer > 0)
+	if (data->sink_timer > 0) {
 		g_source_remove(data->sink_timer);
+		data->sink_timer = 0;
+	}
 
-	if (data->ct_timer > 0)
+	if (data->ct_timer > 0) {
 		g_source_remove(data->ct_timer);
+		data->ct_timer = 0;
+	}
 
-	if (data->tg_timer > 0)
+	if (data->tg_timer > 0) {
 		g_source_remove(data->tg_timer);
+		data->tg_timer = 0;
+	}
+}
 
+static void policy_remove(void *user_data)
+{
+	struct policy_data *data = user_data;
+
+	policy_reset(data);
 	g_free(data);
 }
 
@@ -606,6 +620,11 @@ static void service_cb(struct btd_service *service,
 {
 	struct btd_profile *profile = btd_service_get_profile(service);
 	struct reconnect_data *reconnect;
+	struct policy_data *policy;
+
+	policy = find_data(btd_service_get_device(service));
+	if (policy && policy->auth_failure)
+		return;
 
 	if (g_str_equal(profile->remote_uuid, A2DP_SINK_UUID))
 		sink_cb(service, old_state, new_state);
@@ -704,20 +723,29 @@ static void reconnect_set_timer(struct reconnect_data *reconnect)
 static void disconnect_cb(struct btd_device *dev, uint8_t reason)
 {
 	struct reconnect_data *reconnect;
+	struct policy_data *policy;
 
 	DBG("reason %u", reason);
 
-	if (reason != MGMT_DEV_DISCONN_TIMEOUT)
-		return;
-
-	reconnect = reconnect_find(dev);
-	if (!reconnect || !reconnect->reconnect)
-		return;
+	switch (reason) {
+	case MGMT_DEV_DISCONN_AUTH_FAILURE:
+		policy = policy_get_data(dev);
+		policy_reset(policy);
+		policy->auth_failure = true;
+		break;
+	case MGMT_DEV_DISCONN_TIMEOUT:
+		reconnect = reconnect_find(dev);
+		if (!reconnect || !reconnect->reconnect)
+			break;
 
-	DBG("Device %s identified for auto-reconnection",
+		DBG("Device %s identified for auto-reconnection",
 							device_get_path(dev));
 
-	reconnect_set_timer(reconnect);
+		reconnect_set_timer(reconnect);
+		break;
+	default:
+		break;
+	}
 }
 
 static void conn_fail_cb(struct btd_device *dev, uint8_t status)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 5/5] client: Add support for RebondConsent request
  2016-08-04 13:28 [RFC 0/5] Rebond support Szymon Janc
                   ` (3 preceding siblings ...)
  2016-08-04 13:28 ` [RFC 4/5] plugins/policy: Disable policies on authentication failure Szymon Janc
@ 2016-08-04 13:28 ` Szymon Janc
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2016-08-04 13:28 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This allows to accept or reject rebond consent from bluetoothd.
---
 client/agent.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/client/agent.c b/client/agent.c
index 2cbc292..e4b1f01 100644
--- a/client/agent.c
+++ b/client/agent.c
@@ -144,6 +144,8 @@ dbus_bool_t agent_input(DBusConnection *conn, const char *input)
 		confirm_response(conn, input);
 	else if (!strcmp(member, "AuthorizeService"))
 		confirm_response(conn, input);
+	else if (!strcmp(member, "RebondConsent"))
+		confirm_response(conn, input);
 	else
 		g_dbus_send_error(conn, pending_message,
 					"org.bluez.Error.Canceled", NULL);
@@ -310,6 +312,23 @@ static DBusMessage *authorize_service(DBusConnection *conn,
 	return NULL;
 }
 
+static DBusMessage *rebond_consent(DBusConnection *conn,
+					DBusMessage *msg, void *user_data)
+{
+	const char *device;
+
+	rl_printf("Rebond Consent\n");
+
+	dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+							DBUS_TYPE_INVALID);
+
+	agent_prompt("Remote Device lost bond. Rebond (yes/no): ");
+
+	pending_message = dbus_message_ref(msg);
+
+	return NULL;
+}
+
 static DBusMessage *cancel_request(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
@@ -346,6 +365,9 @@ static const GDBusMethodTable methods[] = {
 	{ GDBUS_ASYNC_METHOD("AuthorizeService",
 			GDBUS_ARGS({ "device", "o" }, { "uuid", "s" }),
 			NULL,  authorize_service) },
+	{ GDBUS_ASYNC_METHOD("RebondConsent",
+			GDBUS_ARGS({ "device", "o" }),
+			NULL, rebond_consent) },
 	{ GDBUS_METHOD("Cancel", NULL, NULL, cancel_request) },
 	{ }
 };
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-08-04 13:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-04 13:28 [RFC 0/5] Rebond support Szymon Janc
2016-08-04 13:28 ` [RFC 1/5] lib/mgmt: Add MGMT_DEV_DISCONN_AUTH_FAILURE definition Szymon Janc
2016-08-04 13:28 ` [RFC 2/5] doc: Add RebondConsent method to agent API Szymon Janc
2016-08-04 13:28 ` [RFC 3/5] core/adapter: Add support for rebond consent Szymon Janc
2016-08-04 13:28 ` [RFC 4/5] plugins/policy: Disable policies on authentication failure Szymon Janc
2016-08-04 13:28 ` [RFC 5/5] client: Add support for RebondConsent request Szymon Janc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.