Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 08/11] android/socket: Register SDP record for application service
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds SDP record for services registered from application
(other than built-in services).
---
 android/socket.c | 40 +++++++++++++++++++++++++++++++---------
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index e560609..9175bf3 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -350,6 +350,22 @@ static sdp_record_t *create_spp_record(uint8_t chan, const char *svc_name)
 	return record;
 }
 
+static sdp_record_t *create_app_record(uint8_t chan,
+						const uint8_t *app_uuid,
+						const char *svc_name)
+{
+	sdp_record_t *record;
+	uuid_t uuid;
+
+	sdp_uuid128_create(&uuid, app_uuid);
+
+	record = create_rfcomm_record(chan, &uuid, svc_name, false);
+	if (!record)
+		return NULL;
+
+	return record;
+}
+
 static const struct profile_info {
 	uint8_t		uuid[16];
 	uint8_t		channel;
@@ -396,19 +412,24 @@ static const struct profile_info {
 	},
 };
 
-static uint32_t sdp_service_register(const struct profile_info *profile,
-							const void *svc_name)
+static uint32_t sdp_service_register(uint8_t channel, const uint8_t *uuid,
+					const struct profile_info *profile,
+					const void *svc_name)
 {
-	sdp_record_t *record;
-
-	if (!profile || !profile->create_record)
-		return 0;
+	sdp_record_t *record = NULL;
+	uint8_t svc_hint = 0;
+
+	if (profile && profile->create_record) {
+		record = profile->create_record(channel, svc_name);
+		svc_hint = profile->svc_hint;
+	} else if (uuid) {
+		record = create_app_record(channel, uuid, svc_name);
+	}
 
-	record = profile->create_record(profile->channel, svc_name);
 	if (!record)
 		return 0;
 
-	if (bt_adapter_add_record(record, profile->svc_hint) < 0) {
+	if (bt_adapter_add_record(record, svc_hint) < 0) {
 		error("Failed to register on SDP record");
 		sdp_record_free(record);
 		return 0;
@@ -782,7 +803,8 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 		goto failed;
 	}
 
-	rfsock->service_handle = sdp_service_register(profile, name);
+	rfsock->service_handle = sdp_service_register(chan, uuid, profile,
+									name);
 
 	servers[chan].rfsock = rfsock;
 
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 07/11] android/socket: Add support for dynamic channel numbers
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds support to register server with channel number assigned
dynamically, i.e. first free number is assigned. Channels which are
reserved for built-in services are not assigned for other services.
---
 android/socket.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 4e823dd..e560609 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -677,6 +677,21 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
 	new_rfsock->bt_watch = id;
 }
 
+static int find_free_channel(void)
+{
+	int ch;
+
+	/* channel 0 is reserver so we don't use it */
+	for (ch = 1; ch <= RFCOMM_CHANNEL_MAX; ch++) {
+		struct rfcomm_channel *srv = &servers[ch];
+
+		if (!srv->reserved && srv->rfsock == NULL)
+			return ch;
+	}
+
+	return 0;
+}
+
 static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 						uint8_t flags, int *hal_sock)
 {
@@ -704,15 +719,20 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 
 	profile = get_profile_by_uuid(uuid);
 	if (!profile) {
-		if (chan <= 0)
-			return HAL_STATUS_INVALID;
-
 		sec_level = BT_IO_SEC_MEDIUM;
 	} else {
 		chan = profile->channel;
 		sec_level = profile->sec_level;
 	}
 
+	if (chan <= 0)
+		chan = find_free_channel();
+
+	if (!chan) {
+		error("No free channels");
+		return HAL_STATUS_BUSY;
+	}
+
 	if (servers[chan].rfsock != NULL) {
 		error("Channel already registered (%d)", chan);
 		return HAL_STATUS_BUSY;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 06/11] android/tester: Update test data
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

Trying to listen on already assigned channel will now return busy
status instead of just fail.
---
 android/android-tester.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/android-tester.c b/android/android-tester.c
index 870ad8d..9198514 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -2757,7 +2757,7 @@ static const struct socket_data btsock_inv_listen_listen = {
 	.service_uuid = NULL,
 	.service_name = "Test service",
 	.flags = 0,
-	.expected_status = BT_STATUS_FAIL,
+	.expected_status = BT_STATUS_BUSY,
 	.test_channel = true,
 };
 
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 05/11] android/socket: Make servers list as static array
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

Since there is only small, fixed number of channels to allocate for
RFCOMM servers we can store them in static array. This will make
lookup for free channel simpler once we add support to assign channel
numbers dynamically.

At startup, channels reserved for built-in services which have static
channel number are marked as reserved so they cannot be assigned for
other service.
---
 android/socket.c | 44 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 37 insertions(+), 7 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 32de91a..4e823dd 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -45,6 +45,8 @@
 #include "utils.h"
 #include "socket.h"
 
+#define RFCOMM_CHANNEL_MAX 30
+
 #define SPP_DEFAULT_CHANNEL	3
 #define OPP_DEFAULT_CHANNEL	9
 #define PBAP_DEFAULT_CHANNEL	15
@@ -64,9 +66,6 @@ static bdaddr_t adapter_addr;
 
 static const uint8_t zero_uuid[16] = { 0 };
 
-/* Simple list of RFCOMM server sockets */
-GList *servers = NULL;
-
 /* Simple list of RFCOMM connected sockets */
 GList *connections = NULL;
 
@@ -90,6 +89,13 @@ struct rfcomm_sock {
 	const struct profile_info *profile;
 };
 
+struct rfcomm_channel {
+	bool reserved;
+	struct rfcomm_sock *rfsock;
+};
+
+static struct rfcomm_channel servers[RFCOMM_CHANNEL_MAX + 1];
+
 static int rfsock_set_buffer(struct rfcomm_sock *rfsock)
 {
 	socklen_t len = sizeof(int);
@@ -599,7 +605,7 @@ static gboolean jv_sock_server_event_cb(GIOChannel *io, GIOCondition cond,
 		return FALSE;
 
 	if (cond & (G_IO_ERR | G_IO_HUP )) {
-		servers = g_list_remove(servers, rfsock);
+		servers[rfsock->channel].rfsock = NULL;
 		cleanup_rfsock(rfsock);
 	}
 
@@ -690,7 +696,8 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 	DBG("chan %d flags 0x%02x uuid %s name %s", chan, flags, uuid_str,
 									name);
 
-	if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) {
+	if ((!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) ||
+			(chan > RFCOMM_CHANNEL_MAX)) {
 		error("Invalid rfcomm listen params");
 		return HAL_STATUS_INVALID;
 	}
@@ -706,12 +713,19 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 		sec_level = profile->sec_level;
 	}
 
+	if (servers[chan].rfsock != NULL) {
+		error("Channel already registered (%d)", chan);
+		return HAL_STATUS_BUSY;
+	}
+
 	DBG("chan %d sec_level %d", chan, sec_level);
 
 	rfsock = create_rfsock(-1, hal_sock);
 	if (!rfsock)
 		return HAL_STATUS_FAILED;
 
+	rfsock->channel = chan;
+
 	io = bt_io_listen(accept_cb, NULL, rfsock, NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
 				BT_IO_OPT_CHANNEL, chan,
@@ -750,7 +764,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 
 	rfsock->service_handle = sdp_service_register(profile, name);
 
-	servers = g_list_append(servers, rfsock);
+	servers[chan].rfsock = rfsock;
 
 	return HAL_STATUS_SUCCESS;
 
@@ -1050,8 +1064,17 @@ static const struct ipc_handler cmd_handlers[] = {
 
 void bt_socket_register(const bdaddr_t *addr)
 {
+	size_t i;
+
 	DBG("");
 
+	/* make sure channels assigned for profiles are reserved and not used
+	 * for app services
+	 */
+	for (i = 0; i < G_N_ELEMENTS(profiles); i++)
+		if (profiles[i].channel)
+			servers[profiles[i].channel].reserved = true;
+
 	bacpy(&adapter_addr, addr);
 	ipc_register(HAL_SERVICE_ID_SOCK, cmd_handlers,
 						G_N_ELEMENTS(cmd_handlers));
@@ -1059,10 +1082,17 @@ void bt_socket_register(const bdaddr_t *addr)
 
 void bt_socket_unregister(void)
 {
+	int ch;
+
 	DBG("");
 
 	g_list_free_full(connections, cleanup_rfsock);
-	g_list_free_full(servers, cleanup_rfsock);
+
+	for (ch = 0; ch <= RFCOMM_CHANNEL_MAX; ch++)
+		if (servers[ch].rfsock)
+			cleanup_rfsock(&servers[ch]);
+
+	memset(servers, 0, sizeof(servers));
 
 	ipc_unregister(HAL_SERVICE_ID_SOCK);
 }
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 04/11] android/socket: Simplify SDP records handling
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

Records are now created using helper function which creates SDP record
with common contents like service class, name and protocols. Other
attributes are then added by custom functions.
---
 android/socket.c | 281 ++++++++++++++++---------------------------------------
 1 file changed, 80 insertions(+), 201 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 5045911..32de91a 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -180,18 +180,14 @@ static struct rfcomm_sock *create_rfsock(int bt_sock, int *hal_sock)
 	return rfsock;
 }
 
-static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
+static sdp_record_t *create_rfcomm_record(uint8_t chan, uuid_t *uuid,
+						const char *svc_name,
+						bool has_obex)
 {
-	const char *service_name = "OBEX Object Push";
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
-	void *dtds[sizeof(formats)], *values[sizeof(formats)];
-	unsigned int i;
-	uint8_t dtd = SDP_UINT8;
-	sdp_data_t *sflist;
+	sdp_list_t *svclass_id;
+	sdp_list_t *seq, *proto_seq, *pbg_seq;
+	sdp_list_t *proto[2];
+	uuid_t l2cap_uuid, rfcomm_uuid, obex_uuid, pbg_uuid;
 	sdp_data_t *channel;
 	sdp_record_t *record;
 
@@ -201,267 +197,150 @@ static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
 
 	record->handle =  sdp_next_handle();
 
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &opush_uuid);
+	svclass_id = sdp_list_append(NULL, uuid);
 	sdp_set_service_classes(record, svclass_id);
 
-	sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
-	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(NULL, profile);
-	sdp_set_profile_descs(record, pfseq);
-
 	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
 	proto[0] = sdp_list_append(NULL, &l2cap_uuid);
-	apseq = sdp_list_append(NULL, proto[0]);
+	seq = sdp_list_append(NULL, proto[0]);
 
 	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
 	proto[1] = sdp_list_append(NULL, &rfcomm_uuid);
 	channel = sdp_data_alloc(SDP_UINT8, &chan);
 	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
+	seq = sdp_list_append(seq, proto[1]);
 
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto[2] = sdp_list_append(NULL, &obex_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
+	if (has_obex) {
+		sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+		proto[2] = sdp_list_append(NULL, &obex_uuid);
+		seq = sdp_list_append(seq, proto[2]);
+	}
 
-	aproto = sdp_list_append(NULL, apseq);
-	sdp_set_access_protos(record, aproto);
+	proto_seq = sdp_list_append(NULL, seq);
+	sdp_set_access_protos(record, proto_seq);
 
-	for (i = 0; i < sizeof(formats); i++) {
-		dtds[i] = &dtd;
-		values[i] = &formats[i];
-	}
-	sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
-	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
+	sdp_uuid16_create(&pbg_uuid, PUBLIC_BROWSE_GROUP);
+	pbg_seq = sdp_list_append(NULL, &pbg_uuid);
+	sdp_set_browse_groups(record, pbg_seq);
 
 	if (svc_name)
-		service_name = svc_name;
-
-	sdp_set_info_attr(record, service_name, NULL, NULL);
+		sdp_set_info_attr(record, svc_name, NULL, NULL);
 
 	sdp_data_free(channel);
 	sdp_list_free(proto[0], NULL);
 	sdp_list_free(proto[1], NULL);
-	sdp_list_free(proto[2], NULL);
-	sdp_list_free(apseq, NULL);
-	sdp_list_free(pfseq, NULL);
-	sdp_list_free(aproto, NULL);
-	sdp_list_free(root, NULL);
+	if (has_obex)
+		sdp_list_free(proto[2], NULL);
+	sdp_list_free(seq, NULL);
+	sdp_list_free(proto_seq, NULL);
+	sdp_list_free(pbg_seq, NULL);
 	sdp_list_free(svclass_id, NULL);
 
 	return record;
 }
 
-static sdp_record_t *create_pbap_record(uint8_t chan, const char *svc_name)
+static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
 {
-	const char *service_name = "OBEX Phonebook Access Server";
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, pbap_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
-	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_data_t *channel;
-	uint8_t formats[] = { 0x01 };
+	uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
 	uint8_t dtd = SDP_UINT8;
-	sdp_data_t *sflist;
+	uuid_t uuid;
+	sdp_list_t *seq;
+	sdp_profile_desc_t profile[1];
+	void *dtds[sizeof(formats)], *values[sizeof(formats)];
+	sdp_data_t *formats_list;
 	sdp_record_t *record;
+	size_t i;
 
-	record = sdp_record_alloc();
+	sdp_uuid16_create(&uuid, OBEX_OBJPUSH_SVCLASS_ID);
+
+	record = create_rfcomm_record(chan, &uuid, svc_name, true);
 	if (!record)
 		return NULL;
 
-	record->handle =  sdp_next_handle();
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&pbap_uuid, PBAP_PSE_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &pbap_uuid);
-	sdp_set_service_classes(record, svclass_id);
-
-	sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
+	sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
 	profile[0].version = 0x0100;
-	pfseq = sdp_list_append(NULL, profile);
-	sdp_set_profile_descs(record, pfseq);
+	seq = sdp_list_append(NULL, profile);
+	sdp_set_profile_descs(record, seq);
 
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(NULL, &l2cap_uuid);
-	apseq = sdp_list_append(NULL, proto[0]);
+	for (i = 0; i < sizeof(formats); i++) {
+		dtds[i] = &dtd;
+		values[i] = &formats[i];
+	}
+	formats_list = sdp_seq_alloc(dtds, values, sizeof(formats));
+	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, formats_list);
 
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(NULL, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &chan);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
+	sdp_list_free(seq, NULL);
 
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto[2] = sdp_list_append(NULL, &obex_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
+	return record;
+}
 
-	aproto = sdp_list_append(NULL, apseq);
-	sdp_set_access_protos(record, aproto);
+static sdp_record_t *create_pbap_record(uint8_t chan, const char *svc_name)
+{
+	sdp_list_t *seq;
+	sdp_profile_desc_t profile[1];
+	uint8_t formats = 0x01;
+	sdp_record_t *record;
+	uuid_t uuid;
 
-	sflist = sdp_data_alloc(dtd, formats);
-	sdp_attr_add(record, SDP_ATTR_SUPPORTED_REPOSITORIES, sflist);
+	sdp_uuid16_create(&uuid, PBAP_PSE_SVCLASS_ID);
 
-	if (svc_name)
-		service_name = svc_name;
+	record = create_rfcomm_record(chan, &uuid, svc_name, true);
+	if (!record)
+		return NULL;
 
-	sdp_set_info_attr(record, service_name, NULL, NULL);
+	sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
+	profile[0].version = 0x0100;
+	seq = sdp_list_append(NULL, profile);
+	sdp_set_profile_descs(record, seq);
 
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], NULL);
-	sdp_list_free(proto[1], NULL);
-	sdp_list_free(proto[2], NULL);
-	sdp_list_free(apseq, NULL);
-	sdp_list_free(pfseq, NULL);
-	sdp_list_free(aproto, NULL);
-	sdp_list_free(root, NULL);
-	sdp_list_free(svclass_id, NULL);
+	sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_REPOSITORIES, SDP_UINT8,
+								&formats);
+
+	sdp_list_free(seq, NULL);
 
 	return record;
 }
 
 static sdp_record_t *create_mas_record(uint8_t chan, const char *svc_name)
 {
-	const char *service_name = "MAP MAS SMS";
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, mse_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+	sdp_list_t *seq;
 	sdp_profile_desc_t profile[1];
-	sdp_list_t *aproto, *proto[3];
-	sdp_data_t *channel;
 	uint8_t minst = DEFAULT_MAS_INSTANCE;
 	uint8_t mtype = DEFAULT_MAS_MSG_TYPE;
 	sdp_record_t *record;
+	uuid_t uuid;
 
-	record = sdp_record_alloc();
+	sdp_uuid16_create(&uuid, MAP_MSE_SVCLASS_ID);
+
+	record = create_rfcomm_record(chan, &uuid, svc_name, true);
 	if (!record)
 		return NULL;
 
-	record->handle =  sdp_next_handle();
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&mse_uuid, MAP_MSE_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &mse_uuid);
-	sdp_set_service_classes(record, svclass_id);
-
 	sdp_uuid16_create(&profile[0].uuid, MAP_PROFILE_ID);
 	profile[0].version = 0x0101;
