Diff between 6e5c2bf7aed6bbed9b6279e1595f915bddb42c45 and ce18c8661a5419a46904f19cdead3b9dc65c22cc

Changed Files

File Additions Deletions Status
src/device.c +96 -13 modified

Full Patch

diff --git a/src/device.c b/src/device.c
index d356631..e94b222 100644
--- a/src/device.c
+++ b/src/device.c
@@ -112,6 +112,12 @@ struct browse_req {
 	guint listener_id;
 };
 
+struct included_search {
+	struct browse_req *req;
+	GSList *services;
+	GSList *current;
+};
+
 struct attio_data {
 	guint id;
 	attio_connect_cb cfunc;
@@ -2192,21 +2198,10 @@ static void device_unregister_services(struct btd_device *device)
 	device->services = NULL;
 }
 
-static void primary_cb(GSList *services, guint8 status, gpointer user_data)
+static void register_all_services(struct browse_req *req, GSList *services)
 {
-	struct browse_req *req = user_data;
 	struct btd_device *device = req->device;
 
-	if (status) {
-		if (req->msg) {
-			DBusMessage *reply;
-			reply = btd_error_failed(req->msg,
-							att_ecode2str(status));
-			g_dbus_send_message(btd_get_dbus_connection(), reply);
-		}
-		goto done;
-	}
-
 	device_set_temporary(device, FALSE);
 
 	if (device->services)
@@ -2231,11 +2226,99 @@ static void primary_cb(GSList *services, guint8 status, gpointer user_data)
 
 	store_services(device);
 
-done:
 	device->browse = NULL;
 	browse_request_free(req);
 }
 
+static int service_by_range_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct gatt_primary *prim = a;
+	const struct att_range *range = b;
+
+	return memcmp(&prim->range, range, sizeof(*range));
+}
+
+static void find_included_cb(GSList *includes, uint8_t status,
+						gpointer user_data)
+{
+	struct included_search *search = user_data;
+	struct btd_device *device = search->req->device;
+	struct gatt_primary *prim;
+	GSList *l;
+
+	if (includes == NULL)
+		goto done;
+
+	for (l = includes; l; l = l->next) {
+		struct gatt_included *incl = l->data;
+
+		if (g_slist_find_custom(search->services, &incl->range,
+						service_by_range_cmp))
+			continue;
+
+		prim = g_new0(struct gatt_primary, 1);
+		memcpy(prim->uuid, incl->uuid, sizeof(prim->uuid));
+		memcpy(&prim->range, &incl->range, sizeof(prim->range));
+
+		search->services = g_slist_append(search->services, prim);
+	}
+
+done:
+	search->current = search->current->next;
+	if (search->current == NULL) {
+		register_all_services(search->req, search->services);
+		g_slist_free(search->services);
+		g_free(search);
+		return;
+	}
+
+	prim = search->current->data;
+	gatt_find_included(device->attrib, prim->range.start, prim->range.end,
+					find_included_cb, search);
+}
+
+static void find_included_services(struct browse_req *req, GSList *services)
+{
+	struct btd_device *device = req->device;
+	struct included_search *search;
+	struct gatt_primary *prim;
+
+	if (services == NULL)
+		return;
+
+	search = g_new0(struct included_search, 1);
+	search->req = req;
+	search->services = g_slist_copy(services);
+	search->current = search->services;
+
+	prim = search->current->data;
+	gatt_find_included(device->attrib, prim->range.start, prim->range.end,
+					find_included_cb, search);
+
+}
+
+static void primary_cb(GSList *services, guint8 status, gpointer user_data)
+{
+	struct browse_req *req = user_data;
+
+	if (status) {
+		struct btd_device *device = req->device;
+
+		if (req->msg) {
+			DBusMessage *reply;
+			reply = btd_error_failed(req->msg,
+							att_ecode2str(status));
+			g_dbus_send_message(btd_get_dbus_connection(), reply);
+		}
+
+		device->browse = NULL;
+		browse_request_free(req);
+		return;
+	}
+
+	find_included_services(req, services);
+}
+
 static void bonding_request_free(struct bonding_req *bonding)
 {
 	struct btd_device *device;