Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCHv2 4/5] android/ipc-tester: Add test case to send cmd to registered service
From: Marcin Kraglak @ 2014-01-16  9:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389865538-28157-1-git-send-email-marcin.kraglak@tieto.com>

This will test sending command to previously registered service.
---
 android/test-ipc.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/android/test-ipc.c b/android/test-ipc.c
index 99f8559..930f9f4 100644
--- a/android/test-ipc.c
+++ b/android/test-ipc.c
@@ -46,6 +46,9 @@ struct test_data {
 	uint32_t expected_signal;
 	const struct hal_hdr *cmd;
 	uint16_t cmd_size;
+	uint8_t service;
+	const struct ipc_handler *handlers;
+	uint8_t handlers_size;
 };
 
 struct context {
@@ -74,11 +77,23 @@ static void context_quit(struct context *context)
 static gboolean cmd_watch(GIOChannel *io, GIOCondition cond,
 						gpointer user_data)
 {
+	struct context *context = user_data;
+	const struct test_data *test_data = context->data;
+	uint8_t buf[128];
+	int sk;
+
 	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
 		g_assert(FALSE);
 		return FALSE;
 	}
 
+	sk = g_io_channel_unix_get_fd(io);
+
+	g_assert(read(sk, buf, sizeof(buf)) == test_data->cmd_size);
+	g_assert(!memcmp(test_data->cmd, buf, test_data->cmd_size));
+
+	context_quit(context);
+
 	return TRUE;
 }
 
@@ -280,6 +295,17 @@ static gboolean send_cmd(gpointer user_data)
 	return FALSE;
 }
 
+static gboolean register_service(gpointer user_data)
+{
+	struct context *context = user_data;
+	const struct test_data *test_data = context->data;
+
+	ipc_register(test_data->service, test_data->handlers,
+						test_data->handlers_size);
+
+	return FALSE;
+}
+
 static void test_cmd(gconstpointer data)
 {
 	struct context *context = create_context(data);
@@ -293,6 +319,28 @@ static void test_cmd(gconstpointer data)
 	ipc_cleanup();
 }
 
+static void test_cmd_reg(gconstpointer data)
+{
+	struct context *context = create_context(data);
+	const struct test_data *test_data = context->data;
+
+	ipc_init();
+
+	g_idle_add(register_service, context);
+	g_idle_add(send_cmd, context);
+
+	execute_context(context);
+
+	ipc_unregister(test_data->service);
+
+	ipc_cleanup();
+}
+
+static void test_cmd_handler(const void *buf, uint16_t len)
+{
+	ipc_send_rsp(0, 1, 0);
+}
+
 static const struct test_data test_init_1 = {};
 
 static const struct hal_hdr test_cmd_1_hdr = {
@@ -307,6 +355,18 @@ static const struct test_data test_cmd_1 = {
 	.expected_signal = SIGTERM
 };
 
+static const struct ipc_handler cmd_handlers[] = {
+	{ test_cmd_handler, false, 0 }
+};
+
+static const struct test_data test_cmd_2 = {
+	.cmd = &test_cmd_1_hdr,
+	.cmd_size = sizeof(test_cmd_1_hdr),
+	.service = 0,
+	.handlers = cmd_handlers,
+	.handlers_size = 1
+};
+
 int main(int argc, char *argv[])
 {
 	g_test_init(&argc, &argv, NULL);
@@ -316,6 +376,8 @@ int main(int argc, char *argv[])
 
 	g_test_add_data_func("/android_ipc/init", &test_init_1, test_init);
 	g_test_add_data_func("/android_ipc/send_cmd_1", &test_cmd_1, test_cmd);
+	g_test_add_data_func("/android_ipc/send_cmd_2", &test_cmd_2,
+							test_cmd_reg);
 
 	return g_test_run();
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCHv2 3/5] android/ipc-tester: Add test case to send cmd
From: Marcin Kraglak @ 2014-01-16  9:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389865538-28157-1-git-send-email-marcin.kraglak@tieto.com>

This test case will check if ipc lib will raise SIGTERM
after sending cmd to not registered service.
---
 android/test-ipc.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/android/test-ipc.c b/android/test-ipc.c
index 6ac1175..99f8559 100644
--- a/android/test-ipc.c
+++ b/android/test-ipc.c
@@ -44,6 +44,8 @@
 
 struct test_data {
 	uint32_t expected_signal;
+	const struct hal_hdr *cmd;
+	uint16_t cmd_size;
 };
 
 struct context {
@@ -95,6 +97,7 @@ static gboolean connect_handler(GIOChannel *io, GIOCondition cond,
 						gpointer user_data)
 {
 	struct context *context = user_data;
+	const struct test_data *test_data = context->data;
 	GIOChannel *new_io;
 	GIOCondition watch_cond;
 	int sk;
@@ -126,7 +129,7 @@ static gboolean connect_handler(GIOChannel *io, GIOCondition cond,
 		context->cmd_io = new_io;
 	}
 
-	if (context->cmd_source && context->notif_source)
+	if (context->cmd_source && context->notif_source && !test_data->cmd)
 		context_quit(context);
 
 	return TRUE;
@@ -262,8 +265,48 @@ static void test_init(gconstpointer data)
 	ipc_cleanup();
 }
 
+static gboolean send_cmd(gpointer user_data)
+{
+	struct context *context = user_data;
+	const struct test_data *test_data = context->data;
+	int sk;
+
+	sk = g_io_channel_unix_get_fd(context->cmd_io);
+	g_assert(sk >= 0);
+
+	g_assert(write(sk, test_data->cmd, test_data->cmd_size) ==
+						test_data->cmd_size);
+
+	return FALSE;
+}
+
+static void test_cmd(gconstpointer data)
+{
+	struct context *context = create_context(data);
+
+	ipc_init();
+
+	g_idle_add(send_cmd, context);
+
+	execute_context(context);
+
+	ipc_cleanup();
+}
+
 static const struct test_data test_init_1 = {};
 
+static const struct hal_hdr test_cmd_1_hdr = {
+	.service_id = 0,
+	.opcode = 1,
+	.len = 0
+};
+
+static const struct test_data test_cmd_1 = {
+	.cmd = &test_cmd_1_hdr,
+	.cmd_size = sizeof(test_cmd_1_hdr),
+	.expected_signal = SIGTERM
+};
+
 int main(int argc, char *argv[])
 {
 	g_test_init(&argc, &argv, NULL);
@@ -272,6 +315,7 @@ int main(int argc, char *argv[])
 		__btd_log_init("*", 0);
 
 	g_test_add_data_func("/android_ipc/init", &test_init_1, test_init);
+	g_test_add_data_func("/android_ipc/send_cmd_1", &test_cmd_1, test_cmd);
 
 	return g_test_run();
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCHv2 2/5] android: Fix ipc cleanup
From: Marcin Kraglak @ 2014-01-16  9:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389865538-28157-1-git-send-email-marcin.kraglak@tieto.com>

Remove sources while cleanup. It will avoid receiving
events after cleanup.
---
 android/ipc.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/android/ipc.c b/android/ipc.c
index ed3ef3c..d6b96e3 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -45,6 +45,9 @@ static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
 static GIOChannel *cmd_io = NULL;
 static GIOChannel *notif_io = NULL;
 
+static guint cmd_watch = 0;
+static guint notif_watch = 0;
+
 int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
 						const void *buf, ssize_t len)
 {
@@ -192,11 +195,11 @@ static gboolean notif_connect_cb(GIOChannel *io, GIOCondition cond,
 
 	cond = G_IO_ERR | G_IO_HUP | G_IO_NVAL;
 
-	g_io_add_watch(io, cond, notif_watch_cb, NULL);
+	notif_watch = g_io_add_watch(io, cond, notif_watch_cb, NULL);
 
 	cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
 
-	g_io_add_watch(cmd_io, cond, cmd_watch_cb, NULL);
+	cmd_watch = g_io_add_watch(cmd_io, cond, cmd_watch_cb, NULL);
 
 	info("IPC: successfully connected");
 
@@ -232,12 +235,22 @@ void ipc_init(void)
 
 void ipc_cleanup(void)
 {
+	if (cmd_watch) {
+		g_source_remove(cmd_watch);
+		cmd_watch = 0;
+	}
+
 	if (cmd_io) {
 		g_io_channel_shutdown(cmd_io, TRUE, NULL);
 		g_io_channel_unref(cmd_io);
 		cmd_io = NULL;
 	}
 
+	if (notif_watch) {
+		g_source_remove(notif_watch);
+		notif_watch = 0;
+	}
+
 	if (notif_io) {
 		g_io_channel_shutdown(notif_io, TRUE, NULL);
 		g_io_channel_unref(notif_io);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCHv2 1/5] android: Add android ipc tester
From: Marcin Kraglak @ 2014-01-16  9:45 UTC (permalink / raw)
  To: linux-bluetooth

This tool will test ipc library. First test case will check
ipc_init() call.
---
 .gitignore          |   1 +
 android/Makefile.am |   8 ++
 android/test-ipc.c  | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 286 insertions(+)
 create mode 100644 android/test-ipc.c

diff --git a/.gitignore b/.gitignore
index ac76fe2..ddd562a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,3 +114,4 @@ android/bluetoothd
 android/haltest
 android/android-tester
 android/bluetoothd-snoop
+android/test-ipc
diff --git a/android/Makefile.am b/android/Makefile.am
index cd4a526..0c61317 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -117,6 +117,14 @@ android_android_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
 android_android_tester_LDFLAGS = -pthread -ldl
 
+noinst_PROGRAMS += android/test-ipc
+
+android_test_ipc_SOURCES = android/test-ipc.c \
+				src/shared/util.h src/shared/util.c \
+				src/log.h src/log.c \
+				android/ipc.c android/ipc.h
+android_test_ipc_LDADD = @GLIB_LIBS@
+
 plugin_LTLIBRARIES += android/audio.a2dp.default.la
 
 android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
diff --git a/android/test-ipc.c b/android/test-ipc.c
new file mode 100644
index 0000000..6ac1175
--- /dev/null
+++ b/android/test-ipc.c
@@ -0,0 +1,277 @@
+/*
+ *
+ *  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 <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/signalfd.h>
+
+#include <glib.h>
+#include "src/shared/util.h"
+#include "src/log.h"
+#include "android/hal-msg.h"
+#include "android/ipc.h"
+
+struct test_data {
+	uint32_t expected_signal;
+};
+
+struct context {
+	GMainLoop *main_loop;
+
+	int sk;
+
+	guint source;
+	guint cmd_source;
+	guint notif_source;
+
+	GIOChannel *cmd_io;
+	GIOChannel *notif_io;
+	GIOChannel *signal_io;
+
+	guint signal_source;
+
+	const struct test_data *data;
+};
+
+static void context_quit(struct context *context)
+{
+	g_main_loop_quit(context->main_loop);
+}
+
+static gboolean cmd_watch(GIOChannel *io, GIOCondition cond,
+						gpointer user_data)
+{
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_assert(FALSE);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean notif_watch(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_assert(FALSE);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean connect_handler(GIOChannel *io, GIOCondition cond,
+						gpointer user_data)
+{
+	struct context *context = user_data;
+	GIOChannel *new_io;
+	GIOCondition watch_cond;
+	int sk;
+
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_assert(FALSE);
+		return FALSE;
+	}
+
+	g_assert(!context->cmd_source || !context->notif_source);
+
+	sk = accept(context->sk, NULL, NULL);
+	g_assert(sk >= 0);
+
+	new_io = g_io_channel_unix_new(sk);
+
+	watch_cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+
+	if (context->cmd_source && !context->notif_source) {
+		context->notif_source = g_io_add_watch(new_io, watch_cond,
+							notif_watch, context);
+		g_assert(context->notif_source > 0);
+		context->notif_io = new_io;
+	}
+
+	if (!context->cmd_source) {
+		context->cmd_source = g_io_add_watch(new_io, watch_cond,
+							cmd_watch, context);
+		context->cmd_io = new_io;
+	}
+
+	if (context->cmd_source && context->notif_source)
+		context_quit(context);
+
+	return TRUE;
+}
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+							gpointer user_data)
+{
+	struct context *context = user_data;
+	const struct test_data *test_data = context->data;
+	struct signalfd_siginfo si;
+	ssize_t result;
+	int fd;
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+		return FALSE;
+
+	fd = g_io_channel_unix_get_fd(channel);
+
+	result = read(fd, &si, sizeof(si));
+	if (result != sizeof(si))
+		return FALSE;
+
+	g_assert(test_data->expected_signal == si.ssi_signo);
+	context_quit(context);
+	return TRUE;
+}
+
+static guint setup_signalfd(gpointer user_data)
+{
+	GIOChannel *channel;
+	guint source;
+	sigset_t mask;
+	int ret;
+	int fd;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGINT);
+	sigaddset(&mask, SIGTERM);
+
+	ret = sigprocmask(SIG_BLOCK, &mask, NULL);
+	g_assert(ret == 0);
+
+	fd = signalfd(-1, &mask, 0);
+	g_assert(fd >= 0);
+
+	channel = g_io_channel_unix_new(fd);
+
+	g_io_channel_set_close_on_unref(channel, TRUE);
+	g_io_channel_set_encoding(channel, NULL, NULL);
+	g_io_channel_set_buffered(channel, FALSE);
+
+	source = g_io_add_watch(channel,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				signal_handler, user_data);
+
+	g_io_channel_unref(channel);
+
+	return source;
+}
+
+static struct context *create_context(gconstpointer data)
+{
+	struct context *context = g_new0(struct context, 1);
+	struct sockaddr_un addr;
+	GIOChannel *io;
+	int ret, sk;
+
+	context->main_loop = g_main_loop_new(NULL, FALSE);
+	g_assert(context->main_loop);
+
+	context->signal_source = setup_signalfd(context);
+	g_assert(context->signal_source);
+
+	sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+	g_assert(sk >= 0);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+
+	memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
+
+	ret = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
+	g_assert(ret == 0);
+
+	ret = listen(sk, 5);
+	g_assert(ret == 0);
+
+	io = g_io_channel_unix_new(sk);
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+
+	context->source = g_io_add_watch(io,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				connect_handler, context);
+	g_assert(context->source > 0);
+
+	g_io_channel_unref(io);
+
+	context->sk = sk;
+	context->data = data;
+
+	return context;
+}
+
+static void execute_context(struct context *context)
+{
+	g_main_loop_run(context->main_loop);
+
+	g_io_channel_shutdown(context->notif_io, true, NULL);
+	g_io_channel_shutdown(context->cmd_io, true, NULL);
+	g_io_channel_unref(context->cmd_io);
+	g_io_channel_unref(context->notif_io);
+
+	g_source_remove(context->notif_source);
+	g_source_remove(context->signal_source);
+	g_source_remove(context->cmd_source);
+	g_source_remove(context->source);
+
+	g_main_loop_unref(context->main_loop);
+
+	g_free(context);
+}
+
+static void test_init(gconstpointer data)
+{
+	struct context *context = create_context(data);
+
+	ipc_init();
+
+	execute_context(context);
+
+	ipc_cleanup();
+}
+
+static const struct test_data test_init_1 = {};
+
+int main(int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	if (g_test_verbose())
+		__btd_log_init("*", 0);
+
+	g_test_add_data_func("/android_ipc/init", &test_init_1, test_init);
+
+	return g_test_run();
+}
-- 
1.8.3.1


^ permalink raw reply related

* Re: [PATCH] Bluetooth: Queue incoming ACL data until BT_CONNECTED state is reached
From: Johan Hedberg @ 2014-01-16  8:53 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <BB667CD7-90B1-4D87-8647-F59CB35A258B@holtmann.org>

Hi Marcel,

On Wed, Jan 15, 2014, Marcel Holtmann wrote:
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -63,6 +63,8 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
> > static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
> > 		     struct sk_buff_head *skbs, u8 event);
> > 
> > +static void process_pending_rx(struct work_struct *work);
> > +
> 
> do we really need this forward declaration?

Believe me I hate forward declarations just as much as you do. Either
this function or then l2cap_recv_frame must be forward declared unless
you want to move the following functions further down in l2cap_core.c:

l2cap_conn_add()
l2cap_chan_connect()
l2cap_connect_cfm()

The last two depend on l2cap_conn_add() which in turn depends on
process_pending_rx(). It's a fairly simple patch looking like this (two
more lines removed because the stat includes removing the forward
declatiation - I'd of course order the patches the other way around when
I send them):

 net/bluetooth/l2cap_core.c | 430 ++++++++++++++++++++--------------------
 1 file changed, 214 insertions(+), 216 deletions(-)

Doing this however means e.g. that l2cap_connect_cfm() isn't any more
grouped in the same place as connect_ind() and the other callbacks. So
I'm not sure if you wanna move those also downwards (making the patch
bigger), not worry about it, or just stick to the forward declaration.

Johan

> > +static void process_pending_rx(struct work_struct *work)
> > +{
> > +	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
> > +					       pending_rx_work);
> > +
> > +	BT_DBG("");
> > +
> > +	while (!skb_queue_empty(&conn->pending_rx)) {
> > +		struct sk_buff *skb;
> > +
> > +		skb = skb_dequeue(&conn->pending_rx);
> > +
> > +		l2cap_recv_frame(conn, skb);
> > +	}
> > +}
> > +
> 
> I realize we have done this skb_queue_empty check and then skb_dequeue
> a bit, but that seems a little bit pointless.
> 
> skb_dequeue is taking a spinlock, but even then checking for empty
> first and then dequeuing it seems more complicated that needed here.
> We could just dequeue it check if skb == NULL.
> 
> 	while (1) {
> 		struct sk_buff *skb;
> 
> 		skb = sbk_dequeue(&conn->pending_rx);
> 		if (!skb)
> 			break;
> 
> 		l2cap_recv_frame(conn, skb);
> 	}

I've fixed this in my v2.

> And we have similar things in l2cap_streaming_send, l2cap_chan_send
> and l2cap_le_credits. I get the feeling we should change all of these.

Sure, I'll send patches for those at some point.

Johan

^ permalink raw reply

* Re: [PATCH 2/5] android: Fix ipc cleanup
From: Szymon Janc @ 2014-01-16  8:41 UTC (permalink / raw)
  To: Marcin Kraglak; +Cc: linux-bluetooth
In-Reply-To: <1389813150-16914-2-git-send-email-marcin.kraglak@tieto.com>

Hi Marcin,

On Wednesday 15 of January 2014 20:12:27 Marcin Kraglak wrote:
> Remove sources while cleanup. It will avoid receiving
> events after cleanup.
> ---
>  android/ipc.c | 17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/android/ipc.c b/android/ipc.c
> index ed3ef3c..4277bfe 100644
> --- a/android/ipc.c
> +++ b/android/ipc.c
> @@ -45,6 +45,9 @@ static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
>  static GIOChannel *cmd_io = NULL;
>  static GIOChannel *notif_io = NULL;
>  
> +static guint cmd_id;
> +static guint notif_id;

Please name it cmd_watch and notif_watch. Also explicitly initialize them to 0 here.

> +
>  int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
>  						const void *buf, ssize_t len)
>  {
> @@ -192,11 +195,11 @@ static gboolean notif_connect_cb(GIOChannel *io, GIOCondition cond,
>  
>  	cond = G_IO_ERR | G_IO_HUP | G_IO_NVAL;
>  
> -	g_io_add_watch(io, cond, notif_watch_cb, NULL);
> +	notif_id = g_io_add_watch(io, cond, notif_watch_cb, NULL);
>  
>  	cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
>  
> -	g_io_add_watch(cmd_io, cond, cmd_watch_cb, NULL);
> +	cmd_id = g_io_add_watch(cmd_io, cond, cmd_watch_cb, NULL);
>  
>  	info("IPC: successfully connected");
>  
> @@ -232,12 +235,22 @@ void ipc_init(void)
>  
>  void ipc_cleanup(void)
>  {
> +	if (cmd_id) {
> +		g_source_remove(cmd_id);
> +		cmd_id = 0;
> +	}
> +
>  	if (cmd_io) {
>  		g_io_channel_shutdown(cmd_io, TRUE, NULL);
>  		g_io_channel_unref(cmd_io);
>  		cmd_io = NULL;
>  	}
>  
> +	if (notif_id) {
> +		g_source_remove(notif_id);
> +		notif_id = 0;
> +	}
> +
>  	if (notif_io) {
>  		g_io_channel_shutdown(notif_io, TRUE, NULL);
>  		g_io_channel_unref(notif_io);
> 

-- 
Best regards, 
Szymon Janc

^ permalink raw reply

* [PATCHv4 8/8] android/ipc-tester: Add more cases for malformed data
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch adds tests for more types of possible data malformations.
---
 android/ipc-tester.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index f4321ce..3f4db82 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -577,6 +577,48 @@ static const struct generic_data malformed_data = {
 	.num_services = 1,
 };
 
+static const struct generic_data malformed_data2 = {
+	.ipc_data = {
+		/* use proper msg */
+		.buffer = &register_bt_msg,
+		/* but write incomplete */
+		.len = sizeof(register_bt_msg) - 1,
+	},
+	.init_services = {HAL_SERVICE_ID_BLUETOOTH},
+	.num_services = 1,
+};
+
+struct malformed_data3_struct {
+	struct regmod_msg valid_msg;
+	int redundant_data;
+}  __attribute__((packed));
+
+static struct malformed_data3_struct malformed_data3_msg = {
+	/* valid register service message */
+	.valid_msg = {
+		.header = {
+			.service_id = HAL_SERVICE_ID_CORE,
+			.opcode = HAL_OP_REGISTER_MODULE,
+			.len = sizeof(struct hal_cmd_register_module),
+			},
+		.cmd = {
+			.service_id = HAL_SERVICE_ID_CORE,
+			},
+	},
+	/* plus redundant data */
+	. redundant_data = 666,
+};
+
+static const struct generic_data malformed_data3 = {
+	.ipc_data = {
+		/* use malformed msg */
+		.buffer = &malformed_data3_msg,
+		.len = sizeof(malformed_data3_msg),
+	},
+	.init_services = {HAL_SERVICE_ID_BLUETOOTH},
+	.num_services = 1,
+};
+
 struct hal_hdr enable_unknown_service_hdr = {
 	.service_id = HAL_SERVICE_ID_MAX + 1,
 	.opcode = HAL_OP_REGISTER_MODULE,
@@ -653,6 +695,10 @@ int main(int argc, char *argv[])
 						setup, ipc_send_tc, teardown);
 	test_bredrle("Malformed data (wrong payload declared)", &malformed_data,
 						setup, ipc_send_tc, teardown);
+	test_bredrle("Malformed data2 (undersized msg)", &malformed_data2,
+						setup, ipc_send_tc, teardown);
+	test_bredrle("Malformed data3 (oversized msg)", &malformed_data3,
+						setup, ipc_send_tc, teardown);
 	test_bredrle("Invalid service", &enable_unknown_service_data,
 						setup, ipc_send_tc, teardown);
 	test_bredrle("Enable unregistered service",
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 7/8] android/ipc-tester: Add basic test cases for IPC's daemon site
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch add first few test cases checking for proper daemon
termination in case of receiving invalid IPC data.
---
 android/ipc-tester.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 117 insertions(+), 3 deletions(-)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 12ab85b..f4321ce 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -532,11 +532,113 @@ static void ipc_send_tc(const void *data)
 							3, user, g_free); \
 	} while (0)
 
-static const struct generic_data dummy_data = {
+struct regmod_msg register_bt_msg = {
+	.header = {
+		.service_id = HAL_SERVICE_ID_CORE,
+		.opcode = HAL_OP_REGISTER_MODULE,
+		.len = sizeof(struct hal_cmd_register_module),
+		},
+	.cmd = {
+		.service_id = HAL_SERVICE_ID_CORE,
+		},
+};
+
+static const struct generic_data too_small_data = {
 	.ipc_data = {
-		.buffer = "",
+		/* valid header and payload */
+		.buffer = &register_bt_msg,
+		/* but write only incomplete header */
 		.len = 1,
 	},
+	.init_services = {},
+	.num_services = 0,
+};
+
+struct regmod_msg register_bt_malformed_size_msg = {
+	.header = {
+		.service_id = HAL_SERVICE_ID_CORE,
+		.opcode = HAL_OP_REGISTER_MODULE,
+		/* wrong payload size declared */
+		.len = sizeof(struct hal_cmd_register_module) - 1,
+		},
+	.cmd = {
+		.service_id = HAL_SERVICE_ID_CORE,
+		},
+};
+
+static const struct generic_data malformed_data = {
+	.ipc_data = {
+		/* use malformed msg - wrong size declared */
+		.buffer = &register_bt_malformed_size_msg,
+		/* but write proper size */
+		.len = sizeof(register_bt_malformed_size_msg),
+	},
+	.init_services = {HAL_SERVICE_ID_BLUETOOTH},
+	.num_services = 1,
+};
+
+struct hal_hdr enable_unknown_service_hdr = {
+	.service_id = HAL_SERVICE_ID_MAX + 1,
+	.opcode = HAL_OP_REGISTER_MODULE,
+	.len = 0,
+};
+
+static const struct generic_data enable_unknown_service_data = {
+	.ipc_data = {
+		/* enable invalid service */
+		.buffer = &enable_unknown_service_hdr,
+		.len = sizeof(enable_unknown_service_hdr),
+	},
+	.init_services = {HAL_SERVICE_ID_BLUETOOTH},
+	.num_services = 1,
+};
+
+struct hal_hdr enable_bt_service_hdr = {
+	.service_id = HAL_SERVICE_ID_BLUETOOTH,
+	.opcode = HAL_OP_ENABLE,
+	.len = 0,
+};
+
+static const struct generic_data enable_unregistered_service_data = {
+	.ipc_data = {
+		/* valid msg */
+		.buffer = &enable_bt_service_hdr,
+		/* send the whole thing */
+		.len = sizeof(enable_bt_service_hdr),
+	},
+	/* but don't register it before enabling */
+	.init_services = {},
+	.num_services = 0,
+};
+
+struct hal_hdr invalid_opcode_hdr = {
+	.service_id = HAL_SERVICE_ID_BLUETOOTH,
+	.opcode = 0x16,
+	.len = 0,
+};
+
+static const struct generic_data invalid_opcode_data = {
+	.ipc_data = {
+		/* valid msg */
+		.buffer = &invalid_opcode_hdr,
+		/* send the whole thing */
+		.len = sizeof(invalid_opcode_hdr),
+	},
+	.init_services = {HAL_SERVICE_ID_BLUETOOTH},
+	.num_services = 1,
+};
+
+struct hal_hdr invalid_msg_size_hdr = {
+	.service_id = HAL_SERVICE_ID_BLUETOOTH,
+	.opcode = HAL_OP_CREATE_BOND,
+	.len = 0,
+};
+
+static const struct generic_data invalid_msg_size_data = {
+	.ipc_data = {
+		.buffer = &invalid_msg_size_hdr,
+		.len = sizeof(invalid_msg_size_hdr),
+	},
 	.init_services = {HAL_SERVICE_ID_BLUETOOTH},
 	.num_services = 1,
 };
@@ -547,7 +649,19 @@ int main(int argc, char *argv[])
 
 	tester_init(&argc, &argv);
 
-	test_bredrle("Test Dummy", &dummy_data, setup, ipc_send_tc, teardown);
+	test_bredrle("Too small data", &too_small_data,
+						setup, ipc_send_tc, teardown);
+	test_bredrle("Malformed data (wrong payload declared)", &malformed_data,
+						setup, ipc_send_tc, teardown);
+	test_bredrle("Invalid service", &enable_unknown_service_data,
+						setup, ipc_send_tc, teardown);
+	test_bredrle("Enable unregistered service",
+					&enable_unregistered_service_data,
+					setup, ipc_send_tc, teardown);
+	test_bredrle("Invalid opcode", &invalid_opcode_data,
+						setup, ipc_send_tc, teardown);
+	test_bredrle("Invalid msg size for opcode", &invalid_msg_size_data,
+						setup, ipc_send_tc, teardown);
 
 	return tester_run();
 }
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 6/8] android/ipc-tester: Register services
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch adds basic bluetooth service registration during setup procedure.
Without this daemon would reject commands for not registered services.
---
 android/ipc-tester.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 0a04fb7..12ab85b 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -396,13 +396,53 @@ static gboolean check_for_daemon(gpointer user_data)
 	return false;
 }
 
+struct regmod_msg {
+	struct hal_hdr header;
+	struct hal_cmd_register_module cmd;
+} __attribute__((packed));
+
+static bool setup_module(int service_id)
+{
+	struct hal_hdr response;
+	struct hal_hdr expected_response;
+
+	struct regmod_msg btmodule_msg = {
+		.header = {
+			.service_id = HAL_SERVICE_ID_CORE,
+			.opcode = HAL_OP_REGISTER_MODULE,
+			.len = sizeof(struct hal_cmd_register_module),
+			},
+		.cmd = {
+			.service_id = service_id,
+			},
+	};
+
+	if (write(cmd_sk, &btmodule_msg, sizeof(btmodule_msg)) < 0)
+		goto fail;
+
+	if (read(cmd_sk, &response, sizeof(response)) < 0)
+		goto fail;
+
+	expected_response = btmodule_msg.header;
+	expected_response.len = 0;
+
+	if (memcmp(&response, &expected_response, sizeof(response)) == 0)
+		return true;
+
+fail:
+	tester_warn("Module registration failed.");
+	return false;
+}
+
 static void setup(const void *data)
 {
+	const struct generic_data *generic_data = data;
 	struct test_data *test_data = tester_get_data();
 	int signal_fd[2];
 	char buf[1024];
 	pid_t pid;
 	int len;
+	unsigned int i;
 
 	if (pipe(signal_fd)) {
 		tester_setup_failed();
@@ -446,9 +486,15 @@ static void setup(const void *data)
 		return;
 	}
 
-	/* TODO: register modules */
+	tester_print("Will init %d services.", generic_data->num_services);
+
+	for (i = 0; i < generic_data->num_services; i++)
+		if (!setup_module(generic_data->init_services[i]))
+			tester_setup_failed();
 
 	test_data->setup_done = true;
+
+	tester_setup_complete();
 }
 
 static void teardown(const void *data)
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 5/8] android/ipc-tester: Add sending test data with ipc
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch adds some data structures used to send data with ipc during test setup
and run stage.
---
 android/ipc-tester.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 6ba6e1f..0a04fb7 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -55,6 +55,18 @@ struct test_data {
 	bool setup_done;
 };
 
+struct ipc_data {
+	void *buffer;
+	size_t len;
+};
+
+struct generic_data {
+	struct ipc_data ipc_data;
+
+	unsigned int num_services;
+	int init_services[];
+};
+
 #define CONNECT_TIMEOUT (5 * 1000)
 #define SERVICE_NAME "bluetoothd"
 
@@ -453,6 +465,13 @@ static void teardown(const void *data)
 
 static void ipc_send_tc(const void *data)
 {
+	const struct generic_data *generic_data = data;
+	const struct ipc_data *ipc_data = &generic_data->ipc_data;
+
+	if (ipc_data->len) {
+		if (write(cmd_sk, ipc_data->buffer, ipc_data->len) < 0)
+			tester_test_failed();
+	}
 }
 
 #define test_bredrle(name, data, test_setup, test, test_teardown) \
@@ -467,13 +486,22 @@ static void ipc_send_tc(const void *data)
 							3, user, g_free); \
 	} while (0)
 
+static const struct generic_data dummy_data = {
+	.ipc_data = {
+		.buffer = "",
+		.len = 1,
+	},
+	.init_services = {HAL_SERVICE_ID_BLUETOOTH},
+	.num_services = 1,
+};
+
 int main(int argc, char *argv[])
 {
 	snprintf(exec_dir, sizeof(exec_dir), "%s", dirname(argv[0]));
 
 	tester_init(&argc, &argv);
 
-	test_bredrle("Test Dummy", NULL, setup, ipc_send_tc, teardown);
+	test_bredrle("Test Dummy", &dummy_data, setup, ipc_send_tc, teardown);
 
 	return tester_run();
 }
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 4/8] android/ipc-tester: Add daemon shutdown handler
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

Handle daemon shutdown asynchronously.
---
 android/ipc-tester.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index b76be32..6ba6e1f 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -52,6 +52,7 @@ struct test_data {
 	struct hciemu *hciemu;
 	enum hciemu_type hciemu_type;
 	pid_t bluetoothd_pid;
+	bool setup_done;
 };
 
 #define CONNECT_TIMEOUT (5 * 1000)
@@ -359,6 +360,30 @@ static void cleanup_ipc(void)
 	cmd_sk = -1;
 }
 
+static gboolean check_for_daemon(gpointer user_data)
+{
+	int status;
+	struct test_data *data = user_data;
+
+	if ((waitpid(data->bluetoothd_pid, &status, WNOHANG))
+							!= data->bluetoothd_pid)
+		return true;
+
+	if (data->setup_done) {
+		if (WIFEXITED(status) &&
+				(WEXITSTATUS(status) == EXIT_SUCCESS)) {
+			tester_test_passed();
+			return false;
+		}
+		tester_test_failed();
+	} else {
+		tester_setup_failed();
+	}
+
+	tester_warn("Unexpected Daemon shutdown with status %d", status);
+	return false;
+}
+
 static void setup(const void *data)
 {
 	struct test_data *test_data = tester_get_data();
@@ -399,6 +424,10 @@ static void setup(const void *data)
 		tester_setup_failed();
 		return;
 	}
+
+	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, check_for_daemon, test_data,
+									NULL);
+
 	if (!init_ipc()) {
 		tester_warn("Cannot initialize IPC mechanism!");
 		tester_setup_failed();
@@ -406,6 +435,8 @@ static void setup(const void *data)
 	}
 
 	/* TODO: register modules */
+
+	test_data->setup_done = true;
 }
 
 static void teardown(const void *data)
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 3/8] android/ipc-tester: Add IPC initialization
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch adds IPC mechanism initialization.
The deamon is being started and IPC socket connection is established.
---
 android/ipc-tester.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index d920ccf..b76be32 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -23,6 +23,8 @@
 
 #include <stdlib.h>
 #include <unistd.h>
+#include <errno.h>
+#include <poll.h>
 
 #include <sys/socket.h>
 #include <sys/types.h>
@@ -38,6 +40,8 @@
 #include "src/shared/mgmt.h"
 #include "src/shared/hciemu.h"
 
+#include "hal-msg.h"
+#include <cutils/properties.h>
 
 #define WAIT_FOR_SIGNAL_TIME 2 /* in seconds */
 #define EMULATOR_SIGNAL "emulator_started"
@@ -50,8 +54,14 @@ struct test_data {
 	pid_t bluetoothd_pid;
 };
 
+#define CONNECT_TIMEOUT (5 * 1000)
+#define SERVICE_NAME "bluetoothd"
+
 static char exec_dir[PATH_MAX + 1];
 
+static int cmd_sk = -1;
+static int notif_sk = -1;
+
 static void read_info_callback(uint8_t status, uint16_t length,
 					const void *param, void *user_data)
 {
@@ -246,6 +256,109 @@ failed:
 	close(fd);
 }
 
+static int accept_connection(int sk)
+{
+	int err;
+	struct pollfd pfd;
+	int new_sk;
+
+	memset(&pfd, 0 , sizeof(pfd));
+	pfd.fd = sk;
+	pfd.events = POLLIN;
+
+	err = poll(&pfd, 1, CONNECT_TIMEOUT);
+	if (err < 0) {
+		err = errno;
+		tester_warn("Failed to poll: %d (%s)", err, strerror(err));
+		return -errno;
+	}
+
+	if (err == 0) {
+		tester_warn("bluetoothd connect timeout");
+		return -errno;
+	}
+
+	new_sk = accept(sk, NULL, NULL);
+	if (new_sk < 0) {
+		err = errno;
+		tester_warn("Failed to accept socket: %d (%s)",
+							err, strerror(err));
+		return -errno;
+	}
+
+	return new_sk;
+}
+
+static bool init_ipc(void)
+{
+	struct sockaddr_un addr;
+
+	int sk;
+	int err;
+
+	sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+	if (sk < 0) {
+		err = errno;
+		tester_warn("Failed to create socket: %d (%s)", err,
+							strerror(err));
+		return false;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+
+	memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = errno;
+		tester_warn("Failed to bind socket: %d (%s)", err,
+								strerror(err));
+		close(sk);
+		return false;
+	}
+
+	if (listen(sk, 2) < 0) {
+		err = errno;
+		tester_warn("Failed to listen on socket: %d (%s)", err,
+								strerror(err));
+		close(sk);
+		return false;
+	}
+
+	/* Start Android Bluetooth daemon service */
+	if (property_set("ctl.start", SERVICE_NAME) < 0) {
+		tester_warn("Failed to start service %s", SERVICE_NAME);
+		close(sk);
+		return false;
+	}
+
+	cmd_sk = accept_connection(sk);
+	if (cmd_sk < 0) {
+		close(sk);
+		return false;
+	}
+
+	notif_sk = accept_connection(sk);
+	if (notif_sk < 0) {
+		close(sk);
+		close(cmd_sk);
+		cmd_sk = -1;
+		return false;
+	}
+
+	tester_print("bluetoothd connected");
+
+	close(sk);
+
+	return true;
+}
+
+static void cleanup_ipc(void)
+{
+	close(cmd_sk);
+	cmd_sk = -1;
+}
+
 static void setup(const void *data)
 {
 	struct test_data *test_data = tester_get_data();
@@ -286,12 +399,21 @@ static void setup(const void *data)
 		tester_setup_failed();
 		return;
 	}
+	if (!init_ipc()) {
+		tester_warn("Cannot initialize IPC mechanism!");
+		tester_setup_failed();
+		return;
+	}
+
+	/* TODO: register modules */
 }
 
 static void teardown(const void *data)
 {
 	struct test_data *test_data = tester_get_data();
 
+	cleanup_ipc();
+
 	if (test_data->bluetoothd_pid)
 		waitpid(test_data->bluetoothd_pid, NULL, 0);
 
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 2/8] android/ipc-tester: Run daemon in separate process
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch adds new process waiting to run daemon when needed.
---
 android/ipc-tester.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 123 insertions(+), 1 deletion(-)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 9a1b4b0..d920ccf 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -21,8 +21,14 @@
  *
  */
 
+#include <stdlib.h>
 #include <unistd.h>
 
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <libgen.h>
 #include <glib.h>
 
 #include "lib/bluetooth.h"
@@ -33,13 +39,19 @@
 #include "src/shared/hciemu.h"
 
 
+#define WAIT_FOR_SIGNAL_TIME 2 /* in seconds */
+#define EMULATOR_SIGNAL "emulator_started"
+
 struct test_data {
 	struct mgmt *mgmt;
 	uint16_t mgmt_index;
 	struct hciemu *hciemu;
 	enum hciemu_type hciemu_type;
+	pid_t bluetoothd_pid;
 };
 
+static char exec_dir[PATH_MAX + 1];
+
 static void read_info_callback(uint8_t status, uint16_t length,
 					const void *param, void *user_data)
 {
@@ -168,13 +180,121 @@ static void test_post_teardown(const void *data)
 	test_data->hciemu = NULL;
 }
 
+static void bluetoothd_start(int hci_index)
+{
+	char prg_name[PATH_MAX + 1];
+	char index[8];
+	char *prg_argv[4];
+
+	snprintf(prg_name, sizeof(prg_name), "%s/%s", exec_dir, "bluetoothd");
+	snprintf(index, sizeof(index), "%d", hci_index);
+
+	prg_argv[0] = prg_name;
+	prg_argv[1] = "-i";
+	prg_argv[2] = index;
+	prg_argv[3] = NULL;
+
+	if (!tester_use_debug())
+		fclose(stderr);
+
+	execve(prg_argv[0], prg_argv, NULL);
+}
+
+static void emulator(int pipe, int hci_index)
+{
+	static const char SYSTEM_SOCKET_PATH[] = "\0android_system";
+	char buf[1024];
+	struct sockaddr_un addr;
+	struct timeval tv;
+	int fd;
+	ssize_t len;
+
+	fd = socket(PF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (fd < 0)
+		goto failed;
+
+	tv.tv_sec = WAIT_FOR_SIGNAL_TIME;
+	tv.tv_usec = 0;
+	setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	memcpy(addr.sun_path, SYSTEM_SOCKET_PATH, sizeof(SYSTEM_SOCKET_PATH));
+
+	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("Failed to bind system socket");
+		goto failed;
+	}
+
+	len = write(pipe, EMULATOR_SIGNAL, sizeof(EMULATOR_SIGNAL));
+
+	if (len != sizeof(EMULATOR_SIGNAL))
+		goto failed;
+
+	memset(buf, 0, sizeof(buf));
+
+	len = read(fd, buf, sizeof(buf));
+	if (len <= 0 || (strcmp(buf, "ctl.start=bluetoothd")))
+		goto failed;
+
+	close(pipe);
+	close(fd);
+	bluetoothd_start(hci_index);
+
+failed:
+	close(pipe);
+	close(fd);
+}
+
 static void setup(const void *data)
 {
-	tester_setup_failed();
+	struct test_data *test_data = tester_get_data();
+	int signal_fd[2];
+	char buf[1024];
+	pid_t pid;
+	int len;
+
+	if (pipe(signal_fd)) {
+		tester_setup_failed();
+		return;
+	}
+
+	pid = fork();
+
+	if (pid < 0) {
+		close(signal_fd[0]);
+		close(signal_fd[1]);
+		tester_setup_failed();
+		return;
+	}
+
+	if (pid == 0) {
+		if (!tester_use_debug())
+			fclose(stderr);
+
+		close(signal_fd[0]);
+		emulator(signal_fd[1], test_data->mgmt_index);
+		exit(0);
+	}
+
+	close(signal_fd[1]);
+	test_data->bluetoothd_pid = pid;
+
+	len = read(signal_fd[0], buf, sizeof(buf));
+	if (len <= 0 || (strcmp(buf, EMULATOR_SIGNAL))) {
+		close(signal_fd[0]);
+		tester_setup_failed();
+		return;
+	}
 }
 
 static void teardown(const void *data)
 {
+	struct test_data *test_data = tester_get_data();
+
+	if (test_data->bluetoothd_pid)
+		waitpid(test_data->bluetoothd_pid, NULL, 0);
+
 	tester_teardown_complete();
 }
 
@@ -196,6 +316,8 @@ static void ipc_send_tc(const void *data)
 
 int main(int argc, char *argv[])
 {
+	snprintf(exec_dir, sizeof(exec_dir), "%s", dirname(argv[0]));
+
 	tester_init(&argc, &argv);
 
 	test_bredrle("Test Dummy", NULL, setup, ipc_send_tc, teardown);
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 1/8] android/ipc-tester: Skeleton for ipc negative tester
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389861512-2326-1-git-send-email-jakub.tyszkowski@tieto.com>

Add skeleton for ipc negative testing.
---
 .gitignore           |   1 +
 android/Makefile.am  |  17 +++++
 android/ipc-tester.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 222 insertions(+)
 create mode 100644 android/ipc-tester.c

diff --git a/.gitignore b/.gitignore
index ac76fe2..73a68e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -113,4 +113,5 @@ android/system-emulator
 android/bluetoothd
 android/haltest
 android/android-tester
+android/ipc-tester
 android/bluetoothd-snoop
diff --git a/android/Makefile.am b/android/Makefile.am
index cd4a526..fb632d4 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -119,6 +119,23 @@ android_android_tester_LDFLAGS = -pthread -ldl
 
 plugin_LTLIBRARIES += android/audio.a2dp.default.la
 
+noinst_PROGRAMS += android/ipc-tester
+
+android_ipc_tester_SOURCES = emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				src/shared/io.h src/shared/io-glib.c \
+				src/shared/queue.h src/shared/queue.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 \
+				android/hal-utils.h android/hal-utils.c \
+				android/ipc-tester.c
+
+android_ipc_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+
+android_ipc_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
 android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
 					android/hal-audio.c \
 					android/hardware/audio.h \
diff --git a/android/ipc-tester.c b/android/ipc-tester.c
new file mode 100644
index 0000000..9a1b4b0
--- /dev/null
+++ b/android/ipc-tester.c
@@ -0,0 +1,204 @@
+/*
+ *
+ *  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
+ *
+ */
+
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.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;
+};
+
+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();
+		return;
+	}
+
+	tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *data)
+{
+	struct test_data *test_data = tester_get_data();
+
+	if (!tester_use_debug())
+		fclose(stderr);
+
+	test_data->mgmt = mgmt_new_default();
+	if (!test_data->mgmt) {
+		tester_warn("Failed to setup management interface");
+		tester_pre_setup_failed();
+		return;
+	}
+
+	mgmt_send(test_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 *data)
+{
+	struct test_data *test_data = tester_get_data();
+
+	hciemu_unref(test_data->hciemu);
+	test_data->hciemu = NULL;
+}
+
+static void setup(const void *data)
+{
+	tester_setup_failed();
+}
+
+static void teardown(const void *data)
+{
+	tester_teardown_complete();
+}
+
+static void ipc_send_tc(const void *data)
+{
+}
+
+#define test_bredrle(name, data, test_setup, test, test_teardown) \
+	do { \
+		struct test_data *user; \
+		user = g_malloc0(sizeof(struct test_data)); \
+		if (!user) \
+			break; \
+		user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+		tester_add_full(name, data, test_pre_setup, test_setup, \
+				test, test_teardown, test_post_teardown, \
+							3, user, g_free); \
+	} while (0)
+
+int main(int argc, char *argv[])
+{
+	tester_init(&argc, &argv);
+
+	test_bredrle("Test Dummy", NULL, setup, ipc_send_tc, teardown);
+
+	return tester_run();
+}
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv4 0/8] IPC negative tester
From: Jakub Tyszkowski @ 2014-01-16  8:38 UTC (permalink / raw)
  To: linux-bluetooth

Following patchset adds IPC negative tester framework with few test cases
checking IPC's behaviour on daemon side. Expected daemon's behaviour is to
shut down gracefully in case of receiving invalid IPC data.

v2 changes:
  * fixed few indentation issues
  * fixed missing __attribute__((packed))
  * fixed amount of data written for 'malformed data' test case
  * fixed opcode for 'invalid service' test case
  * added patch(8) with more 'malformed data' cases

v3 changes:
  * changed license to GPL
  * changed 'ipc-negative-tester' name to 'ipc-tester'

v4 changes:
  * fixed typo in first test case and last commit's message
  * fixed daemon shutdown handler function

Jakub Tyszkowski (8):
  android/ipc-tester: Skeleton for ipc negative tester
  android/ipc-tester: Run daemon in separate process
  android/ipc-tester: Add IPC initialization
  android/ipc-tester: Add daemon shutdown handler
  android/ipc-tester: Add sending test data with ipc
  android/ipc-tester: Register services
  android/ipc-tester: Add basic test cases for IPC's daemon site
  android/ipc-tester: Add more cases for malformed data

 .gitignore           |   1 +
 android/Makefile.am  |  17 ++
 android/ipc-tester.c | 713 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 731 insertions(+)
 create mode 100644 android/ipc-tester.c

--
1.8.5.2


^ permalink raw reply

* Re: [PATCH v2 1/5] Bluetooth: Track Secure Connections support of remote devices
From: Johan Hedberg @ 2014-01-16  8:38 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1389854262-62467-1-git-send-email-marcel@holtmann.org>

Hi Marcel,

On Wed, Jan 15, 2014, Marcel Holtmann wrote:
> It is important to know if Secure Connections support has been enabled
> for a given remote device. The information is provided in the remote
> host features page. So track this information and provide a simple
> helper function to extract the status.
> 
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
>  include/net/bluetooth/hci_core.h | 8 ++++++++
>  net/bluetooth/hci_event.c        | 3 +++
>  2 files changed, 11 insertions(+)

All patches in this set have been applied to bluetooth-next. Thanks.

Johan

^ permalink raw reply

* [PATCH v2] Bluetooth: Queue incoming ACL data until BT_CONNECTED state is reached
From: johan.hedberg @ 2014-01-16  8:33 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds a queue for incoming L2CAP data that's received before
l2cap_connect_cfm is called and processes the data once
l2cap_connect_cfm is called. This way we ensure that we have e.g. all
remote features before processing L2CAP signaling data (which is very
important for making the correct security decisions).

The processing of the pending rx data needs to be done through
queue_work since unlike l2cap_recv_acldata, l2cap_connect_cfm is called
with the hci_dev lock held which could cause potential deadlocks.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
v2: Updated to avoid call to skb_queue_empty()

 include/net/bluetooth/l2cap.h |  3 +++
 net/bluetooth/l2cap_core.c    | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index dbc4a89984ca..40e15cd948c1 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -623,6 +623,9 @@ struct l2cap_conn {
 	__u32			rx_len;
 	__u8			tx_ident;
 
+	struct sk_buff_head	pending_rx;
+	struct work_struct	pending_rx_work;
+
 	__u8			disc_reason;
 
 	struct delayed_work	security_timer;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b0ad2c752d73..001195968f58 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -63,6 +63,8 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
 static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
 		     struct sk_buff_head *skbs, u8 event);
 
+static void process_pending_rx(struct work_struct *work);
+
 static inline __u8 bdaddr_type(struct hci_conn *hcon, __u8 type)
 {
 	if (hcon->type == LE_LINK) {
@@ -1546,6 +1548,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 	}
 
 	mutex_unlock(&conn->chan_lock);
+
+	queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
 }
 
 /* Notify sockets that we cannot guaranty reliability anymore */
@@ -1671,6 +1675,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
 	kfree_skb(conn->rx_skb);
 
+	skb_queue_purge(&conn->pending_rx);
+	flush_work(&conn->pending_rx_work);
+
 	l2cap_unregister_all_users(conn);
 
 	mutex_lock(&conn->chan_lock);
@@ -1773,6 +1780,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
 	else
 		INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
 
+	skb_queue_head_init(&conn->pending_rx);
+	INIT_WORK(&conn->pending_rx_work, process_pending_rx);
+
 	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
 	return conn;
@@ -7084,9 +7094,16 @@ drop:
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct l2cap_hdr *lh = (void *) skb->data;
+	struct hci_conn *hcon = conn->hcon;
 	u16 cid, len;
 	__le16 psm;
 
+	if (hcon->state != BT_CONNECTED) {
+		BT_DBG("queueing pending rx skb");
+		skb_queue_tail(&conn->pending_rx, skb);
+		return;
+	}
+
 	skb_pull(skb, L2CAP_HDR_SIZE);
 	cid = __le16_to_cpu(lh->cid);
 	len = __le16_to_cpu(lh->len);
@@ -7132,6 +7149,24 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 	}
 }
 
+static void process_pending_rx(struct work_struct *work)
+{
+	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+					       pending_rx_work);
+
+	BT_DBG("");
+
+	while (1) {
+		struct sk_buff *skb;
+
+		skb = skb_dequeue(&conn->pending_rx);
+		if (!skb)
+			break;
+
+		l2cap_recv_frame(conn, skb);
+	}
+}
+
 /* ---- L2CAP interface with lower layer (HCI) ---- */
 
 int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCH 1/5] android: Add android ipc tester
From: Szymon Janc @ 2014-01-16  8:20 UTC (permalink / raw)
  To: Marcin Kraglak; +Cc: linux-bluetooth
In-Reply-To: <1389813150-16914-1-git-send-email-marcin.kraglak@tieto.com>

Hi Marcin,

On Wednesday 15 of January 2014 20:12:26 Marcin Kraglak wrote:
> This tool will test ipc library. First test case will check
> ipc_init() call.
> ---
>  .gitignore                 |   1 +
>  android/Makefile.am        |   8 ++
>  android/test-android-ipc.c | 277 +++++++++++++++++++++++++++++++++++++++++++++

I would name this android/test-ipc.c.

>  3 files changed, 286 insertions(+)
>  create mode 100644 android/test-android-ipc.c
> 
> diff --git a/.gitignore b/.gitignore
> index ac76fe2..0d0834b 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -114,3 +114,4 @@ android/bluetoothd
>  android/haltest
>  android/android-tester
>  android/bluetoothd-snoop
> +android/test-android-ipc
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 7806f79..271a3e8 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -117,6 +117,14 @@ android_android_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
>  
>  android_android_tester_LDFLAGS = -pthread -ldl
>  
> +noinst_PROGRAMS += android/test-android-ipc
> +
> +android_test_android_ipc_SOURCES = android/test-android-ipc.c \
> +				src/shared/util.h src/shared/util.c \
> +				src/log.h src/log.c \
> +				android/ipc.c android/ipc.h
> +android_test_android_ipc_LDADD = @GLIB_LIBS@
> +
>  plugin_LTLIBRARIES += android/audio.a2dp.default.la
>  
>  android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
> diff --git a/android/test-android-ipc.c b/android/test-android-ipc.c
> new file mode 100644
> index 0000000..6ac1175
> --- /dev/null
> +++ b/android/test-android-ipc.c
> @@ -0,0 +1,277 @@
> +/*
> + *
> + *  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 <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <sys/signalfd.h>
> +
> +#include <glib.h>
> +#include "src/shared/util.h"
> +#include "src/log.h"
> +#include "android/hal-msg.h"
> +#include "android/ipc.h"
> +
> +struct test_data {
> +	uint32_t expected_signal;
> +};
> +
> +struct context {
> +	GMainLoop *main_loop;
> +
> +	int sk;
> +
> +	guint source;
> +	guint cmd_source;
> +	guint notif_source;
> +
> +	GIOChannel *cmd_io;
> +	GIOChannel *notif_io;
> +	GIOChannel *signal_io;
> +
> +	guint signal_source;
> +
> +	const struct test_data *data;
> +};
> +
> +static void context_quit(struct context *context)
> +{
> +	g_main_loop_quit(context->main_loop);
> +}
> +
> +static gboolean cmd_watch(GIOChannel *io, GIOCondition cond,
> +						gpointer user_data)
> +{
> +	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> +		g_assert(FALSE);
> +		return FALSE;
> +	}
> +
> +	return TRUE;
> +}
> +
> +static gboolean notif_watch(GIOChannel *io, GIOCondition cond,
> +							gpointer user_data)
> +{
> +	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> +		g_assert(FALSE);
> +		return FALSE;
> +	}
> +
> +	return TRUE;
> +}
> +
> +static gboolean connect_handler(GIOChannel *io, GIOCondition cond,
> +						gpointer user_data)
> +{
> +	struct context *context = user_data;
> +	GIOChannel *new_io;
> +	GIOCondition watch_cond;
> +	int sk;
> +
> +	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> +		g_assert(FALSE);
> +		return FALSE;
> +	}
> +
> +	g_assert(!context->cmd_source || !context->notif_source);
> +
> +	sk = accept(context->sk, NULL, NULL);
> +	g_assert(sk >= 0);
> +
> +	new_io = g_io_channel_unix_new(sk);
> +
> +	watch_cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
> +
> +	if (context->cmd_source && !context->notif_source) {
> +		context->notif_source = g_io_add_watch(new_io, watch_cond,
> +							notif_watch, context);
> +		g_assert(context->notif_source > 0);
> +		context->notif_io = new_io;
> +	}
> +
> +	if (!context->cmd_source) {
> +		context->cmd_source = g_io_add_watch(new_io, watch_cond,
> +							cmd_watch, context);
> +		context->cmd_io = new_io;
> +	}
> +
> +	if (context->cmd_source && context->notif_source)
> +		context_quit(context);
> +
> +	return TRUE;
> +}
> +
> +static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
> +							gpointer user_data)
> +{
> +	struct context *context = user_data;
> +	const struct test_data *test_data = context->data;
> +	struct signalfd_siginfo si;
> +	ssize_t result;
> +	int fd;
> +
> +	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
> +		return FALSE;
> +
> +	fd = g_io_channel_unix_get_fd(channel);
> +
> +	result = read(fd, &si, sizeof(si));
> +	if (result != sizeof(si))
> +		return FALSE;
> +
> +	g_assert(test_data->expected_signal == si.ssi_signo);
> +	context_quit(context);
> +	return TRUE;
> +}
> +
> +static guint setup_signalfd(gpointer user_data)
> +{
> +	GIOChannel *channel;
> +	guint source;
> +	sigset_t mask;
> +	int ret;
> +	int fd;
> +
> +	sigemptyset(&mask);
> +	sigaddset(&mask, SIGINT);
> +	sigaddset(&mask, SIGTERM);
> +
> +	ret = sigprocmask(SIG_BLOCK, &mask, NULL);
> +	g_assert(ret == 0);
> +
> +	fd = signalfd(-1, &mask, 0);
> +	g_assert(fd >= 0);
> +
> +	channel = g_io_channel_unix_new(fd);
> +
> +	g_io_channel_set_close_on_unref(channel, TRUE);
> +	g_io_channel_set_encoding(channel, NULL, NULL);
> +	g_io_channel_set_buffered(channel, FALSE);
> +
> +	source = g_io_add_watch(channel,
> +				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> +				signal_handler, user_data);
> +
> +	g_io_channel_unref(channel);
> +
> +	return source;
> +}
> +
> +static struct context *create_context(gconstpointer data)
> +{
> +	struct context *context = g_new0(struct context, 1);
> +	struct sockaddr_un addr;
> +	GIOChannel *io;
> +	int ret, sk;
> +
> +	context->main_loop = g_main_loop_new(NULL, FALSE);
> +	g_assert(context->main_loop);
> +
> +	context->signal_source = setup_signalfd(context);
> +	g_assert(context->signal_source);
> +
> +	sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
> +	g_assert(sk >= 0);
> +
> +	memset(&addr, 0, sizeof(addr));
> +	addr.sun_family = AF_UNIX;
> +
> +	memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
> +
> +	ret = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
> +	g_assert(ret == 0);
> +
> +	ret = listen(sk, 5);
> +	g_assert(ret == 0);
> +
> +	io = g_io_channel_unix_new(sk);
> +
> +	g_io_channel_set_close_on_unref(io, TRUE);
> +
> +	context->source = g_io_add_watch(io,
> +				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> +				connect_handler, context);
> +	g_assert(context->source > 0);
> +
> +	g_io_channel_unref(io);
> +
> +	context->sk = sk;
> +	context->data = data;
> +
> +	return context;
> +}
> +
> +static void execute_context(struct context *context)
> +{
> +	g_main_loop_run(context->main_loop);
> +
> +	g_io_channel_shutdown(context->notif_io, true, NULL);
> +	g_io_channel_shutdown(context->cmd_io, true, NULL);
> +	g_io_channel_unref(context->cmd_io);
> +	g_io_channel_unref(context->notif_io);
> +
> +	g_source_remove(context->notif_source);
> +	g_source_remove(context->signal_source);
> +	g_source_remove(context->cmd_source);
> +	g_source_remove(context->source);
> +
> +	g_main_loop_unref(context->main_loop);
> +
> +	g_free(context);
> +}
> +
> +static void test_init(gconstpointer data)
> +{
> +	struct context *context = create_context(data);
> +
> +	ipc_init();
> +
> +	execute_context(context);
> +
> +	ipc_cleanup();
> +}
> +
> +static const struct test_data test_init_1 = {};
> +
> +int main(int argc, char *argv[])
> +{
> +	g_test_init(&argc, &argv, NULL);
> +
> +	if (g_test_verbose())
> +		__btd_log_init("*", 0);
> +
> +	g_test_add_data_func("/android_ipc/init", &test_init_1, test_init);
> +
> +	return g_test_run();
> +}
> 

-- 
Best regards, 
Szymon Janc

^ permalink raw reply

* Re: [PATCH] android/pics: Add PICS and PIXIT for AVCTP
From: Szymon Janc @ 2014-01-16  8:06 UTC (permalink / raw)
  To: Jakub Tyszkowski; +Cc: linux-bluetooth
In-Reply-To: <1389778295-846-1-git-send-email-jakub.tyszkowski@tieto.com>

Hi Jakub,

On Wednesday 15 of January 2014 10:31:35 Jakub Tyszkowski wrote:
> Add PICS/PIXIT for AVCTP, targeting Android 4.4.
> ---
>  android/Makefile.am     |  1 +
>  android/pics-avctp.txt  | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
>  android/pixit-avctp.txt | 39 +++++++++++++++++++++++++
>  3 files changed, 115 insertions(+)
>  create mode 100644 android/pics-avctp.txt
>  create mode 100644 android/pixit-avctp.txt
> 
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 7806f79..cd4a526 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -147,4 +147,5 @@ EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README \
>  		android/pics-l2cap.txt android/pixit-l2cap.txt \
>  		android/pics-avrcp.txt android/pixit-avrcp.txt \
>  		android/pics-a2dp.txt android/pixit-a2dp.txt \
> +		android/pics-avctp.txt android/pixit-avctp.txt \
>  		android/pts-l2cap.txt
> diff --git a/android/pics-avctp.txt b/android/pics-avctp.txt
> new file mode 100644
> index 0000000..939ffdb
> --- /dev/null
> +++ b/android/pics-avctp.txt
> @@ -0,0 +1,75 @@
> +AVCTP PICS for the PTS tool.
> +
> +PTS version: 5.0
> +
> +* - different than PTS defaults
> +# - not yet implemented/supported
> +
> +M - mandatory if such role selected
> +O - optional
> +
> +		Protocol Version
> +-------------------------------------------------------------------------------
> +Parameter Name	Selected	Description
> +-------------------------------------------------------------------------------
> +TSPC_AVCTP_0_1	False		AVCTP 1.0 (C.1)
> +TSPC_AVCTP_0_2	True (*)	AVCTP 1.2 (C.1)
> +TSPC_AVCTP_0_3	False		AVCTP 1.3 (C.1)
> +TSPC_AVCTP_0_4	False		AVCTP 1.4 (C.1)
> +-------------------------------------------------------------------------------
> +C.1: Mandatory to support only one Protocol Version.
> +-------------------------------------------------------------------------------
> +
> +
> +		Roles
> +-------------------------------------------------------------------------------
> +Parameter Name	Selected	Description
> +-------------------------------------------------------------------------------
> +TSPC_AVCTP_1_1	False		Controller (C.1)
> +TSPC_AVCTP_1_2	True (*)	Target (C.1)
> +-------------------------------------------------------------------------------
> +C.1: Mandatory to support at least one of the defined roles.
> +-------------------------------------------------------------------------------
> +
> +
> +		Controller Features
> +-------------------------------------------------------------------------------
> +Parameter Name	Selected	Description
> +-------------------------------------------------------------------------------
> +TSPC_AVCTP_2_1	False		Message fragmentation (O)
> +TSPC_AVCTP_2_2	False (*)	Transaction label management (M)
> +TSPC_AVCTP_2_3	False (*)	Packet type field management (M)
> +TSPC_AVCTP_2_4	False (*)	Message type field management (M)
> +TSPC_AVCTP_2_5	False (*)	PID field management (M)
> +TSPC_AVCTP_2_6	False (*)	IPID field mangement (M)
> +TSPC_AVCTP_2_7	False (*)	Message information management (M)
> +TSPC_AVCTP_2_8	False		Event registration for message reception (O)
> +TSPC_AVCTP_2_9	False		Event registration for connection request (O)
> +TSPC_AVCTP_2_10	False		Event registration for disconnection (O)
> +TSPC_AVCTP_2_11	False		Connect request (O)
> +TSPC_AVCTP_2_12	False		Disconnect request (O)
> +TSPC_AVCTP_2_13	False		Send message (O)
> +TSPC_AVCTP_2_14	False		Support for multiple AVCTP channel establishment
> +					(O)
> +-------------------------------------------------------------------------------
> +
> +
> +		Target Features
> +-------------------------------------------------------------------------------
> +Parameter Name	Selected	Description
> +-------------------------------------------------------------------------------
> +TSPC_AVCTP_3_1	True (*)	Message fragmentation (O)
> +TSPC_AVCTP_3_2	True		Transaction label management (M)
> +TSPC_AVCTP_3_3	True		Packet type field management (M)
> +TSPC_AVCTP_3_4	True		Message type field management (M)
> +TSPC_AVCTP_3_5	True		PID field management (M)
> +TSPC_AVCTP_3_6	True		IPID field management (M)
> +TSPC_AVCTP_3_7	True		Message information management (M)
> +TSPC_AVCTP_3_8	True (*)	Event registration for message reception (O)
> +TSPC_AVCTP_3_9	True (*)	Event registration for connection request (O)
> +TSPC_AVCTP_3_10	True (*)	Event registration for disconnection request (O)
> +TSPC_AVCTP_3_11	True (*)	Connect request (O)
> +TSPC_AVCTP_3_12	True (*)	Disconnect request (O)
> +TSPC_AVCTP_3_13	True (*)	Send message (O)
> +TSPC_AVCTP_ALL	False		Enables all test cases when set to TRUE
> +-------------------------------------------------------------------------------
> diff --git a/android/pixit-avctp.txt b/android/pixit-avctp.txt
> new file mode 100644
> index 0000000..c5782fd
> --- /dev/null
> +++ b/android/pixit-avctp.txt
> @@ -0,0 +1,39 @@
> +AVCTP PIXIT for the PTS tool.
> +
> +PTS version: 5.0
> +
> +* - different than PTS defaults
> +& - should be set to IUT Bluetooth address
> +# - should be set to PTS's bin/audio folder
> +
> +		Required PIXIT settings
> +-------------------------------------------------------------------------------
> +Parameter Name			Value
> +-------------------------------------------------------------------------------
> +TSPX_avctp_psm			0017
> +TSPX_avctp_profile_id		110E
> +TSPX_connect_avdtp		TRUE
> +TSPX_avctp_tester_command_data
> +TSPX_avctp_tester_response_data
> +TSPX_avctp_iut_command_data
> +TSPX_avctp_iut_response_data
> +TSPX_bd_addr_iut		08606E414394 (&)
> +TSPX_pin_code			0000
> +TSPX_delete_link_key		FALSE
> +TSPX_security_enabled		FALSE
> +TSPX_class_of_device		20050C
> +TSPX_player_feature_bitmask	0000000000000007FFF00070000000000
> +TSPX_avrcp_version
> +TSPX_establish_avdtp_stream	TRUE
> +TSPX_tester_av_role
> +TSPX_time_guard			300000
> +TSPX_avrcp_only			FALSE
> +TSPX_use_implicit_send		TRUE
> +TSPX_media_directory		C:\Program Files\Bluetooth SIG\Bluetooth PTS\
> +					bin\audio (#)
> +TSPX_no_confirmations		FALSE
> +TSPX_auth_password		0000
> +TSPX_auth_user_id		PTS
> +TSPX_rfcomm_channel		8
> +TSPX_l2cap_psm			1011
> +-------------------------------------------------------------------------------
> 

Pushed, thanks.

-- 
Best regards, 
Szymon Janc

^ permalink raw reply

* Re: [PATCH 1/4] android: Add simple rotation of snoop file
From: Szymon Janc @ 2014-01-16  8:02 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1389819699-12055-1-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

On Wednesday 15 of January 2014 22:01:36 Andrzej Kaczmarek wrote:
> Already existing snoop file is renamed by adding ".old" suffix before
> new one is created. This is useful in case phone is restarted so logs
> are not overwritten and for this reason it's only applied in case
> default snoop file name is used.
> ---
>  android/bluetoothd-snoop.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/android/bluetoothd-snoop.c b/android/bluetoothd-snoop.c
> index 02f44e9..23e0bfd 100644
> --- a/android/bluetoothd-snoop.c
> +++ b/android/bluetoothd-snoop.c
> @@ -206,6 +206,9 @@ int main(int argc, char *argv[])
>  
>  	mainloop_set_signal(&mask, signal_callback, NULL, NULL);
>  
> +	if (!strcmp(DEFAULT_SNOOP_FILE, path))
> +		rename(DEFAULT_SNOOP_FILE, DEFAULT_SNOOP_FILE ".old");
> +
>  	if (open_monitor(path) < 0) {
>  		printf("Failed to start bluetoothd_snoop\n");
>  		return EXIT_FAILURE;
> 

All patches in this set applied, thanks.
(after changing commits order to not break build in 1/4)

-- 
Best regards, 
Szymon Janc

^ permalink raw reply

* Re: Wireshark and new BlueZ BTSNOOP format
From: Michal Labedzki @ 2014-01-16  7:00 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org development; +Cc: Szymon Janc, Marcel Holtmann
In-Reply-To: <66980755-B25D-4EE6-A443-5A60AD75351D@holtmann.org>

Hello,

I want to announce that Wireshark from SVN revision 54699 support new
"Bluetooth monitor" BTSNOOP file format. This means that you are able
to open file created by btmon in Wireshark. Support for capturing by
libpcap is already requested to libpcap/tcpdump team (formally,
implementation is done)

By the way: there is also support for Ubertooth for Low Energy Link
Layer, but via USB (usbmon) interface (and ubertooth host tool, for
example: "ubertooth btle -f").


Pozdrawiam / Best regards
---------------------------------------------------------------------------=
----------------------------------
Micha=C5=82 =C5=81ab=C4=99dzki, Software Engineer
Tieto Corporation

Product Development Services

http://www.tieto.com / http://www.tieto.pl
---
ASCII: Michal Labedzki
location: Swobodna 1 Street, 50-088 Wroc=C5=82aw, Poland
room: 5.01 (desk next to 5.08)
---
Please note: The information contained in this message may be legally
privileged and confidential and protected from disclosure. If the
reader of this message is not the intended recipient, you are hereby
notified that any unauthorised use, distribution or copying of this
communication is strictly prohibited. If you have received this
communication in error, please notify us immediately by replying to
the message and deleting it from your computer. Thank You.
---
Please consider the environment before printing this e-mail.
---
Tieto Poland sp=C3=B3=C5=82ka z ograniczon=C4=85 odpowiedzialno=C5=9Bci=C4=
=85 z siedzib=C4=85 w
Szczecinie, ul. Malczewskiego 26. Zarejestrowana w S=C4=85dzie Rejonowym
Szczecin-Centrum w Szczecinie, XIII Wydzia=C5=82 Gospodarczy Krajowego
Rejestru S=C4=85dowego pod numerem 0000124858. NIP: 8542085557. REGON:
812023656. Kapita=C5=82 zak=C5=82adowy: 4 271500 PLN

^ permalink raw reply

* [PATCH v2 5/5] Bluetooth: Add debugfs entry to show Secure Connections Only mode
From: Marcel Holtmann @ 2014-01-16  6:37 UTC (permalink / raw)
  To: linux-bluetooth

For debugging purposes of Secure Connection Only support a simple
debugfs entry is used to indicate if this mode is active or not.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci.h |  1 +
 net/bluetooth/hci_core.c    | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 0064a9aa5df1..232c07804ca8 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -124,6 +124,7 @@ enum {
 	HCI_LE_SCAN,
 	HCI_SSP_ENABLED,
 	HCI_SC_ENABLED,
+	HCI_SC_ONLY,
 	HCI_HS_ENABLED,
 	HCI_LE_ENABLED,
 	HCI_ADVERTISING,
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 499ec1b1095d..369d30750417 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -461,6 +461,24 @@ static const struct file_operations force_sc_support_fops = {
 	.llseek		= default_llseek,
 };
 
+static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	struct hci_dev *hdev = file->private_data;
+	char buf[3];
+
+	buf[0] = test_bit(HCI_SC_ONLY, &hdev->dev_flags) ? 'Y': 'N';
+	buf[1] = '\n';
+	buf[2] = '\0';
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static const struct file_operations sc_only_mode_fops = {
+	.open		= simple_open,
+	.read		= sc_only_mode_read,
+	.llseek		= default_llseek,
+};
+
 static int idle_timeout_set(void *data, u64 val)
 {
 	struct hci_dev *hdev = data;
@@ -1491,6 +1509,8 @@ static int __hci_init(struct hci_dev *hdev)
 				    hdev, &ssp_debug_mode_fops);
 		debugfs_create_file("force_sc_support", 0644, hdev->debugfs,
 				    hdev, &force_sc_support_fops);
+		debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
+				    hdev, &sc_only_mode_fops);
 	}
 
 	if (lmp_sniff_capable(hdev)) {
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 4/5] Bluetooth: Handle security level 4 for RFCOMM connections
From: Marcel Holtmann @ 2014-01-16  6:37 UTC (permalink / raw)
  To: linux-bluetooth

With the introduction of security level 4, the RFCOMM sockets need to
be made aware of this new level. This change ensures that the pairing
requirements are set correctly for these connections.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/rfcomm.h |  1 +
 net/bluetooth/rfcomm/core.c    |  4 +++-
 net/bluetooth/rfcomm/sock.c    | 12 +++++++++++-
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 486213a1aed8..c312cfc4e922 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -295,6 +295,7 @@ struct rfcomm_conninfo {
 #define RFCOMM_LM_TRUSTED	0x0008
 #define RFCOMM_LM_RELIABLE	0x0010
 #define RFCOMM_LM_SECURE	0x0020
+#define RFCOMM_LM_FIPS		0x0040
 
 #define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk)
 
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index facd8a79c038..ba115d472f7b 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -216,6 +216,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d)
 
 	switch (d->sec_level) {
 	case BT_SECURITY_HIGH:
+	case BT_SECURITY_FIPS:
 		auth_type = HCI_AT_GENERAL_BONDING_MITM;
 		break;
 	case BT_SECURITY_MEDIUM:
@@ -2085,7 +2086,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
 				set_bit(RFCOMM_SEC_PENDING, &d->flags);
 				rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
 				continue;
-			} else if (d->sec_level == BT_SECURITY_HIGH) {
+			} else if (d->sec_level == BT_SECURITY_HIGH ||
+				   d->sec_level == BT_SECURITY_FIPS) {
 				set_bit(RFCOMM_ENC_DROP, &d->flags);
 				continue;
 			}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 3c2d3e4aa2f5..fb8158af1f39 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -648,6 +648,11 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
 			break;
 		}
 
+		if (opt & RFCOMM_LM_FIPS) {
+			err = -EINVAL;
+			break;
+		}
+
 		if (opt & RFCOMM_LM_AUTH)
 			rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
 		if (opt & RFCOMM_LM_ENCRYPT)
@@ -762,7 +767,11 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 			break;
 		case BT_SECURITY_HIGH:
 			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
-							RFCOMM_LM_SECURE;
+			      RFCOMM_LM_SECURE;
+			break;
+		case BT_SECURITY_FIPS:
+			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
+			      RFCOMM_LM_SECURE | RFCOMM_LM_FIPS;
 			break;
 		default:
 			opt = 0;
@@ -774,6 +783,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 
 		if (put_user(opt, (u32 __user *) optval))
 			err = -EFAULT;
+
 		break;
 
 	case RFCOMM_CONNINFO:
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 3/5] Bluetooth: Handle security level 4 for L2CAP connections
From: Marcel Holtmann @ 2014-01-16  6:37 UTC (permalink / raw)
  To: linux-bluetooth

With the introduction of security level 4, the L2CAP sockets need to
be made aware of this new level. This change ensures that the pairing
requirements are set correctly for these connections.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/l2cap_core.c    | 11 ++++++++---
 net/bluetooth/l2cap_sock.c    | 10 ++++++++++
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index dbc4a89984ca..c695083eee2b 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -91,6 +91,7 @@ struct l2cap_conninfo {
 #define L2CAP_LM_TRUSTED	0x0008
 #define L2CAP_LM_RELIABLE	0x0010
 #define L2CAP_LM_SECURE		0x0020
+#define L2CAP_LM_FIPS		0x0040
 
 /* L2CAP command codes */
 #define L2CAP_COMMAND_REJ	0x01
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b0ad2c752d73..3f0dd552cb2b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -737,6 +737,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 	case L2CAP_CHAN_RAW:
 		switch (chan->sec_level) {
 		case BT_SECURITY_HIGH:
+		case BT_SECURITY_FIPS:
 			return HCI_AT_DEDICATED_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
 			return HCI_AT_DEDICATED_BONDING;
@@ -749,7 +750,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 			if (chan->sec_level == BT_SECURITY_LOW)
 				chan->sec_level = BT_SECURITY_SDP;
 		}
-		if (chan->sec_level == BT_SECURITY_HIGH)
+		if (chan->sec_level == BT_SECURITY_HIGH ||
+		    chan->sec_level == BT_SECURITY_FIPS)
 			return HCI_AT_NO_BONDING_MITM;
 		else
 			return HCI_AT_NO_BONDING;
@@ -759,7 +761,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 			if (chan->sec_level == BT_SECURITY_LOW)
 				chan->sec_level = BT_SECURITY_SDP;
 
-			if (chan->sec_level == BT_SECURITY_HIGH)
+			if (chan->sec_level == BT_SECURITY_HIGH ||
+			    chan->sec_level == BT_SECURITY_FIPS)
 				return HCI_AT_NO_BONDING_MITM;
 			else
 				return HCI_AT_NO_BONDING;
@@ -768,6 +771,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 	default:
 		switch (chan->sec_level) {
 		case BT_SECURITY_HIGH:
+		case BT_SECURITY_FIPS:
 			return HCI_AT_GENERAL_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
 			return HCI_AT_GENERAL_BONDING;
@@ -7206,7 +7210,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
 	if (encrypt == 0x00) {
 		if (chan->sec_level == BT_SECURITY_MEDIUM) {
 			__set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
-		} else if (chan->sec_level == BT_SECURITY_HIGH)
+		} else if (chan->sec_level == BT_SECURITY_HIGH ||
+			   chan->sec_level == BT_SECURITY_FIPS)
 			l2cap_chan_close(chan, ECONNREFUSED);
 	} else {
 		if (chan->sec_level == BT_SECURITY_MEDIUM)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 20ef748b2906..4aa6704f0b33 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -432,6 +432,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
 			opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
 			      L2CAP_LM_SECURE;
 			break;
+		case BT_SECURITY_FIPS:
+			opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+			      L2CAP_LM_SECURE | L2CAP_LM_FIPS;
+			break;
 		default:
 			opt = 0;
 			break;
@@ -445,6 +449,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
 
 		if (put_user(opt, (u32 __user *) optval))
 			err = -EFAULT;
+
 		break;
 
 	case L2CAP_CONNINFO:
@@ -699,6 +704,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
 			break;
 		}
 
+		if (opt & L2CAP_LM_FIPS) {
+			err = -EINVAL;
+			break;
+		}
+
 		if (opt & L2CAP_LM_AUTH)
 			chan->sec_level = BT_SECURITY_LOW;
 		if (opt & L2CAP_LM_ENCRYPT)
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 2/5] Bluetooth: Introduce requirements for security level 4
From: Marcel Holtmann @ 2014-01-16  6:37 UTC (permalink / raw)
  To: linux-bluetooth

The security level 4 is a new strong security requirement that is based
around 128-bit equivalent strength for link and encryption keys required
using FIPS approved algorithms. Which means that E0, SAFER+ and P-192
are not allowed. Only connections created with P-256 resulting from
using Secure Connections support are allowed.

This security level needs to be enforced when Secure Connection Only
mode is enabled for a controller or a service requires FIPS compliant
strong security. Currently it is not possible to enable either of
these two cases. This patch just puts in the foundation for being
able to handle security level 4 in the future.

It should be noted that devices or services with security level 4
requirement can only communicate using Bluetooth 4.1 controllers
with support for Secure Connections. There is no backward compatibilty
if used with older hardware.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/bluetooth.h |  1 +
 include/net/bluetooth/hci.h       |  1 +
 net/bluetooth/hci_conn.c          | 18 +++++++++++++-----
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index f4f9ee466791..904777c1cd24 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -65,6 +65,7 @@ struct bt_security {
 #define BT_SECURITY_LOW		1
 #define BT_SECURITY_MEDIUM	2
 #define BT_SECURITY_HIGH	3
+#define BT_SECURITY_FIPS	4
 
 #define BT_DEFER_SETUP	7
 
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 2bc19881e250..0064a9aa5df1 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -313,6 +313,7 @@ enum {
 #define HCI_LM_TRUSTED	0x0008
 #define HCI_LM_RELIABLE	0x0010
 #define HCI_LM_SECURE	0x0020
+#define HCI_LM_FIPS	0x0040
 
 /* Authentication types */
 #define HCI_AT_NO_BONDING		0x00
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index cf96b3438a91..0266bd8e4913 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -800,10 +800,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	if (!(conn->link_mode & HCI_LM_AUTH))
 		goto auth;
 
-	/* An authenticated combination key has sufficient security for any
-	   security level. */
-	if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
-	    conn->key_type == HCI_LK_AUTH_COMBINATION_P256)
+	/* An authenticated FIPS approved combination key has sufficient
+	 * security for security level 4. */
+	if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 &&
+	    sec_level == BT_SECURITY_FIPS)
+		goto encrypt;
+
+	/* An authenticated combination key has sufficient security for
+	   security level 3. */
+	if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
+	     conn->key_type == HCI_LK_AUTH_COMBINATION_P256) &&
+	    sec_level == BT_SECURITY_HIGH)
 		goto encrypt;
 
 	/* An unauthenticated combination key has sufficient security for
@@ -818,7 +825,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	   is generated using maximum PIN code length (16).
 	   For pre 2.1 units. */
 	if (conn->key_type == HCI_LK_COMBINATION &&
-	    (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
+	    (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW ||
+	     conn->pin_length == 16))
 		goto encrypt;
 
 auth:
-- 
1.8.4.2


^ 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