-	pfseq = sdp_list_append(NULL, profile);
-	sdp_set_profile_descs(record, pfseq);
+	seq = sdp_list_append(NULL, profile);
+	sdp_set_profile_descs(record, seq);
 
 	sdp_attr_add_new(record, SDP_ATTR_MAS_INSTANCE_ID, SDP_UINT8, &minst);
 	sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_MESSAGE_TYPES, SDP_UINT8,
 									&mtype);
 
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(NULL, &l2cap_uuid);
-	apseq = sdp_list_append(NULL, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(NULL, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &chan);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
-	proto[2] = sdp_list_append(NULL, &obex_uuid);
-	apseq = sdp_list_append(apseq, proto[2]);
-
-	aproto = sdp_list_append(NULL, apseq);
-	sdp_set_access_protos(record, aproto);
-
-	if (svc_name)
-		service_name = svc_name;
-
-	sdp_set_info_attr(record, service_name, NULL, NULL);
-
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], NULL);
-	sdp_list_free(proto[1], NULL);
-	sdp_list_free(proto[2], NULL);
-	sdp_list_free(apseq, NULL);
-	sdp_list_free(pfseq, NULL);
-	sdp_list_free(aproto, NULL);
-	sdp_list_free(root, NULL);
-	sdp_list_free(svclass_id, NULL);
+	sdp_list_free(seq, NULL);
 
 	return record;
 }
 
 static sdp_record_t *create_spp_record(uint8_t chan, const char *svc_name)
 {
-	const char *service_name = "Serial Port";
-	sdp_list_t *svclass_id, *apseq, *profiles, *root;
-	uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_data_t *channel;
 	sdp_record_t *record;
+	uuid_t uuid;
 
-	record = sdp_record_alloc();
+	sdp_uuid16_create(&uuid, SERIAL_PORT_SVCLASS_ID);
+
+	record = create_rfcomm_record(chan, &uuid, svc_name, false);
 	if (!record)
 		return NULL;
 
-	record->handle =  sdp_next_handle();
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(record, root);
-
-	sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
-	svclass_id = sdp_list_append(NULL, &sp_uuid);
-	sdp_set_service_classes(record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
-	profile.version = 0x0100;
-	profiles = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(record, profiles);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(NULL, &l2cap);
-	apseq = sdp_list_append(NULL, proto[0]);
-
-	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
-	proto[1] = sdp_list_append(NULL, &rfcomm);
-	channel = sdp_data_alloc(SDP_UINT8, &chan);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(NULL, apseq);
-	sdp_set_access_protos(record, aproto);
-
-	sdp_add_lang_attr(record);
-
-	if (svc_name)
-		service_name = svc_name;
-
-	sdp_set_info_attr(record, service_name, "BlueZ", "COM Port");
-
-	sdp_set_url_attr(record, "http://www.bluez.org/",
-			"http://www.bluez.org/", "http://www.bluez.org/");
-
-	sdp_set_service_id(record, sp_uuid);
-	sdp_set_service_ttl(record, 0xffff);
-	sdp_set_service_avail(record, 0xff);
-	sdp_set_record_state(record, 0x00001234);
-
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], NULL);
-	sdp_list_free(proto[1], NULL);
-	sdp_list_free(apseq, NULL);
-	sdp_list_free(aproto, NULL);
-	sdp_list_free(root, NULL);
-	sdp_list_free(svclass_id, NULL);
-	sdp_list_free(profiles, NULL);
-
 	return record;
 }
 
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 03/11] android/socket: Improve logging
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch makes logging more consistent by including rfsock pointer in
most messages which identifies socket structure unambigously (instead
of using bunch of file descriptors for the same purpose) and puts other
parameters in order in some cases.

Additionally, some new logs are introduced to better track socket
structures and connections lifetime.
---
 android/socket.c | 71 ++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 43 insertions(+), 28 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 107042e..5045911 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -121,8 +121,8 @@ static void cleanup_rfsock(gpointer data)
 {
 	struct rfcomm_sock *rfsock = data;
 
-	DBG("rfsock: %p jv_sock %d bt_sock %d chan %u",
-		rfsock, rfsock->jv_sock, rfsock->bt_sock, rfsock->channel);
+	DBG("rfsock %p bt_sock %d jv_sock %d", rfsock, rfsock->bt_sock,
+							rfsock->jv_sock);
 
 	if (rfsock->jv_sock >= 0)
 		if (close(rfsock->jv_sock) < 0)
@@ -167,6 +167,8 @@ static struct rfcomm_sock *create_rfsock(int bt_sock, int *hal_sock)
 	*hal_sock = fds[1];
 	rfsock->bt_sock = bt_sock;
 
+	DBG("rfsock %p", rfsock);
+
 	if (bt_sock < 0)
 		return rfsock;
 
@@ -619,8 +621,7 @@ static gboolean jv_sock_client_event_cb(GIOChannel *io, GIOCondition cond,
 	}
 
 	if (cond & (G_IO_ERR | G_IO_NVAL)) {
-		error("Socket error: sock %d cond %d",
-					g_io_channel_unix_get_fd(io), cond);
+		error("Socket %d error", g_io_channel_unix_get_fd(io));
 		goto fail;
 	}
 
@@ -639,6 +640,8 @@ static gboolean jv_sock_client_event_cb(GIOChannel *io, GIOCondition cond,
 
 	return TRUE;
 fail:
+	DBG("rfsock %p jv_sock %d cond %d", rfsock, rfsock->jv_sock, cond);
+
 	connections = g_list_remove(connections, rfsock);
 	cleanup_rfsock(rfsock);
 
@@ -657,8 +660,7 @@ static gboolean bt_sock_event_cb(GIOChannel *io, GIOCondition cond,
 	}
 
 	if (cond & (G_IO_ERR | G_IO_NVAL)) {
-		error("Socket error: sock %d cond %d",
-					g_io_channel_unix_get_fd(io), cond);
+		error("Socket %d error", g_io_channel_unix_get_fd(io));
 		goto fail;
 	}
 
@@ -677,6 +679,8 @@ static gboolean bt_sock_event_cb(GIOChannel *io, GIOCondition cond,
 
 	return TRUE;
 fail:
+	DBG("rfsock %p bt_sock %d cond %d", rfsock, rfsock->bt_sock, cond);
+
 	connections = g_list_remove(connections, rfsock);
 	cleanup_rfsock(rfsock);
 
@@ -710,7 +714,7 @@ static gboolean jv_sock_server_event_cb(GIOChannel *io, GIOCondition cond,
 {
 	struct rfcomm_sock *rfsock = data;
 
-	DBG("sock %d cond %d", g_io_channel_unix_get_fd(io), cond);
+	DBG("rfsock %p jv_sock %d cond %d", rfsock, rfsock->jv_sock, cond);
 
 	if (cond & G_IO_NVAL)
 		return FALSE;
@@ -752,7 +756,8 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
 	}
 
 	ba2str(&dst, address);
-	DBG("Incoming connection from %s rfsock %p", address, rfsock);
+	DBG("Incoming connection from %s on channel %d (rfsock %p)", address,
+						rfsock->channel, rfsock);
 
 	new_sock = g_io_channel_unix_get_fd(io);
 	new_rfsock = create_rfsock(new_sock, &hal_sock);
@@ -761,9 +766,8 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
 		return;
 	}
 
-	DBG("rfsock: jv_sock %d bt_sock %d chan %u new_sock %d",
-		rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
-		new_sock);
+	DBG("new rfsock %p bt_sock %d jv_sock %d hal_sock %d", new_rfsock,
+			new_rfsock->bt_sock, new_rfsock->jv_sock, hal_sock);
 
 	if (!sock_send_accept(rfsock, &dst, hal_sock)) {
 		cleanup_rfsock(new_rfsock);
@@ -786,10 +790,6 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
 	g_io_channel_set_close_on_unref(io, FALSE);
 
 	new_rfsock->bt_watch = id;
-
-	DBG("rfsock %p rfsock_acc %p jv_watch %d bt_watch %d",
-		rfsock, new_rfsock, new_rfsock->jv_watch,
-		new_rfsock->bt_watch);
 }
 
 static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
@@ -802,8 +802,14 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 	GIOCondition cond;
 	GError *err = NULL;
 	guint id;
+	uuid_t uu;
+	char uuid_str[32];
 
-	DBG("");
+	sdp_uuid128_create(&uu, uuid);
+	sdp_uuid2strn(&uu, uuid_str, sizeof(uuid_str));
+
+	DBG("chan %d flags 0x%02x uuid %s name %s", chan, flags, uuid_str,
+									name);
 
 	if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) {
 		error("Invalid rfcomm listen params");
@@ -821,7 +827,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 		sec_level = profile->sec_level;
 	}
 
-	DBG("rfcomm channel %d svc_name %s", chan, name);
+	DBG("chan %d sec_level %d", chan, sec_level);
 
 	rfsock = create_rfsock(-1, hal_sock);
 	if (!rfsock)
@@ -853,8 +859,10 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 
 	rfsock->jv_watch = id;
 
-	DBG("bt_sock %d jv_sock %d hal_sock %d", rfsock->bt_sock,
-						rfsock->jv_sock, *hal_sock);
+	DBG("rfsock %p bt_sock %d jv_sock %d hal_sock %d", rfsock,
+								rfsock->bt_sock,
+								rfsock->jv_sock,
+								*hal_sock);
 
 	if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
 		error("Error sending RFCOMM channel");
@@ -948,11 +956,8 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 	}
 
 	ba2str(dst, address);
-	DBG("Connected to %s", address);
-
-	DBG("rfsock: jv_sock %d bt_sock %d chan %u sock %d",
-		rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
-		g_io_channel_unix_get_fd(io));
+	DBG("Connected to %s on channel %d (rfsock %p)", address,
+						rfsock->channel, rfsock);
 
 	if (!sock_send_connect(rfsock, dst))
 		goto fail;
@@ -987,6 +992,8 @@ static bool do_rfcomm_connect(struct rfcomm_sock *rfsock, int chan)
 	if (rfsock->profile)
 		sec_level = rfsock->profile->sec_level;
 
+	DBG("rfsock %p sec_level %d chan %d", rfsock, sec_level, chan);
+
 	io = bt_io_connect(connect_cb, rfsock, NULL, &gerr,
 				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
 				BT_IO_OPT_DEST_BDADDR, &rfsock->dst,
@@ -1070,7 +1077,16 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
 					int *hal_sock)
 {
 	struct rfcomm_sock *rfsock;
+	char address[18];
 	uuid_t uu;
+	char uuid_str[32];
+
+	sdp_uuid128_create(&uu, uuid);
+	sdp_uuid2strn(&uu, uuid_str, sizeof(uuid_str));
+	ba2str(addr, address);
+
+	DBG("addr %s chan %d flags 0x%02x uuid %s", address, chan, flags,
+								uuid_str);
 
 	if ((!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) ||
 						!bacmp(addr, BDADDR_ANY)) {
@@ -1082,16 +1098,15 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
 	if (!rfsock)
 		return HAL_STATUS_FAILED;
 
+	DBG("rfsock %p jv_sock %d hal_sock %d", rfsock, rfsock->jv_sock,
+							*hal_sock);
+
 	bacpy(&rfsock->dst, addr);
 
 	if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid))) {
 		if (!do_rfcomm_connect(rfsock, chan))
 			goto failed;
 	} else {
-		memset(&uu, 0, sizeof(uu));
-		uu.type = SDP_UUID128;
-		memcpy(&uu.value.uuid128, uuid, sizeof(uint128_t));
-
 		rfsock->profile = get_profile_by_uuid(uuid);
 
 		if (bt_search_service(&adapter_addr, &rfsock->dst, &uu,
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 02/11] android/socket: Refactor socket related symbol names
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch changes names of symbols related to various sockets to be
consistent and easier to follow in code.

Symbols related to actual BT (RFCOMM) socket are prefixed with "bt_".
Symbols related to local socket for Java comm are prefixed with "jv_".
Remote socket for Java comm is called "hal_sock".
---
 android/socket.c | 186 ++++++++++++++++++++++++++++---------------------------
 1 file changed, 95 insertions(+), 91 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 1375625..107042e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -71,12 +71,15 @@ GList *servers = NULL;
 GList *connections = NULL;
 
 struct rfcomm_sock {
-	int fd;		/* descriptor for communication with Java framework */
-	int real_sock;	/* real RFCOMM socket */
 	int channel;	/* RFCOMM channel */
 
-	guint rfcomm_watch;
-	guint stack_watch;
+	/* for socket to BT */
+	int bt_sock;
+	guint bt_watch;
+
+	/* for socket to HAL */
+	int jv_sock;
+	guint jv_watch;
 
 	bdaddr_t dst;
 	uint32_t service_handle;
@@ -92,13 +95,13 @@ static int rfsock_set_buffer(struct rfcomm_sock *rfsock)
 	socklen_t len = sizeof(int);
 	int rcv, snd, size, err;
 
-	err = getsockopt(rfsock->real_sock, SOL_SOCKET, SO_RCVBUF, &rcv, &len);
+	err = getsockopt(rfsock->bt_sock, SOL_SOCKET, SO_RCVBUF, &rcv, &len);
 	if (err < 0) {
 		error("getsockopt(SO_RCVBUF): %s", strerror(errno));
 		return -errno;
 	}
 
-	err = getsockopt(rfsock->real_sock, SOL_SOCKET, SO_SNDBUF, &snd, &len);
+	err = getsockopt(rfsock->bt_sock, SOL_SOCKET, SO_SNDBUF, &snd, &len);
 	if (err < 0) {
 		error("getsockopt(SO_SNDBUF): %s", strerror(errno));
 		return -errno;
@@ -118,25 +121,25 @@ static void cleanup_rfsock(gpointer data)
 {
 	struct rfcomm_sock *rfsock = data;
 
-	DBG("rfsock: %p fd %d real_sock %d chan %u",
-		rfsock, rfsock->fd, rfsock->real_sock, rfsock->channel);
+	DBG("rfsock: %p jv_sock %d bt_sock %d chan %u",
+		rfsock, rfsock->jv_sock, rfsock->bt_sock, rfsock->channel);
 
-	if (rfsock->fd >= 0)
-		if (close(rfsock->fd) < 0)
-			error("close() fd %d failed: %s", rfsock->fd,
+	if (rfsock->jv_sock >= 0)
+		if (close(rfsock->jv_sock) < 0)
+			error("close() fd %d failed: %s", rfsock->jv_sock,
 							strerror(errno));
 
-	if (rfsock->real_sock >= 0)
-		if (close(rfsock->real_sock) < 0)
-			error("close() fd %d: failed: %s", rfsock->real_sock,
+	if (rfsock->bt_sock >= 0)
+		if (close(rfsock->bt_sock) < 0)
+			error("close() fd %d: failed: %s", rfsock->bt_sock,
 							strerror(errno));
 
-	if (rfsock->rfcomm_watch > 0)
-		if (!g_source_remove(rfsock->rfcomm_watch))
-			error("rfcomm_watch source was not found");
+	if (rfsock->bt_watch > 0)
+		if (!g_source_remove(rfsock->bt_watch))
+			error("bt_watch source was not found");
 
-	if (rfsock->stack_watch > 0)
-		if (!g_source_remove(rfsock->stack_watch))
+	if (rfsock->jv_watch > 0)
+		if (!g_source_remove(rfsock->jv_watch))
 			error("stack_watch source was not found");
 
 	if (rfsock->service_handle)
@@ -148,23 +151,23 @@ static void cleanup_rfsock(gpointer data)
 	g_free(rfsock);
 }
 
-static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
+static struct rfcomm_sock *create_rfsock(int bt_sock, int *hal_sock)
 {
 	int fds[2] = {-1, -1};
 	struct rfcomm_sock *rfsock;
 
 	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
 		error("socketpair(): %s", strerror(errno));
-		*hal_fd = -1;
+		*hal_sock = -1;
 		return NULL;
 	}
 
 	rfsock = g_new0(struct rfcomm_sock, 1);
-	rfsock->fd = fds[0];
-	*hal_fd = fds[1];
-	rfsock->real_sock = sock;
+	rfsock->jv_sock = fds[0];
+	*hal_sock = fds[1];
+	rfsock->bt_sock = bt_sock;
 
-	if (sock < 0)
+	if (bt_sock < 0)
 		return rfsock;
 
 	if (rfsock_set_buffer(rfsock) < 0) {
@@ -604,7 +607,7 @@ static int try_write_all(int fd, unsigned char *buf, int len)
 	return sent;
 }
 
-static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
+static gboolean jv_sock_client_event_cb(GIOChannel *io, GIOCondition cond,
 								gpointer data)
 {
 	struct rfcomm_sock *rfsock = data;
@@ -621,14 +624,14 @@ static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
 		goto fail;
 	}
 
-	len = read(rfsock->fd, rfsock->buf, rfsock->buf_size);
+	len = read(rfsock->jv_sock, rfsock->buf, rfsock->buf_size);
 	if (len <= 0) {
 		error("read(): %s", strerror(errno));
 		/* Read again */
 		return TRUE;
 	}
 
-	sent = try_write_all(rfsock->real_sock, rfsock->buf, len);
+	sent = try_write_all(rfsock->bt_sock, rfsock->buf, len);
 	if (sent < 0) {
 		error("write(): %s", strerror(errno));
 		goto fail;
@@ -642,7 +645,7 @@ fail:
 	return FALSE;
 }
 
-static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
+static gboolean bt_sock_event_cb(GIOChannel *io, GIOCondition cond,
 								gpointer data)
 {
 	struct rfcomm_sock *rfsock = data;
@@ -659,14 +662,14 @@ static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
 		goto fail;
 	}
 
-	len = read(rfsock->real_sock, rfsock->buf, rfsock->buf_size);
+	len = read(rfsock->bt_sock, rfsock->buf, rfsock->buf_size);
 	if (len <= 0) {
 		error("read(): %s", strerror(errno));
 		/* Read again */
 		return TRUE;
 	}
 
-	sent = try_write_all(rfsock->fd, rfsock->buf, len);
+	sent = try_write_all(rfsock->jv_sock, rfsock->buf, len);
 	if (sent < 0) {
 		error("write(): %s", strerror(errno));
 		goto fail;
@@ -693,7 +696,7 @@ static bool sock_send_accept(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr,
 	cmd.channel = rfsock->channel;
 	cmd.status = 0;
 
-	len = bt_sock_send_fd(rfsock->fd, &cmd, sizeof(cmd), fd_accepted);
+	len = bt_sock_send_fd(rfsock->jv_sock, &cmd, sizeof(cmd), fd_accepted);
 	if (len != sizeof(cmd)) {
 		error("Error sending accept signal");
 		return false;
@@ -702,7 +705,7 @@ static bool sock_send_accept(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr,
 	return true;
 }
 
-static gboolean sock_server_stack_event_cb(GIOChannel *io, GIOCondition cond,
+static gboolean jv_sock_server_event_cb(GIOChannel *io, GIOCondition cond,
 								gpointer data)
 {
 	struct rfcomm_sock *rfsock = data;
@@ -723,13 +726,13 @@ static gboolean sock_server_stack_event_cb(GIOChannel *io, GIOCondition cond,
 static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
 {
 	struct rfcomm_sock *rfsock = user_data;
-	struct rfcomm_sock *rfsock_acc;
-	GIOChannel *io_stack;
+	struct rfcomm_sock *new_rfsock;
+	GIOChannel *jv_io;
 	GError *gerr = NULL;
 	bdaddr_t dst;
 	char address[18];
-	int sock_acc;
-	int hal_fd;
+	int new_sock;
+	int hal_sock;
 	guint id;
 	GIOCondition cond;
 
@@ -751,51 +754,51 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
 	ba2str(&dst, address);
 	DBG("Incoming connection from %s rfsock %p", address, rfsock);
 
-	sock_acc = g_io_channel_unix_get_fd(io);
-	rfsock_acc = create_rfsock(sock_acc, &hal_fd);
-	if (!rfsock_acc) {
+	new_sock = g_io_channel_unix_get_fd(io);
+	new_rfsock = create_rfsock(new_sock, &hal_sock);
+	if (!new_rfsock) {
 		g_io_channel_shutdown(io, TRUE, NULL);
 		return;
 	}
 
-	DBG("rfsock: fd %d real_sock %d chan %u sock %d",
-		rfsock->fd, rfsock->real_sock, rfsock->channel,
-		sock_acc);
+	DBG("rfsock: jv_sock %d bt_sock %d chan %u new_sock %d",
+		rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
+		new_sock);
 
-	if (!sock_send_accept(rfsock, &dst, hal_fd)) {
-		cleanup_rfsock(rfsock_acc);
+	if (!sock_send_accept(rfsock, &dst, hal_sock)) {
+		cleanup_rfsock(new_rfsock);
 		return;
 	}
 
-	connections = g_list_append(connections, rfsock_acc);
+	connections = g_list_append(connections, new_rfsock);
 
 	/* Handle events from Android */
 	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
-	io_stack = g_io_channel_unix_new(rfsock_acc->fd);
-	id = g_io_add_watch(io_stack, cond, sock_stack_event_cb, rfsock_acc);
-	g_io_channel_unref(io_stack);
+	jv_io = g_io_channel_unix_new(new_rfsock->jv_sock);
+	id = g_io_add_watch(jv_io, cond, jv_sock_client_event_cb, new_rfsock);
+	g_io_channel_unref(jv_io);
 
-	rfsock_acc->stack_watch = id;
+	new_rfsock->jv_watch = id;
 
 	/* Handle rfcomm events */
 	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
-	id = g_io_add_watch(io, cond, sock_rfcomm_event_cb, rfsock_acc);
+	id = g_io_add_watch(io, cond, bt_sock_event_cb, new_rfsock);
 	g_io_channel_set_close_on_unref(io, FALSE);
 
-	rfsock_acc->rfcomm_watch = id;
+	new_rfsock->bt_watch = id;
 
-	DBG("rfsock %p rfsock_acc %p stack_watch %d rfcomm_watch %d",
-		rfsock, rfsock_acc, rfsock_acc->stack_watch,
-		rfsock_acc->rfcomm_watch);
+	DBG("rfsock %p rfsock_acc %p jv_watch %d bt_watch %d",
+		rfsock, new_rfsock, new_rfsock->jv_watch,
+		new_rfsock->bt_watch);
 }
 
 static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
-						uint8_t flags, int *hal_fd)
+						uint8_t flags, int *hal_sock)
 {
 	const struct profile_info *profile;
 	struct rfcomm_sock *rfsock = NULL;
 	BtIOSecLevel sec_level;
-	GIOChannel *io, *io_stack;
+	GIOChannel *io, *jv_io;
 	GIOCondition cond;
 	GError *err = NULL;
 	guint id;
@@ -820,7 +823,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 
 	DBG("rfcomm channel %d svc_name %s", chan, name);
 
-	rfsock = create_rfsock(-1, hal_fd);
+	rfsock = create_rfsock(-1, hal_sock);
 	if (!rfsock)
 		return HAL_STATUS_FAILED;
 
@@ -835,25 +838,25 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 		goto failed;
 	}
 
-	rfsock->real_sock = g_io_channel_unix_get_fd(io);
+	rfsock->bt_sock = g_io_channel_unix_get_fd(io);
 
 	g_io_channel_set_close_on_unref(io, FALSE);
 	g_io_channel_unref(io);
 
 	/* Handle events from Android */
 	cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
-	io_stack = g_io_channel_unix_new(rfsock->fd);
-	id = g_io_add_watch_full(io_stack, G_PRIORITY_HIGH, cond,
-					sock_server_stack_event_cb, rfsock,
+	jv_io = g_io_channel_unix_new(rfsock->jv_sock);
+	id = g_io_add_watch_full(jv_io, G_PRIORITY_HIGH, cond,
+					jv_sock_server_event_cb, rfsock,
 					NULL);
-	g_io_channel_unref(io_stack);
+	g_io_channel_unref(jv_io);
 
-	rfsock->stack_watch = id;
+	rfsock->jv_watch = id;
 
-	DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
-								*hal_fd);
+	DBG("bt_sock %d jv_sock %d hal_sock %d", rfsock->bt_sock,
+						rfsock->jv_sock, *hal_sock);
 
-	if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+	if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
 		error("Error sending RFCOMM channel");
 		goto failed;
 	}
@@ -867,7 +870,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
 failed:
 
 	cleanup_rfsock(rfsock);
-	close(*hal_fd);
+	close(*hal_sock);
 	return HAL_STATUS_FAILED;
 }
 
@@ -875,12 +878,12 @@ static void handle_listen(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_sock_listen *cmd = buf;
 	uint8_t status;
-	int hal_fd;
+	int hal_sock;
 
 	switch (cmd->type) {
 	case HAL_SOCK_RFCOMM:
 		status = rfcomm_listen(cmd->channel, cmd->name, cmd->uuid,
-							cmd->flags, &hal_fd);
+							cmd->flags, &hal_sock);
 		break;
 	case HAL_SOCK_SCO:
 	case HAL_SOCK_L2CAP:
@@ -895,8 +898,8 @@ static void handle_listen(const void *buf, uint16_t len)
 		goto failed;
 
 	ipc_send_rsp_full(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_LISTEN, 0, NULL,
-									hal_fd);
-	close(hal_fd);
+								hal_sock);
+	close(hal_sock);
 	return ;
 
 failed:
@@ -916,7 +919,7 @@ static bool sock_send_connect(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr)
 	cmd.channel = rfsock->channel;
 	cmd.status = 0;
 
-	len = write(rfsock->fd, &cmd, sizeof(cmd));
+	len = write(rfsock->jv_sock, &cmd, sizeof(cmd));
 	if (len < 0) {
 		error("%s", strerror(errno));
 		return false;
@@ -934,7 +937,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 {
 	struct rfcomm_sock *rfsock = user_data;
 	bdaddr_t *dst = &rfsock->dst;
-	GIOChannel *io_stack;
+	GIOChannel *jv_io;
 	char address[18];
 	guint id;
 	GIOCondition cond;
@@ -947,8 +950,8 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 	ba2str(dst, address);
 	DBG("Connected to %s", address);
 
-	DBG("rfsock: fd %d real_sock %d chan %u sock %d",
-		rfsock->fd, rfsock->real_sock, rfsock->channel,
+	DBG("rfsock: jv_sock %d bt_sock %d chan %u sock %d",
+		rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
 		g_io_channel_unix_get_fd(io));
 
 	if (!sock_send_connect(rfsock, dst))
@@ -956,18 +959,18 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 
 	/* Handle events from Android */
 	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
-	io_stack = g_io_channel_unix_new(rfsock->fd);
-	id = g_io_add_watch(io_stack, cond, sock_stack_event_cb, rfsock);
-	g_io_channel_unref(io_stack);
+	jv_io = g_io_channel_unix_new(rfsock->jv_sock);
+	id = g_io_add_watch(jv_io, cond, jv_sock_client_event_cb, rfsock);
+	g_io_channel_unref(jv_io);
 
-	rfsock->stack_watch = id;
+	rfsock->jv_watch = id;
 
 	/* Handle rfcomm events */
 	cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
-	id = g_io_add_watch(io, cond, sock_rfcomm_event_cb, rfsock);
+	id = g_io_add_watch(io, cond, bt_sock_event_cb, rfsock);
 	g_io_channel_set_close_on_unref(io, FALSE);
 
-	rfsock->rfcomm_watch = id;
+	rfsock->bt_watch = id;
 
 	return;
 fail:
@@ -999,12 +1002,12 @@ static bool do_rfcomm_connect(struct rfcomm_sock *rfsock, int chan)
 	g_io_channel_set_close_on_unref(io, FALSE);
 	g_io_channel_unref(io);
 
-	if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+	if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
 		error("Error sending RFCOMM channel");
 		return false;
 	}
 
-	rfsock->real_sock = g_io_channel_unix_get_fd(io);
+	rfsock->bt_sock = g_io_channel_unix_get_fd(io);
 	rfsock_set_buffer(rfsock);
 	rfsock->channel = chan;
 	connections = g_list_append(connections, rfsock);
@@ -1063,7 +1066,8 @@ fail:
 }
 
 static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
-				const uint8_t *uuid, uint8_t flags, int *hal_fd)
+					const uint8_t *uuid, uint8_t flags,
+					int *hal_sock)
 {
 	struct rfcomm_sock *rfsock;
 	uuid_t uu;
@@ -1074,7 +1078,7 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
 		return HAL_STATUS_INVALID;
 	}
 
-	rfsock = create_rfsock(-1, hal_fd);
+	rfsock = create_rfsock(-1, hal_sock);
 	if (!rfsock)
 		return HAL_STATUS_FAILED;
 
@@ -1101,7 +1105,7 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
 
 failed:
 	cleanup_rfsock(rfsock);
-	close(*hal_fd);
+	close(*hal_sock);
 	return HAL_STATUS_FAILED;
 }
 
@@ -1110,7 +1114,7 @@ static void handle_connect(const void *buf, uint16_t len)
 	const struct hal_cmd_sock_connect *cmd = buf;
 	bdaddr_t bdaddr;
 	uint8_t status;
-	int hal_fd;
+	int hal_sock;
 
 	DBG("");
 
@@ -1119,7 +1123,7 @@ static void handle_connect(const void *buf, uint16_t len)
 	switch (cmd->type) {
 	case HAL_SOCK_RFCOMM:
 		status = connect_rfcomm(&bdaddr, cmd->channel, cmd->uuid,
-							cmd->flags, &hal_fd);
+							cmd->flags, &hal_sock);
 		break;
 	case HAL_SOCK_SCO:
 	case HAL_SOCK_L2CAP:
@@ -1134,8 +1138,8 @@ static void handle_connect(const void *buf, uint16_t len)
 		goto failed;
 
 	ipc_send_rsp_full(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_CONNECT, 0, NULL,
-									hal_fd);
-	close(hal_fd);
+								hal_sock);
+	close(hal_sock);
 	return;
 
 failed:
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 01/11] android/bluetooth: Handle 128-bit UUIDs
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1392137901-3403-1-git-send-email-andrzej.kaczmarek@tieto.com>

It's now possible to add record with 128-bit UUID Service Class which
are used for custom applications. To simplify implementation adapter
uuids list stores now full UUID in uuid_t structure instead of uint16_t
short UUID.
---
 android/bluetooth.c | 61 ++++++++++++++++++-----------------------------------
 1 file changed, 21 insertions(+), 40 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 9f8e7b4..c064fe8 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1459,17 +1459,6 @@ static void load_link_keys(GSList *keys, bt_bluetooth_ready cb)
 	}
 }
 
-/* output uint128 is in host order */
-static void uuid16_to_uint128(uint16_t uuid, uint128_t *u128)
-{
-	uuid_t uuid16, uuid128;
-
-	sdp_uuid16_create(&uuid16, uuid);
-	sdp_uuid16_to_uuid128(&uuid128, &uuid16);
-
-	ntoh128(&uuid128.value.uuid128, u128);
-}
-
 static uint8_t get_adapter_uuids(void)
 {
 	struct hal_ev_adapter_props_changed *ev;
@@ -1478,7 +1467,6 @@ static uint8_t get_adapter_uuids(void)
 	int len = uuid_count * sizeof(uint128_t);
 	uint8_t buf[BASELEN_PROP_CHANGED + len];
 	uint8_t *p;
-	int i;
 
 	memset(buf, 0, sizeof(buf));
 	ev = (void *) buf;
@@ -1491,14 +1479,9 @@ static uint8_t get_adapter_uuids(void)
 	p = ev->props->val;
 
 	for (; list; list = g_slist_next(list)) {
-		uint16_t uuid = GPOINTER_TO_UINT(list->data);
-		uint128_t uint128;
-
-		uuid16_to_uint128(uuid, &uint128);
+		uuid_t *uuid = list->data;
 
-		/* Android expects swapped bytes in uuid */
-		for (i = 0; i < 16; i++)
-			p[15 - i] = uint128.data[i];
+		memcpy(p, &uuid->value.uuid128, sizeof(uint128_t));
 
 		p += sizeof(uint128_t);
 	}
@@ -1523,12 +1506,12 @@ static void remove_uuid_complete(uint8_t status, uint16_t length,
 	get_adapter_uuids();
 }
 
-static void remove_uuid(uint16_t uuid)
+static void remove_uuid(uuid_t *uuid)
 {
 	uint128_t uint128;
 	struct mgmt_cp_remove_uuid cp;
 
-	uuid16_to_uint128(uuid, &uint128);
+	ntoh128((uint128_t *) uuid->value.uuid128.data, &uint128);
 	htob128(&uint128, (uint128_t *) cp.uuid);
 
 	mgmt_send(mgmt_if, MGMT_OP_REMOVE_UUID, adapter.index, sizeof(cp), &cp,
@@ -1549,14 +1532,14 @@ static void add_uuid_complete(uint8_t status, uint16_t length,
 	get_adapter_uuids();
 }
 
-static void add_uuid(uint8_t svc_hint, uint16_t uuid)
+static void add_uuid(uint8_t svc_hint, uuid_t *uuid)
 {
 	uint128_t uint128;
 	struct mgmt_cp_add_uuid cp;
 
-	uuid16_to_uint128(uuid, &uint128);
-
+	ntoh128((uint128_t *) uuid->value.uuid128.data, &uint128);
 	htob128(&uint128, (uint128_t *) cp.uuid);
+
 	cp.svc_hint = svc_hint;
 
 	mgmt_send(mgmt_if, MGMT_OP_ADD_UUID, adapter.index, sizeof(cp), &cp,
@@ -1565,22 +1548,19 @@ static void add_uuid(uint8_t svc_hint, uint16_t uuid)
 
 int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint)
 {
-	uint16_t uuid;
+	uuid_t *uuid;
 
-	/* TODO support all types? */
-	if (rec->svclass.type != SDP_UUID16) {
-		warn("Ignoring unsupported UUID type");
-		return -EINVAL;
-	}
+	uuid = sdp_uuid_to_uuid128(&rec->svclass);
 
-	uuid = rec->svclass.value.uuid16;
+	if (g_slist_find_custom(adapter.uuids, uuid, sdp_uuid_cmp)) {
+		char uuid_str[32];
 
-	if (g_slist_find(adapter.uuids, GUINT_TO_POINTER(uuid))) {
-		DBG("UUID 0x%x already added", uuid);
+		sdp_uuid2strn(uuid, uuid_str, sizeof(uuid_str));
+		DBG("UUID %s already added", uuid_str);
 		return -EALREADY;
 	}
 
-	adapter.uuids = g_slist_prepend(adapter.uuids, GUINT_TO_POINTER(uuid));
+	adapter.uuids = g_slist_prepend(adapter.uuids, uuid);
 
 	add_uuid(svc_hint, uuid);
 
@@ -1591,20 +1571,21 @@ void bt_adapter_remove_record(uint32_t handle)
 {
 	sdp_record_t *rec;
 	GSList *uuid_found;
-	uint16_t uuid;
 
 	rec = sdp_record_find(handle);
 	if (!rec)
 		return;
 
-	uuid = rec->svclass.value.uuid16;
-
-	uuid_found = g_slist_find(adapter.uuids, GUINT_TO_POINTER(uuid));
+	uuid_found = g_slist_find_custom(adapter.uuids, &rec->svclass,
+								sdp_uuid_cmp);
 	if (uuid_found) {
+		uuid_t *uuid = uuid_found->data;
+
 		remove_uuid(uuid);
 
-		adapter.uuids = g_slist_remove(adapter.uuids,
-							uuid_found->data);
+		adapter.uuids = g_slist_remove(adapter.uuids, uuid);
+
+		free(uuid);
 	}
 
 	remove_record_from_server(handle);
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 00/11] Socket HAL updates
From: Andrzej Kaczmarek @ 2014-02-11 16:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

Current socket HAL implementation is missing major feature which is
ability to register RFCOMM server from application (so use some UUID
and assign channel number dynamically). This corresponds to
BluetoothAdapter::listenUsing(insecure)RfcommWithServiceRecord APIs
in Android.

This series of patches adds this feature with other required fixes
and also some does some minor refactoring.

Andrzej Kaczmarek (11):
  android/bluetooth: Handle 128-bit UUIDs
  android/socket: Refactor socket related symbol names
  android/socket: Improve logging
  android/socket: Simplify SDP records handling
  android/socket: Make servers list as static array
  android/tester: Update test data
  android/socket: Add support for dynamic channel numbers
  android/socket: Register SDP record for application service
  android/socket: Include HF AG in built-in profiles
  android/socket: Update channel numbers
  android/socket: Fix sockets security

 android/android-tester.c |   2 +-
 android/bluetooth.c      |  61 ++---
 android/hal-msg.h        |   3 +
 android/socket.c         | 658 +++++++++++++++++++++++------------------------
 4 files changed, 349 insertions(+), 375 deletions(-)

-- 
1.8.5.3


^ permalink raw reply

* Re: [PATCH 1/6] shared: Add support for disonnect handler to GLib based IO handling
From: Marcel Holtmann @ 2014-02-11 16:57 UTC (permalink / raw)
  To: Szymon Janc; +Cc: bluez mailin list (linux-bluetooth@vger.kernel.org)
In-Reply-To: <1392137346-26272-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

> ---
> src/shared/io-glib.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 58 insertions(+), 1 deletion(-)
> 
> diff --git a/src/shared/io-glib.c b/src/shared/io-glib.c
> index 77ba19e..a4f982d 100644
> --- a/src/shared/io-glib.c
> +++ b/src/shared/io-glib.c
> @@ -40,6 +40,10 @@ struct io {
> 	io_callback_func_t write_callback;
> 	io_destroy_func_t write_destroy;
> 	void *write_data;
> +	guint disconnect_watch;
> +	io_callback_func_t disconnect_callback;
> +	io_destroy_func_t disconnect_destroy;
> +	void *disconnect_data;
> };
> 
> static struct io *io_ref(struct io *io)
> @@ -258,8 +262,61 @@ done:
> 	return true;
> }
> 
> +static void disconnect_watch_destroy(gpointer user_data)
> +{
> +	struct io *io = user_data;
> +
> +	if (io->disconnect_destroy)
> +		io->disconnect_destroy(io->disconnect_data);
> +
> +	io->disconnect_watch = 0;
> +	io->disconnect_callback = NULL;
> +	io->disconnect_destroy = NULL;
> +	io->disconnect_data = NULL;
> +
> +	io_unref(io);
> +}
> +
> +static gboolean disconnect_callback(GIOChannel *channel, GIOCondition cond,
> +							gpointer user_data)
> +{
> +	struct io *io = user_data;
> +	bool result;
> +
> +	if (io->disconnect_callback)
> +		result = io->disconnect_callback(io, io->disconnect_data);
> +	else
> +		result = false;
> +
> +	return result ? TRUE : FALSE;
> +}
> +
> bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
> 				void *user_data, io_destroy_func_t destroy)
> {
> -	return false;
> +	if (!io)
> +		return false;
> +
> +	if (io->disconnect_watch > 0) {
> +		g_source_remove(io->disconnect_watch);
> +		io->disconnect_watch = 0;
> +	}
> +
> +	if (!callback)
> +		goto done;
> +
> +	io->disconnect_watch = g_io_add_watch_full(io->channel,
> +				G_PRIORITY_DEFAULT,
> +				G_IO_HUP | G_IO_ERR | G_IO_NVAL,

If we are using G_IO_HUP here, we should remove it from the other callback handling?

> +				disconnect_callback, io_ref(io),
> +				disconnect_watch_destroy);
> +	if (io->disconnect_watch == 0)
> +		return false;
> +
> +	io->disconnect_destroy = destroy;
> +	io->disconnect_data = user_data;

we normally have an extra empty line here. You might also fix the previous patch then.

> +done:
> +	io->disconnect_callback = callback;
> +
> +	return true;
> }
> -- 
> 1.8.5.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply

* [PATCH 6/6] android/handsfree: Use HFP code for connection handling
From: Szymon Janc @ 2014-02-11 16:49 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1392137346-26272-1-git-send-email-szymon.janc@tieto.com>

HFP code is now able to handle disconnection on its own so just use
this instead of using own watches.
---
 android/handsfree.c | 50 +++++++++++++-------------------------------------
 1 file changed, 13 insertions(+), 37 deletions(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 9482b2e..a973bd5 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -52,8 +52,6 @@
 static struct {
 	bdaddr_t bdaddr;
 	uint8_t state;
-	GIOChannel *io;
-	guint watch;
 	struct hfp_gw *gw;
 } device;
 
@@ -96,38 +94,23 @@ static void device_cleanup(void)
 		device.gw = NULL;
 	}
 
-	if (device.watch) {
-		g_source_remove(device.watch);
-		device.watch = 0;
-	}
-
-	if (device.io) {
-		g_io_channel_unref(device.io);
-		device.io = NULL;
-	}
-
 	device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED);
 
 	memset(&device, 0, sizeof(device));
 }
 
-static gboolean watch_cb(GIOChannel *chan, GIOCondition cond,
-							gpointer user_data)
+static void at_command_handler(const char *command, void *user_data)
 {
-	DBG("");
-
-	device.watch = 0;
-
-	device_cleanup();
+	hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
 
-	return FALSE;
+	hfp_gw_disconnect(device.gw);
 }
 
-static void at_command_handler(const char *command, void *user_data)
+static void disconnect_watch(void *user_data)
 {
-	hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+	DBG("");
 
-	g_io_channel_shutdown(device.io, TRUE, NULL);
+	device_cleanup();
 }
 
 static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
@@ -139,22 +122,15 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 		goto failed;
 	}
 
-	g_io_channel_set_close_on_unref(chan, TRUE);
-
 	device.gw = hfp_gw_new(g_io_channel_unix_get_fd(chan));
 	if (!device.gw)
 		goto failed;
 
+	g_io_channel_set_close_on_unref(chan, FALSE);
+
 	hfp_gw_set_close_on_unref(device.gw, true);
 	hfp_gw_set_command_handler(device.gw, at_command_handler, NULL, NULL);
-
-	device.watch = g_io_add_watch(chan,
-					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-					watch_cb, NULL);
-	if (device.watch == 0)
-		goto failed;
-
-	device.io = g_io_channel_ref(chan);
+	hfp_gw_set_disconnect_handler(device.gw, disconnect_watch, NULL, NULL);
 
 	device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
 
@@ -332,11 +308,11 @@ static void handle_disconnect(const void *buf, uint16_t len)
 		goto failed;
 	}
 
-	if (device.io) {
-		device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING);
-		g_io_channel_shutdown(device.io, TRUE, NULL);
-	} else {
+	if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING) {
 		device_cleanup();
+	} else {
+		device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING);
+		hfp_gw_disconnect(device.gw);
 	}
 
 	status = HAL_STATUS_SUCCESS;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 5/6] shared: Add support for local disconnect to HFP
From: Szymon Janc @ 2014-02-11 16:49 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1392137346-26272-1-git-send-email-szymon.janc@tieto.com>

This allows to locally trigger disconnection.
---
 src/shared/hfp.c | 8 ++++++++
 src/shared/hfp.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 3944e97..2c793f9 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -445,3 +445,11 @@ bool hfp_gw_set_disconnect_handler(struct hfp_gw *hfp,
 
 	return true;
 }
+
+bool hfp_gw_disconnect(struct hfp_gw *hfp)
+{
+	if (!hfp)
+		return false;
+
+	return io_shutdown(hfp->io);
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 75ec484..5a86dfe 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -92,3 +92,5 @@ bool hfp_gw_set_disconnect_handler(struct hfp_gw *hfp,
 					hfp_disconnect_func_t callback,
 					void *user_data,
 					hfp_destroy_func_t destroy);
+
+bool hfp_gw_disconnect(struct hfp_gw *hfp);
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 4/6] shared: Add support for shutdown to IO
From: Szymon Janc @ 2014-02-11 16:49 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1392137346-26272-1-git-send-email-szymon.janc@tieto.com>

This allows to locally shutdown IO.
---
 src/shared/io-glib.c     | 9 +++++++++
 src/shared/io-mainloop.c | 9 +++++++++
 src/shared/io.h          | 2 ++
 3 files changed, 20 insertions(+)

diff --git a/src/shared/io-glib.c b/src/shared/io-glib.c
index a4f982d..8290745 100644
--- a/src/shared/io-glib.c
+++ b/src/shared/io-glib.c
@@ -320,3 +320,12 @@ done:
 
 	return true;
 }
+
+bool io_shutdown(struct io *io)
+{
+	if (!io || !io->channel)
+		return false;
+
+	return g_io_channel_shutdown(io->channel, TRUE, NULL)
+							== G_IO_STATUS_NORMAL;
+}
diff --git a/src/shared/io-mainloop.c b/src/shared/io-mainloop.c
index 14ab128..f1e3b3b 100644
--- a/src/shared/io-mainloop.c
+++ b/src/shared/io-mainloop.c
@@ -26,6 +26,7 @@
 #endif
 
 #include <unistd.h>
+#include <sys/socket.h>
 
 #include "monitor/mainloop.h"
 #include "src/shared/util.h"
@@ -294,3 +295,11 @@ bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
 
 	return true;
 }
+
+bool io_shutdown(struct io *io)
+{
+	if (!io || io->fd < 0)
+		return false;
+
+	return shutdown(io->fd, SHUT_RDWR) == 0;
+}
diff --git a/src/shared/io.h b/src/shared/io.h
index 2c47e39..2106240 100644
--- a/src/shared/io.h
+++ b/src/shared/io.h
@@ -33,6 +33,8 @@ void io_destroy(struct io *io);
 int io_get_fd(struct io *io);
 bool io_set_close_on_destroy(struct io *io, bool do_close);
 
+bool io_shutdown(struct io *io);
+
 typedef bool (*io_callback_func_t)(struct io *io, void *user_data);
 
 bool io_set_read_handler(struct io *io, io_callback_func_t callback,
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 3/6] shared: Add support for disconnect handler in HFP
From: Szymon Janc @ 2014-02-11 16:49 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1392137346-26272-1-git-send-email-szymon.janc@tieto.com>

It is no longer possible to send any data after disconnection.
Extra reference is taken for disconnect watch to allow users to drop
own reference in disconnect callback.
---
 src/shared/hfp.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/shared/hfp.h |  6 ++++++
 2 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 43e88a6..3944e97 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -51,6 +51,9 @@ struct hfp_gw {
 	hfp_debug_func_t debug_callback;
 	hfp_destroy_func_t debug_destroy;
 	void *debug_data;
+	hfp_disconnect_func_t disconnect_callback;
+	hfp_destroy_func_t disconnect_destroy;
+	void *disconnect_data;
 };
 
 static void write_watch_destroy(void *user_data)
@@ -227,6 +230,7 @@ void hfp_gw_unref(struct hfp_gw *hfp)
 
 	io_set_write_handler(hfp->io, NULL, NULL, NULL);
 	io_set_read_handler(hfp->io, NULL, NULL, NULL);
+	io_set_disconnect_handler(hfp->io, NULL, NULL, NULL);
 
 	io_destroy(hfp->io);
 	hfp->io = NULL;
@@ -307,7 +311,7 @@ bool hfp_gw_send_result(struct hfp_gw *hfp, enum hfp_result result)
 {
 	const char *str;
 
-	if (!hfp)
+	if (!hfp || !hfp->io)
 		return false;
 
 	switch (result) {
@@ -333,7 +337,7 @@ bool hfp_gw_send_result(struct hfp_gw *hfp, enum hfp_result result)
 
 bool hfp_gw_send_error(struct hfp_gw *hfp, enum hfp_error error)
 {
-	if (!hfp)
+	if (!hfp || !hfp->io)
 		return false;
 
 	if (ringbuf_printf(hfp->write_buf, "\r\n+CME ERROR: %u\r\n", error) < 0)
@@ -352,7 +356,7 @@ bool hfp_gw_send_info(struct hfp_gw *hfp, const char *format, ...)
 	char *fmt;
 	int len;
 
-	if (!hfp || !format)
+	if (!hfp || !hfp->io || !format)
 		return false;
 
 	if (asprintf(&fmt, "\r\n%s\r\n", format) < 0)
@@ -391,3 +395,53 @@ bool hfp_gw_set_command_handler(struct hfp_gw *hfp,
 
 	return true;
 }
+
+static void disconnect_watch_destroy(void *user_data)
+{
+	struct hfp_gw *hfp = user_data;
+
+	if (hfp->disconnect_destroy)
+		hfp->disconnect_destroy(hfp->disconnect_data);
+
+	hfp_gw_unref(hfp);
+}
+
+static bool io_disconnected(struct io *io, void *user_data)
+{
+	struct hfp_gw *hfp = user_data;
+
+	io_destroy(hfp->io);
+	hfp->io = NULL;
+
+	if (hfp->disconnect_callback)
+		hfp->disconnect_callback(hfp->disconnect_data);
+
+	return false;
+}
+
+bool hfp_gw_set_disconnect_handler(struct hfp_gw *hfp,
+					hfp_disconnect_func_t callback,
+					void *user_data,
+					hfp_destroy_func_t destroy)
+{
+	if (!hfp)
+		return false;
+
+	if (hfp->disconnect_destroy)
+		hfp->disconnect_destroy(hfp->disconnect_data);
+
+	if (!io_set_disconnect_handler(hfp->io, io_disconnected,
+						hfp_gw_ref(hfp),
+						disconnect_watch_destroy)) {
+		hfp->disconnect_callback = NULL;
+		hfp->disconnect_destroy = NULL;
+		hfp->disconnect_data = NULL;
+		return false;
+	}
+
+	hfp->disconnect_callback = callback;
+	hfp->disconnect_destroy = destroy;
+	hfp->disconnect_data = user_data;
+
+	return true;
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 2eca6d8..75ec484 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -64,6 +64,7 @@ typedef void (*hfp_destroy_func_t)(void *user_data);
 typedef void (*hfp_debug_func_t)(const char *str, void *user_data);
 
 typedef void (*hfp_command_func_t)(const char *command, void *user_data);
+typedef void (*hfp_disconnect_func_t)(void *user_data);
 
 struct hfp_gw;
 
@@ -86,3 +87,8 @@ bool hfp_gw_send_info(struct hfp_gw *hfp, const char *format, ...)
 bool hfp_gw_set_command_handler(struct hfp_gw *hfp,
 				hfp_command_func_t callback,
 				void *user_data, hfp_destroy_func_t destroy);
+
+bool hfp_gw_set_disconnect_handler(struct hfp_gw *hfp,
+					hfp_disconnect_func_t callback,
+					void *user_data,
+					hfp_destroy_func_t destroy);
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 2/6] shared: Add support for disonnect handler to mainloop based IO handling
From: Szymon Janc @ 2014-02-11 16:49 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1392137346-26272-1-git-send-email-szymon.janc@tieto.com>

---
 src/shared/io-mainloop.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/src/shared/io-mainloop.c b/src/shared/io-mainloop.c
index 981ab17..14ab128 100644
--- a/src/shared/io-mainloop.c
+++ b/src/shared/io-mainloop.c
@@ -42,6 +42,9 @@ struct io {
 	io_callback_func_t write_callback;
 	io_destroy_func_t write_destroy;
 	void *write_data;
+	io_callback_func_t disconnect_callback;
+	io_destroy_func_t disconnect_destroy;
+	void *disconnect_data;
 };
 
 static struct io *io_ref(struct io *io)
@@ -75,6 +78,9 @@ static void io_cleanup(void *user_data)
 	if (io->read_destroy)
 		io->read_destroy(io->read_data);
 
+	if (io->disconnect_destroy)
+		io->disconnect_destroy(io->disconnect_data);
+
 	if (io->close_on_destroy)
 		close(io->fd);
 
@@ -122,6 +128,21 @@ static void io_callback(int fd, uint32_t events, void *user_data)
 			mainloop_modify_fd(io->fd, io->events);
 		}
 	}
+
+	if ((events & EPOLLRDHUP) && io->disconnect_callback) {
+		if (!io->disconnect_callback(io, io->disconnect_data)) {
+			if (io->disconnect_destroy)
+				io->disconnect_destroy(io->disconnect_data);
+
+			io->disconnect_callback = NULL;
+			io->disconnect_destroy = NULL;
+			io->disconnect_data = NULL;
+
+			io->events &= ~EPOLLRDHUP;
+
+			mainloop_modify_fd(io->fd, io->events);
+		}
+	}
 }
 
 struct io *io_new(int fd)
@@ -246,5 +267,30 @@ bool io_set_write_handler(struct io *io, io_callback_func_t callback,
 bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
 				void *user_data, io_destroy_func_t destroy)
 {
-	return false;
+	uint32_t events;
+
+	if (!io || io->fd < 0)
+		return false;
+
+	if (io->disconnect_destroy)
+		io->disconnect_destroy(io->disconnect_data);
+
+	if (callback)
+		events = io->events | EPOLLRDHUP;
+	else
+		events = io->events & ~EPOLLRDHUP;
+
+	io->disconnect_callback = callback;
+	io->disconnect_destroy = destroy;
+	io->disconnect_data = user_data;
+
+	if (events == io->events)
+		return true;
+
+	if (mainloop_modify_fd(io->fd, events) < 0)
+		return false;
+
+	io->events = events;
+
+	return true;
 }
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 1/6] shared: Add support for disonnect handler to GLib based IO handling
From: Szymon Janc @ 2014-02-11 16:49 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 src/shared/io-glib.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/src/shared/io-glib.c b/src/shared/io-glib.c
index 77ba19e..a4f982d 100644
--- a/src/shared/io-glib.c
+++ b/src/shared/io-glib.c
@@ -40,6 +40,10 @@ struct io {
 	io_callback_func_t write_callback;
 	io_destroy_func_t write_destroy;
 	void *write_data;
+	guint disconnect_watch;
+	io_callback_func_t disconnect_callback;
+	io_destroy_func_t disconnect_destroy;
+	void *disconnect_data;
 };
 
 static struct io *io_ref(struct io *io)
@@ -258,8 +262,61 @@ done:
 	return true;
 }
 
+static void disconnect_watch_destroy(gpointer user_data)
+{
+	struct io *io = user_data;
+
+	if (io->disconnect_destroy)
+		io->disconnect_destroy(io->disconnect_data);
+
+	io->disconnect_watch = 0;
+	io->disconnect_callback = NULL;
+	io->disconnect_destroy = NULL;
+	io->disconnect_data = NULL;
+
+	io_unref(io);
+}
+
+static gboolean disconnect_callback(GIOChannel *channel, GIOCondition cond,
+							gpointer user_data)
+{
+	struct io *io = user_data;
+	bool result;
+
+	if (io->disconnect_callback)
+		result = io->disconnect_callback(io, io->disconnect_data);
+	else
+		result = false;
+
+	return result ? TRUE : FALSE;
+}
+
 bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
 				void *user_data, io_destroy_func_t destroy)
 {
-	return false;
+	if (!io)
+		return false;
+
+	if (io->disconnect_watch > 0) {
+		g_source_remove(io->disconnect_watch);
+		io->disconnect_watch = 0;
+	}
+
+	if (!callback)
+		goto done;
+
+	io->disconnect_watch = g_io_add_watch_full(io->channel,
+				G_PRIORITY_DEFAULT,
+				G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				disconnect_callback, io_ref(io),
+				disconnect_watch_destroy);
+	if (io->disconnect_watch == 0)
+		return false;
+
+	io->disconnect_destroy = destroy;
+	io->disconnect_data = user_data;
+done:
+	io->disconnect_callback = callback;
+
+	return true;
 }
-- 
1.8.5.3


^ permalink raw reply related

* Re: [PATCH] android/README: Add Valgrind description
From: Szymon Janc @ 2014-02-11 16:34 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1392119033-23035-1-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

On Tuesday 11 of February 2014 12:43:53 Andrzej Kaczmarek wrote:
> ---
>  android/README | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/android/README b/android/README
> index e3c314f..c7145d5 100644
> --- a/android/README
> +++ b/android/README
> @@ -108,6 +108,22 @@ be found at https://backports.wiki.kernel.org. Sample
> kernels using backports for running BlueZ on Android are available at
>  https://code.google.com/p/aosp-bluez.
> 
> +Running with Valgrind
> +=====================
> +
> +BlueZ for Android is preconfigured to be easily run under Valgrind
> memcheck. +Appropriate configuration and required modules are automatically
> included when +building either userdebug or eng variant of Android
> platform.
> +
> +Valgrind can be enabled in runtime by setting
> "persist.sys.bluetooth.valgrind" +property to either literal "true" or any
> numeric value >0. For example: +adb root
> +adb shell setprop persist.sys.bluetooth.valgrind true
> +
> +After changing property value Bluetooth need to be restarted to apply
> changes +(this can be done using UI, just disable and enable it again).
> Property is +persistent, i.e. there's no need to enable Valgrind again
> after reboot. +
>  =============================
>  Building and running on Linux
>  =============================

Pushed, thanks.

-- 
BR
Szymon Janc

^ permalink raw reply

* Re: [PATCH v4] android: Add support for Valgrind in debug variants
From: Szymon Janc @ 2014-02-11 16:34 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1392128934-11906-1-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

On Tuesday 11 of February 2014 15:28:54 Andrzej Kaczmarek wrote:
> This patch allows bluetoothd to be run with Valgrind easily in debug
> variants.
> 
> For userdebug and eng variants bluetoothd is renamed to bluetoothd-main
> and bluetoothd acts a wrapper to launch it either with or without
> Valgrind (this is decided by value of persist.sys.bluetooth.valgrind
> property).
> ---
>  android/Android.mk           | 42 ++++++++++++++++++++++++
>  android/bluetoothd-wrapper.c | 76
> ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118
> insertions(+)
>  create mode 100644 android/bluetoothd-wrapper.c
> 
> diff --git a/android/Android.mk b/android/Android.mk
> index b82ef84..84e96fe 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -91,7 +91,15 @@ $(shell mkdir -p $(LOCAL_PATH)/bluez/lib/bluetooth)
>  $(foreach file,$(lib_headers), $(shell ln -sf ../$(file)
> $(LOCAL_PATH)/bluez/lib/bluetooth/$(file)))
> 
>  LOCAL_MODULE_TAGS := optional
> +
> +# for userdebug/eng this module is bluetoothd-main since bluetoothd is used
> as +# wrapper to launch bluetooth with Valgrind
> +ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
> +LOCAL_MODULE := bluetoothd-main
> +LOCAL_STRIP_MODULE := false
> +else
>  LOCAL_MODULE := bluetoothd
> +endif
> 
>  include $(BUILD_EXECUTABLE)
> 
> @@ -415,3 +423,37 @@ LOCAL_CFLAGS:= \
>  LOCAL_MODULE := libsbc
> 
>  include $(BUILD_SHARED_LIBRARY)
> +
> +ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
> +
> +#
> +# bluetoothd (debug)
> +# this is just a wrapper used in userdebug/eng to launch bluetoothd-main
> +# with/without Valgrind
> +#
> +
> +include $(CLEAR_VARS)
> +
> +LOCAL_SRC_FILES := \
> +	bluez/android/bluetoothd-wrapper.c
> +
> +LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
> +
> +LOCAL_SHARED_LIBRARIES := \
> +	libcutils \
> +
> +LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
> +LOCAL_MODULE_TAGS := optional
> +LOCAL_MODULE := bluetoothd
> +
> +LOCAL_REQUIRED_MODULES := \
> +	bluetoothd-main \
> +	valgrind \
> +	memcheck-$(TARGET_ARCH)-linux \
> +	vgpreload_core-$(TARGET_ARCH)-linux \
> +	vgpreload_memcheck-$(TARGET_ARCH)-linux \
> +	default.supp
> +
> +include $(BUILD_EXECUTABLE)
> +
> +endif
> \ No newline at end of file
> diff --git a/android/bluetoothd-wrapper.c b/android/bluetoothd-wrapper.c
> new file mode 100644
> index 0000000..122e6b0
> --- /dev/null
> +++ b/android/bluetoothd-wrapper.c
> @@ -0,0 +1,76 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *      http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and + *
> limitations under the License.
> + *
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <cutils/properties.h>
> +
> +#define PROPERTY_NAME "persist.sys.bluetooth.valgrind"
> +
> +#define VALGRIND_BIN "/system/bin/valgrind"
> +
> +#define BLUETOOTHD_BIN "/system/bin/bluetoothd-main"
> +
> +static void run_valgrind(void)
> +{
> +	char *prg_argv[4];
> +	char *prg_envp[3];
> +
> +	prg_argv[0] = VALGRIND_BIN;
> +	prg_argv[1] = "--leak-check=full";
> +	prg_argv[2] = BLUETOOTHD_BIN;
> +	prg_argv[3] = NULL;
> +
> +	prg_envp[0] = "G_SLICE=always-malloc";
> +	prg_envp[1] = "G_DEBUG=gc-friendly";
> +	prg_envp[2] = NULL;
> +
> +	execve(prg_argv[0], prg_argv, prg_envp);
> +}
> +
> +static void run_bluetoothd(void)
> +{
> +	char *prg_argv[2];
> +	char *prg_envp[1];
> +
> +	prg_argv[0] = BLUETOOTHD_BIN;
> +	prg_argv[1] = NULL;
> +
> +	prg_envp[0] = NULL;
> +
> +	execve(prg_argv[0], prg_argv, prg_envp);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char value[PROPERTY_VALUE_MAX];
> +
> +	if (property_get(PROPERTY_NAME, value, "") > 0 &&
> +			(!strcasecmp(value, "true") || atoi(value) > 0))
> +		run_valgrind();
> +
> +	/* In case we failed to execute Valgrind, try to run bluetoothd
> +	 * without it
> +	 */
> +
> +	run_bluetoothd();
> +
> +	return 0;
> +}

Applied, thanks.

-- 
BR
Szymon Janc

^ permalink raw reply

* Re: [RFC 2/2] bluetooth: Add initial support for BT chip over SMD
From: Lukasz Rymanowski @ 2014-02-11 16:24 UTC (permalink / raw)
  To: linux-arm-msm; +Cc: Lukasz Rymanowski, linux-bluetooth@vger.kernel.org
In-Reply-To: <1391772937-12802-3-git-send-email-lukasz.rymanowski@tieto.com>

Hi,

On 7 February 2014 12:35, Lukasz Rymanowski <lukasz.rymanowski@tieto.com> wrote:
> This patch adds support for Qualcomm chips which uses msm
> shared memory driver as a transport layer.
>
> This driver based on SMD driver found in  msm kernel branch.
>
> Signed-off-by: Lukasz Rymanowski <lukasz.rymanowski@tieto.com>
> ---
>  drivers/bluetooth/Kconfig   |   9 +
>  drivers/bluetooth/Makefile  |   1 +
>  drivers/bluetooth/hci_smd.c | 460 ++++++++++++++++++++++++++++++++++++++++++++
>  include/net/bluetooth/hci.h |   1 +
>  4 files changed, 471 insertions(+)
>  create mode 100644 drivers/bluetooth/hci_smd.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 11a6104..f8a46c5 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -242,4 +242,13 @@ config BT_WILINK
>
>           Say Y here to compile support for Texas Instrument's WiLink7 driver
>           into the kernel or say M to compile it as module.
> +
> +config BT_HCISMD
> +        tristate "Qualcomm HCI Shared Memory Driver"
> +        help
> +          This enables the Bluetooth driver for Qualcomm BT devices uses SMD interface.
> +
> +          Say Y here to compile support for Qualcomm over SMD driver into kernel or
> +          say M to compile it as module (hci_smd)
> +
>  endmenu
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 9fe8a87..0666e60 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_BT_ATH3K)                += ath3k.o
>  obj-$(CONFIG_BT_MRVL)          += btmrvl.o
>  obj-$(CONFIG_BT_MRVL_SDIO)     += btmrvl_sdio.o
>  obj-$(CONFIG_BT_WILINK)                += btwilink.o
> +obj-$(CONFIG_BT_HCISMD)                += hci_smd.o
>
>  btmrvl-y                       := btmrvl_main.o
>  btmrvl-$(CONFIG_DEBUG_FS)      += btmrvl_debugfs.o
> diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
> new file mode 100644
> index 0000000..9eb3675
> --- /dev/null
> +++ b/drivers/bluetooth/hci_smd.c
> @@ -0,0 +1,460 @@
> +
> +/*
> + *
> + *  HCI_SMD (HCI Shared Memory Driver) is Qualcomm's Shared memory driver
> + *  for the HCI protocol.
> + *
> + *  Copyright (C) 2000-2001  Qualcomm Incorporated
> + *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
> + *  Copyright (C) 2004-2006  Marcel Holtmann <marcel@holtmann.org>
> + *  Copyright (C) 2011, Code Aurora Forum. All rights reserved.
> + *  Copyright (C) 2014, Intel Corporation. All rights reserved.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2
> + *  as published by the Free Software Foundation
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/skbuff.h>
> +#include <linux/workqueue.h>
> +#include <linux/platform_device.h>
> +#include <linux/completion.h>
> +#include <linux/jiffies.h>
> +#include <linux/spinlock.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include <linux/smd.h>
> +
> +#define VERSION "0.1"
> +
> +#define SMD_CMD_CHANNEL "APPS_RIVA_BT_CMD"
> +#define SMD_ACL_CHANNEL "APPS_RIVA_BT_ACL"
> +
> +#define SMD_APPS_RIVA_BT_CMD_READY 0x01
> +#define SMD_APPS_RIVA_BT_ACL_READY 0x02
> +#define SMD_READY ((SMD_APPS_RIVA_BT_CMD_READY) | (SMD_APPS_RIVA_BT_ACL_READY))
> +
> +struct rx_work {
> +       struct work_struct work;
> +       struct smd_data *smd;
> +       struct hci_dev *hdev;
> +       u8 pkt_type;
> +};
> +
> +struct smd_channel_data {
> +       struct hci_dev *hdev;
> +       struct workqueue_struct *wq;
> +       struct smd_data *smd;
> +};
> +
> +struct hci_smd_data {
> +       struct hci_dev *hdev;
> +
> +       struct smd_channel_data *smd_cmd;
> +       struct smd_channel_data *smd_acl;
> +       u8 ready_flags;
> +       struct completion smd_ready;
> +
> +       /* Protects ready_flags */
> +       spinlock_t flags_lock;
> +};
> +
> +static struct hci_smd_data hs;
> +
> +static void hci_smd_channel_open(struct smd_channel_data *scd)
> +{
> +       const char *name = scd->smd->pdev->name;
> +
> +       spin_lock(&hs.flags_lock);
> +       if (scd->hdev) {
> +               set_bit(HCI_RUNNING, &scd->hdev->flags);
> +               spin_unlock(&hs.flags_lock);
> +               return;
> +       }
> +
> +       if (!strncmp(name, SMD_CMD_CHANNEL, sizeof(SMD_CMD_CHANNEL)))
> +               hs.ready_flags |= SMD_APPS_RIVA_BT_CMD_READY;
> +
> +       if (!strncmp(name, SMD_ACL_CHANNEL, sizeof(SMD_ACL_CHANNEL)))
> +               hs.ready_flags |= SMD_APPS_RIVA_BT_ACL_READY;
> +
> +       if ((SMD_READY & hs.ready_flags) != SMD_READY) {
> +               spin_unlock(&hs.flags_lock);
> +               return;
> +       }
> +
> +       spin_unlock(&hs.flags_lock);
> +       complete_all(&hs.smd_ready);
> +}
> +
> +static void hci_smd_channel_close(struct smd_channel_data *scd)
> +{
> +       if (!scd->hdev)
> +               return;
> +
> +       clear_bit(HCI_RUNNING, &scd->hdev->flags);
> +}
> +
> +static int hci_smd_open(struct hci_dev *hdev)
> +{
> +       BT_DBG("hdev %s, %p", hdev->name, hdev);
> +
> +       set_bit(HCI_RUNNING, &hdev->flags);
> +       return 0;
> +}
> +
> +static int hci_smd_close(struct hci_dev *hdev)
> +{
> +       BT_DBG("hdev %s %p", hdev->name, hdev);
> +
> +       clear_bit(HCI_RUNNING, &hdev->flags);
> +       return 0;
> +}
> +
> +static void hci_smd_rx_work(struct work_struct *work)
> +{
> +       struct rx_work *wk = container_of(work, struct rx_work, work);
> +       u8 type = wk->pkt_type;
> +       struct smd_data *smd = wk->smd;
> +       struct hci_dev *hdev = wk->hdev;
> +       struct sk_buff *skb;
> +       int len;
> +
> +       BT_DBG("hdev %p, %02x", hdev, type);
> +
> +       /*It s save to free work here */
> +       kfree(wk);
> +
> +       len = smd->ops.read_avail(smd);
> +       if (len > HCI_MAX_FRAME_SIZE)
> +               return;
> +
> +       while (len) {
> +               int rc = 0;
> +               skb = bt_skb_alloc(len, GFP_KERNEL);
> +               if (!skb)
> +                       return;
> +
> +               rc = smd->ops.read(smd, skb_put(skb, len), len);
> +               if (rc < len) {
> +                       kfree_skb(skb);
> +                       return;
> +               }
> +
> +               skb->dev = (void *)hdev;
> +               bt_cb(skb)->pkt_type = type;
> +               skb_orphan(skb);
> +
> +               rc = hci_recv_frame(hdev, skb);
> +               if (rc < 0) {
> +                       BT_ERR("Failed to pass skb to Bluetooth module");
> +                       kfree_skb(skb);

This is wrong. need to remove it.

> +                       return;
> +               }
> +
> +               len = smd->ops.read_avail(smd);
> +               if (len > HCI_MAX_FRAME_SIZE)
> +                       return;
> +       }
> +}
> +
> +static int hci_smd_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       struct hci_smd_data *hs = hci_get_drvdata(hdev);
> +       struct smd_data *smd;
> +       int sent;
> +
> +       if (!hdev) {
> +               BT_ERR("Frame for unknown HCI device (hdev=NULL)");
> +               return -ENODEV;
> +       }
> +
> +       if (!test_bit(HCI_RUNNING, &(hdev->flags)))
> +               return -EBUSY;
> +
> +       switch (bt_cb(skb)->pkt_type) {
> +       case HCI_COMMAND_PKT:
> +               smd  = hs->smd_cmd->smd;
> +               sent = smd->ops.write(smd, skb->data, skb->len);
> +               break;
> +       case HCI_ACLDATA_PKT:
> +       case HCI_SCODATA_PKT:
> +               smd = hs->smd_acl->smd;
> +               sent = smd->ops.write(smd, skb->data, skb->len);
> +               break;
> +       default:
> +               BT_ERR("Unknown package");
> +               kfree_skb(skb);
> +               return -EPROTO;
> +       }
> +
> +       kfree_skb(skb);
> +
> +       if (sent < 0) {
> +               BT_ERR("Failed to send all data");
> +               return -ENOSPC;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct rx_work *alloc_rx_work(u8 pkt_type, struct smd_data *smd,
> +                                                       struct hci_dev *hdev)
> +{
> +       struct rx_work *w = kmalloc(sizeof(*w), GFP_ATOMIC);
> +
> +       if (!w) {
> +               BT_ERR("Could not allocate work");
> +               return NULL;
> +       }
> +
> +       INIT_WORK(&w->work, hci_smd_rx_work);
> +       w->pkt_type = pkt_type;
> +       w->smd = smd;
> +       w->hdev = hdev;
> +
> +       return w;
> +}
> +
> +static void hci_smd_notify(struct platform_device *pdev,
> +                                       unsigned int event, u8 pkt_type)
> +{
> +       struct smd_channel_data *scd = dev_get_drvdata(&pdev->dev);
> +       struct hci_dev *hdev = scd->hdev;
> +       struct rx_work *w;
> +
> +       if (!scd || !scd->smd) {
> +               BT_ERR("SMD channel data not avaiable");
> +               return;
> +       }
> +
> +       switch (event) {
> +       case SMD_EVENT_DATA:
> +               w = alloc_rx_work(pkt_type, scd->smd, hdev);
> +               if (w && hdev)
> +                       queue_work(scd->wq, &w->work);
> +               else
> +                       BT_ERR("Read failed hdev:%p, work:%p ", hdev, w);
> +               break;
> +       case SMD_EVENT_OPEN:
> +               hci_smd_channel_open(scd);
> +               break;
> +       case SMD_EVENT_CLOSE:
> +               hci_smd_channel_close(scd);
> +               break;
> +       default:
> +               break;
> +       }
> +}
> +
> +static void hci_smd_notify_cmd(struct platform_device *pdev,
> +                                                       unsigned int event)
> +{
> +       hci_smd_notify(pdev, event, HCI_EVENT_PKT);
> +}
> +
> +static void hci_smd_notify_data(struct platform_device *pdev,
> +                                                       unsigned int event)
> +{
> +       hci_smd_notify(pdev, event, HCI_ACLDATA_PKT);
> +}
> +
> +static int hci_smd_register(void)
> +{
> +       struct hci_dev *hdev;
> +       int err;
> +
> +       BT_DBG("hci_smd_register");
> +
> +       /*
> +       * Lets use two different worqueues for Event and ACL data so we make
> +       * sure that Event will never be blocked by ACL data.
> +       */
> +       hs.smd_cmd->wq = alloc_workqueue("smd_event", WQ_HIGHPRI |
> +                                       WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
> +       if (!hs.smd_cmd->wq) {
> +               BT_ERR("Error allocating event workqueue");
> +               err = -ENOMEM;
> +               goto close_smd;
> +       }
> +
> +       hs.smd_acl->wq = alloc_workqueue("data_event", WQ_HIGHPRI |
> +                                       WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
> +       if (!hs.smd_acl->wq) {
> +               BT_ERR("Error allocating data workqueue");
> +               destroy_workqueue(hs.smd_cmd->wq);
> +               err = -ENOMEM;
> +               goto close_smd;
> +       }
> +
> +       /* Initialize and register HCI device */
> +       hdev = hci_alloc_dev();
> +       if (!hdev) {
> +               BT_ERR("Error allocating HCI dev");
> +               err = -ENOMEM;
> +               goto cleanup;
> +       }
> +
> +       hdev->bus = HCI_SMD;
> +       hci_set_drvdata(hdev, &hs);
> +
> +       hdev->open      = hci_smd_open;
> +       hdev->close     = hci_smd_close;
> +       hdev->send      = hci_smd_send_frame;
> +
> +       hs.smd_cmd->hdev = hdev;
> +       hs.smd_acl->hdev = hdev;
> +
> +       err = hci_register_dev(hdev);
> +       if (!err)
> +               return 0;
> +
> +       BT_ERR("Can't register HCI device");
> +       hci_free_dev(hdev);
> +
> +cleanup:
> +       destroy_workqueue(hs.smd_cmd->wq);
> +       destroy_workqueue(hs.smd_acl->wq);
> +close_smd:
> +       hs.smd_cmd->smd->ops.close(hs.smd_cmd->smd);
> +       hs.smd_acl->smd->ops.close(hs.smd_acl->smd);
> +
> +       return err;
> +}
> +
> +static int smd_cmd_channel_probe(struct platform_device *pdev)
> +{
> +       struct smd_data *smd = dev_get_platdata(&pdev->dev);
> +       struct smd_channel_data *scd = kzalloc(sizeof(*scd), GFP_KERNEL);
> +       int err;
> +
> +       scd->smd = smd;
> +       hs.smd_cmd = scd;
> +
> +       dev_set_drvdata(&pdev->dev, scd);
> +
> +       err = smd->ops.open(smd, hci_smd_notify_cmd);
> +       if (err < 0) {
> +               BT_ERR("Can not open %s", SMD_CMD_CHANNEL);
> +               return err;
> +       }
> +
> +       return 0;
> +}
> +
> +static int smd_data_channel_probe(struct platform_device *pdev)
> +{
> +       struct smd_data *smd = dev_get_platdata(&pdev->dev);
> +       struct smd_channel_data *scd = kzalloc(sizeof(*scd), GFP_KERNEL);
> +       int err;
> +
> +       scd->smd = smd;
> +       hs.smd_acl = scd;
> +
> +       dev_set_drvdata(&pdev->dev, scd);
> +
> +       err = smd->ops.open(smd, hci_smd_notify_data);
> +       if (err < 0) {
> +               BT_ERR("Can not open %s", SMD_ACL_CHANNEL);
> +               return err;
> +       }
> +
> +       return 0;
> +}
> +
> +
> +static int smd_channel_remove(struct platform_device *pdev)
> +{
> +       struct smd_data *smd = dev_get_platdata(&pdev->dev);
> +       return smd->ops.close(smd);
> +}
> +
> +static struct platform_driver cmd_drv = {
> +       .driver = {
> +               .owner = THIS_MODULE,
> +               .name = SMD_CMD_CHANNEL,
> +       },
> +       .probe = smd_cmd_channel_probe,
> +       .remove = smd_channel_remove,
> +
> +};
> +
> +static struct platform_driver acl_drv = {
> +       .driver = {
> +               .owner = THIS_MODULE,
> +               .name = SMD_ACL_CHANNEL,
> +       },
> +       .probe = smd_data_channel_probe,
> +       .remove = smd_channel_remove,
> +};
> +
> +static int __init hci_smd_init(void)
> +{
> +       int err;
> +
> +       BT_INFO("hci smd driver ver %s", VERSION);
> +
> +       memset(&hs, 0, sizeof(hs));
> +
> +       spin_lock_init(&hs.flags_lock);
> +       init_completion(&hs.smd_ready);
> +
> +       /*
> +       * SMD channels are represented by platform devices. We need them two
> +       * for BT operations. Channel for BT CMD/EVENT traffic and BT ACL DATA
> +       * traffic.
> +       */
> +       err = platform_driver_register(&cmd_drv);
> +       if (err < 0) {
> +               BT_ERR("Failed to register drv: %s err: %d",
> +                                               cmd_drv.driver.name, err);
> +               return err;
> +       }
> +
> +       err = platform_driver_register(&acl_drv);
> +       if (err < 0) {
> +               BT_ERR("Failed to register drv: %s, err: %d",
> +                                               acl_drv.driver.name, err);
> +               platform_driver_unregister(&cmd_drv);
> +               return err;
> +       }
> +
> +       /* Let's wait until SMD channels are ready */
> +       err = wait_for_completion_killable_timeout(&hs.smd_ready,
> +               msecs_to_jiffies(5000));
> +       if (err <= 0)
> +               return err;
> +
> +       return hci_smd_register();
> +}
> +
> +static void __exit hci_smd_exit(void)
> +{
> +       kfree(hs.smd_cmd);
> +       kfree(hs.smd_acl);
> +
> +       platform_driver_unregister(&cmd_drv);
> +       platform_driver_unregister(&acl_drv);
> +}
> +
> +module_init(hci_smd_init);
> +module_exit(hci_smd_exit);
> +
> +MODULE_AUTHOR("Lukasz Rymanowski <lukasz.rymanowski@tieto.com>");
> +MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
> +MODULE_DESCRIPTION("Bluetooth SMD driver ver " VERSION);
> +MODULE_VERSION(VERSION);
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index 352d3d7..149b06a 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -58,6 +58,7 @@
>  #define HCI_RS232      4
>  #define HCI_PCI                5
>  #define HCI_SDIO       6
> +#define HCI_SMD                7
>
>  /* HCI controller types */
>  #define HCI_BREDR      0x00
> --

Adding linux-arm-msm group for comments on SMD API

BR
Lukasz
> 1.8.4
>

^ permalink raw reply

* Re: [RFC 1/2] Add basic API for shared memory driver
From: Lukasz Rymanowski @ 2014-02-11 16:23 UTC (permalink / raw)
  To: linux-arm-msm; +Cc: Lukasz Rymanowski, linux-bluetooth@vger.kernel.org
In-Reply-To: <1391772937-12802-2-git-send-email-lukasz.rymanowski@tieto.com>

Hi

On 7 February 2014 12:35, Lukasz Rymanowski <lukasz.rymanowski@tieto.com> wrote:
> This patch adds simple API to shared memory driver based on msm-smd.h
> This is required in order to add support for support Qualcomm BT chips
> via SMD
>
> Signed-off-by: Lukasz Rymanowski <lukasz.rymanowski@tieto.com>
> ---
>  include/linux/smd.h | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
>  create mode 100644 include/linux/smd.h
>
> diff --git a/include/linux/smd.h b/include/linux/smd.h
> new file mode 100644
> index 0000000..58de0d4
> --- /dev/null
> +++ b/include/linux/smd.h
> @@ -0,0 +1,69 @@
> +/*
> +* smd.h - API for Shared Memory Driver
> +*
> +* Copyright (c) 2014 Intel Corporation
> +*
> +* This program is free software; you can redistribute it and/or modify
> +* it under the terms of the GNU General Public License version 2 as
> +* published by the Free Software Foundation.
> +*/
> +
> +#ifndef _SMD_H_
> +#define _SMD_H_
> +
> +#include <linux/platform_device.h>
> +
> +/**
> +* Events from smd device.
> +*/
> +#define SMD_EVENT_DATA 1
> +#define SMD_EVENT_OPEN 2
> +#define SMD_EVENT_CLOSE 3
> +
> +struct smd_channel;
> +struct smd_notify_data;
> +struct smd_data;
> +
> +/**
> +* struct smd_ops - specific operation for smd channel
> +*
> +* @open:       Open SMD channel. It should return zero once device is opened.
> +*              On open there is need to pass notification cb which is used
> +*              for notifications form SMD device.
> +* @close       Close SMD channel
> +* @write:      Write data to SMD channel. It should return number of written
> +*              bytes or negative value in case of error.
> +* @read:       Read data from SMD channel.It should return number of written
> +*              bytes or negative value in case of error.
> +*@read_avail:  Returns number of bytes ready to be read. This should be called
> +*              before read in order to allocate enought skb
> +*
> +*/
> +struct smd_ops {
> +       int (*open)(struct smd_data *s,
> +               void (*notify)(struct platform_device *pdev,
> +                                                       unsigned int event));
> +       int (*close)(struct smd_data *s);
> +       int (*write)(struct smd_data *s, const void *data, int len);
> +       int (*read)(struct smd_data *s, void *buf, int len);
> +       int (*read_avail)(struct smd_data *s);
> +};
> +/**
> +* struct smd_data - smd device data for shared memory channel
> +*
> +* @pdev:       Platform device for given smd channel.
> +* @ops:                SMD specific operations for this smd channel.
> +* @ch:         SMD channel which is used by SMD device. Should not be
> +*              used by the driver
> +* @notifier:   SMD notifier data. Shall not be used by driver.
> +*
> +* smd_data are initialized by the platform and are available for driver
> +* in platform_data.
> +*/
> +struct smd_data {
> +       struct platform_device *pdev;
> +       struct smd_ops ops;
> +       struct smd_channel *ch;
> +       struct smd_notify_data *notify_data;
> +};
> +#endif
> --

Adding linux-arm-msm group for comments on SMD API

BR
Lukasz
> 1.8.4
>

^ permalink raw reply

* Re: [RFC 0/2] Add hci_smd driver
From: Lukasz Rymanowski @ 2014-02-11 16:23 UTC (permalink / raw)
  To: linux-arm-msm; +Cc: Lukasz Rymanowski, linux-bluetooth@vger.kernel.org
In-Reply-To: <1391772937-12802-1-git-send-email-lukasz.rymanowski@tieto.com>

Hi

On 7 February 2014 12:35, Lukasz Rymanowski <lukasz.rymanowski@tieto.com> wrote:
> Hello,
>
> This is a try (long shoot) to upstream hci shared memory driver (hci_smd)
> which is used on Qualcomm platforms and BT chips.
>
> To make it build with upstream tree I had to introduce some simple SMD API.
> The idea here is that since SMD channel is represented by platform device
> (as it is done in mach-msm),
> then platfrom_data contains smd_data which contains API for that channel.
>
> Writing this SMD API I was inspired with MSM-SMD and since I'm not an expert
> in this area I'm asking for comments here.
>
> Maybe instead of SMD API I made, I should expose functions like smd_open(), smd_write()
> etc. something similar how sdio does, and  just deliver to upstream dummy device
> implementing this SMD API?
>
> Other options I was considering is to implement  module inside mach-msm which
> would handle registering SMD BT Channels and when it is done, it would register
> new platform device like "smd-bt". Then I could move smd.h to some bluetooth includes
> (althought don't now where at the moment) and hci_smd would register driver for "smd-bt"
> In this case I would also could rid of one static variable I have now in hci_smd
>
> Comments on those options are welcome.
>
> Anyway, Hci_smd is based on one of the older version of this driver found in msm kernel
> branch, so there are no wakelocks as in new version and also workqueues are used
> instead of takslet.
>
> Since SMD expose two channels, one for CMD/EVENT and one for ACL Data I decide to
> do separate worqueues for this. This is to make sure that ACL data never blocks EVENT
> packages
>

Adding linux-arm-msm group for comments on SMD API.

BR
Lukasz


> Lukasz Rymanowski (2):
>   Add basic API for shared memory driver
>   bluetooth: Add initial support for BT chip over SMD
>
>  drivers/bluetooth/Kconfig   |   9 +
>  drivers/bluetooth/Makefile  |   1 +
>  drivers/bluetooth/hci_smd.c | 461 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/smd.h         |  68 +++++++
>  include/net/bluetooth/hci.h |   1 +
>  5 files changed, 540 insertions(+)
>  create mode 100644 drivers/bluetooth/hci_smd.c
>  create mode 100644 include/linux/smd.h
>
> --
> 1.8.4
>

^ permalink raw reply

* Re: [PATCH] btusb.c add IMC Networks id 13d3:3404 (bcm20702A0)
From: Jurgen Kramer @ 2014-02-11 16:00 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: BlueZ development
In-Reply-To: <F0885393-70B7-483B-8F97-C4AB73B451E6@holtmann.org>

Hi Marcel,

On Mon, 2014-02-10 at 10:33 -0800, Marcel Holtmann wrote:
> HI Jurgen,
> 
> > Attached patch adds support for IMC Networks (13d3:3404) to BCM20702A0
> > in btusb.c. This device is used on the Asrock Z87E-ITX motherboard.
> > Tested against 3.12.9.
> > 
> > diff -uNrp
> > linux-3.12.9-301.jk1.fc20.x86_64.orig/drivers/bluetooth/btusb.c
> > linux-3.12.9-301.jk1.fc20.x86_64.new/drivers/bluetooth/btusb.c
> > --- a/drivers/bluetooth/btusb.c	2014-02-10 11:35:08.976975562 +0100
> > +++ b/drivers/bluetooth/btusb.c	2014-02-10 11:37:03.864921122 +0100
> > @@ -106,6 +106,7 @@ static struct usb_device_id btusb_table[
> > 	{ USB_DEVICE(0x04ca, 0x2003) },
> > 	{ USB_DEVICE(0x0489, 0xe042) },
> > 	{ USB_DEVICE(0x413c, 0x8197) },
> > +	{ USB_DEVICE(0x13d3, 0x3404) },
> > 
> > 	/* Foxconn - Hon Hai */
> > 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
> > 
> > Signed-off-by: Jurgen Kramer <gtm.kramer@xs4all.nl>
> > 
> > Jurgen
> > <btusb-bcm20702a0-add-imc-networks.patch>
> 
> please send patches inline created from git-format-patch and include /sys/kernel/debug/usb/devices details for this device.
OK. I'll resend in a couple of days.

Regards,
Jurgen

^ permalink raw reply

* Re: [PATCH] Bluetooth: Fix channel check when binding RFCOMM sock
From: Marcel Holtmann @ 2014-02-11 15:58 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: bluez mailin list (linux-bluetooth@vger.kernel.org)
In-Reply-To: <1392119413-26341-1-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

> When binding RFCOMM socket we should only check if there is another
> socket bound or listening on the same channel number. In other case,
> it won't be possible to bind/listen on a channel in case we have
> connection made to remote device on the same channel number.

since this has been used for years now, you need to be more specific on when this fails.

> Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@tieto.com>
> ---
> net/bluetooth/rfcomm/sock.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
> index 00573fb..9912e23 100644
> --- a/net/bluetooth/rfcomm/sock.c
> +++ b/net/bluetooth/rfcomm/sock.c
> @@ -331,6 +331,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
> {
> 	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
> 	struct sock *sk = sock->sk;
> +	struct sock *sk1;
> 	int err = 0;
> 
> 	BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
> @@ -352,7 +353,9 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
> 
> 	write_lock(&rfcomm_sk_list.lock);
> 
> -	if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
> +	sk1 = __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr);
> +	if (sa->rc_channel && sk1 && (sk1->sk_state == BT_BOUND ||
> +						sk1->sk_state == BT_LISTEN)) {
> 		err = -EADDRINUSE;

can we find a better name than sk1 here.

> 	} else {
> 		/* Save source address */

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 1/4] android/avrcp: Decouple AVRCP logic from btio
From: Szymon Janc @ 2014-02-11 14:37 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <20140211130306.GG8980@aemeltch-MOBL1>

Hi Andrei,

On Tuesday 11 of February 2014 15:03:07 Andrei Emeltchenko wrote:
> Hi All
> 
> On Thu, Feb 06, 2014 at 06:06:11PM +0200, Andrei Emeltchenko wrote:
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > 
> > The patch makes AVRCP to be channel-agnostic so that it might be used in
> > unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
> > channel stuff got to avrcp.
> 
> Any comments regarding this patch?

Waiting for V2 as discussed offline.

-- 
BR
Szymon Janc

^ permalink raw reply

* [PATCH v4] android: Add support for Valgrind in debug variants
From: Andrzej Kaczmarek @ 2014-02-11 14:28 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

This patch allows bluetoothd to be run with Valgrind easily in debug
variants.

For userdebug and eng variants bluetoothd is renamed to bluetoothd-main
and bluetoothd acts a wrapper to launch it either with or without
Valgrind (this is decided by value of persist.sys.bluetooth.valgrind
property).
---
 android/Android.mk           | 42 ++++++++++++++++++++++++
 android/bluetoothd-wrapper.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)
 create mode 100644 android/bluetoothd-wrapper.c

diff --git a/android/Android.mk b/android/Android.mk
index b82ef84..84e96fe 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -91,7 +91,15 @@ $(shell mkdir -p $(LOCAL_PATH)/bluez/lib/bluetooth)
 $(foreach file,$(lib_headers), $(shell ln -sf ../$(file) $(LOCAL_PATH)/bluez/lib/bluetooth/$(file)))
 
 LOCAL_MODULE_TAGS := optional
+
+# for userdebug/eng this module is bluetoothd-main since bluetoothd is used as
+# wrapper to launch bluetooth with Valgrind
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+LOCAL_MODULE := bluetoothd-main
+LOCAL_STRIP_MODULE := false
+else
 LOCAL_MODULE := bluetoothd
+endif
 
 include $(BUILD_EXECUTABLE)
 
@@ -415,3 +423,37 @@ LOCAL_CFLAGS:= \
 LOCAL_MODULE := libsbc
 
 include $(BUILD_SHARED_LIBRARY)
+
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+
+#
+# bluetoothd (debug)
+# this is just a wrapper used in userdebug/eng to launch bluetoothd-main
+# with/without Valgrind
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	bluez/android/bluetoothd-wrapper.c
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetoothd
+
+LOCAL_REQUIRED_MODULES := \
+	bluetoothd-main \
+	valgrind \
+	memcheck-$(TARGET_ARCH)-linux \
+	vgpreload_core-$(TARGET_ARCH)-linux \
+	vgpreload_memcheck-$(TARGET_ARCH)-linux \
+	default.supp
+
+include $(BUILD_EXECUTABLE)
+
+endif
\ No newline at end of file
diff --git a/android/bluetoothd-wrapper.c b/android/bluetoothd-wrapper.c
new file mode 100644
index 0000000..122e6b0
--- /dev/null
+++ b/android/bluetoothd-wrapper.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+
+#define PROPERTY_NAME "persist.sys.bluetooth.valgrind"
+
+#define VALGRIND_BIN "/system/bin/valgrind"
+
+#define BLUETOOTHD_BIN "/system/bin/bluetoothd-main"
+
+static void run_valgrind(void)
+{
+	char *prg_argv[4];
+	char *prg_envp[3];
+
+	prg_argv[0] = VALGRIND_BIN;
+	prg_argv[1] = "--leak-check=full";
+	prg_argv[2] = BLUETOOTHD_BIN;
+	prg_argv[3] = NULL;
+
+	prg_envp[0] = "G_SLICE=always-malloc";
+	prg_envp[1] = "G_DEBUG=gc-friendly";
+	prg_envp[2] = NULL;
+
+	execve(prg_argv[0], prg_argv, prg_envp);
+}
+
+static void run_bluetoothd(void)
+{
+	char *prg_argv[2];
+	char *prg_envp[1];
+
+	prg_argv[0] = BLUETOOTHD_BIN;
+	prg_argv[1] = NULL;
+
+	prg_envp[0] = NULL;
+
+	execve(prg_argv[0], prg_argv, prg_envp);
+}
+
+int main(int argc, char *argv[])
+{
+	char value[PROPERTY_VALUE_MAX];
+
+	if (property_get(PROPERTY_NAME, value, "") > 0 &&
+			(!strcasecmp(value, "true") || atoi(value) > 0))
+		run_valgrind();
+
+	/* In case we failed to execute Valgrind, try to run bluetoothd
+	 * without it
+	 */
+
+	run_bluetoothd();
+
+	return 0;
+}
-- 
1.8.5.3


^ permalink raw reply related


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