[RFC PATCH 1/2] plugin: add bonding complete and cancel callbacks with optional retry

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Allow plugins to register a device-level bonding complete callback
which, if it returns TRUE, specifies that a failed bonding attempt
should be retried after a short backoff period.

Since these will likely store state, require them to register a
bonding cancelled callback at the same time so they can clean up.
---
 src/adapter.c |    2 +-
 src/device.c  |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/device.h  |   12 ++++++++
 3 files changed, 99 insertions(+), 1 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index a75a0c4..d489e50 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2975,7 +2975,7 @@ void adapter_remove_connection(struct btd_adapter *adapter,
 	if (device_is_authenticating(device))
 		device_cancel_authentication(device, TRUE);
 
-	if (device_is_temporary(device)) {
+	if (device_is_temporary(device) && !device_is_retrying(device)) {
 		const char *path = device_get_path(device);
 
 		DBG("Removing temporary device %s", path);
diff --git a/src/device.c b/src/device.c
index 16855b1..50dfe8c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -86,6 +86,7 @@ struct bonding_req {
 	GIOChannel *io;
 	guint listener_id;
 	struct btd_device *device;
+	uint8_t capability;
 };
 
 struct authentication_req {
@@ -149,6 +150,10 @@ struct btd_device {
 	guint		auto_id;		/* Auto connect source id */
 
 	gboolean	connected;
+	GSList          *bonding_callbacks;
+	GSList          *bonding_cancel_callbacks;
+	uint8_t         bonding_retry_status;
+	guint           bonding_retry_timer;
 
 	sdp_list_t	*tmp_records;
 
@@ -232,6 +237,9 @@ static void device_free(gpointer user_data)
 	g_slist_free_full(device->attios, g_free);
 	g_slist_free_full(device->attios_offline, g_free);
 
+	g_slist_free(device->bonding_callbacks);
+	g_slist_free(device->bonding_cancel_callbacks);
+
 	g_attrib_unref(device->attrib);
 
 	if (device->tmp_records)
@@ -247,6 +255,9 @@ static void device_free(gpointer user_data)
 	if (device->auto_id)
 		g_source_remove(device->auto_id);
 
+	if (device->bonding_retry_timer)
+		g_source_remove(device->bonding_retry_timer);
+
 	DBG("%p", device);
 
 	g_free(device->authr);
@@ -2340,6 +2351,65 @@ static void device_auth_req_free(struct btd_device *device)
 	device->authr = NULL;
 }
 
+void btd_device_register_bonding_cb(struct btd_device *device,
+					btd_device_bonding_cb_t cb,
+					btd_device_bonding_cancel_cb_t ccb) {
+	device->bonding_callbacks = g_slist_prepend(
+					device->bonding_callbacks, cb);
+	device->bonding_cancel_callbacks = g_slist_prepend(
+					device->bonding_cancel_callbacks, ccb);
+}
+
+void btd_device_unregister_bonding_cb(struct btd_device *device,
+					btd_device_bonding_cb_t cb,
+					btd_device_bonding_cancel_cb_t ccb) {
+	device->bonding_callbacks = g_slist_remove(
+					device->bonding_callbacks, cb);
+	device->bonding_cancel_callbacks = g_slist_remove(
+					device->bonding_cancel_callbacks, ccb);
+}
+
+static gboolean device_bonding_retry(gpointer data)
+{
+	struct btd_device *device = data;
+	struct btd_adapter *adapter = device_get_adapter(device);
+	struct bonding_req *bonding = device->bonding;
+	int err;
+
+	DBG("retrying");
+	err = adapter_create_bonding(adapter, &device->bdaddr,
+							bonding->capability);
+	if (err < 0) {
+		DBG("retry failed");
+		device_bonding_complete(device, device->bonding_retry_status);
+	}
+
+	return FALSE;
+}
+
+static gboolean device_bonding_get_retry(struct btd_device *device,
+								uint8_t status)
+{
+	GSList *l;
+	btd_device_bonding_cb_t cb;
+	gboolean retry = FALSE;
+
+	for (l = device->bonding_callbacks; l != NULL; l = g_slist_next(l)) {
+		cb = l->data;
+		retry |= cb(device, status);
+	}
+
+	g_slist_free(device->bonding_callbacks);
+	device->bonding_callbacks = NULL;
+
+	return retry;
+}
+
+gboolean device_is_retrying(struct btd_device *device)
+{
+	return device->bonding_retry_timer != 0;
+}
+
 void device_bonding_complete(struct btd_device *device, uint8_t status)
 {
 	struct bonding_req *bonding = device->bonding;
@@ -2347,6 +2417,14 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
 
 	DBG("bonding %p status 0x%02x", bonding, status);
 
+	if (device_bonding_get_retry(device, status) && status) {
+		DBG("retrying in 3s");
+		device->bonding_retry_status = status;
+		device->bonding_retry_timer = g_timeout_add(3000,
+						device_bonding_retry, device);
+		return;
+	}
+
 	if (auth && auth->type == AUTH_TYPE_NOTIFY && auth->agent)
 		agent_cancel(auth->agent);
 
@@ -2437,6 +2515,8 @@ void device_cancel_bonding(struct btd_device *device, uint8_t status)
 	struct bonding_req *bonding = device->bonding;
 	DBusMessage *reply;
 	char addr[18];
+	GSList *l;
+	btd_device_bonding_cancel_cb_t ccb;
 
 	if (!bonding)
 		return;
@@ -2444,6 +2524,12 @@ void device_cancel_bonding(struct btd_device *device, uint8_t status)
 	ba2str(&device->bdaddr, addr);
 	DBG("Canceling bonding request for %s", addr);
 
+	for (l = device->bonding_cancel_callbacks; l != NULL;
+							l = g_slist_next(l)) {
+		ccb = l->data;
+		ccb(device);
+	}
+
 	if (device->authr)
 		device_cancel_authentication(device, FALSE);
 
diff --git a/src/device.h b/src/device.h
index 13005ae..4f7fd53 100644
--- a/src/device.h
+++ b/src/device.h
@@ -73,6 +73,7 @@ void device_set_temporary(struct btd_device *device, gboolean temporary);
 void device_set_bonded(struct btd_device *device, gboolean bonded);
 void device_set_auto_connect(struct btd_device *device, gboolean enable);
 gboolean device_is_connected(struct btd_device *device);
+gboolean device_is_retrying(struct btd_device *device);
 DBusMessage *device_create_bonding(struct btd_device *device,
 				DBusConnection *conn, DBusMessage *msg,
 				const char *agent_path, uint8_t capability);
@@ -100,6 +101,17 @@ guint device_add_disconnect_watch(struct btd_device *device,
 void device_remove_disconnect_watch(struct btd_device *device, guint id);
 void device_set_class(struct btd_device *device, uint32_t value);
 
+typedef gboolean (*btd_device_bonding_cb_t) (struct btd_device *device,
+								uint8_t status);
+typedef void (*btd_device_bonding_cancel_cb_t) (struct btd_device *device);
+
+void btd_device_register_bonding_cb(struct btd_device *dev,
+				btd_device_bonding_cb_t cb,
+				btd_device_bonding_cancel_cb_t ccb);
+void btd_device_unregister_bonding_cb(struct btd_device *dev, 
+				btd_device_bonding_cb_t cb,
+				btd_device_bonding_cancel_cb_t ccb);
+
 #define BTD_UUIDS(args...) ((const char *[]) { args, NULL } )
 
 struct btd_device_driver {
-- 
1.7.7.3

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux