Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange
@ 2012-08-20 17:22 Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 01/10] gatt: Add Service Changed read Claudio Takahasi
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch series implements Service Changed attribute of the remote
Generic Attribute Profile Service, and the MTU exchange sub-procedure.

Service Changed characteristic is used to indicate to connected devices
that services have changed (i.e., added, removed or modified).

The MTU exchange sub-procedure is used by the client to set the ATT_MTU
to the maximum possible value that can be supported by both devices when
the client supports a value greater than the default ATT_MTU for the
Attribute Protocol. BlueZ host will always start this sub-procedure when
the ATT channel is established.

Claudio Takahasi (10):
  gatt: Add Service Changed read
  gatt: Add Service Changed CCC discovery
  gatt: Enable indication for Service Changed
  gatt: Confirm the indication received
  gatt: Start Discover Services when handle changes
  core: Rename update_services
  core: Add updating GATT services
  gatt: Primary service interval may not change
  core: Rename services_changed to uuids_changed
  gatt: Add MTU exchange procedure

 attrib/gatt.h       |    1 +
 profiles/gatt/gas.c |  214 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/device.c        |  101 +++++++++++++++++++------
 src/device.h        |    2 +
 4 files changed, 295 insertions(+), 23 deletions(-)

-- 
1.7.8.6


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

* [PATCH BlueZ v0 01/10] gatt: Add Service Changed read
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 02/10] gatt: Add Service Changed CCC discovery Claudio Takahasi
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch implements the Service Changed GATT charateristic value read.
Force reading the value is necessary while Service Changed value handle
is not stored. Indication can be lost since it is the first data sent
from the GATT server when the connection is established, and the client
may not be filtering the ATT indications.
---
 profiles/gatt/gas.c |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index 54f5842..01017fe 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -98,9 +98,32 @@ done:
 	att_data_list_free(list);
 }
 
+static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
+					guint16 plen, gpointer user_data)
+{
+	uint16_t start, end;
+
+	if (status) {
+		error("Read GATT Service Changed failed: %s",
+						att_ecode2str(status));
+		return;
+	}
+
+	if (plen != 5) {
+		error("Service Changed: PDU length mismatch");
+		return;
+	}
+
+	start = att_get_u16(&pdu[1]);
+	end = att_get_u16(&pdu[3]);
+
+	DBG("GATT Service Changed start: 0x%04X end: 0x%04X", start, end);
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct gas *gas = user_data;
+	bt_uuid_t changed_uuid;
 	uint16_t app;
 
 	gas->attrib = g_attrib_ref(attrib);
@@ -116,6 +139,16 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 	}
 
 	/* TODO: Read other GAP characteristics - See Core spec page 1739 */
+
+	/*
+	 * Always read the characteristic value in the first connection
+	 * since attribute handles caching is not supported at the moment.
+	 */
+	bt_uuid16_create(&changed_uuid, GATT_CHARAC_SERVICE_CHANGED);
+
+	gatt_read_char_by_uuid(gas->attrib, gas->gatt.start,
+					gas->gatt.end, &changed_uuid,
+					gatt_service_changed_cb, gas);
 }
 
 static void attio_disconnected_cb(gpointer user_data)
-- 
1.7.8.6


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

* [PATCH BlueZ v0 02/10] gatt: Add Service Changed CCC discovery
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 01/10] gatt: Add Service Changed read Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 03/10] gatt: Enable indication for Service Changed Claudio Takahasi
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch adds the Client Characteristic discovery of the Service
Changed Changed characteristic.
---
 profiles/gatt/gas.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 102 insertions(+), 5 deletions(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index 01017fe..d36a457 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -43,6 +43,8 @@ struct gas {
 	struct att_range gatt;	/* GATT Primary service range */
 	GAttrib *attrib;
 	guint attioid;
+	guint changed_ind;
+	uint16_t changed_handle;
 };
 
 static GSList *devices = NULL;
@@ -98,6 +100,26 @@ done:
 	att_data_list_free(list);
 }
 
