All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/5] sco: Integrate SCO socket option in user space.
@ 2013-06-26 17:32 Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 1/5] lib: SCO voice setting support header Frédéric Dalleau
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Frédéric Dalleau @ 2013-06-26 17:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Frédéric Dalleau

Hi,

This is the required patches for taking advantage of SCO voice setting from
userspace. This RFC add a sco-tester inspired from l2cap-tester that uses hci_vhci to
test SCO

Regards,
Fred

Frédéric Dalleau (5):
  lib: SCO voice setting support header
  btio: Add option for SCO voice setting
  btiotest: Add option for SCO voice setting
  scotest: Add option for SCO voice setting
  sco-tester: Initial sco tester implementation

 Makefile.tools     |   12 +-
 btio/btio.c        |   18 +-
 btio/btio.h        |    1 +
 emulator/btdev.c   |   30 +++
 lib/bluetooth.h    |    8 +
 tools/btiotest.c   |   18 +-
 tools/sco-tester.c |  560 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/scotest.c    |   40 +++-
 8 files changed, 675 insertions(+), 12 deletions(-)
 create mode 100644 tools/sco-tester.c

-- 
1.7.9.5


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

* [RFC 1/5] lib: SCO voice setting support header
  2013-06-26 17:32 [RFC 0/5] sco: Integrate SCO socket option in user space Frédéric Dalleau
@ 2013-06-26 17:32 ` Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 2/5] btio: Add option for SCO voice setting Frédéric Dalleau
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Frédéric Dalleau @ 2013-06-26 17:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Frédéric Dalleau

Modify headers to enable support for changing SCO voice setting.
Corresponding commit implements functionality on kernel side.
---
 lib/bluetooth.h |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/bluetooth.h b/lib/bluetooth.h
index 48323f0..012fde4 100644
--- a/lib/bluetooth.h
+++ b/lib/bluetooth.h
@@ -104,6 +104,14 @@ struct bt_security {
  */
 #define BT_CHANNEL_POLICY_AMP_PREFERRED		2
 
+#define BT_VOICE		11
+struct bt_voice {
+	uint16_t setting;
+};
+
+#define BT_VOICE_TRANSPARENT			0x0003
+#define BT_VOICE_CVSD_16BIT			0x0060
+
 /* Connection and socket states */
 enum {
 	BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
-- 
1.7.9.5


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

* [RFC 2/5] btio: Add option for SCO voice setting
  2013-06-26 17:32 [RFC 0/5] sco: Integrate SCO socket option in user space Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 1/5] lib: SCO voice setting support header Frédéric Dalleau
@ 2013-06-26 17:32 ` Frédéric Dalleau
  2013-07-01  7:54   ` Luiz Augusto von Dentz
  2013-06-26 17:32 ` [RFC 3/5] btiotest: " Frédéric Dalleau
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Frédéric Dalleau @ 2013-06-26 17:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Frédéric Dalleau

---
 btio/btio.c |   18 +++++++++++++++---
 btio/btio.h |    1 +
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/btio/btio.c b/btio/btio.c
index cb8860a..df1630e 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -78,6 +78,7 @@ struct set_opts {
 	uint8_t mode;
 	int flushable;
 	uint32_t priority;
+	uint16_t sco_voice;
 };
 
 struct connect {
@@ -723,9 +724,10 @@ static int sco_connect(int sock, const bdaddr_t *dst)
 	return 0;
 }
 
-static gboolean sco_set(int sock, uint16_t mtu, GError **err)
+static gboolean sco_set(int sock, uint16_t mtu, uint16_t sco_voice, GError **err)
 {
 	struct sco_options sco_opt;
+	struct bt_voice voice;
 	socklen_t len;
 
 	if (!mtu)
@@ -745,6 +747,13 @@ static gboolean sco_set(int sock, uint16_t mtu, GError **err)
 		return FALSE;
 	}
 
+	voice.setting = sco_voice;
+	if (setsockopt(sock, SOL_BLUETOOTH, BT_VOICE, &voice,
+						sizeof(voice)) < 0) {
+		ERROR_FAILED(err, "setsockopt(BT_VOICE)", errno);
+		return FALSE;
+	}
+
 	return TRUE;
 }
 
@@ -832,6 +841,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
 		case BT_IO_OPT_PRIORITY:
 			opts->priority = va_arg(args, int);
 			break;
+		case BT_IO_OPT_SCO_VOICE:
+			opts->sco_voice = va_arg(args, int);
+			break;
 		default:
 			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
@@ -1310,7 +1322,7 @@ gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 	case BT_IO_RFCOMM:
 		return rfcomm_set(sock, opts.sec_level, opts.master, err);
 	case BT_IO_SCO:
-		return sco_set(sock, opts.mtu, err);
+		return sco_set(sock, opts.mtu, opts.sco_voice, err);
 	default:
 		g_set_error(err, BT_IO_ERROR, EINVAL,
 				"Unknown BtIO type %d", type);
@@ -1377,7 +1389,7 @@ static GIOChannel *create_io(gboolean server, struct set_opts *opts,
 		}
 		if (sco_bind(sock, &opts->src, err) < 0)
 			goto failed;
-		if (!sco_set(sock, opts->mtu, err))
+		if (!sco_set(sock, opts->mtu, opts->sco_voice, err))
 			goto failed;
 		break;
 	default:
diff --git a/btio/btio.h b/btio/btio.h
index ac1366b..9959483 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -55,6 +55,7 @@ typedef enum {
 	BT_IO_OPT_MODE,
 	BT_IO_OPT_FLUSHABLE,
 	BT_IO_OPT_PRIORITY,
+	BT_IO_OPT_SCO_VOICE,
 } BtIOOption;
 
 typedef enum {
-- 
1.7.9.5


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

* [RFC 3/5] btiotest: Add option for SCO voice setting
  2013-06-26 17:32 [RFC 0/5] sco: Integrate SCO socket option in user space Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 1/5] lib: SCO voice setting support header Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 2/5] btio: Add option for SCO voice setting Frédéric Dalleau
@ 2013-06-26 17:32 ` Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 4/5] scotest: " Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 5/5] sco-tester: Initial sco tester implementation Frédéric Dalleau
  4 siblings, 0 replies; 7+ messages in thread
From: Frédéric Dalleau @ 2013-06-26 17:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Frédéric Dalleau

---
 tools/btiotest.c |   18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/tools/btiotest.c b/tools/btiotest.c
index 2c77fb3..0c056f2 100644
--- a/tools/btiotest.c
+++ b/tools/btiotest.c
@@ -445,7 +445,7 @@ static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
 	g_io_channel_unref(rc_srv);
 }
 
-static void sco_connect(const char *src, const char *dst, int disconn)
+static void sco_connect(const char *src, const char *dst, int disconn, int voice)
 {
 	struct io_data *data;
 	GError *err = NULL;
@@ -460,12 +460,14 @@ static void sco_connect(const char *src, const char *dst, int disconn)
 						&err,
 						BT_IO_OPT_SOURCE, src,
 						BT_IO_OPT_DEST, dst,
+						BT_IO_OPT_SCO_VOICE, voice,
 						BT_IO_OPT_INVALID);
 	else
 		data->io = bt_io_connect(connect_cb, data,
 						(GDestroyNotify) io_data_unref,
 						&err,
 						BT_IO_OPT_DEST, dst,
+						BT_IO_OPT_SCO_VOICE, voice,
 						BT_IO_OPT_INVALID);
 
 	if (!data->io) {
@@ -476,7 +478,7 @@ static void sco_connect(const char *src, const char *dst, int disconn)
 }
 
 static void sco_listen(const char *src, gboolean defer, int reject,
-				int disconn, int accept)
+				int disconn, int accept, int voice)
 {
 	struct io_data *data;
 	BtIOConnect conn;
@@ -501,11 +503,14 @@ static void sco_listen(const char *src, gboolean defer, int reject,
 					(GDestroyNotify) io_data_unref,
 					&err,
 					BT_IO_OPT_SOURCE, src,
+					BT_IO_OPT_SCO_VOICE, voice,
 					BT_IO_OPT_INVALID);
 	else
 		sco_srv = bt_io_listen(conn, cfm, data,
 					(GDestroyNotify) io_data_unref,
-					&err, BT_IO_OPT_INVALID);
+					&err,
+					BT_IO_OPT_SCO_VOICE, voice,
+					BT_IO_OPT_INVALID);
 
 	if (!sco_srv) {
 		printf("Listening failed: %s\n", err->message);
@@ -520,6 +525,7 @@ static int opt_channel = -1;
 static int opt_psm = 0;
 static gboolean opt_sco = FALSE;
 static gboolean opt_defer = FALSE;
+static gint opt_voice = 0;
 static char *opt_dev = NULL;
 static int opt_reject = -1;
 static int opt_disconn = -1;
@@ -546,6 +552,8 @@ static GOptionEntry options[] = {
 				"Use SCO" },
 	{ "defer", 'd', 0, G_OPTION_ARG_NONE, &opt_defer,
 				"Use DEFER_SETUP for incoming connections" },
+	{ "voice", 'V', 0, G_OPTION_ARG_INT, &opt_voice,
+				"Which voice setting to use (0x0060 CVSD, 0x0003 Transparent)" },
 	{ "sec-level", 'S', 0, G_OPTION_ARG_INT, &opt_sec,
 				"Security level" },
 	{ "update-sec-level", 'U', 0, G_OPTION_ARG_INT, &opt_update_sec,
@@ -611,10 +619,10 @@ int main(int argc, char *argv[])
 
 	if (opt_sco) {
 		if (argc > 1)
-			sco_connect(opt_dev, argv[1], opt_disconn);
+			sco_connect(opt_dev, argv[1], opt_disconn, opt_voice);
 		else
 			sco_listen(opt_dev, opt_defer, opt_reject,
-					opt_disconn, opt_accept);
+					opt_disconn, opt_accept, opt_voice);
 	}
 
 	signal(SIGTERM, sig_term);
-- 
1.7.9.5


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

* [RFC 4/5] scotest: Add option for SCO voice setting
  2013-06-26 17:32 [RFC 0/5] sco: Integrate SCO socket option in user space Frédéric Dalleau
                   ` (2 preceding siblings ...)
  2013-06-26 17:32 ` [RFC 3/5] btiotest: " Frédéric Dalleau
@ 2013-06-26 17:32 ` Frédéric Dalleau
  2013-06-26 17:32 ` [RFC 5/5] sco-tester: Initial sco tester implementation Frédéric Dalleau
  4 siblings, 0 replies; 7+ messages in thread
From: Frédéric Dalleau @ 2013-06-26 17:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Frédéric Dalleau

---
 tools/scotest.c |   40 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/tools/scotest.c b/tools/scotest.c
index a40e395..7148be6 100644
--- a/tools/scotest.c
+++ b/tools/scotest.c
@@ -58,6 +58,7 @@ static long data_size = 672;
 static bdaddr_t bdaddr;
 
 static int defer_setup = 0;
+static int voice = 0;
 
 static float tv2fl(struct timeval tv)
 {
@@ -68,6 +69,7 @@ static int do_connect(char *svr)
 {
 	struct sockaddr_sco addr;
 	struct sco_conninfo conn;
+	struct bt_voice opts;
 	socklen_t optlen;
 	int sk;
 
@@ -90,6 +92,15 @@ static int do_connect(char *svr)
 		goto error;
 	}
 
+	/* SCO voice setting */
+	memset(&opts, 0, sizeof(opts));
+	opts.setting = voice;
+	if (setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &opts, sizeof(opts)) < 0) {
+		syslog(LOG_ERR, "Can't set socket options: %s (%d)",
+							strerror(errno), errno);
+		goto error;
+	}
+
 	/* Connect to remote device */
 	memset(&addr, 0, sizeof(addr));
 	addr.sco_family = AF_BLUETOOTH;
@@ -229,8 +240,16 @@ error:
 
 static void dump_mode(int sk)
 {
+	struct bt_voice opts;
 	int len;
 
+	/* SCO voice setting */
+	memset(&opts, 0, sizeof(opts));
+	opts.setting = voice;
+	if (setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &opts, sizeof(opts)) < 0)
+		syslog(LOG_ERR, "Can't set socket options: %s (%d)",
+							strerror(errno), errno);
+
 	if (defer_setup) {
 		len = read(sk, buf, sizeof(buf));
 		if (len < 0)
@@ -248,9 +267,17 @@ static void dump_mode(int sk)
 static void recv_mode(int sk)
 {
 	struct timeval tv_beg,tv_end,tv_diff;
+	struct bt_voice opts;
 	long total;
 	int len;
 
+	/* SCO voice setting */
+	memset(&opts, 0, sizeof(opts));
+	opts.setting = voice;
+	if (setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &opts, sizeof(opts)) < 0)
+		syslog(LOG_ERR, "Can't set socket options: %s (%d)",
+							strerror(errno), errno);
+
 	if (defer_setup) {
 		len = read(sk, buf, sizeof(buf));
 		if (len < 0)
@@ -271,7 +298,9 @@ static void recv_mode(int sk)
 				if (r < 0)
 					syslog(LOG_ERR, "Read failed: %s (%d)",
 							strerror(errno), errno);
-				return;
+				if (errno != ENOTCONN)
+					return;
+				r = 0;
 			}
 			total += r;
 		}
@@ -381,7 +410,8 @@ static void usage(void)
 		"\t-n connect and be silent (client)\n"
 		"Options:\n"
 		"\t[-b bytes]\n"
-		"\t[-W seconds] enable deferred setup\n");
+		"\t[-W seconds] enable deferred setup\n"
+		"\t[-V voice] select SCO voice setting (0x0060 cvsd, 0x0003 transparent)\n");
 }
 
 int main(int argc ,char *argv[])
@@ -389,7 +419,7 @@ int main(int argc ,char *argv[])
 	struct sigaction sa;
 	int opt, sk, mode = RECV;
 
-	while ((opt = getopt(argc, argv, "rdscmnb:W:")) != EOF) {
+	while ((opt = getopt(argc, argv, "rdscmnb:W:V:")) != EOF) {
 		switch(opt) {
 		case 'r':
 			mode = RECV;
@@ -423,6 +453,10 @@ int main(int argc ,char *argv[])
 			defer_setup = atoi(optarg);
 			break;
 
+		case 'V':
+			voice = atoi(optarg);
+			break;
+
 		default:
 			usage();
 			exit(1);
-- 
1.7.9.5


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

* [RFC 5/5] sco-tester: Initial sco tester implementation
  2013-06-26 17:32 [RFC 0/5] sco: Integrate SCO socket option in user space Frédéric Dalleau
                   ` (3 preceding siblings ...)
  2013-06-26 17:32 ` [RFC 4/5] scotest: " Frédéric Dalleau
@ 2013-06-26 17:32 ` Frédéric Dalleau
  4 siblings, 0 replies; 7+ messages in thread
From: Frédéric Dalleau @ 2013-06-26 17:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Frédéric Dalleau

---
 Makefile.tools     |   12 +-
 emulator/btdev.c   |   30 +++
 tools/sco-tester.c |  560 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 601 insertions(+), 1 deletion(-)
 create mode 100644 tools/sco-tester.c

diff --git a/Makefile.tools b/Makefile.tools
index 8f245e0..135954b 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -28,7 +28,7 @@ endif
 if EXPERIMENTAL
 noinst_PROGRAMS += emulator/btvirt emulator/b1ee \
 					tools/mgmt-tester tools/gap-tester \
-					tools/l2cap-tester
+					tools/l2cap-tester tools/sco-tester
 
 emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
 					monitor/mainloop.h monitor/mainloop.c \
@@ -65,6 +65,16 @@ tools_gap_tester_SOURCES = $(gdbus_sources) \
 				src/shared/tester.h src/shared/tester.c
 
 tools_gap_tester_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
+
+tools_sco_tester_SOURCES = tools/sco-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_sco_tester_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
+
 endif
 
 if TOOLS
diff --git a/emulator/btdev.c b/emulator/btdev.c
index a602c05..4d39190 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -660,6 +660,28 @@ static void conn_complete(struct btdev *btdev,
 	send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
 }
 
