Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ v3 09/10] android/A2DP: Add stream resume command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the definitions to stream resume command and response.
---
 android/a2dp.c      | 9 +++++++++
 android/audio-msg.h | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index 7c49bc9..5d540f3 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -382,6 +382,13 @@ static void bt_stream_close(const void *buf, uint16_t len)
 	audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_FAILED);
 }
 
+static void bt_stream_resume(const void *buf, uint16_t len)
+{
+	DBG("Not Implemented");
+
+	audio_ipc_send_rsp(AUDIO_OP_RESUME_STREAM, AUDIO_STATUS_FAILED);
+}
+
 static const struct ipc_handler audio_handlers[] = {
 	/* AUDIO_OP_OPEN */
 	{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -391,6 +398,8 @@ static const struct ipc_handler audio_handlers[] = {
 	{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
 	/* AUDIO_OP_CLOSE_STREAM */
 	{ bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
+	/* AUDIO_OP_RESUME_STREAM */
+	{ bt_stream_resume, false, sizeof(struct audio_cmd_resume_stream) },
 };
 
 bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 4dfa8cf..8f92413 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -72,3 +72,8 @@ struct audio_rsp_open_stream {
 struct audio_cmd_close_stream {
 	uint8_t id;
 } __attribute__((packed));
+
+#define AUDIO_OP_RESUME_STREAM		0x05
+struct audio_cmd_resume_stream {
+	uint8_t id;
+} __attribute__((packed));
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 08/10] android/A2DP: Add stream close command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the definitions to stream close command and response.
---
 android/a2dp.c      | 9 +++++++++
 android/audio-msg.h | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index 09a65e1..7c49bc9 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -375,6 +375,13 @@ static void bt_stream_open(const void *buf, uint16_t len)
 	audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
 }
 
+static void bt_stream_close(const void *buf, uint16_t len)
+{
+	DBG("Not Implemented");
+
+	audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_FAILED);
+}
+
 static const struct ipc_handler audio_handlers[] = {
 	/* AUDIO_OP_OPEN */
 	{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -382,6 +389,8 @@ static const struct ipc_handler audio_handlers[] = {
 	{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
 	/* AUDIO_OP_OPEN_STREAM */
 	{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
+	/* AUDIO_OP_CLOSE_STREAM */
+	{ bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
 };
 
 bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 0f0309a..4dfa8cf 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -67,3 +67,8 @@ struct audio_rsp_open_stream {
 	uint8_t len;
 	uint8_t data[0];
 } __attribute__((packed));
+
+#define AUDIO_OP_CLOSE_STREAM		0x04
+struct audio_cmd_close_stream {
+	uint8_t id;
+} __attribute__((packed));
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 07/10] android/A2DP: Add stream open command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the definitions to stream open command and response.
---
 android/a2dp.c      |  9 +++++++++
 android/audio-msg.h | 10 ++++++++++
 2 files changed, 19 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index 97e2778..09a65e1 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -368,11 +368,20 @@ static void bt_audio_close(const void *buf, uint16_t len)
 	audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
 }
 
+static void bt_stream_open(const void *buf, uint16_t len)
+{
+	DBG("Not Implemented");
+
+	audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
+}
+
 static const struct ipc_handler audio_handlers[] = {
 	/* AUDIO_OP_OPEN */
 	{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
 	/* AUDIO_OP_CLOSE */
 	{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
+	/* AUDIO_OP_OPEN_STREAM */
+	{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
 };
 
 bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 6ac1fff..0f0309a 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -57,3 +57,13 @@ struct audio_rsp_open {
 struct audio_cmd_close {
 	uint8_t id;
 } __attribute__((packed));
+
+#define AUDIO_OP_OPEN_STREAM		0x03
+struct audio_cmd_open_stream {
+	uint8_t id;
+} __attribute__((packed));
+
+struct audio_rsp_open_stream {
+	uint8_t len;
+	uint8_t data[0];
+} __attribute__((packed));
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 06/10] android/A2DP: Add audio close command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the definitions to audio close command and response.
---
 android/a2dp.c      | 9 +++++++++
 android/audio-msg.h | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/android/a2dp.c b/android/a2dp.c
index 38384f6..97e2778 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -361,9 +361,18 @@ static void bt_audio_open(const void *buf, uint16_t len)
 	audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
 }
 
+static void bt_audio_close(const void *buf, uint16_t len)
+{
+	DBG("Not Implemented");
+
+	audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
+}
+
 static const struct ipc_handler audio_handlers[] = {
 	/* AUDIO_OP_OPEN */
 	{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
+	/* AUDIO_OP_CLOSE */
+	{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
 };
 
 bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 158a2ab..6ac1fff 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -52,3 +52,8 @@ struct audio_cmd_open {
 struct audio_rsp_open {
 	uint8_t id;
 } __attribute__((packed));
+
+#define AUDIO_OP_CLOSE			0x02
+struct audio_cmd_close {
+	uint8_t id;
+} __attribute__((packed));
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 05/10] android/A2DP: Add audio open command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the definitions to audio open command and response.
---
 android/a2dp.c            |  9 +++++++++
 android/audio-ipc-api.txt |  2 +-
 android/audio-msg.h       | 18 ++++++++++++++++++
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index c12d8f1..38384f6 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -354,7 +354,16 @@ static sdp_record_t *a2dp_record(void)
 	return record;
 }
 
+static void bt_audio_open(const void *buf, uint16_t len)
+{
+	DBG("Not Implemented");
+
+	audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
+}
+
 static const struct ipc_handler audio_handlers[] = {
+	/* AUDIO_OP_OPEN */
+	{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
 };
 
 bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-ipc-api.txt b/android/audio-ipc-api.txt
index 1c42800..37a1569 100644
--- a/android/audio-ipc-api.txt
+++ b/android/audio-ipc-api.txt
@@ -49,9 +49,9 @@ Identifier: "audio" (BT_AUDIO_ID)
 
 		Command parameters: Service UUID (16 octets)
 				    Codec ID (1 octet)
+				    Number of codec presets (1 octet)
 				    Codec capabilities length (1 octet)
 				    Codec capabilities (variable)
-				    Number of codec presets (1 octet)
 				    Codec preset # length (1 octet)
 				    Codec preset # configuration (variable)
 				    ...
diff --git a/android/audio-msg.h b/android/audio-msg.h
index ae8a168..158a2ab 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -34,3 +34,21 @@ static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
 struct audio_status {
 	uint8_t code;
 } __attribute__((packed));
+
+#define AUDIO_OP_OPEN			0x01
+struct audio_preset {
+	uint8_t len;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct audio_cmd_open {
+	uint16_t uuid;
+	uint8_t codec;
+	uint8_t presets;
+	uint8_t len;
+	struct audio_preset preset[0];
+} __attribute__((packed));
+
+struct audio_rsp_open {
+	uint8_t id;
+} __attribute__((packed));
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 04/10] android/A2DP: Add initial code to handle audio IPC commands
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds initial code to handle audio IPC commands.
---
 android/a2dp.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 581d094..c12d8f1 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -44,6 +44,8 @@
 #include "utils.h"
 #include "bluetooth.h"
 #include "avdtp.h"
+#include "audio-msg.h"
+#include "audio-ipc.h"
 
 #define L2CAP_PSM_AVDTP 0x19
 #define SVC_HINT_CAPTURING 0x08
@@ -352,6 +354,9 @@ static sdp_record_t *a2dp_record(void)
 	return record;
 }
 
+static const struct ipc_handler audio_handlers[] = {
+};
+
 bool bt_a2dp_register(const bdaddr_t *addr)
 {
 	GError *err = NULL;
@@ -359,6 +364,8 @@ bool bt_a2dp_register(const bdaddr_t *addr)
 
 	DBG("");
 
+	audio_ipc_init();
+
 	bacpy(&adapter_addr, addr);
 
 	server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
@@ -388,6 +395,8 @@ bool bt_a2dp_register(const bdaddr_t *addr)
 	ipc_register(HAL_SERVICE_ID_A2DP, cmd_handlers,
 						G_N_ELEMENTS(cmd_handlers));
 
+	audio_ipc_register(audio_handlers, G_N_ELEMENTS(audio_handlers));
+
 	return true;
 
 fail:
@@ -411,8 +420,9 @@ void bt_a2dp_unregister(void)
 	g_slist_foreach(devices, a2dp_device_disconnected, NULL);
 	devices = NULL;
 
-
 	ipc_unregister(HAL_SERVICE_ID_A2DP);
+	audio_ipc_unregister();
+
 	bt_adapter_remove_record(record_id);
 	record_id = 0;
 
@@ -421,4 +431,6 @@ void bt_a2dp_unregister(void)
 		g_io_channel_unref(server);
 		server = NULL;
 	}
+
+	audio_ipc_cleanup();
 }
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 03/10] android/ipc: Add audio_ipc_send_rsp and audio_ipc_send_rsp_full
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

These functions can be used to respond to commands recieved over audio
IPC.
---
 android/audio-ipc.c | 23 +++++++++++++++++++++++
 android/audio-ipc.h |  3 +++
 android/audio-msg.h |  8 ++++++++
 android/ipc.c       |  2 +-
 android/ipc.h       |  2 ++
 5 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/android/audio-ipc.c b/android/audio-ipc.c
index 0c5433a..f4b55e3 100644
--- a/android/audio-ipc.c
+++ b/android/audio-ipc.c
@@ -123,3 +123,26 @@ void audio_ipc_unregister(void)
 	service.handler = NULL;
 	service.size = 0;
 }
+
+void audio_ipc_send_rsp(uint8_t opcode, uint8_t status)
+{
+	struct audio_status s;
+	int sk;
+
+	sk = g_io_channel_unix_get_fd(audio_io);
+
+	if (status == AUDIO_STATUS_SUCCESS) {
+		ipc_send(sk, AUDIO_SERVICE_ID, opcode, 0, NULL, -1);
+		return;
+	}
+
+	s.code = status;
+
+	ipc_send(sk, AUDIO_SERVICE_ID, AUDIO_OP_STATUS, sizeof(s), &s, -1);
+}
+
+void audio_ipc_send_rsp_full(uint8_t opcode, uint16_t len, void *param, int fd)
+{
+	ipc_send(g_io_channel_unix_get_fd(audio_io), AUDIO_SERVICE_ID, opcode,
+							len, param, fd);
+}
diff --git a/android/audio-ipc.h b/android/audio-ipc.h
index 1dfa245..0b5f216 100644
--- a/android/audio-ipc.h
+++ b/android/audio-ipc.h
@@ -26,3 +26,6 @@ void audio_ipc_cleanup(void);
 
 void audio_ipc_register(const struct ipc_handler *handlers, uint8_t size);
 void audio_ipc_unregister(void);
+
+void audio_ipc_send_rsp(uint8_t opcode, uint8_t status);
+void audio_ipc_send_rsp_full(uint8_t opcode, uint16_t len, void *param, int fd);
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 1ec2520..ae8a168 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -26,3 +26,11 @@
 static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
 
 #define AUDIO_SERVICE_ID		0
+
+#define AUDIO_STATUS_SUCCESS		0x00
+#define AUDIO_STATUS_FAILED		0x01
+
+#define AUDIO_OP_STATUS			0x00
+struct audio_status {
+	uint8_t code;
+} __attribute__((packed));
diff --git a/android/ipc.c b/android/ipc.c
index 1499962..03bdc35 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -245,7 +245,7 @@ void ipc_cleanup(void)
 	}
 }
 
-static void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
+void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
 							void *param, int fd)
 {
 	struct msghdr msg;
diff --git a/android/ipc.h b/android/ipc.h
index 7b8bdeb..b1cc5c5 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -43,6 +43,8 @@ void ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
 							void *param, int fd);
 void ipc_send_notif(uint8_t service_id, uint8_t opcode,  uint16_t len,
 								void *param);
+void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
+							void *param, int fd);
 void ipc_register(uint8_t service, const struct ipc_handler *handlers,
 								uint8_t size);
 void ipc_unregister(uint8_t service);
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 02/10] android/ipc: Add message handling for audio IPC
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds audio_ipc_register and audio_ipc_unregister and adapt
ipc_handle_msg to be able to handle audio services messages.
---
 android/audio-ipc.c | 23 +++++++++++++++++++-
 android/audio-ipc.h |  3 +++
 android/audio-msg.h |  2 ++
 android/ipc.c       | 60 +++++++++++++++++++++++++----------------------------
 android/ipc.h       |  8 +++++++
 5 files changed, 63 insertions(+), 33 deletions(-)