+static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct gas *gas = user_data;
+	uint16_t handle, start, end;
+
+	if (len < 7) { /* 1-byte opcode + 2-byte handle + 4 range */
+		error("Malformed ATT notification");
+		return;
+	}
+
+	handle = att_get_u16(&pdu[1]);
+	start = att_get_u16(&pdu[3]);
+	end = att_get_u16(&pdu[5]);
+
+	if (handle != gas->changed_handle)
+		return;
+
+	DBG("Service Changed start: 0x%04X end: 0x%04X", start, end);
+}
+
 static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
 					guint16 plen, gpointer user_data)
 {
@@ -120,14 +142,76 @@ static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
 	DBG("GATT Service Changed start: 0x%04X end: 0x%04X", start, end);
 }
 
+static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct att_data_list *list;
+	int i;
+	uint8_t format;
+
+	if (status) {
+		error("Discover all GATT characteristic descriptors: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (list == NULL)
+		return;
+
+	if (format != 0x01)
+		goto done;
+
+	for (i = 0; i < list->num; i++) {
+		uint16_t uuid16, ccc;
+		uint8_t *value;
+
+		value = list->data[i];
+		ccc = att_get_u16(value);
+		uuid16 = att_get_u16(&value[2]);
+		DBG("CCC: 0x%04x UUID: 0x%04x", ccc, uuid16);
+	}
+
+done:
+	att_data_list_free(list);
+}
+
+static void gatt_characteristic_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct gas *gas = user_data;
+	struct gatt_char *chr;
+	uint16_t start, end;
+
+	if (status) {
+		error("Discover Service Changed handle: %s", att_ecode2str(status));
+		return;
+	}
+
+	chr = characteristics->data;
+
+	start = chr->value_handle + 1;
+	end = gas->gatt.end;
+
+	if (start <= end) {
+		error("Inconsistent database: Service Changed CCC missing");
+		return;
+	}
+
+	gas->changed_handle = chr->value_handle;
+	gatt_find_info(gas->attrib, start, end, gatt_descriptors_cb, gas);
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct gas *gas = user_data;
-	bt_uuid_t changed_uuid;
 	uint16_t app;
 
 	gas->attrib = g_attrib_ref(attrib);
 
+	gas->changed_ind = g_attrib_register(gas->attrib, ATT_OP_HANDLE_IND,
+						indication_cb, gas, NULL);
+
 	if (device_get_appearance(gas->device, &app) < 0) {
 		bt_uuid_t uuid;
 
@@ -143,18 +227,31 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 	/*
 	 * Always read the characteristic value in the first connection
 	 * since attribute handles caching is not supported at the moment.
+	 * When re-connecting <<Service Changed>> handle and characteristic
+	 * value doesn't need to read again: known information from the
+	 * previous interaction.
 	 */
-	bt_uuid16_create(&changed_uuid, GATT_CHARAC_SERVICE_CHANGED);
+	if (gas->changed_handle == 0) {
+		bt_uuid_t uuid;
+
+		bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
 
-	gatt_read_char_by_uuid(gas->attrib, gas->gatt.start,
-					gas->gatt.end, &changed_uuid,
-					gatt_service_changed_cb, gas);
+		gatt_read_char_by_uuid(gas->attrib, gas->gatt.start,
+						gas->gatt.end, &uuid,
+						gatt_service_changed_cb, gas);
+
+		gatt_discover_char(gas->attrib, gas->gatt.start, gas->gatt.end,
+					&uuid, gatt_characteristic_cb, gas);
+	}
 }
 
 static void attio_disconnected_cb(gpointer user_data)
 {
 	struct gas *gas = user_data;
 
+	g_attrib_unregister(gas->attrib, gas->changed_ind);
+	gas->changed_ind = 0;
+
 	g_attrib_unref(gas->attrib);
 	gas->attrib = NULL;
 }
-- 
1.7.8.6


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

* [PATCH BlueZ v0 03/10] gatt: Enable indication for Service Changed
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 01/10] gatt: Add Service Changed read Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 02/10] gatt: Add Service Changed CCC discovery Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 04/10] gatt: Confirm the indication received Claudio Takahasi
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch enables indication of the Service Changed characteristic
setting the indication bit in the Client Characteristic Configuration
descriptor.
---
 profiles/gatt/gas.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index d36a457..dda4886 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -100,6 +100,27 @@ done:
 	att_data_list_free(list);
 }
 
+static void ccc_written_cb(guint8 status, const guint8 *pdu, guint16 plen,
+							gpointer user_data)
+{
+	if (status) {
+		error("Write Service Changed CCC failed: %s",
+						att_ecode2str(status));
+		return;
+	}
+
+	DBG("Service Changed indications enabled");
+}
+
+static void write_ccc(GAttrib *attrib, uint16_t handle, gpointer user_data)
+{
+	uint8_t value[2];
+
+	att_put_u16(GATT_CLIENT_CHARAC_CFG_IND_BIT, value);
+	gatt_write_char(attrib, handle, value, sizeof(value), ccc_written_cb,
+								user_data);
+}
+
 static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
 	struct gas *gas = user_data;
@@ -145,6 +166,7 @@ static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
 static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
 {
+	struct gas *gas = user_data;
 	struct att_data_list *list;
 	int i;
 	uint8_t format;
@@ -170,6 +192,7 @@ static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
 		ccc = att_get_u16(value);
 		uuid16 = att_get_u16(&value[2]);
 		DBG("CCC: 0x%04x UUID: 0x%04x", ccc, uuid16);
+		write_ccc(gas->attrib, ccc, user_data);
 	}
 
 done:
-- 
1.7.8.6


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

* [PATCH BlueZ v0 04/10] gatt: Confirm the indication received
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (2 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 03/10] gatt: Enable indication for Service Changed Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 05/10] gatt: Start Discover Services when handle changes Claudio Takahasi
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch adds the ATT command reply for the Service Changed
indication value received.
---
 profiles/gatt/gas.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index dda4886..4bf8090 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -124,7 +124,9 @@ static void write_ccc(GAttrib *attrib, uint16_t handle, gpointer user_data)
 static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
 	struct gas *gas = user_data;
-	uint16_t handle, start, end;
+	uint16_t handle, start, end, olen;
+	size_t plen;
+	uint8_t *opdu;
 
 	if (len < 7) { /* 1-byte opcode + 2-byte handle + 4 range */
 		error("Malformed ATT notification");
@@ -139,6 +141,11 @@ static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
 		return;
 
 	DBG("Service Changed start: 0x%04X end: 0x%04X", start, end);
+
+	/* Confirming indication received */
+	opdu = g_attrib_get_buffer(gas->attrib, &plen);
+	olen = enc_confirmation(opdu, plen);
+	g_attrib_send(gas->attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
 }
 
 static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
-- 
1.7.8.6


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

* [PATCH BlueZ v0 05/10] gatt: Start Discover Services when handle changes
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (3 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 04/10] gatt: Confirm the indication received Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 06/10] core: Rename update_services Claudio Takahasi
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch starts the Discover All Primary services when a Service
Changed indication is received or the Service Changed characteristic
value is read.
---
 profiles/gatt/gas.c |   18 ++++++++++++++++++
 src/device.c        |    8 --------
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index 4bf8090..3e3c3db 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -41,6 +41,7 @@ struct gas {
 	struct btd_device *device;
 	struct att_range gap;	/* GAP Primary service range */
 	struct att_range gatt;	/* GATT Primary service range */
+	struct att_range changed; /* Affected handle range */
 	GAttrib *attrib;
 	guint attioid;
 	guint changed_ind;
@@ -146,11 +147,20 @@ static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
 	opdu = g_attrib_get_buffer(gas->attrib, &plen);
 	olen = enc_confirmation(opdu, plen);
 	g_attrib_send(gas->attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
+
+	if (gas->changed.start == start && gas->changed.end == end)
+		return;
+
+	gas->changed.start = start;
+	gas->changed.end = end;
+
+	device_browse_primary(gas->device, NULL, NULL, FALSE);
 }
 
 static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
 					guint16 plen, gpointer user_data)
 {
+	struct gas *gas = user_data;
 	uint16_t start, end;
 
 	if (status) {
@@ -167,7 +177,15 @@ static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
 	start = att_get_u16(&pdu[1]);
 	end = att_get_u16(&pdu[3]);
 
+	if (gas->changed.start == start && gas->changed.end == end)
+		return;
+
+	gas->changed.start = start;
+	gas->changed.end = end;
+
 	DBG("GATT Service Changed start: 0x%04X end: 0x%04X", start, end);
+
+	device_browse_primary(gas->device, NULL, NULL, FALSE);
 }
 
 static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
diff --git a/src/device.c b/src/device.c
index f6161aa..5fee11e 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2022,14 +2022,6 @@ int device_browse_primary(struct btd_device *device, DBusConnection *conn,
 	if (device->browse)
 		return -EBUSY;
 
-	/* FIXME: GATT service updates (implemented in update_services() for
-	 * SDP) are not supported yet. It will be supported once client side
-	 * "Services Changed" characteristic handling is implemented. */
-	if (device->primaries) {
-		error("Could not update GATT services");
-		return -ENOSYS;
-	}
-
 	req = g_new0(struct browse_req, 1);
 	req->device = btd_device_ref(device);
 	adapter_get_address(adapter, &src);
-- 
1.7.8.6


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

* [PATCH BlueZ v0 06/10] core: Rename update_services
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (4 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 05/10] gatt: Start Discover Services when handle changes Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 07/10] core: Add updating GATT services Claudio Takahasi
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch renames update_services functions to avoid clashing with GATT
based services.
---
 src/device.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/device.c b/src/device.c
index 5fee11e..57e7897 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1434,7 +1434,7 @@ static int rec_cmp(const void *a, const void *b)
 	return r1->handle - r2->handle;
 }
 
-static void update_services(struct browse_req *req, sdp_list_t *recs)
+static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
 {
 	struct btd_device *device = req->device;
 	struct btd_adapter *adapter = device_get_adapter(device);
@@ -1618,7 +1618,7 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 		goto send_reply;
 	}
 
-	update_services(req, recs);
+	update_bredr_services(req, recs);
 
 	if (device->tmp_records)
 		sdp_list_free(device->tmp_records,
@@ -1706,7 +1706,7 @@ static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
 			goto done;
 	}
 
-	update_services(req, recs);
+	update_bredr_services(req, recs);
 
 	adapter_get_address(adapter, &src);
 
-- 
1.7.8.6


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

* [PATCH BlueZ v0 07/10] core: Add updating GATT services
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (5 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 06/10] core: Rename update_services Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 08/10] gatt: Primary service interval may not change Claudio Takahasi
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch adds the functions to manage Profiles added, and removed
after a Discover All Primary Services procedure.
---
 src/device.c |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/src/device.c b/src/device.c
index 57e7897..8626ad6 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1532,6 +1532,46 @@ static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
 	}
 }
 
+static gint primary_cmp(gconstpointer a, gconstpointer b)
+{
+	return memcmp(a, b, sizeof(struct gatt_primary));
+}
+
+static void update_gatt_services(struct browse_req *req, GSList *current,
+								GSList *found)
+{
+	GSList *l, *lmatch, *left = g_slist_copy(current);
+
+	/* Added Profiles */
+	for (l = found; l; l = g_slist_next(l)) {
+		struct gatt_primary *prim = l->data;
+
+		/* Entry found ? */
+		lmatch = g_slist_find_custom(current, prim, primary_cmp);
+		if (lmatch) {
+			left = g_slist_remove(left, lmatch->data);
+			continue;
+		}
+
+		/* New entry */
+		req->profiles_added = g_slist_append(req->profiles_added,
+							g_strdup(prim->uuid));
+
+		DBG("UUID Added: %s", prim->uuid);
+	}
+
+	/* Removed Profiles */
+	for (l = left; l; l = g_slist_next(l)) {
+		struct gatt_primary *prim = l->data;
+		req->profiles_removed = g_slist_append(req->profiles_removed,
+							g_strdup(prim->uuid));
+
+		DBG("UUID Removed: %s", prim->uuid);
+	}
+
+	g_slist_free(left);
+}
+
 static void store_profiles(struct btd_device *device)
 {
 	struct btd_adapter *adapter = device->adapter;
@@ -1830,11 +1870,17 @@ done:
 	return FALSE;
 }
 