+
+static void sync_conn_complete(struct btdev *btdev, uint16_t voice_setting, uint8_t status)
+{
+	struct bt_hci_evt_sync_conn_complete cc;
+
+	if (!btdev->conn)
+		return;
+
+	cc.status = status;
+	memcpy(cc.bdaddr, btdev->conn->bdaddr, 6);
+
+	cc.handle = cpu_to_le16(status == BT_HCI_ERR_SUCCESS ? 257 : 0);
+	cc.link_type = 0x02;
+	cc.tx_interval = 0x000c;
+	cc.retrans_window = 0x06;
+	cc.rx_pkt_len = 60;
+	cc.tx_pkt_len = 60;
+	cc.air_mode = (voice_setting == 0x0060) ? 0x02 : 0x03;
+
+	send_event(btdev, BT_HCI_EVT_SYNC_CONN_COMPLETE, &cc, sizeof(cc));
+}
+
 static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
 {
 	struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
@@ -840,6 +862,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
 	const struct bt_hci_cmd_set_event_mask_page2 *semp2;
 	const struct bt_hci_cmd_le_set_event_mask *lsem;
 	const struct bt_hci_cmd_le_set_adv_data *lsad;
+	const struct bt_hci_cmd_setup_sync_conn *ssc;
 	struct bt_hci_rsp_read_default_link_policy rdlp;
 	struct bt_hci_rsp_read_stored_link_key rslk;
 	struct bt_hci_rsp_write_stored_link_key wslk;
@@ -1492,6 +1515,13 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
 		cmd_complete(btdev, opcode, &status, sizeof(status));
 		break;
 
+	case BT_HCI_CMD_SETUP_SYNC_CONN:
+		ssc = data;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		sync_conn_complete(btdev, ssc->voice_setting, BT_HCI_ERR_SUCCESS);
+		break;
+
 	default:
 		goto unsupported;
 	}
diff --git a/tools/sco-tester.c b/tools/sco-tester.c
new file mode 100644
index 0000000..6732e0c
--- /dev/null
+++ b/tools/sco-tester.c
@@ -0,0 +1,560 @@
+/*
+ *
+ *  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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sco.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 {
+	const void *test_data;
+	struct mgmt *mgmt;
+	uint16_t mgmt_index;
+	struct hciemu *hciemu;
+	enum hciemu_type hciemu_type;
+	unsigned int io_id;
+};
+
+struct sco_client_data {
+	int expect_err;
+};
+
+struct sco_server_data {
+	int expect_err;
+};
+
+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(HCIEMU_TYPE_BREDRLE);
+	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;
+
+	if (data->io_id > 0)
+		g_source_remove(data->io_id);
+
+	free(data);
+}
+
+#define test_sco(name, data, setup, func) \
+	do { \
+		struct test_data *user; \
+		user = malloc(sizeof(struct test_data)); \
+		if (!user) \
+			break; \
+		user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+		user->io_id = 0; \
+		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)
+
+#define test_sco_long(name, data, setup, func) \
+	do { \
+		struct test_data *user; \
+		user = malloc(sizeof(struct test_data)); \
+		if (!user) \
+			break; \
+		user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+		user->io_id = 0; \
+		user->test_data = data; \
+		tester_add_full(name, data, \
+				test_pre_setup, setup, func, NULL, \
+				test_post_teardown, 8, user, test_data_free); \
+	} while (0)
+
+
+static const struct sco_client_data client_success_test = {
+	.expect_err = 0
+};
+
+static const struct sco_client_data client_timeout_test = {
+		.expect_err = ECONNABORTED
+};
+
+static void client_connectable_complete(uint16_t opcode, uint8_t status,
+					const void *param, uint8_t len,
+					void *user_data)
+{
+	if (opcode != BT_HCI_CMD_WRITE_SCAN_ENABLE)
+		return;
+
+	tester_print("Client set connectable status 0x%02x", status);
+
+	if (status)
+		tester_setup_failed();
+	else
+		tester_setup_complete();
+}
+
+static void setup_powered_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);
+	bthost_write_scan_enable(bthost, 0x03);
+}
+
+static void setup_powered(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	unsigned char param[] = { 0x01 };
+
+	tester_print("Powering on controller");
+
+	mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+					sizeof(param), param,
+					NULL, NULL, NULL);
+
+	mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+				sizeof(param), param, NULL, NULL, NULL);
+
+	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_callback, NULL, NULL);
+}
+
+static void test_framework(const void *test_data)
+{
+	tester_test_passed();
+}
+
+static void test_socket(const void *test_data)
+{
+	int sk;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+	if (sk < 0) {
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		return;
+	}
+
+	close(sk);
+
+	tester_test_passed();
+}
+
+static void test_getsockopt(const void *test_data)
+{
+	int sk, err;
+	socklen_t len;
+	struct bt_voice voice;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+	if (sk < 0) {
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		return;
+	}
+
+	voice.setting = 0;
+	len = sizeof(voice);
+	err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
+	if (err < 0) {
+		tester_warn("Can't get socket option : %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		goto end;
+	}
+
+	if (voice.setting != BT_VOICE_CVSD_16BIT) {
+		tester_warn("Invalid voice setting");
+		tester_test_failed();
+		goto end;
+	}
+
+	tester_test_passed();
+
+end:
+	close(sk);
+}
+
+static void test_setsockopt(const void *test_data)
+{
+	int sk, err;
+	socklen_t len;
+	struct bt_voice voice;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+	if (sk < 0) {
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		goto end;
+	}
+
+
+	voice.setting = 0;
+	len = sizeof(voice);
+	err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
+	if (err < 0) {
+		tester_warn("Can't get socket option : %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		goto end;
+	}
+
+	if (voice.setting != BT_VOICE_CVSD_16BIT) {
+		tester_warn("Invalid voice setting");
+		tester_test_failed();
+		goto end;
+	}
+
+	voice.setting = BT_VOICE_TRANSPARENT;
+	err = setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, sizeof(voice));
+	if (err < 0) {
+		tester_warn("Can't set socket option : %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		goto end;
+	}
+
+	voice.setting = 0;
+	len = sizeof(voice);
+	err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
+	if (err < 0) {
+		tester_warn("Can't get socket option : %s (%d)", strerror(errno),
+									errno);
+		tester_test_failed();
+		goto end;
+	}
+
+	if (voice.setting != BT_VOICE_TRANSPARENT) {
+		tester_warn("Invalid voice setting");
+		tester_test_failed();
+		goto end;
+	}
+
+	tester_test_passed();
+
+end:
+	close(sk);
+}
+
+static int create_sco_sock(struct test_data *data, uint16_t psm)
+{
+	const uint8_t *master_bdaddr;
+	struct sockaddr_sco addr;
+	int sk, err;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK,
+								BTPROTO_SCO);
+	if (sk < 0) {
+		err = -errno;
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		return err;
+	}
+
+	master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
+	if (!master_bdaddr) {
+		tester_warn("No master bdaddr");
+		return -ENODEV;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sco_family = AF_BLUETOOTH;
+	bacpy(&addr.sco_bdaddr, (void *) master_bdaddr);
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = -errno;
+		tester_warn("Can't bind socket: %s (%d)", strerror(errno),
+									errno);
+		close(sk);
+		return err;
+	}
+
+	return sk;
+}
+
+static int connect_sco_sock(struct test_data *data, int sk)
+{
+	const uint8_t *client_bdaddr;
+	struct sockaddr_sco addr;
+	int err;
+
+	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+	if (!client_bdaddr) {
+		tester_warn("No client bdaddr");
+		return -ENODEV;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sco_family = AF_BLUETOOTH;
+	bacpy(&addr.sco_bdaddr, (void *) client_bdaddr);
+
+	err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
+		err = -errno;
+		tester_warn("Can't connect socket: %s (%d)", strerror(errno),
+									errno);
+		return err;
+	}
+
+	return 0;
+}
+
+static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct sco_client_data *scodata = data->test_data;
+	int err, sk_err, sk;
+	socklen_t len = sizeof(sk_err);
+
+	data->io_id = 0;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+		err = -errno;
+	else
+		err = -sk_err;
+
+	if (err < 0)
+		tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
+	else
+		tester_print("Successfully connected");
+
+	if (-err != scodata->expect_err)
+		tester_test_failed();
+	else
+		tester_test_passed();
+
+	return FALSE;
+}
+
+static void test_connect(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	GIOChannel *io;
+	int sk;
+
+	sk = create_sco_sock(data, 0);
+	if (sk < 0) {
+		tester_test_failed();
+		return;
+	}
+
+	if (connect_sco_sock(data, sk) < 0) {
+		close(sk);
+		tester_test_failed();
+		return;
+	}
+
+	io = g_io_channel_unix_new(sk);
+	g_io_channel_set_close_on_unref(io, TRUE);
+
+	data->io_id = g_io_add_watch(io, G_IO_OUT, sco_connect_cb, NULL);
+
+	g_io_channel_unref(io);
+
+	tester_print("Connect in progress");
+}
+
+int main(int argc, char *argv[])
+{
+	tester_init(&argc, &argv);
+
+	test_sco("Basic Framework - Success", NULL, setup_powered,
+								test_framework);
+
+	test_sco("Basic SCO Socket - Success", NULL, setup_powered,
+								test_socket);
+
+	test_sco("Basic SCO Get Socket Option - Success", NULL, setup_powered,
+								test_getsockopt);
+
+	test_sco("Basic SCO Set Socket Option - Success", NULL, setup_powered,
+								test_setsockopt);
+
+	test_sco_long("SCO Socket Client - Success", &client_success_test, setup_powered,
+								test_connect);
+
+	return tester_run();
+}
-- 
1.7.9.5


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

* Re: [RFC 2/5] btio: Add option for SCO voice setting
  2013-06-26 17:32 ` [RFC 2/5] btio: Add option for SCO voice setting Frédéric Dalleau
@ 2013-07-01  7:54   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2013-07-01  7:54 UTC (permalink / raw)
  To: Frédéric Dalleau; +Cc: linux-bluetooth

Hi Fred,

On Wed, Jun 26, 2013 at 8:32 PM, Frédéric Dalleau
<frederic.dalleau@linux.intel.com> wrote:
> ---
>  btio/btio.c |   18 +++++++++++++++---
>  btio/btio.h |    1 +
>  2 files changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/btio/btio.c b/btio/btio.c
> index cb8860a..df1630e 100644
> --- a/btio/btio.c
> +++ b/btio/btio.c
> @@ -78,6 +78,7 @@ struct set_opts {
>         uint8_t mode;
>         int flushable;
>         uint32_t priority;
> +       uint16_t sco_voice;
>  };
>
>  struct connect {
> @@ -723,9 +724,10 @@ static int sco_connect(int sock, const bdaddr_t *dst)
>         return 0;
>  }
>
> -static gboolean sco_set(int sock, uint16_t mtu, GError **err)
> +static gboolean sco_set(int sock, uint16_t mtu, uint16_t sco_voice, GError **err)
>  {
>         struct sco_options sco_opt;
> +       struct bt_voice voice;
>         socklen_t len;
>
>         if (!mtu)
> @@ -745,6 +747,13 @@ static gboolean sco_set(int sock, uint16_t mtu, GError **err)
>                 return FALSE;
>         }
>
> +       voice.setting = sco_voice;
> +       if (setsockopt(sock, SOL_BLUETOOTH, BT_VOICE, &voice,
> +                                               sizeof(voice)) < 0) {
> +               ERROR_FAILED(err, "setsockopt(BT_VOICE)", errno);
> +               return FALSE;
> +       }
> +
>         return TRUE;
>  }
>
> @@ -832,6 +841,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
>                 case BT_IO_OPT_PRIORITY:
>                         opts->priority = va_arg(args, int);
>                         break;
> +               case BT_IO_OPT_SCO_VOICE:
> +                       opts->sco_voice = va_arg(args, int);
> +                       break;
>                 default:
>                         g_set_error(err, BT_IO_ERROR, EINVAL,
>                                         "Unknown option %d", opt);
> @@ -1310,7 +1322,7 @@ gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...)
>         case BT_IO_RFCOMM:
>                 return rfcomm_set(sock, opts.sec_level, opts.master, err);
>         case BT_IO_SCO:
> -               return sco_set(sock, opts.mtu, err);
> +               return sco_set(sock, opts.mtu, opts.sco_voice, err);
>         default:
>                 g_set_error(err, BT_IO_ERROR, EINVAL,
>                                 "Unknown BtIO type %d", type);
> @@ -1377,7 +1389,7 @@ static GIOChannel *create_io(gboolean server, struct set_opts *opts,
>                 }
>                 if (sco_bind(sock, &opts->src, err) < 0)
>                         goto failed;
> -               if (!sco_set(sock, opts->mtu, err))
> +               if (!sco_set(sock, opts->mtu, opts->sco_voice, err))
>                         goto failed;
>                 break;
>         default:
> diff --git a/btio/btio.h b/btio/btio.h
> index ac1366b..9959483 100644
> --- a/btio/btio.h
> +++ b/btio/btio.h
> @@ -55,6 +55,7 @@ typedef enum {
>         BT_IO_OPT_MODE,
>         BT_IO_OPT_FLUSHABLE,
>         BT_IO_OPT_PRIORITY,
> +       BT_IO_OPT_SCO_VOICE,

I believe here is better to use BT_IO_OPT_VOICE for simplicity, the
socket option itself doesn't carry SCO name so I don't thing it is
necessary here either.


--
Luiz Augusto von Dentz

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

end of thread, other threads:[~2013-07-01  7:54 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-26 17:32 [RFC 0/5] sco: Integrate SCO socket option in user space Frédéric Dalleau
2013-06-26 17:32 ` [RFC 1/5] lib: SCO voice setting support header Frédéric Dalleau
2013-06-26 17:32 ` [RFC 2/5] btio: Add option for SCO voice setting Frédéric Dalleau
2013-07-01  7:54   ` Luiz Augusto von Dentz
2013-06-26 17:32 ` [RFC 3/5] btiotest: " Frédéric Dalleau
2013-06-26 17:32 ` [RFC 4/5] scotest: " Frédéric Dalleau
2013-06-26 17:32 ` [RFC 5/5] sco-tester: Initial sco tester implementation Frédéric Dalleau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.