public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR
@ 2014-07-10 14:30 Szymon Janc
  2014-07-10 14:30 ` [PATCH v2 2/5] android/bluetooth: Add function for checking last seen bearer Szymon Janc
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Szymon Janc @ 2014-07-10 14:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This adds listening on both LE and BR/EDR and SDP records for GAP,
GATT and DIS.
---
 android/gatt.c | 243 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 193 insertions(+), 50 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 1e2366d..e07226c 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -35,6 +35,7 @@
 #include "ipc.h"
 #include "ipc-common.h"
 #include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
 #include "bluetooth.h"
 #include "gatt.h"
@@ -190,7 +191,12 @@ static struct gatt_db *gatt_db = NULL;
 
 static uint16_t service_changed_handle = 0;
 
-static GIOChannel *listening_io = NULL;
+static GIOChannel *le_io = NULL;
+static GIOChannel *bredr_io = NULL;
+
+static uint32_t gatt_sdp_handle = 0;
+static uint32_t gap_sdp_handle = 0;
+static uint32_t dis_sdp_handle = 0;
 
 static struct bt_crypto *crypto = NULL;
 
@@ -4742,6 +4748,93 @@ static void notify_service_change(void *data, void *user_data)
 	notify_att_range_change(data, &range);
 }
 
+static sdp_record_t *get_sdp_record(uuid_t *uuid, uint16_t start, uint16_t end,
+							const char *name)
+{
+	sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
+	uuid_t root_uuid, proto_uuid, l2cap;
+	sdp_record_t *record;
+	sdp_data_t *psm, *sh, *eh;
+	uint16_t lp = ATT_PSM;
+
+	record = sdp_record_alloc();
+	if (record == NULL)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(NULL, &root_uuid);
+	sdp_set_browse_groups(record, root);
+	sdp_list_free(root, NULL);
+
+	svclass_id = sdp_list_append(NULL, uuid);
+	sdp_set_service_classes(record, svclass_id);
+	sdp_list_free(svclass_id, NULL);
+
+	sdp_uuid16_create(&l2cap, L2CAP_UUID);
+	proto[0] = sdp_list_append(NULL, &l2cap);
+	psm = sdp_data_alloc(SDP_UINT16, &lp);
+	proto[0] = sdp_list_append(proto[0], psm);
+	apseq = sdp_list_append(NULL, proto[0]);
+
+	sdp_uuid16_create(&proto_uuid, ATT_UUID);
+	proto[1] = sdp_list_append(NULL, &proto_uuid);
+	sh = sdp_data_alloc(SDP_UINT16, &start);
+	proto[1] = sdp_list_append(proto[1], sh);
+	eh = sdp_data_alloc(SDP_UINT16, &end);
+	proto[1] = sdp_list_append(proto[1], eh);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(NULL, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	if (name)
+		sdp_set_info_attr(record, name, "BlueZ for Android", NULL);
+
+	sdp_data_free(psm);
+	sdp_data_free(sh);
+	sdp_data_free(eh);
+	sdp_list_free(proto[0], NULL);
+	sdp_list_free(proto[1], NULL);
+	sdp_list_free(apseq, NULL);
+	sdp_list_free(aproto, NULL);
+
+	return record;
+}
+
+static uint32_t add_sdp_record(const bt_uuid_t *uuid, uint16_t start,
+						uint16_t end, const char *name)
+{
+	sdp_record_t *rec;
+	uuid_t u, u32;
+
+	switch (uuid->type) {
+	case BT_UUID16:
+		sdp_uuid16_create(&u, uuid->value.u16);
+		break;
+	case BT_UUID32:
+		sdp_uuid32_create(&u32, uuid->value.u32);
+		sdp_uuid32_to_uuid128(&u, &u32);
+		break;
+	case BT_UUID128:
+		sdp_uuid128_create(&u, &uuid->value.u128);
+		break;
+	default:
+		return 0;
+	}
+
+	rec = get_sdp_record(&u, start, end, name);
+	if (!rec)
+		return 0;
+
+	if (bt_adapter_add_record(rec, 0) < 0) {
+		error("gatt: Failed to register SDP record");
+		sdp_record_free(rec);
+		return 0;
+	}
+
+	return rec->handle;
+}
+
 static void handle_server_start_service(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_gatt_server_start_service *cmd = buf;
@@ -5884,6 +5977,7 @@ done:
 
 static void register_gap_service(void)
 {
+	uint16_t start, end;
 	bt_uuid_t uuid;
 
 	/* GAP UUID */
@@ -5918,6 +6012,14 @@ static void register_gap_service(void)
 							NULL);
 
 	gatt_db_service_set_active(gatt_db, gap_srvc_data.srvc , true);
+
+	/* SDP */
+	start = gap_srvc_data.srvc;
+	end = gatt_db_get_end_handle(gatt_db, gap_srvc_data.srvc);
+	gap_sdp_handle = add_sdp_record(&uuid, start, end,
+						"Generic Access Profile");
+	if (!gap_sdp_handle)
+		error("gatt: Failed to register GAP SDP record");
 }
 
 /* TODO: Get those data from device possible via androig/bluetooth.c */
@@ -5973,7 +6075,7 @@ done:
 static void register_device_info_service(void)
 {
 	bt_uuid_t uuid;
-	uint16_t srvc_handle;
+	uint16_t srvc_handle, end_handle;
 
 	DBG("");
 
@@ -6019,6 +6121,13 @@ static void register_device_info_service(void)
 					(void *) device_info.manufacturer_name);
 
 	gatt_db_service_set_active(gatt_db, srvc_handle, true);
+
+	/* SDP */
+	end_handle = gatt_db_get_end_handle(gatt_db, srvc_handle);
+	dis_sdp_handle = add_sdp_record(&uuid, srvc_handle, end_handle,
+						"Device Information Service");
+	if (!dis_sdp_handle)
+		error("gatt: Failed to register DIS SDP record");
 }
 
 static void gatt_srvc_change_write_cb(uint16_t handle, uint16_t offset,
@@ -6087,8 +6196,8 @@ static void gatt_srvc_change_read_cb(uint16_t handle, uint16_t offset,
 
 static void register_gatt_service(void)
 {
+	uint16_t srvc_handle, end_handle;
 	bt_uuid_t uuid;
-	uint16_t srvc_handle;
 
 	DBG("");
 
@@ -6108,22 +6217,34 @@ static void register_gatt_service(void)
 					gatt_srvc_change_write_cb, NULL);
 
 	gatt_db_service_set_active(gatt_db, srvc_handle, true);
+
+	/* SDP */
+	end_handle = gatt_db_get_end_handle(gatt_db, srvc_handle);
+	gatt_sdp_handle = add_sdp_record(&uuid, srvc_handle, end_handle,
+						"Generic Attribute Profile");
+
+	if (!gatt_sdp_handle)
+		error("gatt: Failed to register GATT SDP record");
 }
 
-static bool start_listening_io(void)
+static bool start_listening(void)
 {
-	GError *gerr = NULL;
+	/* BR/EDR socket */
+	bredr_io = bt_io_listen(NULL, connect_confirm, NULL, NULL, NULL,
+					BT_IO_OPT_SOURCE_TYPE, BDADDR_BREDR,
+					BT_IO_OPT_PSM, ATT_PSM,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+					BT_IO_OPT_INVALID);
 
-	/* For now only listen on BLE */
-	listening_io = bt_io_listen(NULL, connect_confirm,
-					&listening_io, NULL, &gerr,
+	/* LE socket */
+	le_io = bt_io_listen(NULL, connect_confirm, NULL, NULL, NULL,
 					BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
 					BT_IO_OPT_CID, ATT_CID,
 					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 					BT_IO_OPT_INVALID);
-	if (!listening_io) {
-		error("gatt: Failed to start listening IO (%s)", gerr->message);
-		g_error_free(gerr);
+
+	if (!le_io && !bredr_io) {
+		error("gatt: Failed to start listening IO");
 		return false;
 	}
 
@@ -6134,26 +6255,13 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
 {
 	DBG("");
 
-	if (!start_listening_io())
-		return false;
-
-	if (!bt_le_register(le_device_found_handler)) {
-		error("gatt: bt_le_register failed");
-
-		g_io_channel_unref(listening_io);
-		listening_io = NULL;
-
+	if (!start_listening())
 		return false;
-	}
 
 	crypto = bt_crypto_new();
 	if (!crypto) {
 		error("gatt: Failed to setup crypto");
-
-		g_io_channel_unref(listening_io);
-		listening_io = NULL;
-
-		return false;
+		goto failed;
 	}
 
 	gatt_devices = queue_new();
@@ -6165,28 +6273,12 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
 	if (!gatt_devices || !gatt_apps || !listen_apps || !app_connections ||
 								!gatt_db) {
 		error("gatt: Failed to allocate memory for queues");
+		goto failed;
+	}
 
-		queue_destroy(gatt_apps, NULL);
-		gatt_apps = NULL;
-
-		queue_destroy(gatt_devices, NULL);
-		gatt_devices = NULL;
-
-		queue_destroy(app_connections, NULL);
-		app_connections = NULL;
-
-		queue_destroy(listen_apps, NULL);
-		listen_apps = NULL;
-
-		gatt_db_destroy(gatt_db);
-		gatt_db = NULL;
-
-		g_io_channel_unref(listening_io);
-		listening_io = NULL;
-
-		bt_crypto_unref(crypto);
-
-		return false;
+	if (!bt_le_register(le_device_found_handler)) {
+		error("gatt: bt_le_register failed");
+		goto failed;
 	}
 
 	bacpy(&adapter_addr, addr);
@@ -6200,7 +6292,41 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
 	register_device_info_service();
 	register_gatt_service();
 
+	info("gatt: LE: %s BR/EDR: %s", le_io ? "enabled" : "disabled",
+					bredr_io ? "enabled" : "disabled");
+
 	return true;
+
+failed:
+	queue_destroy(gatt_apps, NULL);
+	gatt_apps = NULL;
+
+	queue_destroy(gatt_devices, NULL);
+	gatt_devices = NULL;
+
+	queue_destroy(app_connections, NULL);
+	app_connections = NULL;
+
+	queue_destroy(listen_apps, NULL);
+	listen_apps = NULL;
+
+	gatt_db_destroy(gatt_db);
+	gatt_db = NULL;
+
+	bt_crypto_unref(crypto);
+	crypto = NULL;
+
+	if (le_io) {
+		g_io_channel_unref(le_io);
+		le_io = NULL;
+	}
+
+	if (bredr_io) {
+		g_io_channel_unref(bredr_io);
+		bredr_io = NULL;
+	}
+
+	return false;
 }
 
 void bt_gatt_unregister(void)
@@ -6225,8 +6351,26 @@ void bt_gatt_unregister(void)
 	gatt_db_destroy(gatt_db);
 	gatt_db = NULL;
 
-	g_io_channel_unref(listening_io);
-	listening_io = NULL;
+	g_io_channel_unref(le_io);
+	le_io = NULL;
+
+	g_io_channel_unref(bredr_io);
+	bredr_io = NULL;
+
+	if (gap_sdp_handle) {
+		bt_adapter_remove_record(gap_sdp_handle);
+		gap_sdp_handle = 0;
+	}
+
+	if (gatt_sdp_handle) {
+		bt_adapter_remove_record(gatt_sdp_handle);
+		gatt_sdp_handle = 0;
+	}
+
+	if (dis_sdp_handle) {
+		bt_adapter_remove_record(dis_sdp_handle);
+		dis_sdp_handle = 0;
+	}
 
 	bt_crypto_unref(crypto);
 	crypto = NULL;
@@ -6234,7 +6378,6 @@ void bt_gatt_unregister(void)
 	bt_le_unregister();
 }
 
-
 unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
 							gatt_conn_cb_t func)
 {
-- 
1.9.1


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

* [PATCH v2 2/5] android/bluetooth: Add function for checking last seen bearer
  2014-07-10 14:30 [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
@ 2014-07-10 14:30 ` Szymon Janc
  2014-07-10 14:30 ` [PATCH v2 3/5] android/gatt: Choose LE or BR/EDR based on " Szymon Janc
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2014-07-10 14:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/bluetooth.c | 11 +++++++++++
 android/bluetooth.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 54c69b8..a2ab445 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -3985,6 +3985,17 @@ static uint8_t select_device_bearer(struct device *dev)
 	return dev->bredr ? BDADDR_BREDR : dev->bdaddr_type;
 }
 
+uint8_t bt_device_last_seen_bearer(const bdaddr_t *bdaddr)
+{
+	 struct device *dev;
+
+	dev = find_device(bdaddr);
+	if (!dev)
+		return BDADDR_BREDR;
+
+	return select_device_bearer(dev);
+}
+
 static bool device_is_paired(struct device *dev, uint8_t addr_type)
 {
 	if (addr_type == BDADDR_BREDR)
diff --git a/android/bluetooth.h b/android/bluetooth.h
index dde477d..e00634c 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -58,6 +58,7 @@ bool bt_le_set_advertising(bool advertising, bt_le_set_advertising_done cb,
 
 uint8_t bt_get_device_android_type(const bdaddr_t *addr);
 bool bt_is_device_le(const bdaddr_t *addr);
+uint8_t bt_device_last_seen_bearer(const bdaddr_t *bdaddr);
 
 const char *bt_get_adapter_name(void);
 bool bt_device_is_bonded(const bdaddr_t *bdaddr);
-- 
1.9.1


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

* [PATCH v2 3/5] android/gatt: Choose LE or BR/EDR based on last seen bearer
  2014-07-10 14:30 [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
  2014-07-10 14:30 ` [PATCH v2 2/5] android/bluetooth: Add function for checking last seen bearer Szymon Janc