+static void device_unregister_services(struct btd_device *device)
+{
+	attrib_client_unregister(device->services);
+	g_slist_free_full(device->services, g_free);
+	device->services = NULL;
+}
+
 static void primary_cb(GSList *services, guint8 status, gpointer user_data)
 {
 	struct browse_req *req = user_data;
 	struct btd_device *device = req->device;
-	GSList *l, *uuids = NULL;
 
 	if (status) {
 		if (req->msg) {
@@ -1848,20 +1894,22 @@ static void primary_cb(GSList *services, guint8 status, gpointer user_data)
 
 	device_set_temporary(device, FALSE);
 
-	for (l = services; l; l = l->next) {
-		struct gatt_primary *prim = l->data;
+	if (device->services)
+		device_unregister_services(device);
 
-		uuids = g_slist_append(uuids, prim->uuid);
-	}
+	update_gatt_services(req, device->primaries, services);
+	g_slist_free_full(device->primaries, g_free);
+	device->primaries = NULL;
 
 	device_register_services(req->conn, device, g_slist_copy(services), -1);
-	device_probe_drivers(device, uuids);
+	if (req->profiles_removed)
+		device_remove_drivers(device, req->profiles_removed);
+
+	device_probe_drivers(device, req->profiles_added);
 
 	if (device->attios == NULL && device->attios_offline == NULL)
 		attio_cleanup(device);
 
-	g_slist_free(uuids);
-
 	services_changed(device);
 	if (req->msg)
 		create_device_reply(device, req);
-- 
1.7.8.6


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

* [PATCH BlueZ v0 08/10] gatt: Primary service interval may not change
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (6 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 07/10] core: Add updating GATT services Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 09/10] core: Rename services_changed to uuids_changed Claudio Takahasi
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch address the "Service Changed" scenario on which the start
and end Primary Service attribute handle interval doesn't change.
---
 attrib/gatt.h       |    1 +
 profiles/gatt/gas.c |    4 ++--
 src/device.c        |   15 +++++++++++++++
 src/device.h        |    2 ++
 4 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/attrib/gatt.h b/attrib/gatt.h
index 7690fba..a15e92f 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -57,6 +57,7 @@ typedef void (*gatt_cb_t) (GSList *l, guint8 status, gpointer user_data);
 
 struct gatt_primary {
 	char uuid[MAX_LEN_UUID_STR + 1];
+	gboolean changed;
 	struct att_range range;
 };
 
diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index 3e3c3db..de23a13 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -154,7 +154,7 @@ static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
 	gas->changed.start = start;
 	gas->changed.end = end;
 
-	device_browse_primary(gas->device, NULL, NULL, FALSE);
+	btd_device_gatt_set_service_changed(gas->device, start, end);
 }
 
 static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
@@ -185,7 +185,7 @@ static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
 
 	DBG("GATT Service Changed start: 0x%04X end: 0x%04X", start, end);
 
-	device_browse_primary(gas->device, NULL, NULL, FALSE);
+	btd_device_gatt_set_service_changed(gas->device, start, end);
 }
 
 static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
diff --git a/src/device.c b/src/device.c
index 8626ad6..c4b5554 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2938,6 +2938,21 @@ GSList *btd_device_get_primaries(struct btd_device *device)
 	return device->primaries;
 }
 