diff --git a/android/audio-ipc.c b/android/audio-ipc.c
index b537f21..0c5433a 100644
--- a/android/audio-ipc.c
+++ b/android/audio-ipc.c
@@ -41,12 +41,14 @@
 
 static GIOChannel *audio_io = NULL;
 
+static struct service_handler service;
+
 static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
 	char buf[BLUEZ_AUDIO_MTU];
 	ssize_t ret;
-	int fd;
+	int fd, err;
 
 	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
 		info("Audio IPC: command socket closed");
@@ -61,6 +63,13 @@ static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
 		goto fail;
 	}
 
+	err = ipc_handle_msg(&service, AUDIO_SERVICE_ID, buf, ret);
+	if (err < 0) {
+		error("Audio IPC: failed to handle message (%s)",
+							strerror(-err));
+		goto fail;
+	}
+
 	return TRUE;
 
 fail:
@@ -102,3 +111,15 @@ void audio_ipc_cleanup(void)
 		audio_io = NULL;
 	}
 }
+
+void audio_ipc_register(const struct ipc_handler *handlers, uint8_t size)
+{
+	service.handler = handlers;
+	service.size = size;
+}
+
+void audio_ipc_unregister(void)
+{
+	service.handler = NULL;
+	service.size = 0;
+}
diff --git a/android/audio-ipc.h b/android/audio-ipc.h
index 769bfd6..1dfa245 100644
--- a/android/audio-ipc.h
+++ b/android/audio-ipc.h
@@ -23,3 +23,6 @@
 
 void audio_ipc_init(void);
 void audio_ipc_cleanup(void);
+
+void audio_ipc_register(const struct ipc_handler *handlers, uint8_t size);
+void audio_ipc_unregister(void);
diff --git a/android/audio-msg.h b/android/audio-msg.h
index d5b4099..1ec2520 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -24,3 +24,5 @@
 #define BLUEZ_AUDIO_MTU 1024
 
 static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
+
+#define AUDIO_SERVICE_ID		0
diff --git a/android/ipc.c b/android/ipc.c
index 8a91248..1499962 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -40,56 +40,45 @@
 #include "ipc.h"
 #include "log.h"
 
-struct service_handler {
-	const struct ipc_handler *handler;
-	uint8_t size;
-};
-
 static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
 
 static GIOChannel *cmd_io = NULL;
 static GIOChannel *notif_io = NULL;
 
-static void ipc_handle_msg(const void *buf, ssize_t len)
+int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
+						const void *buf, ssize_t len)
 {
 	const struct hal_hdr *msg = buf;
 	const struct ipc_handler *handler;
 
 	if (len < (ssize_t) sizeof(*msg)) {
-		error("IPC: message too small (%zd bytes), terminating", len);
-		raise(SIGTERM);
-		return;
+		DBG("message too small (%zd bytes)", len);
+		return -EBADMSG;
 	}
 
 	if (len != (ssize_t) (sizeof(*msg) + msg->len)) {
-		error("IPC: message malformed (%zd bytes), terminating", len);
-		raise(SIGTERM);
-		return;
+		DBG("message malformed (%zd bytes)", len);
+		return -EBADMSG;
 	}
 
 	/* if service is valid */
-	if (msg->service_id > HAL_SERVICE_ID_MAX) {
-		error("IPC: unknown service (0x%x), terminating",
-							msg->service_id);
-		raise(SIGTERM);
-		return;
+	if (msg->service_id > max_index) {
+		DBG("unknown service (0x%x)", msg->service_id);
+		return -EOPNOTSUPP;
 	}
 
 	/* if service is registered */
-	if (!services[msg->service_id].handler) {
-		error("IPC: unregistered service (0x%x), terminating",
-							msg->service_id);
-		raise(SIGTERM);
-		return;
+	if (!handlers[msg->service_id].handler) {
+		DBG("service not registered (0x%x)", msg->service_id);
+		return -EOPNOTSUPP;
 	}
 
 	/* if opcode is valid */
 	if (msg->opcode == HAL_OP_STATUS ||
-			msg->opcode > services[msg->service_id].size) {
-		error("IPC: invalid opcode 0x%x for service 0x%x, terminating",
-						msg->opcode, msg->service_id);
-		raise(SIGTERM);
-		return;
+			msg->opcode > handlers[msg->service_id].size) {
+		DBG("invalid opcode 0x%x for service 0x%x", msg->opcode,
+							msg->service_id);
+		return -EOPNOTSUPP;
 	}
 
 	/* opcode is table offset + 1 */
@@ -98,13 +87,14 @@ static void ipc_handle_msg(const void *buf, ssize_t len)
 	/* if payload size is valid */
 	if ((handler->var_len && handler->data_len > msg->len) ||
 			(!handler->var_len && handler->data_len != msg->len)) {
-		error("IPC: size invalid opcode 0x%x service 0x%x, terminating",
+		DBG("invalid size for opcode 0x%x service 0x%x",
 						msg->service_id, msg->opcode);
-		raise(SIGTERM);
-		return;
+		return -EMSGSIZE;
 	}
 
 	handler->handler(msg->payload, msg->len);
+
+	return 0;
 }
 
 static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
@@ -112,7 +102,7 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 {
 	char buf[BLUEZ_HAL_MTU];
 	ssize_t ret;
-	int fd;
+	int fd, err;
 
 	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
 		info("IPC: command socket closed, terminating");
@@ -128,7 +118,13 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 		goto fail;
 	}
 
-	ipc_handle_msg(buf, ret);
+	err = ipc_handle_msg(services, HAL_SERVICE_ID_MAX, buf, ret);
+	if (err < 0) {
+		error("IPC: failed to handle message, terminating (%s)",
+							strerror(-err));
+		goto fail;
+	}
+
 	return TRUE;
 
 fail:
diff --git a/android/ipc.h b/android/ipc.h
index 02ad6bb..7b8bdeb 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -26,9 +26,17 @@ struct ipc_handler {
 	bool var_len;
 	size_t data_len;
 };
+
+struct service_handler {
+	const struct ipc_handler *handler;
+	uint8_t size;
+};
+
 void ipc_init(void);
 void ipc_cleanup(void);
 GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb);
+int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
+						const void *buf, ssize_t len);
 
 void ipc_send_rsp(uint8_t service_id, uint8_t opcode, uint8_t status);
 void ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ v3 01/10] android/ipc: Add initial code for audio IPC
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This add initial code for listen and accept connections on the abstract
socket defined for the audio IPC.
---
v2: Split audio IPC services for HAL services and fix invalid messages or
disconnections causing the daemon to exit. The audio HAL is independent of
bluetooth and should only affect A2DP service.
v3: Split audio IPC related functions to separate files (audio-ipc.{c,h}),
please disregard git thinking there is a copy of hdp code because they are
similar.

 android/Android.mk                                 |   1 +
 android/Makefile.am                                |   2 +
 android/audio-ipc.c                                | 104 +++++++++++++++++++++
 .../health/hdp_manager.h => android/audio-ipc.h    |   7 +-
 monitor/analyze.h => android/audio-msg.h           |   7 +-
 android/ipc.c                                      |  14 +--
 android/ipc.h                                      |   1 +
 7 files changed, 124 insertions(+), 12 deletions(-)
 create mode 100644 android/audio-ipc.c
 copy profiles/health/hdp_manager.h => android/audio-ipc.h (86%)
 copy monitor/analyze.h => android/audio-msg.h (83%)

diff --git a/android/Android.mk b/android/Android.mk
index 7d9cc4f..27631cc 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -26,6 +26,7 @@ LOCAL_SRC_FILES := \
 	hidhost.c \
 	socket.c \
 	ipc.c ipc.h \
+	audio-ipc.c audio-ipc.h \
 	avdtp.c \
 	a2dp.c \
 	pan.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 7d9b580..8810369 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -15,6 +15,7 @@ noinst_PROGRAMS += android/bluetoothd
 android_bluetoothd_SOURCES = android/main.c \
 				src/log.c \
 				android/hal-msg.h \
+				android/audio-msg.h \
 				android/utils.h \
 				src/sdpd-database.c src/sdpd-server.c \
 				src/sdpd-service.c src/sdpd-request.c \
@@ -25,6 +26,7 @@ android_bluetoothd_SOURCES = android/main.c \
 				android/bluetooth.h android/bluetooth.c \
 				android/hidhost.h android/hidhost.c \
 				android/ipc.h android/ipc.c \
+				android/audio-ipc.h android/audio-ipc.c \
 				android/avdtp.h android/avdtp.c \
 				android/a2dp.h android/a2dp.c \
 				android/socket.h android/socket.c \
diff --git a/android/audio-ipc.c b/android/audio-ipc.c
new file mode 100644
index 0000000..b537f21
--- /dev/null
+++ b/android/audio-ipc.c
@@ -0,0 +1,104 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stddef.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "audio-msg.h"
+#include "audio-ipc.h"
+
+static GIOChannel *audio_io = NULL;
+
+static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	char buf[BLUEZ_AUDIO_MTU];
+	ssize_t ret;
+	int fd;
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		info("Audio IPC: command socket closed");
+		goto fail;
+	}
+
+	fd = g_io_channel_unix_get_fd(io);
+
+	ret = read(fd, buf, sizeof(buf));
+	if (ret < 0) {
+		error("Audio IPC: command read failed (%s)", strerror(errno));
+		goto fail;
+	}
+
+	return TRUE;
+
+fail:
+	audio_ipc_cleanup();
+	return FALSE;
+}
+
+static gboolean audio_connect_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	DBG("");
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		error("Audio IPC: socket connect failed");
+		audio_ipc_cleanup();
+		return FALSE;
+	}
+
+	cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+	g_io_add_watch(audio_io, cond, audio_watch_cb, NULL);
+
+	info("Audio IPC: successfully connected");
+
+	return FALSE;
+}
+
+void audio_ipc_init(void)
+{
+	audio_io = ipc_connect(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
+							audio_connect_cb);
+}
+
+void audio_ipc_cleanup(void)
+{
+	if (audio_io) {
+		g_io_channel_shutdown(audio_io, TRUE, NULL);
+		g_io_channel_unref(audio_io);
+		audio_io = NULL;
+	}
+}
diff --git a/profiles/health/hdp_manager.h b/android/audio-ipc.h
similarity index 86%
copy from profiles/health/hdp_manager.h
copy to android/audio-ipc.h
index 1cab4d0..769bfd6 100644
--- a/profiles/health/hdp_manager.h
+++ b/android/audio-ipc.h
@@ -2,7 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *  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 as published by
@@ -20,5 +21,5 @@
  *
  */
 
-int hdp_manager_init(void);
-void hdp_manager_exit(void);
+void audio_ipc_init(void);
+void audio_ipc_cleanup(void);
diff --git a/monitor/analyze.h b/android/audio-msg.h
similarity index 83%
copy from monitor/analyze.h
copy to android/audio-msg.h
index 7cdda51..d5b4099 100644
--- a/monitor/analyze.h
+++ b/android/audio-msg.h
@@ -2,8 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2014  Intel Corporation. All rights reserved.
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -22,4 +21,6 @@
  *
  */
 
-void analyze_trace(const char *path);
+#define BLUEZ_AUDIO_MTU 1024
+
+static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
diff --git a/android/ipc.c b/android/ipc.c
index 9e8ccc3..8a91248 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -145,7 +145,7 @@ static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
 	return FALSE;
 }
 
-static GIOChannel *connect_hal(GIOFunc connect_cb)
+GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb)
 {
 	struct sockaddr_un addr;
 	GIOCondition cond;
@@ -167,11 +167,11 @@ static GIOChannel *connect_hal(GIOFunc connect_cb)
 	memset(&addr, 0, sizeof(addr));
 	addr.sun_family = AF_UNIX;
 
-	memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
+	memcpy(addr.sun_path, path, size);
 
 	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		error("IPC: failed to connect HAL socket: %d (%s)", errno,
-							strerror(errno));
+		error("IPC: failed to connect HAL socket %s: %d (%s)", &path[1],
+							errno, strerror(errno));
 		g_io_channel_unref(io);
 		return NULL;
 	}
@@ -218,7 +218,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
 		return FALSE;
 	}
 
-	notif_io = connect_hal(notif_connect_cb);
+	notif_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
+							notif_connect_cb);
 	if (!notif_io)
 		raise(SIGTERM);
 
@@ -227,7 +228,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
 
 void ipc_init(void)
 {
-	cmd_io = connect_hal(cmd_connect_cb);
+	cmd_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
+							cmd_connect_cb);
 	if (!cmd_io)
 		raise(SIGTERM);
 }
diff --git a/android/ipc.h b/android/ipc.h
index 6cd102b..02ad6bb 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -28,6 +28,7 @@ struct ipc_handler {
 };
 void ipc_init(void);
 void ipc_cleanup(void);
+GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb);
 
 void ipc_send_rsp(uint8_t service_id, uint8_t opcode, uint8_t status);
 void ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH_v2 4/4] android/pan: Remove connected PAN devices on profile unregister call
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>

---
 android/pan.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/android/pan.c b/android/pan.c
index 65777c8..e195061 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -764,10 +764,20 @@ bool bt_pan_register(const bdaddr_t *addr)
 	return true;
 }
 
+static void pan_device_disconnected(gpointer data, gpointer user_data)
+{
+	struct pan_device *dev = data;
+
+	bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
 void bt_pan_unregister(void)
 {
 	DBG("");
 
+	g_slist_foreach(devices, pan_device_disconnected, NULL);
+	devices = NULL;
+
 	bnep_cleanup();
 
 	ipc_unregister(HAL_SERVICE_ID_PAN);
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH_v2 3/4] android/pan: Implement PAN enable HAL api at daemon side
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>

---
 android/pan.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/android/pan.c b/android/pan.c
index 0b32fbc..65777c8 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -589,18 +589,38 @@ static void bt_pan_enable(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_pan_enable *cmd = buf;
 	uint8_t status;
+	int err;
+
+	DBG("");
+
+	if (local_role == cmd->local_role) {
+		status = HAL_STATUS_SUCCESS;
+		goto reply;
+	}
+
+	/* destroy existing server */
+	destroy_nap_device();
 
 	switch (cmd->local_role) {
 	case HAL_PAN_ROLE_PANU:
-	case HAL_PAN_ROLE_NAP:
-		DBG("Not Implemented");
-		status  = HAL_STATUS_FAILED;
-		break;
-	default:
 		status = HAL_STATUS_UNSUPPORTED;
-		break;
+		goto reply;
+	case HAL_PAN_ROLE_NONE:
+		status = HAL_STATUS_SUCCESS;
+		goto reply;
+	}
+
+	local_role = cmd->local_role;
+	err = register_nap_server();
+	if (err < 0) {
+		status = HAL_STATUS_FAILED;
+		destroy_nap_device();
+		goto reply;
 	}
 
+	status = HAL_STATUS_SUCCESS;
+
+reply:
 	ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE, status);
 }
 
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH_v2 2/4] android/pan: Listen for incoming connections and accept in NAP role
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>

Listen for incoming connections and accept it. Create bnep interface
add it to bridge and notify control and connection state information
through HAL. Remove the device on disconnect request. If android
settings UI does not have bluetooth tethering enabled it immediately
sends disconnect signal.
---
 android/pan.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 190 insertions(+), 2 deletions(-)

diff --git a/android/pan.c b/android/pan.c
index 80eb275..0b32fbc 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -63,12 +63,17 @@ struct pan_device {
 	uint8_t		role;
 	GIOChannel	*io;
 	struct bnep	*session;
+	guint		watch;
 };
 
 static struct {
 	uint32_t	record_id;
+	guint		watch;
+	GIOChannel	*io;
 } nap_dev = {
 	.record_id = 0,
+	.watch = 0,
+	.io = NULL,
 };
 
 static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -81,13 +86,21 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
 
 static void pan_device_free(struct pan_device *dev)
 {
+	if (dev->watch > 0) {
+		bnep_server_delete(BNEP_BRIDGE, dev->iface, &dev->dst);
+		g_source_remove(dev->watch);
+		dev->watch = 0;
+	}
+
 	if (dev->io) {
 		g_io_channel_shutdown(dev->io, FALSE, NULL);
 		g_io_channel_unref(dev->io);
 		dev->io = NULL;
 	}
 
-	bnep_free(dev->session);
+	if (dev->session)
+		bnep_free(dev->session);
+
 	devices = g_slist_remove(devices, dev);
 	g_free(dev);
 
@@ -298,7 +311,7 @@ static void bt_pan_disconnect(const void *buf, uint16_t len)
 
 	dev = l->data;
 
-	if (dev->conn_state == HAL_PAN_STATE_CONNECTED)
+	if (dev->conn_state == HAL_PAN_STATE_CONNECTED && dev->session)
 		bnep_disconnect(dev->session);
 
 	bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
@@ -308,6 +321,154 @@ failed:
 	ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
 }
 
+static gboolean nap_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	struct pan_device *dev = user_data;
+
+	DBG("disconnected");
+
+	bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+
+	return FALSE;
+}
+static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	struct pan_device *dev = user_data;
+	uint8_t packet[BNEP_MTU];
+	struct bnep_setup_conn_req *req = (void *) packet;
+	uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
+	int sk, n;
+
+	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+		error("Hangup or error or inval on BNEP socket");
+		return FALSE;
+	}
+
+	sk = g_io_channel_unix_get_fd(chan);
+
+	/* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
+	n = read(sk, packet, sizeof(packet));
+	if (n  < 0) {
+		error("read(): %s(%d)", strerror(errno), errno);
+		goto failed;
+	}
+
+	/* Highest known control command id BNEP_FILTER_MULT_ADDR_RSP 0x06 */
+	if (req->type == BNEP_CONTROL &&
+			req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
+		error("cmd not understood");
+		bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_CMD_NOT_UNDERSTOOD,
+								req->ctrl);
+		goto failed;
+	}
+
+	if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) {
+		error("cmd is not BNEP_SETUP_CONN_REQ %02X %02X", req->type,
+								req->ctrl);
+		goto failed;
+	}
+
+	rsp = bnep_setup_decode(req, &dst_role, &src_role);
+	if (rsp) {
+		error("bnep_setup_decode failed");
+		goto failed;
+	}
+
+	rsp = bnep_setup_chk(dst_role, src_role);
+	if (rsp) {
+		error("benp_setup_chk failed");
+		goto failed;
+	}
+
+	if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
+							&dev->dst) < 0) {
+		error("server_connadd failed");
+		rsp = BNEP_CONN_NOT_ALLOWED;
+		goto failed;
+	}
+
+	rsp = BNEP_SUCCESS;
+	bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+
+	dev->watch = g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+							nap_watchdog_cb, dev);
+	g_io_channel_unref(dev->io);
+	dev->io = NULL;
+
+	bt_pan_notify_ctrl_state(dev, HAL_PAN_CTRL_ENABLED);
+	bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTED);
+
+	return FALSE;
+
+failed:
+	bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+	pan_device_free(dev);
+
+	return FALSE;
+}
+
+static void nap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+	struct pan_device *dev = user_data;
+
+	DBG("");
+
+	if (err) {
+		error("%s", err->message);
+		bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+		return;
+	}
+
+	g_io_channel_set_close_on_unref(chan, TRUE);
+	dev->watch = g_io_add_watch(chan,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				nap_setup_cb, dev);
+}
+
+static void nap_confirm_cb(GIOChannel *chan, gpointer data)
+{
+	struct pan_device *dev = NULL;
+	bdaddr_t dst;
+	char address[18];
+	GError *err = NULL;
+
+	DBG("");
+
+	bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto failed;
+	}
+
+	DBG("incoming connect request from %s", address);
+	dev = g_new0(struct pan_device, 1);
+	bacpy(&dev->dst, &dst);
+	local_role = HAL_PAN_ROLE_NAP;
+	dev->role = HAL_PAN_ROLE_PANU;
+
+	dev->io = g_io_channel_ref(chan);
+	g_io_channel_set_close_on_unref(dev->io, TRUE);
+
+	if (!bt_io_accept(dev->io, nap_connect_cb, dev, NULL, &err)) {
+		error("bt_io_accept: %s", err->message);
+		g_error_free(err);
+		goto failed;
+	}
+
+	devices = g_slist_append(devices, dev);
+	bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTING);
+
+	return;
+
+failed:
+	g_free(dev);
+	bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
 static int set_forward_delay(void)
 {
 	FILE *f;
@@ -382,10 +543,22 @@ static void destroy_nap_device(void)
 	nap_remove_bridge();
 
 	nap_dev.record_id = 0;
+
+	if (nap_dev.watch > 0) {
+		g_source_remove(nap_dev.watch);
+		nap_dev.watch = 0;
+	}
+
+	if (nap_dev.io) {
+		g_io_channel_shutdown(nap_dev.io, FALSE, NULL);
+		g_io_channel_unref(nap_dev.io);
+		nap_dev.io = NULL;
+	}
 }
 
 static int register_nap_server(void)
 {
+	GError *gerr;
 	int err;
 
 	DBG("");
@@ -394,6 +567,21 @@ static int register_nap_server(void)
 	if (err < 0)
 		return err;
 
+	nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
+					BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+					BT_IO_OPT_PSM, BNEP_PSM,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+					BT_IO_OPT_OMTU, BNEP_MTU,
+					BT_IO_OPT_IMTU, BNEP_MTU,
+					BT_IO_OPT_INVALID);
+
+	if (!nap_dev.io) {
+		destroy_nap_device();
+		error("%s", gerr->message);
+		g_error_free(gerr);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH_v2 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>

Register NAP server and adds bnep bridge. Removes bridge
on destroy call. Bridge mechanism is needed when device acting
as a server and listen for incoming connections.
---
 android/pan.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 112 insertions(+), 4 deletions(-)

diff --git a/android/pan.c b/android/pan.c
index 38e353d..80eb275 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -28,6 +28,11 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <glib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <linux/sockios.h>
 
 #include "btio/btio.h"
 #include "lib/bluetooth.h"
@@ -45,11 +50,11 @@
 #include "bluetooth.h"
 
 #define SVC_HINT_NETWORKING 0x02
+#define BNEP_BRIDGE	"bnep"
 
 static bdaddr_t adapter_addr;
 GSList *devices = NULL;
 uint8_t local_role = HAL_PAN_ROLE_NONE;
-static uint32_t record_id = 0;
 
 struct pan_device {
 	char		iface[16];
@@ -60,6 +65,12 @@ struct pan_device {
 	struct bnep	*session;
 };
 
+static struct {
+	uint32_t	record_id;
+} nap_dev = {
+	.record_id = 0,
+};
+
 static int device_cmp(gconstpointer s, gconstpointer user_data)
 {
 	const struct pan_device *dev = s;
@@ -297,6 +308,95 @@ failed:
 	ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
 }
 
+static int set_forward_delay(void)
+{
+	FILE *f;
+	char *path;
+
+	path = g_strdup_printf("/sys/class/net/%s/bridge/forward_delay",
+								BNEP_BRIDGE);
+	if (!path)
+		return -ENOMEM;
+
+	f = fopen(path, "r+");
+	g_free(path);
+	if (!f)
+		return -errno;
+
+	fprintf(f, "%d", 0);
+	fclose(f);
+
+	return 0;
+}
+
+static int nap_create_bridge(void)
+{
+	int sk, err;
+
+	DBG(" %s", BNEP_BRIDGE);
+
+	sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+	if (sk < 0)
+		return -EOPNOTSUPP;
+
+	if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) == -1) {
+		err = -errno;
+		if (err != -EEXIST) {
+			close(sk);
+			return -EOPNOTSUPP;
+		}
+	}
+
+	err = set_forward_delay();
+	if (err < 0)
+		ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+
+	close(sk);
+
+	return err;
+}
+
+static int nap_remove_bridge(void)
+{
+	int sk, err;
+
+	DBG(" %s", BNEP_BRIDGE);
+
+	sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+	if (sk < 0)
+		return -EOPNOTSUPP;
+
+	err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+	close(sk);
+
+	if (err < 0)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static void destroy_nap_device(void)
+{
+	DBG("");
+
+	nap_remove_bridge();
+
+	nap_dev.record_id = 0;
+}
+
+static int register_nap_server(void)
+{
+	int err;
+
+	DBG("");
+
+	err = nap_create_bridge();
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
 static void bt_pan_enable(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_pan_enable *cmd = buf;
@@ -441,7 +541,15 @@ bool bt_pan_register(const bdaddr_t *addr)
 		return false;
 	}
 
-	record_id = rec->handle;
+	err = register_nap_server();
+	if (err < 0) {
+		bt_adapter_remove_record(rec->handle);
+		sdp_record_free(rec);
+		bnep_cleanup();
+		return false;
+	}
+
+	nap_dev.record_id = rec->handle;
 	ipc_register(HAL_SERVICE_ID_PAN, cmd_handlers,
 						G_N_ELEMENTS(cmd_handlers));
 
@@ -455,6 +563,6 @@ void bt_pan_unregister(void)
 	bnep_cleanup();
 
 	ipc_unregister(HAL_SERVICE_ID_PAN);
-	bt_adapter_remove_record(record_id);
-	record_id = 0;
+	bt_adapter_remove_record(nap_dev.record_id);
+	destroy_nap_device();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH_v2 0/4] Add support for NAP role
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally

v2: Fixed Johan's comments.

v1: This patch set add support for NAP role. It register NAP server and create
  bnep bridge and listen for incoming connections from client devices.
  On incoming connection request it accepts connection, creates bnep interface
  and notifies control state and connection state infromation. Removes device
  on disconnect request. Android related changes are required to enable this
  role. Patches sent to respective ML.

Ravi kumar Veeramally (4):
  android/pan: Register Network Access Point
  android/pan: Listen for incoming connections and accept in NAP role
  android/pan: Implement PAN enable HAL api at daemon side
  android/pan: Remove connected PAN devices on profile unregister call

 android/pan.c | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 338 insertions(+), 12 deletions(-)

-- 
1.8.3.2


^ permalink raw reply

* [PATCHv2 5/5] emulator/bthost: Add method to create rfcomm server
From: Marcin Kraglak @ 2014-01-07 10:59 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389092354-32544-1-git-send-email-marcin.kraglak@tieto.com>

It allows user to create rfcomm server on bthost.
---
 emulator/bthost.c | 32 ++++++++++++++++++++++++++++++++
 emulator/bthost.h |  6 ++++++
 2 files changed, 38 insertions(+)

diff --git a/emulator/bthost.c b/emulator/bthost.c
index 8638f13..676c0ae 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -99,6 +99,13 @@ struct l2cap_conn_cb_data {
 	struct l2cap_conn_cb_data *next;
 };
 
+struct rfcomm_conn_cb_data {
+	uint8_t channel;
+	bthost_rfcomm_connect_cb func;
+	void *user_data;
+	struct rfcomm_conn_cb_data *next;
+};
+
 struct bthost {
 	uint8_t bdaddr[6];
 	bthost_send_func send_handler;
@@ -111,6 +118,7 @@ struct bthost {
 	bthost_new_conn_cb new_conn_cb;
 	void *new_conn_data;
 	struct l2cap_conn_cb_data *new_l2cap_conn_data;
+	struct rfcomm_conn_cb_data *new_rfcomm_conn_data;
 	struct l2cap_pending_req *l2reqs;
 };
 
@@ -246,6 +254,13 @@ void bthost_destroy(struct bthost *bthost)
 		free(cb);
 	}
 
+	while (bthost->new_rfcomm_conn_data) {
+		struct rfcomm_conn_cb_data *cb = bthost->new_rfcomm_conn_data;
+
+		bthost->new_rfcomm_conn_data = cb->next;
+		free(cb);
+	}
+
 	free(bthost);
 }
 
@@ -1392,6 +1407,23 @@ void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm,
 	bthost->new_l2cap_conn_data = data;
 }
 
+void bthost_add_rfcomm_server(struct bthost *bthost, uint8_t channel,
+				bthost_rfcomm_connect_cb func, void *user_data)
+{
+	struct rfcomm_conn_cb_data *data;
+
+	data = malloc(sizeof(struct rfcomm_conn_cb_data));
+	if (!data)
+		return;
+
+	data->channel = channel;
+	data->user_data = user_data;
+	data->func = func;
+	data->next = bthost->new_rfcomm_conn_data;
+
+	bthost->new_rfcomm_conn_data = data;
+}
+
 void bthost_start(struct bthost *bthost)
 {
 	if (!bthost)
diff --git a/emulator/bthost.h b/emulator/bthost.h
index 97f011b..7186aa0 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
@@ -80,5 +80,11 @@ typedef void (*bthost_l2cap_connect_cb) (uint16_t handle, uint16_t cid,
 void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm,
 				bthost_l2cap_connect_cb func, void *user_data);
 
+typedef void (*bthost_rfcomm_connect_cb) (uint16_t handle, uint16_t cid,
+					uint8_t channel, void *user_data);
+
+void bthost_add_rfcomm_server(struct bthost *bthost, uint8_t channel,
+			bthost_rfcomm_connect_cb func, void *user_data);
+
 void bthost_start(struct bthost *bthost);
 void bthost_stop(struct bthost *bthost);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCHv2 4/5] emulator/bthost: Add initial rfcomm handling
From: Marcin Kraglak @ 2014-01-07 10:59 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389092354-32544-1-git-send-email-marcin.kraglak@tieto.com>

This is initial rfcomm handling in bthost.
---
 emulator/bthost.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 66 insertions(+), 1 deletion(-)

diff --git a/emulator/bthost.c b/emulator/bthost.c
index 83bfdee..8638f13 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -36,6 +36,7 @@
 #include "bluetooth/bluetooth.h"
 
 #include "monitor/bt.h"
+#include "monitor/rfcomm.h"
 #include "bthost.h"
 
 /* ACL handle and flags pack/unpack */
@@ -1173,6 +1174,64 @@ static struct cid_hook *find_cid_hook(struct btconn *conn, uint16_t cid)
 	return NULL;
 }
 
+static void rfcomm_sabm_recv(struct bthost *bthost, struct btconn *conn,
+				struct l2conn *l2conn, const void *data,
+				uint16_t len)
+{
+}
+
+static void rfcomm_disc_recv(struct bthost *bthost, struct btconn *conn,
+				struct l2conn *l2conn, const void *data,
+				uint16_t len)
+{
+}
+
+static void rfcomm_ua_recv(struct bthost *bthost, struct btconn *conn,
+				struct l2conn *l2conn, const void *data,
+				uint16_t len)
+{
+}
+
+static void rfcomm_dm_recv(struct bthost *bthost, struct btconn *conn,
+				struct l2conn *l2conn, const void *data,
+				uint16_t len)
+{
+}
+
+static void rfcomm_uih_recv(struct bthost *bthost, struct btconn *conn,
+				struct l2conn *l2conn, const void *data,
+				uint16_t len)
+{
+}
+
+static void process_rfcomm(struct bthost *bthost, struct btconn *conn,
+				struct l2conn *l2conn, const void *data,
+				uint16_t len)
+{
+	const struct rfcomm_hdr *hdr = data;
+
+	switch (RFCOMM_GET_TYPE(hdr->control)) {
+	case RFCOMM_SABM:
+		rfcomm_sabm_recv(bthost, conn, l2conn, data, len);
+		break;
+	case RFCOMM_DISC:
+		rfcomm_disc_recv(bthost, conn, l2conn, data, len);
+		break;
+	case RFCOMM_UA:
+		rfcomm_ua_recv(bthost, conn, l2conn, data, len);
+		break;
+	case RFCOMM_DM:
+		rfcomm_dm_recv(bthost, conn, l2conn, data, len);
+		break;
+	case RFCOMM_UIH:
+		rfcomm_uih_recv(bthost, conn, l2conn, data, len);
+		break;
+	default:
+		printf("Unknown frame type\n");
+		break;
+	}
+}
+
 static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
 {
 	const struct bt_hci_acl_hdr *acl_hdr = data;
@@ -1180,6 +1239,7 @@ static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
 	uint16_t handle, cid, acl_len, l2_len;
 	struct cid_hook *hook;
 	struct btconn *conn;
+	struct l2conn *l2conn;
 	const void *l2_data;
 
 	if (len < sizeof(*acl_hdr) + sizeof(*l2_hdr))
@@ -1218,7 +1278,12 @@ static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
 		l2cap_le_sig(bthost, conn, l2_data, l2_len);
 		break;
 	default:
-		printf("Packet for unknown CID 0x%04x (%u)\n", cid, cid);
+		l2conn = btconn_find_l2cap_conn_by_scid(conn, cid);
+		if (l2conn->psm == 0x0003)
+			process_rfcomm(bthost, conn, l2conn, l2_data, l2_len);
+		else
+			printf("Packet for unknown CID 0x%04x (%u)\n", cid,
+									cid);
 		break;
 	}
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCHv2 3/5] monitor: Add rfcomm.h to tree
From: Marcin Kraglak @ 2014-01-07 10:59 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389092354-32544-1-git-send-email-marcin.kraglak@tieto.com>

Add initial rfcomm structs and defines to rfcomm.h.
---
 monitor/rfcomm.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 monitor/rfcomm.h

diff --git a/monitor/rfcomm.h b/monitor/rfcomm.h
new file mode 100644
index 0000000..02a1256
--- /dev/null
+++ b/monitor/rfcomm.h
@@ -0,0 +1,47 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define RFCOMM_SABM	0x2f
+#define RFCOMM_DISC	0x43
+#define RFCOMM_UA	0x63
+#define RFCOMM_DM	0x0f
+#define RFCOMM_UIH	0xef
+
+#define RFCOMM_GET_TYPE(control)	((control) & 0xef)
+#define RFCOMM_GET_DLCI(address)	((address & 0xfc) >> 2)
+#define RFCOMM_GET_CHANNEL(address)	((address & 0xf8) >> 3)
+#define RFCOMM_GET_DIR(address)	((address & 0x04) >> 2)
+#define RFCOMM_TEST_EA(length)	((length & 0x01))
+
+struct rfcomm_hdr {
+	uint8_t address;
+	uint8_t control;
+	uint8_t length;
+} __attribute__((packed));
+
+struct rfcomm_cmd {
+	uint8_t address;
+	uint8_t control;
+	uint8_t length;
+	uint8_t fcs;
+} __attribute__((packed));
-- 
1.8.3.1


^ permalink raw reply related

* [PATCHv2 2/5] tools/rfcomm-tester: Add basic rfcomm test case
From: Marcin Kraglak @ 2014-01-07 10:59 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389092354-32544-1-git-send-email-marcin.kraglak@tieto.com>

This test case verifies creating rfcomm socket.
---
 Makefile.tools        |   9 +-
 tools/rfcomm-tester.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 264 insertions(+), 2 deletions(-)

diff --git a/Makefile.tools b/Makefile.tools
index ef17305..6f716fd 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -76,8 +76,13 @@ tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \
 				src/shared/tester.h src/shared/tester.c
 tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
-tools_rfcomm_tester_SOURCES = tools/rfcomm-tester.c src/shared/tester.h \
-				src/shared/tester.c
+tools_rfcomm_tester_SOURCES = tools/rfcomm-tester.c monitor/bt.h \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				src/shared/util.h src/shared/util.c \
+				src/shared/mgmt.h src/shared/mgmt.c \
+				src/shared/hciemu.h src/shared/hciemu.c \
+				src/shared/tester.h src/shared/tester.c
 tools_rfcomm_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
 tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \
diff --git a/tools/rfcomm-tester.c b/tools/rfcomm-tester.c
index 194e2e6..af87f75 100644
--- a/tools/rfcomm-tester.c
+++ b/tools/rfcomm-tester.c
@@ -25,12 +25,269 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
 #include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+
 #include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/hciemu.h"
+
+struct test_data {
+	struct mgmt *mgmt;
+	uint16_t mgmt_index;
+	struct hciemu *hciemu;
+	enum hciemu_type hciemu_type;
+	const void *test_data;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct mgmt_rp_read_info *rp = param;
+	char addr[18];
+	uint16_t manufacturer;
+	uint32_t supported_settings, current_settings;
+
+	tester_print("Read Info callback");
+	tester_print("  Status: 0x%02x", status);
+
+	if (status || !param) {
+		tester_pre_setup_failed();
+		return;
+	}
+
+	ba2str(&rp->bdaddr, addr);
+	manufacturer = btohs(rp->manufacturer);
+	supported_settings = btohl(rp->supported_settings);
+	current_settings = btohl(rp->current_settings);
+
+	tester_print("  Address: %s", addr);
+	tester_print("  Version: 0x%02x", rp->version);
+	tester_print("  Manufacturer: 0x%04x", manufacturer);
+	tester_print("  Supported settings: 0x%08x", supported_settings);
+	tester_print("  Current settings: 0x%08x", current_settings);
+	tester_print("  Class: 0x%02x%02x%02x",
+			rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+	tester_print("  Name: %s", rp->name);
+	tester_print("  Short name: %s", rp->short_name);
+
+	if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+		tester_pre_setup_failed();
+		return;
+	}
+
+	tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Index Added callback");
+	tester_print("  Index: 0x%04x", index);
+
+	data->mgmt_index = index;
+
+	mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+					read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Index Removed callback");
+	tester_print("  Index: 0x%04x", index);
+
+	if (index != data->mgmt_index)
+		return;
+
+	mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+	mgmt_unref(data->mgmt);
+	data->mgmt = NULL;
+
+	tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Read Index List callback");
+	tester_print("  Status: 0x%02x", status);
+
+	if (status || !param) {
+		tester_pre_setup_failed();
+		return;
+	}
+
+	mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+					index_added_callback, NULL, NULL);
+
+	mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+					index_removed_callback, NULL, NULL);
+
+	data->hciemu = hciemu_new(data->hciemu_type);
+	if (!data->hciemu) {
+		tester_warn("Failed to setup HCI emulation");
+		tester_pre_setup_failed();
+	}
+
+	tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	data->mgmt = mgmt_new_default();
+	if (!data->mgmt) {
+		tester_warn("Failed to setup management interface");
+		tester_pre_setup_failed();
+		return;
+	}
+
+	if (tester_use_debug())
+		mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+	mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+					read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	hciemu_unref(data->hciemu);
+	data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+	struct test_data *data = test_data;
+
+	free(data);
+}
+
+static void client_connectable_complete(uint16_t opcode, uint8_t status,
+					const void *param, uint8_t len,
+					void *user_data)
+{
+	switch (opcode) {
+	case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+	case BT_HCI_CMD_LE_SET_ADV_ENABLE:
+		break;
+	default:
+		return;
+	}
+
+	tester_print("Client set connectable status 0x%02x", status);
+
+	if (status)
+		tester_setup_failed();
+	else
+		tester_setup_complete();
+}
+
+static void setup_powered_client_callback(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	struct bthost *bthost;
+
+	if (status != MGMT_STATUS_SUCCESS) {
+		tester_setup_failed();
+		return;
+	}
+
+	tester_print("Controller powered on");
+
+	bthost = hciemu_client_get_host(data->hciemu);
+	bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
+	if (data->hciemu_type == HCIEMU_TYPE_LE)
+		bthost_set_adv_enable(bthost, 0x01);
+	else
+		bthost_write_scan_enable(bthost, 0x03);
+}
+
+static void setup_powered_client(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	unsigned char param[] = { 0x01 };
+
+	tester_print("Powering on controller");
+
+	if (data->hciemu_type == HCIEMU_TYPE_BREDR)
+		mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+				sizeof(param), param, NULL, NULL, NULL);
+	else
+		mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+				sizeof(param), param, NULL, NULL, NULL);
+
+	mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+			sizeof(param), param, setup_powered_client_callback,
+			NULL, NULL);
+}
+
+static void test_basic(const void *test_data)
+{
+	int sk;
+
+	sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+	if (sk < 0) {
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		return;
+	}
+
+	close(sk);
+
+	tester_test_passed();
+}
+
+#define test_rfcomm_bredr(name, data, setup, func) \
+	do { \
+		struct test_data *user; \
+		user = malloc(sizeof(struct test_data)); \
+		if (!user) \
+			break; \
+		user->hciemu_type = HCIEMU_TYPE_BREDR; \
+		user->test_data = data; \
+		tester_add_full(name, data, \
+				test_pre_setup, setup, func, NULL, \
+				test_post_teardown, 2, user, test_data_free); \
+	} while (0)
 
 int main(int argc, char *argv[])
 {
 	tester_init(&argc, &argv);
 
+	test_rfcomm_bredr("Basic RFCOMM Socket - Success", NULL,
+					setup_powered_client, test_basic);
+
 	return tester_run();
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCHv2 1/5] tools/rfcomm-tester: Initial version of rfcomm-tester
From: Marcin Kraglak @ 2014-01-07 10:59 UTC (permalink / raw)
  To: linux-bluetooth

Add rfcomm-tester to tree.
---
 .gitignore            |  1 +
 Makefile.tools        |  6 +++++-
 tools/rfcomm-tester.c | 36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 tools/rfcomm-tester.c

diff --git a/.gitignore b/.gitignore
index 3e0641d..4ac216d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,6 +81,7 @@ unit/test-mgmt
 tools/mgmt-tester
 tools/smp-tester
 tools/gap-tester
+tools/rfcomm-tester
 tools/btattach
 tools/btmgmt
 tools/btsnoop
diff --git a/Makefile.tools b/Makefile.tools
index c78cc50..ef17305 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -39,7 +39,7 @@ if EXPERIMENTAL
 noinst_PROGRAMS += emulator/btvirt emulator/b1ee tools/3dsp \
 					tools/mgmt-tester tools/gap-tester \
 					tools/l2cap-tester tools/sco-tester \
-					tools/smp-tester
+					tools/smp-tester tools/rfcomm-tester
 
 emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
 					monitor/mainloop.h monitor/mainloop.c \
@@ -76,6 +76,10 @@ tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \
 				src/shared/tester.h src/shared/tester.c
 tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
+tools_rfcomm_tester_SOURCES = tools/rfcomm-tester.c src/shared/tester.h \
+				src/shared/tester.c
+tools_rfcomm_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
 tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \
 				emulator/btdev.h emulator/btdev.c \
 				emulator/bthost.h emulator/bthost.c \
diff --git a/tools/rfcomm-tester.c b/tools/rfcomm-tester.c
new file mode 100644
index 0000000..194e2e6
--- /dev/null
+++ b/tools/rfcomm-tester.c
@@ -0,0 +1,36 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include "src/shared/tester.h"
+
+int main(int argc, char *argv[])
+{
+	tester_init(&argc, &argv);
+
+	return tester_run();
+}
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 2/2] android: Send remote devices properties on enable
From: Lukasz Rymanowski @ 2014-01-07 10:53 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: szymon.janc, Lukasz Rymanowski
In-Reply-To: <1389092005-10302-1-git-send-email-lukasz.rymanowski@tieto.com>

If there is any bonded device stored then on bluetooth enable we
should send notification with its properties.

Change-Id: Ia14ae7379dd986d67e81161b86f3c02475540d7b
---
 android/bluetooth.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index e0673bb..9da988b 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2636,6 +2636,18 @@ static void get_remote_device_props(struct device *dev)
 	get_device_timestamp(dev);
 }
 
+static void send_bonded_devices_props(void)
+{
+	GSList *l;
+
+	for (l = devices; l; l = g_slist_next(l)) {
+		struct device *dev = l->data;
+
+		if (dev->bond_state == HAL_BOND_STATE_BONDED)
+			get_remote_device_props(dev);
+	}
+}
+
 static void handle_enable_cmd(const void *buf, uint16_t len)
 {
 	uint8_t status;
@@ -2644,6 +2656,9 @@ static void handle_enable_cmd(const void *buf, uint16_t len)
 	 * enabling adapter */
 	get_adapter_properties();
 
+	/* Sent also properties of bonded devices */
+	send_bonded_devices_props();
+
 	if (adapter.current_settings & MGMT_SETTING_POWERED) {
 		status = HAL_STATUS_DONE;
 		goto failed;
-- 
1.8.4


^ permalink raw reply related

* [PATCH 1/2] android: Add wrapper function for get remote dev properties
From: Lukasz Rymanowski @ 2014-01-07 10:53 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: szymon.janc, Lukasz Rymanowski

Change-Id: Iab584580562534e2489dc6c8213f6066bbd8bd46
---
 android/bluetooth.c | 123 +++++++++++++++++++++++++++-------------------------
 1 file changed, 64 insertions(+), 59 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 3cbf68d..e0673bb 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2550,56 +2550,6 @@ static void handle_get_remote_services_cmd(const void *buf, uint16_t len)
 									status);
 }
 
-static void handle_enable_cmd(const void *buf, uint16_t len)
-{
-	uint8_t status;
-
-	/* Framework expects all properties to be emitted while
-	 * enabling adapter */
-	get_adapter_properties();
-
-	if (adapter.current_settings & MGMT_SETTING_POWERED) {
-		status = HAL_STATUS_DONE;
-		goto failed;
-	}
-
-	if (!set_mode(MGMT_OP_SET_POWERED, 0x01)) {
-		status = HAL_STATUS_FAILED;
-		goto failed;
-	}
-
-	status = HAL_STATUS_SUCCESS;
-failed:
-	ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_ENABLE, status);
-}
-
-static void handle_disable_cmd(const void *buf, uint16_t len)
-{
-	uint8_t status;
-
-	if (!(adapter.current_settings & MGMT_SETTING_POWERED)) {
-		status = HAL_STATUS_DONE;
-		goto failed;
-	}
-
-	if (!set_mode(MGMT_OP_SET_POWERED, 0x00)) {
-		status = HAL_STATUS_FAILED;
-		goto failed;
-	}
-
-	status = HAL_STATUS_SUCCESS;
-failed:
-	ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_DISABLE, status);
-}
-
-static void handle_get_adapter_props_cmd(const void *buf, uint16_t len)
-{
-	get_adapter_properties();
-
-	ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROPS,
-							HAL_STATUS_SUCCESS);
-}
-
 static uint8_t get_device_uuids(struct device *dev)
 {
 	send_device_uuids_notif(dev);
@@ -2673,6 +2623,69 @@ static uint8_t get_device_timestamp(struct device *dev)
 	return HAL_STATUS_SUCCESS;
 }
 
+static void get_remote_device_props(struct device *dev)
+{
+	get_device_name(dev);
+	get_device_uuids(dev);
+	get_device_class(dev);
+	get_device_type(dev);
+	get_device_service_rec(dev);
+	get_device_friendly_name(dev);
+	get_device_rssi(dev);
+	get_device_version_info(dev);
+	get_device_timestamp(dev);
+}
+
+static void handle_enable_cmd(const void *buf, uint16_t len)
+{
+	uint8_t status;
+
+	/* Framework expects all properties to be emitted while
+	 * enabling adapter */
+	get_adapter_properties();
+
+	if (adapter.current_settings & MGMT_SETTING_POWERED) {
+		status = HAL_STATUS_DONE;
+		goto failed;
+	}
+
+	if (!set_mode(MGMT_OP_SET_POWERED, 0x01)) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	status = HAL_STATUS_SUCCESS;
+failed:
+	ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_ENABLE, status);
+}
+
+static void handle_disable_cmd(const void *buf, uint16_t len)
+{
+	uint8_t status;
+
+	if (!(adapter.current_settings & MGMT_SETTING_POWERED)) {
+		status = HAL_STATUS_DONE;
+		goto failed;
+	}
+
+	if (!set_mode(MGMT_OP_SET_POWERED, 0x00)) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	status = HAL_STATUS_SUCCESS;
+failed:
+	ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_DISABLE, status);
+}
+
+static void handle_get_adapter_props_cmd(const void *buf, uint16_t len)
+{
+	get_adapter_properties();
+
+	ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROPS,
+							HAL_STATUS_SUCCESS);
+}
+
 static void handle_get_remote_device_props_cmd(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_get_remote_device_props *cmd = buf;
@@ -2688,15 +2701,7 @@ static void handle_get_remote_device_props_cmd(const void *buf, uint16_t len)
 		goto failed;
 	}
 
-	get_device_name(l->data);
-	get_device_uuids(l->data);
-	get_device_class(l->data);
-	get_device_type(l->data);
-	get_device_service_rec(l->data);
-	get_device_friendly_name(l->data);
-	get_device_rssi(l->data);
-	get_device_version_info(l->data);
-	get_device_timestamp(l->data);
+	get_remote_device_props(l->data);
 
 	status = HAL_STATUS_SUCCESS;
 
-- 
1.8.4


^ permalink raw reply related

* Re: [PATCH 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-07 10:48 UTC (permalink / raw)
  To: linux-bluetooth, johan.hedberg
In-Reply-To: <20140107101842.GA20861@x220.p-661hnu-f1>

Hi Johan,

On 01/07/2014 12:18 PM, Johan Hedberg wrote:
> Hi Ravi,
>
> On Tue, Jan 07, 2014, Ravi kumar Veeramally wrote:
>>>> @@ -49,7 +54,7 @@
>>>>   static bdaddr_t adapter_addr;
>>>>   GSList *devices = NULL;
>>>>   uint8_t local_role = HAL_PAN_ROLE_NONE;
>>>> -static uint32_t record_id = 0;
>>>> +char bridge[5] = "bnep\0";
>>> This last line raises several questions. Firstly, C-strings have an
>>> implicit nul-character at the end so no need to explicitly try to add
>>> one there. You also don't need to have an explicit size between the
>>> square brackets since this is automatically calculated if you do
>>> initialization upon declaration. Why isn't this static? Why isn't it
>>> const? Would a simple define make more sense instead of a dedicated
>>> variable?
>>   I tried these but there are some warnings.
>>
>> #define BNEP_BRIDGE   "bnep"
>> static char bridge[] = "bnep";
>> static char *bridge = "bnep";
>>
>> ==10198== Warning: noted but unhandled ioctl 0x89a1 with no
>> size/direction hints
>> ==10198==    This could cause spurious value errors to appear.
>> ==10198==    See README_MISSING_SYSCALL_OR_IOCTL for guidance on
>> writing a proper wrapper.
> Is this from valgrind?
    Yes.
> If so, then I think it's fine to ignore it as it
> simply doesn't know the details of all ioctls. We get this kind of
> stuff for Bluetooth specific ioctls too. I.e. go with whatever is the
> simplest (probably the define).
  Ok, I will change to define and send you v2.

Regards,
Ravi.

^ permalink raw reply

* Re: [PATCH 1/4] android/pan: Register Network Access Point
From: Johan Hedberg @ 2014-01-07 10:18 UTC (permalink / raw)
  To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <52CBCF93.7060604@linux.intel.com>

Hi Ravi,

On Tue, Jan 07, 2014, Ravi kumar Veeramally wrote:
> >>@@ -49,7 +54,7 @@
> >>  static bdaddr_t adapter_addr;
> >>  GSList *devices = NULL;
> >>  uint8_t local_role = HAL_PAN_ROLE_NONE;
> >>-static uint32_t record_id = 0;
> >>+char bridge[5] = "bnep\0";
> >This last line raises several questions. Firstly, C-strings have an
> >implicit nul-character at the end so no need to explicitly try to add
> >one there. You also don't need to have an explicit size between the
> >square brackets since this is automatically calculated if you do
> >initialization upon declaration. Why isn't this static? Why isn't it
> >const? Would a simple define make more sense instead of a dedicated
> >variable?
> 
>  I tried these but there are some warnings.
> 
> #define BNEP_BRIDGE   "bnep"
> static char bridge[] = "bnep";
> static char *bridge = "bnep";
> 
> ==10198== Warning: noted but unhandled ioctl 0x89a1 with no
> size/direction hints
> ==10198==    This could cause spurious value errors to appear.
> ==10198==    See README_MISSING_SYSCALL_OR_IOCTL for guidance on
> writing a proper wrapper.

Is this from valgrind? If so, then I think it's fine to ignore it as it
simply doesn't know the details of all ioctls. We get this kind of
stuff for Bluetooth specific ioctls too. I.e. go with whatever is the
simplest (probably the define).

Johan

^ permalink raw reply

* Re: [PATCH 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-07  9:57 UTC (permalink / raw)
  To: linux-bluetooth, johan.hedberg
In-Reply-To: <20140107085930.GB9155@x220.p-661hnu-f1>

Hi Johan,

On 01/07/2014 10:59 AM, Johan Hedberg wrote:
> Hi Ravi,
>
> On Mon, Jan 06, 2014, Ravi kumar Veeramally wrote:
>> Register NAP server and adds bnep bridge. Removes bridge
>> on destroy call. Bridge mechanism is needed when device acting
>> as a server and listen for incoming connections.
>> ---
>>   android/pan.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 112 insertions(+), 4 deletions(-)
>>
>> diff --git a/android/pan.c b/android/pan.c
>> index 38e353d..93f712f 100644
>> --- a/android/pan.c
>> +++ b/android/pan.c
>> @@ -28,6 +28,11 @@
>>   #include <unistd.h>
>>   #include <fcntl.h>
>>   #include <glib.h>
>> +#include <sys/ioctl.h>
>> +#include <sys/socket.h>
>> +#include <sys/wait.h>
>> +#include <net/if.h>
>> +#include <linux/sockios.h>
>>   
>>   #include "btio/btio.h"
>>   #include "lib/bluetooth.h"
>> @@ -49,7 +54,7 @@
>>   static bdaddr_t adapter_addr;
>>   GSList *devices = NULL;
>>   uint8_t local_role = HAL_PAN_ROLE_NONE;
>> -static uint32_t record_id = 0;
>> +char bridge[5] = "bnep\0";
> This last line raises several questions. Firstly, C-strings have an
> implicit nul-character at the end so no need to explicitly try to add
> one there. You also don't need to have an explicit size between the
> square brackets since this is automatically calculated if you do
> initialization upon declaration. Why isn't this static? Why isn't it
> const? Would a simple define make more sense instead of a dedicated
> variable?

  I tried these but there are some warnings.

#define BNEP_BRIDGE   "bnep"
static char bridge[] = "bnep";
static char *bridge = "bnep";

==10198== Warning: noted but unhandled ioctl 0x89a1 with no 
size/direction hints
==10198==    This could cause spurious value errors to appear.
==10198==    See README_MISSING_SYSCALL_OR_IOCTL for guidance on writing 
a proper wrapper.

char bridge[5] = "bnep\0"; worked fine (yes, like you said static can be used).

Regards,
Ravi.


^ permalink raw reply

* Re: [PATCH 1/4] android/pan: Register Network Access Point
From: Johan Hedberg @ 2014-01-07  8:59 UTC (permalink / raw)
  To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <1389043592-5616-2-git-send-email-ravikumar.veeramally@linux.intel.com>

Hi Ravi,

On Mon, Jan 06, 2014, Ravi kumar Veeramally wrote:
> Register NAP server and adds bnep bridge. Removes bridge
> on destroy call. Bridge mechanism is needed when device acting
> as a server and listen for incoming connections.
> ---
>  android/pan.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 112 insertions(+), 4 deletions(-)
> 
> diff --git a/android/pan.c b/android/pan.c
> index 38e353d..93f712f 100644
> --- a/android/pan.c
> +++ b/android/pan.c
> @@ -28,6 +28,11 @@
>  #include <unistd.h>
>  #include <fcntl.h>
>  #include <glib.h>
> +#include <sys/ioctl.h>
> +#include <sys/socket.h>
> +#include <sys/wait.h>
> +#include <net/if.h>
> +#include <linux/sockios.h>
>  
>  #include "btio/btio.h"
>  #include "lib/bluetooth.h"
> @@ -49,7 +54,7 @@
>  static bdaddr_t adapter_addr;
>  GSList *devices = NULL;
>  uint8_t local_role = HAL_PAN_ROLE_NONE;
> -static uint32_t record_id = 0;
> +char bridge[5] = "bnep\0";

This last line raises several questions. Firstly, C-strings have an
implicit nul-character at the end so no need to explicitly try to add
one there. You also don't need to have an explicit size between the
square brackets since this is automatically calculated if you do
initialization upon declaration. Why isn't this static? Why isn't it
const? Would a simple define make more sense instead of a dedicated
variable?

Johan

^ permalink raw reply


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