@ 2014-07-10 14:30 ` Szymon Janc
  2014-07-10 14:30 ` [PATCH v2 4/5] shared/gatt: Add function for getting service UUID Szymon Janc
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2014-07-10 14:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This allows to connect both over LE and BR/EDR bearer.
---
 android/gatt.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index e07226c..6f04439 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -1702,6 +1702,49 @@ static void app_disconnect_devices(struct gatt_app *client)
 	}
 }
 
+static int connect_bredr(struct gatt_device *dev)
+{
+	BtIOSecLevel sec_level;
+	GIOChannel *io;
+	GError *gerr = NULL;
+	char addr[18];
+
+	ba2str(&dev->bdaddr, addr);
+
+	/* There is one connection attempt going on */
+	if (dev->att_io) {
+		info("gatt: connection to dev %s is ongoing", addr);
+		return -EALREADY;
+	}
+
+	DBG("Connection attempt to: %s", addr);
+
+	sec_level = bt_device_is_bonded(&dev->bdaddr) ? BT_IO_SEC_MEDIUM :
+								BT_IO_SEC_LOW;
+
+	io = bt_io_connect(connect_cb, device_ref(dev), NULL, &gerr,
+			BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+			BT_IO_OPT_SOURCE_TYPE, BDADDR_BREDR,
+			BT_IO_OPT_DEST_BDADDR, &dev->bdaddr,
+			BT_IO_OPT_DEST_TYPE, BDADDR_BREDR,
+			BT_IO_OPT_PSM, ATT_PSM,
+			BT_IO_OPT_SEC_LEVEL, sec_level,
+			BT_IO_OPT_INVALID);
+	if (!io) {
+		error("gatt: Failed bt_io_connect(%s): %s", addr,
+							gerr->message);
+		g_error_free(gerr);
+		return -EIO;
+	}
+
+	device_set_state(dev, DEVICE_CONNECT_READY);
+
+	/* Keep this, so we can cancel the connection */
+	dev->att_io = io;
+
+	return 0;
+}
+
 static bool trigger_connection(struct app_connection *connection)
 {
 	switch (connection->device->state) {
@@ -1715,6 +1758,11 @@ static bool trigger_connection(struct app_connection *connection)
 		break;
 	}
 
+	/* If device was last seen over BR/EDR connect over it */
+	if (bt_device_last_seen_bearer(&connection->device->bdaddr) ==
+								BDADDR_BREDR)
+		return connect_bredr(connection->device) == 0;
+
 	/* after state change trigger discovering */
 	if (!scanning && (connection->device->state == DEVICE_CONNECT_INIT))
 		if (!bt_le_discovery_start()) {
-- 
1.9.1


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

* [PATCH v2 4/5] shared/gatt: Add function for getting service UUID
  2014-07-10 14:30 [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
  2014-07-10 14:30 ` [PATCH v2 2/5] android/bluetooth: Add function for checking last seen bearer Szymon Janc
  2014-07-10 14:30 ` [PATCH v2 3/5] android/gatt: Choose LE or BR/EDR based on " Szymon Janc
@ 2014-07-10 14:30 ` Szymon Janc
  2014-07-10 14:30 ` [PATCH v2 5/5] android/gatt: Register SDP records for services Szymon Janc
  2014-07-11 20:10 ` [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2014-07-10 14:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 src/shared/gatt-db.c | 31 +++++++++++++++++++++++++++++++
 src/shared/gatt-db.h |  2 ++
 2 files changed, 33 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 9cbf409..bd25d47 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -732,6 +732,37 @@ uint16_t gatt_db_get_end_handle(struct gatt_db *db, uint16_t handle)
 	return service->attributes[0]->handle + service->num_handles - 1;
 }
 
+bool gatt_db_get_service_uuid(struct gatt_db *db, uint16_t handle,
+								bt_uuid_t *uuid)
+{
+	struct gatt_db_service *service;
+
+	service = queue_find(db->services, find_service_for_handle,
+						INT_TO_PTR(handle));
+	if (!service)
+		return false;
+
+	if (service->attributes[0]->value_len == 2) {
+		uint16_t value;
+
+		value = get_le16(service->attributes[0]->value);
+		bt_uuid16_create(uuid, value);
+
+		return true;
+	}
+
+	if (service->attributes[0]->value_len == 8) {
+		uint128_t value;
+
+		bswap_128(service->attributes[0]->value, &value);
+		bt_uuid128_create(uuid, value);
+
+		return true;
+	}
+
+	return false;
+}
+
 bool gatt_db_get_attribute_permissions(struct gatt_db *db, uint16_t handle,
 							uint32_t *permissions)
 {
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index a88f637..8d18434 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -91,6 +91,8 @@ const bt_uuid_t *gatt_db_get_attribute_type(struct gatt_db *db,
 							uint16_t handle);
 
 uint16_t gatt_db_get_end_handle(struct gatt_db *db, uint16_t handle);
+bool gatt_db_get_service_uuid(struct gatt_db *db, uint16_t handle,
+							bt_uuid_t *uuid);
 
 bool gatt_db_get_attribute_permissions(struct gatt_db *db, uint16_t handle,
 							uint32_t *permissions);
-- 
1.9.1


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

* [PATCH v2 5/5] android/gatt: Register SDP records for services
  2014-07-10 14:30 [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
                   ` (2 preceding siblings ...)
  2014-07-10 14:30 ` [PATCH v2 4/5] shared/gatt: Add function for getting service UUID Szymon Janc
@ 2014-07-10 14:30 ` Szymon Janc
  2014-07-11 20:10 ` [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2014-07-10 14:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/gatt.c    | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 android/hal-msg.h |   4 ++
 2 files changed, 124 insertions(+), 6 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 6f04439..696b772 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -177,6 +177,11 @@ struct app_connection {
 	bool wait_execute_write;
 };
 
+struct service_sdp {
+	int32_t service_handle;
+	uint32_t sdp_handle;
+};
+
 static struct ipc *hal_ipc = NULL;
 static bdaddr_t adapter_addr;
 static bool scanning = false;
@@ -186,6 +191,8 @@ static struct queue *gatt_apps = NULL;
 static struct queue *gatt_devices = NULL;
 static struct queue *app_connections = NULL;
 
+static struct queue *services_sdp = NULL;
+
 static struct queue *listen_apps = NULL;
 static struct gatt_db *gatt_db = NULL;
 
@@ -4883,6 +4890,84 @@ static uint32_t add_sdp_record(const bt_uuid_t *uuid, uint16_t start,
 	return rec->handle;
 }
 
+static bool match_service_sdp(const void *data, const void *user_data)
+{
+	const struct service_sdp *s = data;
+
+	return s->service_handle == PTR_TO_INT(user_data);
+}
+
+static struct service_sdp *new_service_sdp_record(int32_t service_handle)
+{
+	bt_uuid_t uuid;
+	struct service_sdp *s;
+	uint16_t end_handle;
+
+	end_handle = gatt_db_get_end_handle(gatt_db, service_handle);
+	if (!end_handle)
+		return NULL;
+
+	if (!gatt_db_get_service_uuid(gatt_db, service_handle, &uuid))
+		return NULL;
+
+	s = new0(struct service_sdp, 1);
+	if (!s)
+		return NULL;
+
+	s->service_handle = service_handle;
+	s->sdp_handle = add_sdp_record(&uuid, service_handle, end_handle, NULL);
+	if (!s->sdp_handle) {
+		free(s);
+		return NULL;
+	}
+
+	return s;
+}
+
+static void free_service_sdp_record(void *data)
+{
+	struct service_sdp *s = data;
+
+	if (!s)
+		return;
+
+	bt_adapter_remove_record(s->sdp_handle);
+	free(s);
+}
+
+static bool add_service_sdp_record(int32_t service_handle)
+{
+	struct service_sdp *s;
+
+	s = queue_find(services_sdp, match_service_sdp,
+						INT_TO_PTR(service_handle));
+	if (s)
+		return true;
+
+	s = new_service_sdp_record(service_handle);
+	if (!s)
+		return false;
+
+	if (!queue_push_tail(services_sdp, s)) {
+		free_service_sdp_record(s);
+		return false;
+	}
+
+	return true;
+}
+
+static void remove_service_sdp_record(int32_t service_handle)
+{
+	struct service_sdp *s;
+
+	s = queue_remove_if(services_sdp, match_service_sdp,
+						INT_TO_PTR(service_handle));
+	if (!s)
+		return;
+
+	free_service_sdp_record(s);
+}
+
 static void handle_server_start_service(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_gatt_server_start_service *cmd = buf;
@@ -4900,10 +4985,26 @@ static void handle_server_start_service(const void *buf, uint16_t len)
 		goto failed;
 	}
 
-	/* TODO: support BR/EDR (cmd->transport) */
+	switch (cmd->transport) {
+	case GATT_SERVER_TRANSPORT_BREDR:
+	case GATT_SERVER_TRANSPORT_LE_BREDR:
+		if (!add_service_sdp_record(cmd->service_handle)) {
+			status = HAL_STATUS_FAILED;
+			goto failed;
+		}
+		break;
+	case GATT_SERVER_TRANSPORT_LE:
+		break;
+	default:
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
 
 	if (!gatt_db_service_set_active(gatt_db, cmd->service_handle, true)) {
-		/* we ignore service now */
+		/*
+		 * no need to clean SDP since this can fail only if service
+		 * handle is invalid in which case add_sdp_record() also fails
+		 */
 		status = HAL_STATUS_FAILED;
 		goto failed;
 	}
@@ -4942,10 +5043,14 @@ static void handle_server_stop_service(const void *buf, uint16_t len)
 		goto failed;
 	}
 
-	if (!gatt_db_service_set_active(gatt_db, cmd->service_handle, false))
+	if (!gatt_db_service_set_active(gatt_db, cmd->service_handle, false)) {
 		status = HAL_STATUS_FAILED;
-	else
-		status = HAL_STATUS_SUCCESS;
+		goto failed;
+	}
+
+	remove_service_sdp_record(cmd->service_handle);
+
+	status = HAL_STATUS_SUCCESS;
 
 	queue_foreach(gatt_devices, notify_service_change,
 					UINT_TO_PTR(cmd->service_handle));
@@ -4984,6 +5089,8 @@ static void handle_server_delete_service(const void *buf, uint16_t len)
 		goto failed;
 	}
 
+	remove_service_sdp_record(cmd->service_handle);
+
 	status = HAL_STATUS_SUCCESS;
 
 failed:
@@ -6316,10 +6423,11 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
 	gatt_apps = queue_new();
 	app_connections = queue_new();
 	listen_apps = queue_new();
+	services_sdp = queue_new();
 	gatt_db = gatt_db_new();
 
 	if (!gatt_devices || !gatt_apps || !listen_apps || !app_connections ||
-								!gatt_db) {
+						!services_sdp || !gatt_db) {
 		error("gatt: Failed to allocate memory for queues");
 		goto failed;
 	}
@@ -6358,6 +6466,9 @@ failed:
 	queue_destroy(listen_apps, NULL);
 	listen_apps = NULL;
 
+	queue_destroy(services_sdp, NULL);
+	services_sdp = NULL;
+
 	gatt_db_destroy(gatt_db);
 	gatt_db = NULL;
 
@@ -6393,6 +6504,9 @@ void bt_gatt_unregister(void)
 	queue_destroy(gatt_devices, destroy_device);
 	gatt_devices = NULL;
 
+	queue_destroy(services_sdp, free_service_sdp_record);
+	services_sdp = NULL;
+
 	queue_destroy(listen_apps, NULL);
 	listen_apps = NULL;
 
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 7f13e84..8adb9f1 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -826,6 +826,10 @@ struct hal_cmd_gatt_server_add_descriptor {
 	int32_t permissions;
 } __attribute__((packed));
 
+#define GATT_SERVER_TRANSPORT_LE		0x00
+#define GATT_SERVER_TRANSPORT_BREDR		0x01
+#define GATT_SERVER_TRANSPORT_LE_BREDR		0x02
+
 #define HAL_OP_GATT_SERVER_START_SERVICE	0x1f
 struct hal_cmd_gatt_server_start_service {
 	int32_t server_if;
-- 
1.9.1


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

* Re: [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR
  2014-07-10 14:30 [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
                   ` (3 preceding siblings ...)
  2014-07-10 14:30 ` [PATCH v2 5/5] android/gatt: Register SDP records for services Szymon Janc
@ 2014-07-11 20:10 ` Szymon Janc
  4 siblings, 0 replies; 6+ messages in thread
From: Szymon Janc @ 2014-07-11 20:10 UTC (permalink / raw)
  To: linux-bluetooth

On Thursday 10 of July 2014 16:30:32 Szymon Janc wrote:
> This adds listening on both LE and BR/EDR and SDP records for GAP,
> GATT and DIS.
> ---
>  android/gatt.c | 243
> +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed,
> 193 insertions(+), 50 deletions(-)
> 
> diff --git a/android/gatt.c b/android/gatt.c
> index 1e2366d..e07226c 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -35,6 +35,7 @@
>  #include "ipc.h"
>  #include "ipc-common.h"
>  #include "lib/sdp.h"
> +#include "lib/sdp_lib.h"
>  #include "lib/uuid.h"
>  #include "bluetooth.h"
>  #include "gatt.h"
> @@ -190,7 +191,12 @@ static struct gatt_db *gatt_db = NULL;
> 
>  static uint16_t service_changed_handle = 0;
> 
> -static GIOChannel *listening_io = NULL;
> +static GIOChannel *le_io = NULL;
> +static GIOChannel *bredr_io = NULL;
> +
> +static uint32_t gatt_sdp_handle = 0;
> +static uint32_t gap_sdp_handle = 0;
> +static uint32_t dis_sdp_handle = 0;
> 
>  static struct bt_crypto *crypto = NULL;
> 
> @@ -4742,6 +4748,93 @@ static void notify_service_change(void *data, void
> *user_data) notify_att_range_change(data, &range);
>  }
> 
> +static sdp_record_t *get_sdp_record(uuid_t *uuid, uint16_t start, uint16_t
> end, +							const char *name)
> +{
> +	sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
> +	uuid_t root_uuid, proto_uuid, l2cap;
> +	sdp_record_t *record;
> +	sdp_data_t *psm, *sh, *eh;
> +	uint16_t lp = ATT_PSM;
> +
> +	record = sdp_record_alloc();
> +	if (record == NULL)
> +		return NULL;
> +
> +	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
> +	root = sdp_list_append(NULL, &root_uuid);
> +	sdp_set_browse_groups(record, root);
> +	sdp_list_free(root, NULL);
> +
> +	svclass_id = sdp_list_append(NULL, uuid);
> +	sdp_set_service_classes(record, svclass_id);
> +	sdp_list_free(svclass_id, NULL);
> +
> +	sdp_uuid16_create(&l2cap, L2CAP_UUID);
> +	proto[0] = sdp_list_append(NULL, &l2cap);
> +	psm = sdp_data_alloc(SDP_UINT16, &lp);
> +	proto[0] = sdp_list_append(proto[0], psm);
> +	apseq = sdp_list_append(NULL, proto[0]);
> +
> +	sdp_uuid16_create(&proto_uuid, ATT_UUID);
> +	proto[1] = sdp_list_append(NULL, &proto_uuid);
> +	sh = sdp_data_alloc(SDP_UINT16, &start);
> +	proto[1] = sdp_list_append(proto[1], sh);
> +	eh = sdp_data_alloc(SDP_UINT16, &end);
> +	proto[1] = sdp_list_append(proto[1], eh);
> +	apseq = sdp_list_append(apseq, proto[1]);
> +
> +	aproto = sdp_list_append(NULL, apseq);
> +	sdp_set_access_protos(record, aproto);
> +
> +	if (name)
> +		sdp_set_info_attr(record, name, "BlueZ for Android", NULL);
> +
> +	sdp_data_free(psm);
> +	sdp_data_free(sh);
> +	sdp_data_free(eh);
> +	sdp_list_free(proto[0], NULL);
> +	sdp_list_free(proto[1], NULL);
> +	sdp_list_free(apseq, NULL);
> +	sdp_list_free(aproto, NULL);
> +
> +	return record;
> +}
> +
> +static uint32_t add_sdp_record(const bt_uuid_t *uuid, uint16_t start,
> +						uint16_t end, const char *name)
> +{
> +	sdp_record_t *rec;
> +	uuid_t u, u32;
> +
> +	switch (uuid->type) {
> +	case BT_UUID16:
> +		sdp_uuid16_create(&u, uuid->value.u16);
> +		break;
> +	case BT_UUID32:
> +		sdp_uuid32_create(&u32, uuid->value.u32);
> +		sdp_uuid32_to_uuid128(&u, &u32);
> +		break;
> +	case BT_UUID128:
> +		sdp_uuid128_create(&u, &uuid->value.u128);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	rec = get_sdp_record(&u, start, end, name);
> +	if (!rec)
> +		return 0;
> +
> +	if (bt_adapter_add_record(rec, 0) < 0) {
> +		error("gatt: Failed to register SDP record");
> +		sdp_record_free(rec);
> +		return 0;
> +	}
> +
> +	return rec->handle;
> +}
> +
>  static void handle_server_start_service(const void *buf, uint16_t len)
>  {
>  	const struct hal_cmd_gatt_server_start_service *cmd = buf;
> @@ -5884,6 +5977,7 @@ done:
> 
>  static void register_gap_service(void)
>  {
> +	uint16_t start, end;
>  	bt_uuid_t uuid;
> 
>  	/* GAP UUID */
> @@ -5918,6 +6012,14 @@ static void register_gap_service(void)
>  							NULL);
> 
>  	gatt_db_service_set_active(gatt_db, gap_srvc_data.srvc , true);
> +
> +	/* SDP */
> +	start = gap_srvc_data.srvc;
> +	end = gatt_db_get_end_handle(gatt_db, gap_srvc_data.srvc);
> +	gap_sdp_handle = add_sdp_record(&uuid, start, end,
> +						"Generic Access Profile");
> +	if (!gap_sdp_handle)
> +		error("gatt: Failed to register GAP SDP record");
>  }
> 
>  /* TODO: Get those data from device possible via androig/bluetooth.c */
> @@ -5973,7 +6075,7 @@ done:
>  static void register_device_info_service(void)
>  {
>  	bt_uuid_t uuid;
> -	uint16_t srvc_handle;
> +	uint16_t srvc_handle, end_handle;
> 
>  	DBG("");
> 
> @@ -6019,6 +6121,13 @@ static void register_device_info_service(void)
>  					(void *) device_info.manufacturer_name);
> 
>  	gatt_db_service_set_active(gatt_db, srvc_handle, true);
> +
> +	/* SDP */
> +	end_handle = gatt_db_get_end_handle(gatt_db, srvc_handle);
> +	dis_sdp_handle = add_sdp_record(&uuid, srvc_handle, end_handle,
> +						"Device Information Service");
> +	if (!dis_sdp_handle)
> +		error("gatt: Failed to register DIS SDP record");
>  }
> 
>  static void gatt_srvc_change_write_cb(uint16_t handle, uint16_t offset,
> @@ -6087,8 +6196,8 @@ static void gatt_srvc_change_read_cb(uint16_t handle,
> uint16_t offset,
> 
>  static void register_gatt_service(void)
>  {
> +	uint16_t srvc_handle, end_handle;
>  	bt_uuid_t uuid;
> -	uint16_t srvc_handle;
> 
>  	DBG("");
> 
> @@ -6108,22 +6217,34 @@ static void register_gatt_service(void)
>  					gatt_srvc_change_write_cb, NULL);
> 
>  	gatt_db_service_set_active(gatt_db, srvc_handle, true);
> +
> +	/* SDP */
> +	end_handle = gatt_db_get_end_handle(gatt_db, srvc_handle);
> +	gatt_sdp_handle = add_sdp_record(&uuid, srvc_handle, end_handle,
> +						"Generic Attribute Profile");
> +
> +	if (!gatt_sdp_handle)
> +		error("gatt: Failed to register GATT SDP record");
>  }
> 
> -static bool start_listening_io(void)
> +static bool start_listening(void)
>  {
> -	GError *gerr = NULL;
> +	/* BR/EDR socket */
> +	bredr_io = bt_io_listen(NULL, connect_confirm, NULL, NULL, NULL,
> +					BT_IO_OPT_SOURCE_TYPE, BDADDR_BREDR,
> +					BT_IO_OPT_PSM, ATT_PSM,
> +					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
> +					BT_IO_OPT_INVALID);
> 
> -	/* For now only listen on BLE */
> -	listening_io = bt_io_listen(NULL, connect_confirm,
> -					&listening_io, NULL, &gerr,
> +	/* LE socket */
> +	le_io = bt_io_listen(NULL, connect_confirm, NULL, NULL, NULL,
>  					BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
>  					BT_IO_OPT_CID, ATT_CID,
>  					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
>  					BT_IO_OPT_INVALID);
> -	if (!listening_io) {
> -		error("gatt: Failed to start listening IO (%s)", gerr->message);
> -		g_error_free(gerr);
> +
> +	if (!le_io && !bredr_io) {
> +		error("gatt: Failed to start listening IO");
>  		return false;
>  	}
> 
> @@ -6134,26 +6255,13 @@ bool bt_gatt_register(struct ipc *ipc, const
> bdaddr_t *addr) {
>  	DBG("");
> 
> -	if (!start_listening_io())
> -		return false;
> -
> -	if (!bt_le_register(le_device_found_handler)) {
> -		error("gatt: bt_le_register failed");
> -
> -		g_io_channel_unref(listening_io);
> -		listening_io = NULL;
> -
> +	if (!start_listening())
>  		return false;
> -	}
> 
>  	crypto = bt_crypto_new();
>  	if (!crypto) {
>  		error("gatt: Failed to setup crypto");
> -
> -		g_io_channel_unref(listening_io);
> -		listening_io = NULL;
> -
> -		return false;
> +		goto failed;
>  	}
> 
>  	gatt_devices = queue_new();
> @@ -6165,28 +6273,12 @@ bool bt_gatt_register(struct ipc *ipc, const
> bdaddr_t *addr) if (!gatt_devices || !gatt_apps || !listen_apps ||
> !app_connections || !gatt_db) {
>  		error("gatt: Failed to allocate memory for queues");
> +		goto failed;
> +	}
> 
> -		queue_destroy(gatt_apps, NULL);
> -		gatt_apps = NULL;
> -
> -		queue_destroy(gatt_devices, NULL);
> -		gatt_devices = NULL;
> -
> -		queue_destroy(app_connections, NULL);
> -		app_connections = NULL;
> -
> -		queue_destroy(listen_apps, NULL);
> -		listen_apps = NULL;
> -
> -		gatt_db_destroy(gatt_db);
> -		gatt_db = NULL;
> -
> -		g_io_channel_unref(listening_io);
> -		listening_io = NULL;
> -
> -		bt_crypto_unref(crypto);
> -
> -		return false;
> +	if (!bt_le_register(le_device_found_handler)) {
> +		error("gatt: bt_le_register failed");
> +		goto failed;
>  	}
> 
>  	bacpy(&adapter_addr, addr);
> @@ -6200,7 +6292,41 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t
> *addr) register_device_info_service();
>  	register_gatt_service();
> 
> +	info("gatt: LE: %s BR/EDR: %s", le_io ? "enabled" : "disabled",
> +					bredr_io ? "enabled" : "disabled");
> +
>  	return true;
> +
> +failed:
> +	queue_destroy(gatt_apps, NULL);
> +	gatt_apps = NULL;
> +
> +	queue_destroy(gatt_devices, NULL);
> +	gatt_devices = NULL;
> +
> +	queue_destroy(app_connections, NULL);
> +	app_connections = NULL;
> +
> +	queue_destroy(listen_apps, NULL);
> +	listen_apps = NULL;
> +
> +	gatt_db_destroy(gatt_db);
> +	gatt_db = NULL;
> +
> +	bt_crypto_unref(crypto);
> +	crypto = NULL;
> +
> +	if (le_io) {
> +		g_io_channel_unref(le_io);
> +		le_io = NULL;
> +	}
> +
> +	if (bredr_io) {
> +		g_io_channel_unref(bredr_io);
> +		bredr_io = NULL;
> +	}
> +
> +	return false;
>  }
> 
>  void bt_gatt_unregister(void)
> @@ -6225,8 +6351,26 @@ void bt_gatt_unregister(void)
>  	gatt_db_destroy(gatt_db);
>  	gatt_db = NULL;
> 
> -	g_io_channel_unref(listening_io);
> -	listening_io = NULL;
> +	g_io_channel_unref(le_io);
> +	le_io = NULL;
> +
> +	g_io_channel_unref(bredr_io);
> +	bredr_io = NULL;
> +
> +	if (gap_sdp_handle) {
> +		bt_adapter_remove_record(gap_sdp_handle);
> +		gap_sdp_handle = 0;
> +	}
> +
> +	if (gatt_sdp_handle) {
> +		bt_adapter_remove_record(gatt_sdp_handle);
> +		gatt_sdp_handle = 0;
> +	}
> +
> +	if (dis_sdp_handle) {
> +		bt_adapter_remove_record(dis_sdp_handle);
> +		dis_sdp_handle = 0;
> +	}
> 
>  	bt_crypto_unref(crypto);
>  	crypto = NULL;
> @@ -6234,7 +6378,6 @@ void bt_gatt_unregister(void)
>  	bt_le_unregister();
>  }
> 
> -
>  unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
>  							gatt_conn_cb_t func)
>  {

Pushed.

-- 
BR
Szymon Janc

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

end of thread, other threads:[~2014-07-11 20:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-10 14:30 [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc
2014-07-10 14:30 ` [PATCH v2 2/5] android/bluetooth: Add function for checking last seen bearer Szymon Janc
2014-07-10 14:30 ` [PATCH v2 3/5] android/gatt: Choose LE or BR/EDR based on " Szymon Janc
2014-07-10 14:30 ` [PATCH v2 4/5] shared/gatt: Add function for getting service UUID Szymon Janc
2014-07-10 14:30 ` [PATCH v2 5/5] android/gatt: Register SDP records for services Szymon Janc
2014-07-11 20:10 ` [PATCH v2 1/5] android/gatt: Add support for GATT over BR/EDR Szymon Janc

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