+void btd_device_gatt_set_service_changed(struct btd_device *device,
+						uint16_t start, uint16_t end)
+{
+	GSList *l;
+
+	for (l = device->primaries; l; l = g_slist_next(l)) {
+		struct gatt_primary *prim = l->data;
+
+		if (start <= prim->range.end && end >= prim->range.start)
+			prim->changed = TRUE;
+	}
+
+	device_browse_primary(device, NULL, NULL, FALSE);
+}
+
 void btd_device_add_uuid(struct btd_device *device, const char *uuid)
 {
 	GSList *uuid_list;
diff --git a/src/device.h b/src/device.h
index 85d265a..a65de26 100644
--- a/src/device.h
+++ b/src/device.h
@@ -53,6 +53,8 @@ void device_probe_drivers(struct btd_device *device, GSList *profiles);
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
 						const char *uuid);
 GSList *btd_device_get_primaries(struct btd_device *device);
+void btd_device_gatt_set_service_changed(struct btd_device *device,
+						uint16_t start, uint16_t end);
 void device_register_services(DBusConnection *conn, struct btd_device *device,
 						GSList *prim_list, int psm);
 GSList *device_services_from_record(struct btd_device *device,
-- 
1.7.8.6


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

* [PATCH BlueZ v0 09/10] core: Rename services_changed to uuids_changed
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (7 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 08/10] gatt: Primary service interval may not change Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:22 ` [PATCH BlueZ v0 10/10] gatt: Add MTU exchange procedure Claudio Takahasi
  2012-08-20 17:44 ` [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Johan Hedberg
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch renames the services_changed function to uuids_changed to
avoid misinterpretation. "Service Changed" expression is used to refer
to a GATT operation used to notify clients that a given attribute range
in the GATT server is not valid anymore.
---
 src/device.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/device.c b/src/device.c
index c4b5554..7b44e27 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1409,7 +1409,7 @@ static void device_remove_drivers(struct btd_device *device, GSList *uuids)
 		sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
 }
 
-static void services_changed(struct btd_device *device)
+static void uuids_changed(struct btd_device *device)
 {
 	DBusConnection *conn = get_dbus_connection();
 	char **uuids;
@@ -1689,7 +1689,7 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 		device_remove_drivers(device, req->profiles_removed);
 
 	/* Propagate services changes */
-	services_changed(req->device);
+	uuids_changed(req->device);
 
 send_reply:
 	if (!req->msg)
@@ -1910,7 +1910,7 @@ static void primary_cb(GSList *services, guint8 status, gpointer user_data)
 	if (device->attios == NULL && device->attios_offline == NULL)
 		attio_cleanup(device);
 
-	services_changed(device);
+	uuids_changed(device);
 	if (req->msg)
 		create_device_reply(device, req);
 
@@ -2971,7 +2971,7 @@ void btd_device_add_uuid(struct btd_device *device, const char *uuid)
 	g_slist_free(uuid_list);
 
 	store_profiles(device);
-	services_changed(device);
+	uuids_changed(device);
 }
 
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
-- 
1.7.8.6


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

* [PATCH BlueZ v0 10/10] gatt: Add MTU exchange procedure
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (8 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 09/10] core: Rename services_changed to uuids_changed Claudio Takahasi
@ 2012-08-20 17:22 ` Claudio Takahasi
  2012-08-20 17:44 ` [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Johan Hedberg
  10 siblings, 0 replies; 12+ messages in thread
From: Claudio Takahasi @ 2012-08-20 17:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

GATT Exchange MTU is a procedure defined by the Generic Attribute
Profile, it is not related to the remote GATT primary service. However,
gatt plugin is the most suitable place to manage this procedure.
---
 profiles/gatt/gas.c |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index de23a13..61e6745 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -32,6 +32,7 @@
 #include "att.h"
 #include "gattrib.h"
 #include "attio.h"
+#include "btio.h"
 #include "gatt.h"
 #include "log.h"
 #include "gas.h"
@@ -46,6 +47,7 @@ struct gas {
 	guint attioid;
 	guint changed_ind;
 	uint16_t changed_handle;
+	uint16_t mtu;
 };
 
 static GSList *devices = NULL;
@@ -250,12 +252,46 @@ static void gatt_characteristic_cb(GSList *characteristics, guint8 status,
 	gatt_find_info(gas->attrib, start, end, gatt_descriptors_cb, gas);
 }
 
+static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
+							gpointer user_data)
+{
+	struct gas *gas = user_data;
+	uint16_t rmtu;
+
+	if (status) {
+		error("MTU exchange: %s", att_ecode2str(status));
+		return;
+	}
+
+	if (!dec_mtu_resp(pdu, plen, &rmtu)) {
+		error("MTU exchange: protocol error");
+		return;
+	}
+
+	gas->mtu = MIN(rmtu, gas->mtu);
+	if (g_attrib_set_mtu(gas->attrib, gas->mtu))
+		DBG("MTU exchange succeeded: %d", gas->mtu);
+	else
+		DBG("MTU exchange failed");
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct gas *gas = user_data;
+	GIOChannel *io;
+	GError *gerr = NULL;
+	uint16_t cid, imtu;
 	uint16_t app;
 
 	gas->attrib = g_attrib_ref(attrib);
+	io = g_attrib_get_channel(attrib);
+
+	if (bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_IMTU, &imtu,
+				BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID)) {
+		gatt_exchange_mtu(gas->attrib, imtu, exchange_mtu_cb, gas);
+		gas->mtu = imtu;
+		DBG("MTU Exchange: Requesting %d", imtu);
+	}
 
 	gas->changed_ind = g_attrib_register(gas->attrib, ATT_OP_HANDLE_IND,
 						indication_cb, gas, NULL);
-- 
1.7.8.6


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

* Re: [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange
  2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
                   ` (9 preceding siblings ...)
  2012-08-20 17:22 ` [PATCH BlueZ v0 10/10] gatt: Add MTU exchange procedure Claudio Takahasi
@ 2012-08-20 17:44 ` Johan Hedberg
  10 siblings, 0 replies; 12+ messages in thread
From: Johan Hedberg @ 2012-08-20 17:44 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth

Hi Claudio,

On Mon, Aug 20, 2012, Claudio Takahasi wrote:
> This patch series implements Service Changed attribute of the remote
> Generic Attribute Profile Service, and the MTU exchange sub-procedure.
> 
> Service Changed characteristic is used to indicate to connected devices
> that services have changed (i.e., added, removed or modified).
> 
> The MTU exchange sub-procedure is used by the client to set the ATT_MTU
> to the maximum possible value that can be supported by both devices when
> the client supports a value greater than the default ATT_MTU for the
> Attribute Protocol. BlueZ host will always start this sub-procedure when
> the ATT channel is established.
> 
> Claudio Takahasi (10):
>   gatt: Add Service Changed read
>   gatt: Add Service Changed CCC discovery
>   gatt: Enable indication for Service Changed
>   gatt: Confirm the indication received
>   gatt: Start Discover Services when handle changes
>   core: Rename update_services
>   core: Add updating GATT services
>   gatt: Primary service interval may not change
>   core: Rename services_changed to uuids_changed
>   gatt: Add MTU exchange procedure
> 
>  attrib/gatt.h       |    1 +
>  profiles/gatt/gas.c |  214 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/device.c        |  101 +++++++++++++++++++------
>  src/device.h        |    2 +
>  4 files changed, 295 insertions(+), 23 deletions(-)

All patches in this set have been applied. Thanks.

Johan

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

end of thread, other threads:[~2012-08-20 17:44 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-20 17:22 [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 01/10] gatt: Add Service Changed read Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 02/10] gatt: Add Service Changed CCC discovery Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 03/10] gatt: Enable indication for Service Changed Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 04/10] gatt: Confirm the indication received Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 05/10] gatt: Start Discover Services when handle changes Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 06/10] core: Rename update_services Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 07/10] core: Add updating GATT services Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 08/10] gatt: Primary service interval may not change Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 09/10] core: Rename services_changed to uuids_changed Claudio Takahasi
2012-08-20 17:22 ` [PATCH BlueZ v0 10/10] gatt: Add MTU exchange procedure Claudio Takahasi
2012-08-20 17:44 ` [PATCH BlueZ v0 00/10] GATT plugin: Service Changed and MTU exchange Johan Hedberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox