Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 3/5] core: Add flags parameter to bt_search_service
From: Szymon Janc @ 2014-01-20 11:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390216116-23670-1-git-send-email-szymon.janc@tieto.com>

From: Szymon Janc <szymon.janc@gmail.com>

This allows to pass custom SDP flags to sdp_connect.
---
 android/bluetooth.c        | 4 ++--
 android/hidhost.c          | 4 ++--
 android/socket.c           | 2 +-
 profiles/health/hdp_util.c | 6 +++---
 src/device.c               | 5 +++--
 src/profile.c              | 2 +-
 src/sdp-client.c           | 8 ++++----
 src/sdp-client.h           | 2 +-
 8 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 505d5a7..83612b4 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -693,7 +693,7 @@ static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
 	if (uuid_list[req->search_uuid]) {
 		sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
 		bt_search_service(&adapter.bdaddr, &req->bdaddr, &uuid,
-						browse_cb, user_data, NULL);
+						browse_cb, user_data, NULL, 0);
 		return;
 	}
 
@@ -729,7 +729,7 @@ static uint8_t browse_remote_sdp(const bdaddr_t *addr)
 	sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
 
 	if (bt_search_service(&adapter.bdaddr,
-			&req->bdaddr, &uuid, browse_cb, req, NULL) < 0) {
+			&req->bdaddr, &uuid, browse_cb, req, NULL , 0) < 0) {
 		browse_req_free(req);
 		return HAL_STATUS_FAILED;
 	}
diff --git a/android/hidhost.c b/android/hidhost.c
index aed9899..d66e863 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -751,7 +751,7 @@ static void bt_hid_connect(const void *buf, uint16_t len)
 
 	bt_string2uuid(&uuid, HID_UUID);
 	if (bt_search_service(&adapter_addr, &dev->dst, &uuid,
-					hid_sdp_search_cb, dev, NULL) < 0) {
+					hid_sdp_search_cb, dev, NULL, 0) < 0) {
 		error("Failed to search sdp details");
 		hid_device_free(dev);
 		status = HAL_STATUS_FAILED;
@@ -1254,7 +1254,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 
 		bt_string2uuid(&uuid, HID_UUID);
 		if (bt_search_service(&src, &dev->dst, &uuid,
-					hid_sdp_search_cb, dev, NULL) < 0) {
+					hid_sdp_search_cb, dev, NULL, 0) < 0) {
 			error("failed to search sdp details");
 			hid_device_free(dev);
 			return;
diff --git a/android/socket.c b/android/socket.c
index 69b39ee..f662e79 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -1091,7 +1091,7 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
 		rfsock->profile = get_profile_by_uuid(uuid);
 
 		if (bt_search_service(&adapter_addr, &rfsock->dst, &uu,
-					sdp_search_cb, rfsock, NULL) < 0) {
+					sdp_search_cb, rfsock, NULL, 0) < 0) {
 			error("Failed to search SDP records");
 			goto failed;
 		}
diff --git a/profiles/health/hdp_util.c b/profiles/health/hdp_util.c
index 7de87a8..b9a09e9 100644
--- a/profiles/health/hdp_util.c
+++ b/profiles/health/hdp_util.c
@@ -864,7 +864,7 @@ gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app,
 
 	bt_string2uuid(&uuid, HDP_UUID);
 	if (bt_search_service(src, dst, &uuid, get_mdep_cb, mdep_data,
-							free_mdep_data) < 0) {
+						free_mdep_data, 0) < 0) {
 		g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
 						"Can't get remote SDP record");
 		g_free(mdep_data);
@@ -1092,7 +1092,7 @@ gboolean hdp_establish_mcl(struct hdp_device *device,
 
 	bt_string2uuid(&uuid, HDP_UUID);
 	if (bt_search_service(src, dst, &uuid, search_cb, conn_data,
-						destroy_con_mcl_data) < 0) {
+					destroy_con_mcl_data, 0) < 0) {
 		g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
 						"Can't get remote SDP record");
 		g_free(conn_data);
@@ -1161,7 +1161,7 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func,
 
 	bt_string2uuid(&uuid, HDP_UUID);
 	if (bt_search_service(src, dst, &uuid, get_dcpsm_cb, dcpsm_data,
-							free_dcpsm_data) < 0) {
+						free_dcpsm_data, 0) < 0) {
 		g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
 						"Can't get remote SDP record");
 		g_free(dcpsm_data);
diff --git a/src/device.c b/src/device.c
index bcc5561..1bd27a1 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2971,7 +2971,7 @@ static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
 		sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
 		bt_search_service(btd_adapter_get_address(adapter),
 						&device->bdaddr, &uuid,
-						browse_cb, user_data, NULL);
+						browse_cb, user_data, NULL, 0);
 		return;
 	}
 
@@ -3513,7 +3513,8 @@ static int device_browse_sdp(struct btd_device *device, DBusMessage *msg)
 	sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
 
 	err = bt_search_service(btd_adapter_get_address(adapter),
-				&device->bdaddr, &uuid, browse_cb, req, NULL);
+				&device->bdaddr, &uuid, browse_cb, req, NULL,
+				0);
 	if (err < 0) {
 		browse_request_free(req);
 		return err;
diff --git a/src/profile.c b/src/profile.c
index 3c0d27c..e833181 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -1605,7 +1605,7 @@ static int resolve_service(struct ext_io *conn, const bdaddr_t *src,
 	bt_string2uuid(&uuid, ext->remote_uuid);
 	sdp_uuid128_to_uuid(&uuid);
 
-	err = bt_search_service(src, dst, &uuid, record_cb, conn, NULL);
+	err = bt_search_service(src, dst, &uuid, record_cb, conn, NULL, 0);
 	if (err == 0)
 		conn->resolving = true;
 
diff --git a/src/sdp-client.c b/src/sdp-client.c
index 0599626..ff06b4d 100644
--- a/src/sdp-client.c
+++ b/src/sdp-client.c
@@ -264,7 +264,7 @@ failed:
 static int create_search_context(struct search_context **ctxt,
 					const bdaddr_t *src,
 					const bdaddr_t *dst,
-					uuid_t *uuid)
+					uuid_t *uuid, uint16_t flags)
 {
 	sdp_session_t *s;
 	GIOChannel *chan;
@@ -276,7 +276,7 @@ static int create_search_context(struct search_context **ctxt,
 
 	s = get_cached_sdp_session(src, dst);
 	if (!s)
-		s = sdp_connect(src, dst, SDP_NON_BLOCKING);
+		s = sdp_connect(src, dst, SDP_NON_BLOCKING | flags);
 
 	if (!s)
 		return -errno;
@@ -311,7 +311,7 @@ static int create_search_context(struct search_context **ctxt,
 
 int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
 			uuid_t *uuid, bt_callback_t cb, void *user_data,
-			bt_destroy_t destroy)
+			bt_destroy_t destroy, uint16_t flags)
 {
 	struct search_context *ctxt = NULL;
 	int err;
@@ -319,7 +319,7 @@ int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
 	if (!cb)
 		return -EINVAL;
 
-	err = create_search_context(&ctxt, src, dst, uuid);
+	err = create_search_context(&ctxt, src, dst, uuid, flags);
 	if (err < 0)
 		return err;
 
diff --git a/src/sdp-client.h b/src/sdp-client.h
index 9191594..9aa5a4d 100644
--- a/src/sdp-client.h
+++ b/src/sdp-client.h
@@ -26,6 +26,6 @@ typedef void (*bt_destroy_t) (gpointer user_data);
 
 int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
 			uuid_t *uuid, bt_callback_t cb, void *user_data,
-			bt_destroy_t destroy);
+			bt_destroy_t destroy, uint16_t flags);
 int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst);
 void bt_clear_cached_session(const bdaddr_t *src, const bdaddr_t *dst);
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH v2 2/5] core: Opencode get_sdp_session in sdp-client
From: Szymon Janc @ 2014-01-20 11:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390216116-23670-1-git-send-email-szymon.janc@tieto.com>

From: Szymon Janc <szymon.janc@gmail.com>

This is only used once and provides no benefit compared to opencoding.
---
 src/sdp-client.c | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/src/sdp-client.c b/src/sdp-client.c
index 51f3048..0599626 100644
--- a/src/sdp-client.c
+++ b/src/sdp-client.c
@@ -86,17 +86,6 @@ static sdp_session_t *get_cached_sdp_session(const bdaddr_t *src, const bdaddr_t
 	return NULL;
 }
 
-static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
-{
-	sdp_session_t *session;
-
-	session = get_cached_sdp_session(src, dst);
-	if (session)
-		return session;
-
-	return sdp_connect(src, dst, SDP_NON_BLOCKING);
-}
-
 static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
 						sdp_session_t *session)
 {
@@ -285,7 +274,10 @@ static int create_search_context(struct search_context **ctxt,
 	if (!ctxt)
 		return -EINVAL;
 
-	s = get_sdp_session(src, dst);
+	s = get_cached_sdp_session(src, dst);
+	if (!s)
+		s = sdp_connect(src, dst, SDP_NON_BLOCKING);
+
 	if (!s)
 		return -errno;
 
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH v2 1/5] lib: Add flag to force large MTU size used for SDP connection
From: Szymon Janc @ 2014-01-20 11:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

From: Szymon Janc <szymon.janc@gmail.com>

This will allow to workaround Dualshock4 not respecting L2CAP MTU
size while sending SDP response. Use same L2CAP MTU value base on
RFCOMM.
---
 lib/sdp.c     | 27 +++++++++++++++++++++++++++
 lib/sdp_lib.h |  1 +
 2 files changed, 28 insertions(+)

diff --git a/lib/sdp.c b/lib/sdp.c
index 886e7cf..3b26ec3 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -67,6 +67,9 @@ static uint128_t bluetooth_base_uuid = {
 
 #define SDP_MAX_ATTR_LEN 65535
 
+/* match MTU used by RFCOMM */
+#define SDP_LARGE_L2CAP_MTU 1013
+
 static sdp_data_t *sdp_copy_seq(sdp_data_t *data);
 static int sdp_attr_add_new_with_length(sdp_record_t *rec,
 	uint16_t attr, uint8_t dtd, const void *value, uint32_t len);
@@ -4644,6 +4647,26 @@ static int sdp_connect_local(sdp_session_t *session)
 	return connect(session->sock, (struct sockaddr *) &sa, sizeof(sa));
 }
 
+static int set_l2cap_mtu(int sk, uint16_t mtu)
+{
+	struct l2cap_options l2o;
+	socklen_t len;
+
+	memset(&l2o, 0, sizeof(l2o));
+	len = sizeof(l2o);
+
+	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0)
+		return -1;
+
+	l2o.imtu = mtu;
+	l2o.omtu = mtu;
+
+	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0)
+		return -1;
+
+	return 0;
+}
+
 static int sdp_connect_l2cap(const bdaddr_t *src,
 		const bdaddr_t *dst, sdp_session_t *session)
 {
@@ -4678,6 +4701,10 @@ static int sdp_connect_l2cap(const bdaddr_t *src,
 		setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
 	}
 
+	if ((flags & SDP_LARGE_MTU) &&
+				set_l2cap_mtu(sk, SDP_LARGE_L2CAP_MTU) < 0)
+		return -1;
+
 	sa.l2_psm = htobs(SDP_PSM);
 	sa.l2_bdaddr = *dst;
 
diff --git a/lib/sdp_lib.h b/lib/sdp_lib.h
index 6e1eb91..3ded393 100644
--- a/lib/sdp_lib.h
+++ b/lib/sdp_lib.h
@@ -81,6 +81,7 @@ static inline void sdp_list_foreach(sdp_list_t *list, sdp_list_func_t f, void *u
 #define SDP_RETRY_IF_BUSY	0x01
 #define SDP_WAIT_ON_CLOSE	0x02
 #define SDP_NON_BLOCKING	0x04
+#define SDP_LARGE_MTU		0x08
 
 /*
  * a session with an SDP server
-- 
1.8.3.2


^ permalink raw reply related

* Re: [PATCH 1/2] tester: Remove test timeout for setup failure
From: Johan Hedberg @ 2014-01-20 10:20 UTC (permalink / raw)
  To: Jakub Tyszkowski; +Cc: linux-bluetooth
In-Reply-To: <1390212008-5376-1-git-send-email-jakub.tyszkowski@tieto.com>

Hi Jakub,

On Mon, Jan 20, 2014, Jakub Tyszkowski wrote:
> If setup fails, timeout function is not removed and still can be called,
> causing random subsequent case failure.
> ---
>  src/shared/tester.c | 5 +++++
>  1 file changed, 5 insertions(+)

Both patches have been applied. Thanks.

Johan

^ permalink raw reply

* [PATCH 2/2] android/pan: Initialize GError with NULL
From: Jakub Tyszkowski @ 2014-01-20 10:00 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390212008-5376-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch fixes the following issue:

bluetoothd[10552]: android/pan.c:register_nap_server()
bluetoothd[10552]: android/pan.c:nap_create_bridge() bnep
(bluetoothd:10552): GLib-WARNING **: GError set over the top of a previous GError or uninitialized memory.
This indicates a bug in someone's code. You must ensure an error is NULL before it's set.
The overwriting error message was: l2cap_bind: Address already in use (98)
bluetoothd[10552]: android/pan.c:destroy_nap_device()
---
 android/pan.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/pan.c b/android/pan.c
index dfd7762..3544d74 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -542,7 +542,7 @@ static void destroy_nap_device(void)
 
 static int register_nap_server(void)
 {
-	GError *gerr;
+	GError *gerr = NULL;
 	int err;
 
 	DBG("");
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 1/2] tester: Remove test timeout for setup failure
From: Jakub Tyszkowski @ 2014-01-20 10:00 UTC (permalink / raw)
  To: linux-bluetooth

If setup fails, timeout function is not removed and still can be called,
causing random subsequent case failure.
---
 src/shared/tester.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/shared/tester.c b/src/shared/tester.c
index f3edd74..06fc415 100644
--- a/src/shared/tester.c
+++ b/src/shared/tester.c
@@ -460,6 +460,11 @@ void tester_setup_failed(void)
 	if (test->stage != TEST_STAGE_SETUP)
 		return;
 
+	if (test->timeout_id > 0) {
+		g_source_remove(test->timeout_id);
+		test->timeout_id = 0;
+	}
+
 	print_progress(test->name, COLOR_RED, "setup failed");
 
 	g_idle_add(done_callback, test);
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 11/11] android/ipc-tester: Add cases for BT message data size
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch adds sending invalid size data for each of
Bluetooth service opcodes.
---
 android/ipc-tester.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 3d1561d..ed0dd10 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -721,5 +721,148 @@ int main(int argc, char *argv[])
 	test_datasize_valid("CORE Unregister-", HAL_SERVICE_ID_CORE,
 			HAL_OP_UNREGISTER_MODULE,
 			sizeof(struct hal_cmd_register_module), -1);
+
+	/* check for valid data size for BLUETOOTH */
+	test_datasize_valid("BT Enable+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_ENABLE,
+			0, 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Disable+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_DISABLE,
+			0, 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Adapter Props+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_ADAPTER_PROPS,
+			0, 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Adapter Prop+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_ADAPTER_PROP,
+			sizeof(struct hal_cmd_get_adapter_prop), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Adapter Prop-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_ADAPTER_PROP,
+			sizeof(struct hal_cmd_get_adapter_prop), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Set Adapter Prop+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_SET_ADAPTER_PROP,
+			sizeof(struct hal_cmd_set_adapter_prop), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Set Adapter Prop-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_SET_ADAPTER_PROP,
+			sizeof(struct hal_cmd_set_adapter_prop), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote Props+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_DEVICE_PROPS,
+			sizeof(struct hal_cmd_get_remote_device_props), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote Props-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_DEVICE_PROPS,
+			sizeof(struct hal_cmd_get_remote_device_props), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote Prop+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_DEVICE_PROP,
+			sizeof(struct hal_cmd_get_remote_device_prop), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote Prop-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_DEVICE_PROP,
+			sizeof(struct hal_cmd_get_remote_device_prop), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Set Remote Prop+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_SET_REMOTE_DEVICE_PROP,
+			sizeof(struct hal_cmd_set_remote_device_prop), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Set Remote Prop-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_SET_REMOTE_DEVICE_PROP,
+			sizeof(struct hal_cmd_set_remote_device_prop), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote SV Rec+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_SERVICE_REC,
+			sizeof(struct hal_cmd_get_remote_service_rec), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote SV Rec-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_SERVICE_REC,
+			sizeof(struct hal_cmd_get_remote_service_rec), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote Services+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_SERVICES,
+			sizeof(struct hal_cmd_get_remote_services), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Get Remote Services-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_GET_REMOTE_SERVICES,
+			sizeof(struct hal_cmd_get_remote_services), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Start Discovery+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_START_DISCOVERY,
+			0, 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Cancel Discovery+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_CANCEL_DISCOVERY,
+			0, 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Create Bond+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_CREATE_BOND,
+			sizeof(struct hal_cmd_create_bond), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Create Bond-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_CREATE_BOND,
+			sizeof(struct hal_cmd_create_bond), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Remove Bond+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_REMOVE_BOND,
+			sizeof(struct hal_cmd_remove_bond), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Remove Bond-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_REMOVE_BOND,
+			sizeof(struct hal_cmd_remove_bond), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Cancel Bond+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_CANCEL_BOND,
+			sizeof(struct hal_cmd_cancel_bond), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Cancel Bond-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_CANCEL_BOND,
+			sizeof(struct hal_cmd_cancel_bond), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Pin Reply+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_PIN_REPLY,
+			sizeof(struct hal_cmd_pin_reply), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT Pin Reply-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_PIN_REPLY,
+			sizeof(struct hal_cmd_pin_reply), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT SSP Reply+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_SSP_REPLY,
+			sizeof(struct hal_cmd_ssp_reply), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT SSP Reply-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_SSP_REPLY,
+			sizeof(struct hal_cmd_ssp_reply), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT DUT Mode Conf+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_DUT_MODE_CONF,
+			sizeof(struct hal_cmd_dut_mode_conf), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT DUT Mode Conf-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_DUT_MODE_CONF,
+			sizeof(struct hal_cmd_dut_mode_conf), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT DUT Mode Send+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_DUT_MODE_SEND,
+			sizeof(struct hal_cmd_dut_mode_send), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT DUT Mode Send-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_DUT_MODE_SEND,
+			sizeof(struct hal_cmd_dut_mode_send), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT LE Test+", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_LE_TEST_MODE,
+			sizeof(struct hal_cmd_le_test_mode), 1,
+			HAL_SERVICE_ID_BLUETOOTH);
+	test_datasize_valid("BT LE Test-", HAL_SERVICE_ID_BLUETOOTH,
+			HAL_OP_LE_TEST_MODE,
+			sizeof(struct hal_cmd_le_test_mode), -1,
+			HAL_SERVICE_ID_BLUETOOTH);
+
 	return tester_run();
 }
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 10/11] android/ipc-tester: Add cases for Core message data size
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

Add testing for improper data sizes for Core service opcodes.
---
 android/ipc-tester.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index cebe751..3d1561d 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -573,6 +573,27 @@ static void ipc_send_tc(const void *data)
 				_servicelist);				\
 	} while (0)
 
+struct vardata {
+	struct hal_hdr hdr;
+	uint8_t buf[BLUEZ_HAL_MTU];
+} __attribute__((packed));
+
+#define test_datasize_valid(_name, _service, _opcode, _hlen, _addatasize, \
+							_servicelist...) \
+	do {								\
+		static struct vardata vdata = {				\
+			.hdr.service_id = _service,			\
+			.hdr.opcode = _opcode,				\
+			.hdr.len = (_hlen) + (_addatasize),		\
+			.buf = {},					\
+		};							\
+		test_generic("Data size "_name,				\
+				ipc_send_tc, setup, teardown,		\
+				&vdata,					\
+				sizeof(vdata.hdr) + (_hlen) + (_addatasize),\
+				_servicelist);				\
+	} while (0)
+
 struct regmod_msg register_bt_msg = {
 	.header = {
 		.service_id = HAL_SERVICE_ID_CORE,
@@ -686,5 +707,19 @@ int main(int argc, char *argv[])
 
 	test_opcode_valid("A2DP", HAL_SERVICE_ID_A2DP, 0x03, 0,
 			HAL_SERVICE_ID_BLUETOOTH, HAL_SERVICE_ID_A2DP);
+
+	/* check for valid data size */
+	test_datasize_valid("CORE Register+", HAL_SERVICE_ID_CORE,
+			HAL_OP_REGISTER_MODULE,
+			sizeof(struct hal_cmd_register_module), 1);
+	test_datasize_valid("CORE Register-", HAL_SERVICE_ID_CORE,
+			HAL_OP_REGISTER_MODULE,
+			sizeof(struct hal_cmd_register_module), -1);
+	test_datasize_valid("CORE Unregister+", HAL_SERVICE_ID_CORE,
+			HAL_OP_UNREGISTER_MODULE,
+			sizeof(struct hal_cmd_register_module), 1);
+	test_datasize_valid("CORE Unregister-", HAL_SERVICE_ID_CORE,
+			HAL_OP_UNREGISTER_MODULE,
+			sizeof(struct hal_cmd_register_module), -1);
 	return tester_run();
 }
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 09/11] android/ipc-tester: Add cases for service opcode boundaries
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

This patch adds tests sending out of range opcode for each service.
---
 android/ipc-tester.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index db0a30a..cebe751 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -558,6 +558,21 @@ static void ipc_send_tc(const void *data)
 				3, user, g_free);			\
 	} while (0)
 
+#define test_opcode_valid(_name, _service, _opcode, _len, _servicelist...) \
+	do {								\
+		static struct hal_hdr hdr = {				\
+			.service_id = _service,				\
+			.opcode = _opcode,				\
+			.len = _len,					\
+		};							\
+									\
+		test_generic("Opcode out of range: "_name,		\
+				ipc_send_tc, setup, teardown,		\
+				&hdr,					\
+				sizeof(hdr),				\
+				_servicelist);				\
+	} while (0)
+
 struct regmod_msg register_bt_msg = {
 	.header = {
 		.service_id = HAL_SERVICE_ID_CORE,
@@ -654,5 +669,22 @@ int main(int argc, char *argv[])
 				&enable_bt_service_hdr,
 				sizeof(enable_bt_service_hdr));
 
+	/* check service handler's max opcode value */
+	test_opcode_valid("CORE", HAL_SERVICE_ID_CORE, 0x03, 0);
+
+	test_opcode_valid("BLUETOOTH", HAL_SERVICE_ID_BLUETOOTH, 0x15, 0,
+			HAL_SERVICE_ID_BLUETOOTH);
+
+	test_opcode_valid("SOCK", HAL_SERVICE_ID_SOCK, 0x03, 0,
+			HAL_SERVICE_ID_BLUETOOTH, HAL_SERVICE_ID_SOCK);
+
+	test_opcode_valid("HIDHOST", HAL_SERVICE_ID_HIDHOST, 0x10, 0,
+			HAL_SERVICE_ID_BLUETOOTH, HAL_SERVICE_ID_HIDHOST);
+
+	test_opcode_valid("PAN", HAL_SERVICE_ID_PAN, 0x05, 0,
+			HAL_SERVICE_ID_BLUETOOTH, HAL_SERVICE_ID_PAN);
+
+	test_opcode_valid("A2DP", HAL_SERVICE_ID_A2DP, 0x03, 0,
+			HAL_SERVICE_ID_BLUETOOTH, HAL_SERVICE_ID_A2DP);
 	return tester_run();
 }
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 08/11] android/ipc-tester: Add more cases for malformed data
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

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

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index c8bc9b8..db0a30a 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -581,6 +581,27 @@ struct regmod_msg register_bt_malformed_size_msg = {
 		},
 };
 
+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,
+};
+
 struct hal_hdr enable_unknown_service_hdr = {
 	.service_id = HAL_SERVICE_ID_MAX + 1,
 	.opcode = HAL_OP_REGISTER_MODULE,
@@ -610,6 +631,18 @@ int main(int argc, char *argv[])
 				sizeof(register_bt_malformed_size_msg),
 				HAL_SERVICE_ID_BLUETOOTH);
 
+	test_generic("Malformed data2 (undersized msg)",
+				ipc_send_tc, setup, teardown,
+				&register_bt_msg,
+				sizeof(register_bt_msg) - 1,
+				HAL_SERVICE_ID_BLUETOOTH);
+
+	test_generic("Malformed data3 (oversized msg)",
+				ipc_send_tc, setup, teardown,
+				&malformed_data3_msg,
+				sizeof(malformed_data3_msg),
+				HAL_SERVICE_ID_BLUETOOTH);
+
 	test_generic("Invalid service",
 				ipc_send_tc, setup, teardown,
 				&enable_unknown_service_hdr,
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 07/11] android/ipc-tester: Add basic test cases for IPC's daemon site
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

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

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 816719c..c8bc9b8 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -569,15 +569,57 @@ struct regmod_msg register_bt_msg = {
 		},
 };
 
+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,
+		},
+};
+
+struct hal_hdr enable_unknown_service_hdr = {
+	.service_id = HAL_SERVICE_ID_MAX + 1,
+	.opcode = HAL_OP_REGISTER_MODULE,
+	.len = 0,
+};
+
+struct hal_hdr enable_bt_service_hdr = {
+	.service_id = HAL_SERVICE_ID_BLUETOOTH,
+	.opcode = HAL_OP_ENABLE,
+	.len = 0,
+};
+
 int main(int argc, char *argv[])
 {
 	snprintf(exec_dir, sizeof(exec_dir), "%s", dirname(argv[0]));
 
 	tester_init(&argc, &argv);
 
+	/* check general IPC errors */
 	test_generic("Too small data",
 				ipc_send_tc, setup, teardown,
 				&register_bt_msg, 1);
 
+	test_generic("Malformed data (wrong payload declared)",
+				ipc_send_tc, setup, teardown,
+				&register_bt_malformed_size_msg,
+				sizeof(register_bt_malformed_size_msg),
+				HAL_SERVICE_ID_BLUETOOTH);
+
+	test_generic("Invalid service",
+				ipc_send_tc, setup, teardown,
+				&enable_unknown_service_hdr,
+				sizeof(enable_unknown_service_hdr),
+				HAL_SERVICE_ID_BLUETOOTH);
+
+	test_generic("Enable unregistered service",
+				ipc_send_tc, setup, teardown,
+				&enable_bt_service_hdr,
+				sizeof(enable_bt_service_hdr));
+
 	return tester_run();
 }
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 06/11] android/ipc-tester: Register services
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-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 | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 7cd50f5..816719c 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -407,13 +407,48 @@ static gboolean check_for_daemon(gpointer user_data)
 	return false;
 }
 
+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))
 		goto failed;
@@ -451,9 +486,17 @@ static void setup(const void *data)
 		tester_warn("Cannot initialize IPC mechanism!");
 		goto failed;
 	}
-	/* 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])) {
+			cleanup_ipc();
+			goto failed;
+		}
 
 	test_data->setup_done = true;
+
+	tester_setup_complete();
 	return;
 
 failed:
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 05/11] android/ipc-tester: Add sending test data with ipc
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-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. Test execution macro is extended for easy
data preparation.
---
 android/ipc-tester.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 58 insertions(+), 4 deletions(-)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index b6f8131..7cd50f5 100644
--- a/android/ipc-tester.c
+++ b/android/ipc-tester.c
@@ -55,6 +55,23 @@ 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[];
+};
+
+struct regmod_msg {
+	struct hal_hdr header;
+	struct hal_cmd_register_module cmd;
+} __attribute__((packed));
+
 #define CONNECT_TIMEOUT (5 * 1000)
 #define SERVICE_NAME "bluetoothd"
 
@@ -460,27 +477,64 @@ 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_generic(name, data, test_setup, test, test_teardown) \
+#define service_data(args...) { args }
+
+#define gen_data(writelen, writebuf, servicelist...) \
+	{								\
+		.ipc_data = {						\
+			.buffer = writebuf,				\
+			.len = writelen,				\
+		},							\
+		.init_services = service_data(servicelist),		\
+		.num_services = sizeof((const int[])			\
+					service_data(servicelist)) /	\
+					sizeof(int),			\
+	}
+
+#define test_generic(name, test, setup, teardown, buffer, writelen, \
+							services...) \
 	do {								\
 		struct test_data *user;					\
+		static const struct generic_data data =			\
+				gen_data(writelen, buffer, services);	\
 		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,\
+		tester_add_full(name, &data, test_pre_setup, setup,	\
+				test, teardown, test_post_teardown,	\
 				3, user, g_free);			\
 	} while (0)
 
+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_BLUETOOTH,
+		},
+};
+
 int main(int argc, char *argv[])
 {
 	snprintf(exec_dir, sizeof(exec_dir), "%s", dirname(argv[0]));
 
 	tester_init(&argc, &argv);
 
-	test_generic("Test Dummy", NULL, setup, ipc_send_tc, teardown);
+	test_generic("Too small data",
+				ipc_send_tc, setup, teardown,
+				&register_bt_msg, 1);
 
 	return tester_run();
 }
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 04/11] android/ipc-tester: Add daemon shutdown handler
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

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

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index ff17ced..b6f8131 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)
@@ -364,6 +365,31 @@ 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();
+		test_post_teardown(data);
+	}
+
+	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();
@@ -401,24 +427,29 @@ static void setup(const void *data)
 		goto failed;
 	}
 
+	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, check_for_daemon, test_data,
+									NULL);
+
 	if (!init_ipc()) {
 		tester_warn("Cannot initialize IPC mechanism!");
 		goto failed;
 	}
 	/* TODO: register modules */
 
+	test_data->setup_done = true;
 	return;
 
 failed:
+	g_idle_remove_by_data(test_data);
 	tester_setup_failed();
 	test_post_teardown(data);
 }
 
-
 static void teardown(const void *data)
 {
 	struct test_data *test_data = tester_get_data();
 
+	g_idle_remove_by_data(test_data);
 	cleanup_ipc();
 
 	if (test_data->bluetoothd_pid)
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 03/11] android/ipc-tester: Add IPC initialization
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-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 | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index c8d1f0b..ff17ced 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)
 {
@@ -248,6 +258,112 @@ 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)
+{
+	if (cmd_sk < 0)
+		return;
+
+	close(cmd_sk);
+	cmd_sk = -1;
+}
+
 static void setup(const void *data)
 {
 	struct test_data *test_data = tester_get_data();
@@ -285,6 +401,12 @@ static void setup(const void *data)
 		goto failed;
 	}
 
+	if (!init_ipc()) {
+		tester_warn("Cannot initialize IPC mechanism!");
+		goto failed;
+	}
+	/* TODO: register modules */
+
 	return;
 
 failed:
@@ -292,10 +414,13 @@ failed:
 	test_post_teardown(data);
 }
 
+
 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

* [PATCHv5 02/11] android/ipc-tester: Run daemon in separate process
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

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

diff --git a/android/ipc-tester.c b/android/ipc-tester.c
index 021919e..c8d1f0b 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)
 {
@@ -170,14 +182,123 @@ static void test_post_teardown(const void *data)
 	}
 }
 
+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)
 {
+	struct test_data *test_data = tester_get_data();
+	int signal_fd[2];
+	char buf[1024];
+	pid_t pid;
+	int len;
+
+	if (pipe(signal_fd))
+		goto failed;
+
+	pid = fork();
+
+	if (pid < 0) {
+		close(signal_fd[0]);
+		close(signal_fd[1]);
+		goto failed;
+	}
+
+	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]);
+		goto failed;
+	}
+
+	return;
+
+failed:
 	tester_setup_failed();
 	test_post_teardown(data);
 }
 
 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();
 }
 
@@ -199,6 +320,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_generic("Test Dummy", NULL, setup, ipc_send_tc, teardown);
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 01/11] android/ipc-tester: Skeleton for ipc negative tester
From: Jakub Tyszkowski @ 2014-01-20  9:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210570-28260-1-git-send-email-jakub.tyszkowski@tieto.com>

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

diff --git a/.gitignore b/.gitignore
index 2c8e033..67e9850 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,4 +114,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 f24b754..e027cff 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -120,6 +120,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-msg.h \
 					android/hal-audio.c \
diff --git a/android/ipc-tester.c b/android/ipc-tester.c
new file mode 100644
index 0000000..021919e
--- /dev/null
+++ b/android/ipc-tester.c
@@ -0,0 +1,207 @@
+/*
+ *
+ *  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();
+
+	if (test_data->hciemu) {
+		hciemu_unref(test_data->hciemu);
+		test_data->hciemu = NULL;
+	}
+}
+
+static void setup(const void *data)
+{
+	tester_setup_failed();
+	test_post_teardown(data);
+}
+
+static void teardown(const void *data)
+{
+	tester_teardown_complete();
+}
+
+static void ipc_send_tc(const void *data)
+{
+}
+
+#define test_generic(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_generic("Test Dummy", NULL, setup, ipc_send_tc, teardown);
+
+	return tester_run();
+}
-- 
1.8.5.2


^ permalink raw reply related

* [PATCHv5 00/11] IPC negative tester
From: Jakub Tyszkowski @ 2014-01-20  9:35 UTC (permalink / raw)
  To: linux-bluetooth

Following patchset adds IPC negative tester framework along with 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

v5 changes:
  * added clean up in case of setup failure
  * added test execution macro enhancement for easy data creation
  * added test cases for core BT interfaces (Patches: 9, 10, 11)

Jakub Tyszkowski (11):
  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
  android/ipc-tester: Add cases for service opcode boundaries
  android/ipc-tester: Add cases for Core message data size
  android/ipc-tester: Add cases for BT message data size

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

--
1.8.5.2


^ permalink raw reply

* [PATCH SBC 2/2] sbc: Add sbc_init_a2dp to sbc.sym
From: Luiz Augusto von Dentz @ 2014-01-20  9:31 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390210303-22692-1-git-send-email-luiz.dentz@gmail.com>

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

---
 sbc/sbc.sym | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sbc/sbc.sym b/sbc/sbc.sym
index 3a0c6bf..0c23a05 100644
--- a/sbc/sbc.sym
+++ b/sbc/sbc.sym
@@ -19,3 +19,7 @@ SBC_1.1 {
 global:
 	sbc_init_msbc;
 } SBC_1.0;
+SBC_1.2 {
+global:
+	sbc_init_a2dp;
+} SBC_1.1;
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH SBC 1/2] sbc: Add sbc_init_a2dp
From: Luiz Augusto von Dentz @ 2014-01-20  9:31 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds sbc_init_a2dp that can be used to convert A2DP configuration to
the internal representation since they are not binary compatible.
---
 sbc/sbc.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sbc/sbc.h |   1 +
 2 files changed, 139 insertions(+)

diff --git a/sbc/sbc.c b/sbc/sbc.c
index c589217..4483074 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -57,6 +57,55 @@
 #define MSBC_SYNCWORD	0xAD
 #define MSBC_BLOCKS	15
 
+#define A2DP_SAMPLING_FREQ_16000		(1 << 3)
+#define A2DP_SAMPLING_FREQ_32000		(1 << 2)
+#define A2DP_SAMPLING_FREQ_44100		(1 << 1)
+#define A2DP_SAMPLING_FREQ_48000		1
+
+#define A2DP_CHANNEL_MODE_MONO			(1 << 3)
+#define A2DP_CHANNEL_MODE_DUAL_CHANNEL		(1 << 2)
+#define A2DP_CHANNEL_MODE_STEREO		(1 << 1)
+#define A2DP_CHANNEL_MODE_JOINT_STEREO		1
+
+#define A2DP_BLOCK_LENGTH_4			(1 << 3)
+#define A2DP_BLOCK_LENGTH_8			(1 << 2)
+#define A2DP_BLOCK_LENGTH_12			(1 << 1)
+#define A2DP_BLOCK_LENGTH_16			1
+
+#define A2DP_SUBBANDS_4				(1 << 1)
+#define A2DP_SUBBANDS_8				1
+
+#define A2DP_ALLOCATION_SNR			(1 << 1)
+#define A2DP_ALLOCATION_LOUDNESS		1
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+typedef struct {
+	uint8_t channel_mode:4;
+	uint8_t frequency:4;
+	uint8_t allocation_method:2;
+	uint8_t subbands:2;
+	uint8_t block_length:4;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed)) a2dp_sbc_t;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+typedef struct {
+	uint8_t frequency:4;
+	uint8_t channel_mode:4;
+	uint8_t block_length:4;
+	uint8_t subbands:2;
+	uint8_t allocation_method:2;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed)) a2dp_sbc_t;
+
+#else
+#error "Unknown byte order"
+#endif
+
 /* This structure contains an unpacked SBC frame.
    Yes, there is probably quite some unused space herein */
 struct sbc_frame {
@@ -1046,6 +1095,95 @@ SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags)
 	return 0;
 }
 
+SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags, void *data)
+{
+	a2dp_sbc_t *a2dp = data;
+	int err;
+
+	err = sbc_init(sbc, flags);
+	if (err < 0)
+		return err;
+
+	switch (a2dp->frequency) {
+        case A2DP_SAMPLING_FREQ_16000:
+		sbc->frequency = SBC_FREQ_16000;
+		break;
+	case A2DP_SAMPLING_FREQ_32000:
+		sbc->frequency = SBC_FREQ_32000;
+		break;
+	case A2DP_SAMPLING_FREQ_44100:
+		sbc->frequency = SBC_FREQ_44100;
+		break;
+	case A2DP_SAMPLING_FREQ_48000:
+		sbc->frequency = SBC_FREQ_48000;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->channel_mode) {
+	case A2DP_CHANNEL_MODE_MONO:
+		sbc->mode = SBC_MODE_MONO;
+		break;
+	case A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+		sbc->mode = SBC_MODE_DUAL_CHANNEL;
+		break;
+	case A2DP_CHANNEL_MODE_STEREO:
+		sbc->mode = SBC_MODE_STEREO;
+		break;
+	case A2DP_CHANNEL_MODE_JOINT_STEREO:
+		sbc->mode = SBC_MODE_JOINT_STEREO;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->allocation_method) {
+	case A2DP_ALLOCATION_SNR:
+		sbc->allocation = SBC_AM_SNR;
+		break;
+	case A2DP_ALLOCATION_LOUDNESS:
+		sbc->allocation = SBC_AM_LOUDNESS;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->subbands) {
+	case A2DP_SUBBANDS_4:
+		sbc->subbands = SBC_SB_4;
+		break;
+        case A2DP_SUBBANDS_8:
+		sbc->subbands = SBC_SB_8;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->block_length) {
+	case A2DP_BLOCK_LENGTH_4:
+		sbc->blocks = SBC_BLK_4;
+		break;
+	case A2DP_BLOCK_LENGTH_8:
+		sbc->blocks = SBC_BLK_8;
+		break;
+	case A2DP_BLOCK_LENGTH_12:
+		sbc->blocks = SBC_BLK_12;
+		break;
+	case A2DP_BLOCK_LENGTH_16:
+		sbc->blocks = SBC_BLK_16;
+		break;
+	default:
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	sbc_finish(sbc);
+	return -EINVAL;
+}
+
 SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
 {
 	return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
diff --git a/sbc/sbc.h b/sbc/sbc.h
index 5f8a1fc..1d1c5a1 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -84,6 +84,7 @@ typedef struct sbc_struct sbc_t;
 int sbc_init(sbc_t *sbc, unsigned long flags);
 int sbc_reinit(sbc_t *sbc, unsigned long flags);
 int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
+int sbc_init_a2dp(sbc_t *sbc, unsigned long flags, void *data);
 
 ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 3/3] android/pts: Add PTS test results document for AVCTP
From: Jakub Tyszkowski @ 2014-01-20  8:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390208087-22838-1-git-send-email-jakub.tyszkowski@tieto.com>

This will allow for better tracking of current state of implementation.
---
 android/Makefile.am   |  1 +
 android/pts-avctp.txt | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)
 create mode 100644 android/pts-avctp.txt

diff --git a/android/Makefile.am b/android/Makefile.am
index 9020a46..924917a 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -169,4 +169,5 @@ EXTRA_DIST += android/Android.mk android/README \
 				android/pts-map.txt \
 				android/pts-a2dp.txt \
 				android/pts-avrcp.txt \
+				android/pts-avctp.txt \
 				android/pts-pbap.txt
diff --git a/android/pts-avctp.txt b/android/pts-avctp.txt
new file mode 100644
index 0000000..c057a10
--- /dev/null
+++ b/android/pts-avctp.txt
@@ -0,0 +1,41 @@
+PTS test results for AVCTP
+
+PTS version: 5.0
+Tested: --not yet tested--
+
+Results:
+PASS	test passed
+FAIL	test failed
+INC	test is inconclusive
+N/A	test is disabled due to PICS setup
+
+		Controller (CT)
+-------------------------------------------------------------------------------
+Test Name		Result	Notes
+-------------------------------------------------------------------------------
+TC_CT_CCM_BV_01_C	N/A
+TC_CT_CCM_BV_02_C	N/A
+TC_CT_CCM_BV_03_C	N/A
+TC_CT_CCM_BV_04_C	N/A
+TC_CT_CCM_BI_01_C	N/A
+TC_CT_NFR_BV_01_C	N/A
+TC_CT_NFR_BV_04_C	N/A
+TC_CT_FRA_BV_01_C	N/A
+TC_CT_FRA_BV_04_C	N/A
+-------------------------------------------------------------------------------
+
+
+		Target (TG)
+-------------------------------------------------------------------------------
+Test Name		Result	Notes
+-------------------------------------------------------------------------------
+TC_TG_CCM_BV_01_C	INC
+TC_TG_CCM_BV_02_C	INC
+TC_TG_CCM_BV_03_C	INC
+TC_TG_CCM_BV_04_C	INC
+TC_TG_NFR_BV_02_C	INC
+TC_TG_NFR_BV_03_C	INC
+TC_TG_NFR_BI_01_C	INC
+TC_TG_FRA_BV_02_C	INC
+TC_TG_FRA_BV_03_C	INC
+-------------------------------------------------------------------------------
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 2/3] android/pts: Add PTS test results document for AVRCP
From: Jakub Tyszkowski @ 2014-01-20  8:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390208087-22838-1-git-send-email-jakub.tyszkowski@tieto.com>

This will allow for better tracking of current state of implementation.
---
 android/Makefile.am   |   1 +
 android/pts-avrcp.txt | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 195 insertions(+)
 create mode 100644 android/pts-avrcp.txt

diff --git a/android/Makefile.am b/android/Makefile.am
index d4508a4..9020a46 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -168,4 +168,5 @@ EXTRA_DIST += android/Android.mk android/README \
 				android/pts-opp.txt \
 				android/pts-map.txt \
 				android/pts-a2dp.txt \
+				android/pts-avrcp.txt \
 				android/pts-pbap.txt
diff --git a/android/pts-avrcp.txt b/android/pts-avrcp.txt
new file mode 100644
index 0000000..f2533b4
--- /dev/null
+++ b/android/pts-avrcp.txt
@@ -0,0 +1,194 @@
+PTS test results for AVRCP
+
+PTS version: 5.0
+Tested: --not yet tested--
+
+Results:
+PASS	test passed
+FAIL	test failed
+INC	test is inconclusive
+N/A	test is disabled due to PICS setup
+
+		Controller (CT)
+-------------------------------------------------------------------------------
+Test Name		Result	Notes
+-------------------------------------------------------------------------------
+TC_CT_BGN_BV_01_I	N/A
+TC_CT_BGN_BV_02_I	N/A
+TC_CT_CEC_BV_01_I	N/A
+TC_CT_CEC_BV_02_I	N/A
+TC_CT_CFG_BV_01_C	N/A
+TC_CT_CON_BV_01_C	N/A
+TC_CT_CON_BV_03_C	N/A
+TC_CT_CRC_BV_01_I	N/A
+TC_CT_CRC_BV_02_I	N/A
+TC_CT_ICC_BV_01_I	N/A
+TC_CT_ICC_BV_02_I	N/A
+TC_CT_MCN_CB_BV_01_C	N/A
+TC_CT_MCN_CB_BV_01_I	N/A
+TC_CT_MCN_CB_BV_02_I	N/A
+TC_CT_MCN_CB_BV_03_I	N/A
+TC_CT_MCN_CB_BV_04_C	N/A
+TC_CT_MCN_CB_BV_04_I	N/A
+TC_CT_MCN_CB_BV_05_I	N/A
+TC_CT_MCN_CB_BV_06_I	N/A
+TC_CT_MCN_CB_BV_07_C	N/A
+TC_CT_MCN_CB_BV_07_I	N/A
+TC_CT_MCN_NP_BV_01_C	N/A
+TC_CT_MCN_NP_BV_01_I	N/A
+TC_CT_MCN_NP_BV_02_I	N/A
+TC_CT_MCN_NP_BV_03_C	N/A
+TC_CT_MCN_NP_BV_03_I	N/A
+TC_CT_MCN_NP_BV_04_I	N/A
+TC_CT_MCN_NP_BV_05_C	N/A
+TC_CT_MCN_NP_BV_05_I	N/A
+TC_CT_MCN_NP_BV_06_I	N/A
+TC_CT_MCN_NP_BV_07_I	N/A
+TC_CT_MCN_NP_BV_08_C	N/A
+TC_CT_MCN_SRC_BV_01_C	N/A
+TC_CT_MCN_SRC_BV_01_I	N/A
+TC_CT_MCN_SRC_BV_02_I	N/A
+TC_CT_MCN_SRC_BV_03_C	N/A
+TC_CT_MCN_SRC_BV_03_I	N/A
+TC_CT_MCN_SRC_BV_04_I	N/A
+TC_CT_MCN_SRC_BV_05_C	N/A
+TC_CT_MDI_BV_01_C	N/A
+TC_CT_MDI_BV_03_C	N/A
+TC_CT_MPS_BV_01_C	N/A
+TC_CT_MPS_BV_01_I	N/A
+TC_CT_MPS_BV_02_I	N/A
+TC_CT_MPS_BV_03_C	N/A
+TC_CT_MPS_BV_03_I	N/A
+TC_CT_MPS_BV_08_C	N/A
+TC_CT_NFY_BV_01_C	N/A
+TC_CT_PAS_BV_01_C	N/A
+TC_CT_PAS_BV_03_C	N/A
+TC_CT_PAS_BV_05_C	N/A
+TC_CT_PAS_BV_07_C	N/A
+TC_CT_PAS_BV_09_C	N/A
+TC_CT_PAS_BV_11_C	N/A
+TC_CT_PTH_BV_01_C	N/A
+TC_CT_PTH_BV_02_C	N/A
+TC_CT_PTT_BV_01_I	N/A
+TC_CT_PTT_BV_02_I	N/A
+TC_CT_PTT_BV_03_I	N/A
+TC_CT_PTT_BV_04_I	N/A
+TC_CT_PTT_BV_05_I	N/A
+TC_CT_RCR_BV_01_C	N/A
+TC_CT_RCR_BV_03_C	N/A
+TC_CT_VLH_BI_03_C	N/A
+TC_CT_VLH_BI_04_C	N/A
+TC_CT_VLH_BV_01_C	N/A
+TC_CT_VLH_BV_01_I	N/A
+TC_CT_VLH_BV_02_I	N/A
+TC_CT_VLH_BV_03_C	N/A
+-------------------------------------------------------------------------------
+
+
+		Target (TG)
+-------------------------------------------------------------------------------
+Test Name		Result	Notes
+-------------------------------------------------------------------------------
+TC_TG_BGN_BV_01_I	N/A
+TC_TG_BGN_BV_02_I	N/A
+TC_TG_CEC_BV_01_I	INC
+TC_TG_CEC_BV_02_I	INC
+TC_TG_CFG_BI_01_C	INC
+TC_TG_CFG_BV_02_C	INC
+TC_TG_CON_BV_02_C	N/A
+TC_TG_CON_BV_04_C	N/A
+TC_TG_CON_BV_05_C	N/A
+TC_TG_CRC_BV_01_I	INC
+TC_TG_CRC_BV_02_I	INC
+TC_TG_ICC_BV_01_I	INC
+TC_TG_ICC_BV_02_I	INC
+TC_TG_INV_BI_01_C	INC
+TC_TG_INV_BI_02_C	N/A
+TC_TG_MCN_CB_BI_01_C	N/A
+TC_TG_MCN_CB_BI_02_C	N/A
+TC_TG_MCN_CB_BI_03_C	N/A
+TC_TG_MCN_CB_BI_04_C	N/A
+TC_TG_MCN_CB_BI_05_C	N/A
+TC_TG_MCN_CB_BV_01_I	N/A
+TC_TG_MCN_CB_BV_02_C	N/A
+TC_TG_MCN_CB_BV_02_I	N/A
+TC_TG_MCN_CB_BV_03_C	N/A
+TC_TG_MCN_CB_BV_03_I	N/A
+TC_TG_MCN_CB_BV_04_I	N/A
+TC_TG_MCN_CB_BV_05_C	N/A
+TC_TG_MCN_CB_BV_05_I	N/A
+TC_TG_MCN_CB_BV_06_C	N/A
+TC_TG_MCN_CB_BV_06_I	N/A
+TC_TG_MCN_CB_BV_07_I	N/A
+TC_TG_MCN_CB_BV_08_C	N/A
+TC_TG_MCN_CB_BV_09_C	N/A
+TC_TG_MCN_CB_BV_10_C	N/A
+TC_TG_MCN_CB_BV_11_C	N/A
+TC_TG_MCN_NP_BI_01_C	N/A
+TC_TG_MCN_NP_BI_02_C	N/A
+TC_TG_MCN_NP_BV_01_I	N/A
+TC_TG_MCN_NP_BV_02_C	N/A
+TC_TG_MCN_NP_BV_02_I	N/A
+TC_TG_MCN_NP_BV_03_I	N/A
+TC_TG_MCN_NP_BV_04_C	N/A
+TC_TG_MCN_NP_BV_04_I	N/A
+TC_TG_MCN_NP_BV_05_I	N/A
+TC_TG_MCN_NP_BV_06_C	N/A
+TC_TG_MCN_NP_BV_06_I	N/A
+TC_TG_MCN_NP_BV_07_C	N/A
+TC_TG_MCN_NP_BV_07_I	N/A
+TC_TG_MCN_NP_BV_09_C	N/A
+TC_TG_MCN_SRC_BV_01_I	N/A
+TC_TG_MCN_SRC_BV_02_C	N/A
+TC_TG_MCN_SRC_BV_02_I	N/A
+TC_TG_MCN_SRC_BV_03_I	N/A
+TC_TG_MCN_SRC_BV_04_C	N/A
+TC_TG_MCN_SRC_BV_04_I	N/A
+TC_TG_MCN_SRC_BV_06_C	N/A
+TC_TG_MDI_BV_02_C	INC
+TC_TG_MDI_BV_04_C	INC
+TC_TG_MDI_BV_05_C	INC
+TC_TG_MPS_BI_01_C	N/A
+TC_TG_MPS_BI_02_C	N/A
+TC_TG_MPS_BV_01_I	N/A
+TC_TG_MPS_BV_02_C	N/A
+TC_TG_MPS_BV_02_I	N/A
+TC_TG_MPS_BV_03_I	N/A
+TC_TG_MPS_BV_04_C	N/A
+TC_TG_MPS_BV_05_C	N/A
+TC_TG_MPS_BV_06_C	N/A
+TC_TG_MPS_BV_07_C	N/A
+TC_TG_MPS_BV_09_C	N/A
+TC_TG_MPS_BV_10_C	N/A
+TC_TG_NFY_BI_01_C	INC
+TC_TG_NFY_BV_02_C	INC
+TC_TG_NFY_BV_03_C	N/A
+TC_TG_NFY_BV_04_C	INC
+TC_TG_NFY_BV_05_C	INC
+TC_TG_NFY_BV_06_C	N/A
+TC_TG_NFY_BV_07_C	N/A
+TC_TG_NFY_BV_08_C	INC
+TC_TG_PAS_BI_01_C	N/A
+TC_TG_PAS_BI_02_C	N/A
+TC_TG_PAS_BI_03_C	N/A
+TC_TG_PAS_BI_04_C	N/A
+TC_TG_PAS_BI_05_C	N/A
+TC_TG_PAS_BV_02_C	N/A
+TC_TG_PAS_BV_04_C	N/A
+TC_TG_PAS_BV_06_C	N/A
+TC_TG_PAS_BV_08_C	N/A
+TC_TG_PAS_BV_10_C	N/A
+TC_TG_PTT_BV_01_I	INC
+TC_TG_PTT_BV_02_I	N/A
+TC_TG_PTT_BV_03_I	N/A
+TC_TG_PTT_BV_04_I	N/A
+TC_TG_PTT_BV_05_I	N/A
+TC_TG_RCR_BV_02_C	INC
+TC_TG_RCR_BV_04_C	INC
+TC_TG_VLH_BI_01_C	N/A
+TC_TG_VLH_BI_02_C	N/A
+TC_TG_VLH_BV_01_I	N/A
+TC_TG_VLH_BV_02_C	N/A
+TC_TG_VLH_BV_02_I	N/A
+TC_TG_VLH_BV_04_C	N/A
+-------------------------------------------------------------------------------
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH 1/3] android/pts: Add PTS test results document for A2DP
From: Jakub Tyszkowski @ 2014-01-20  8:54 UTC (permalink / raw)
  To: linux-bluetooth

This will allow for better tracking of current state of implementation.
---
 android/Makefile.am  |  1 +
 android/pts-a2dp.txt | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 android/pts-a2dp.txt

diff --git a/android/Makefile.am b/android/Makefile.am
index f24b754..d4508a4 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -167,4 +167,5 @@ EXTRA_DIST += android/Android.mk android/README \
 				android/pts-hid.txt \
 				android/pts-opp.txt \
 				android/pts-map.txt \
+				android/pts-a2dp.txt \
 				android/pts-pbap.txt
diff --git a/android/pts-a2dp.txt b/android/pts-a2dp.txt
new file mode 100644
index 0000000..a269ec1
--- /dev/null
+++ b/android/pts-a2dp.txt
@@ -0,0 +1,57 @@
+PTS test results for A2DP
+
+PTS version: 5.0
+Tested: --not yet tested--
+
+Results:
+PASS	test passed
+FAIL	test failed
+INC	test is inconclusive
+N/A	test is disabled due to PICS setup
+
+		Source (SRC)
+-------------------------------------------------------------------------------
+Test Name		Result	Notes
+-------------------------------------------------------------------------------
+TC_SRC_CC_BV_09_I	INC
+TC_SRC_CC_BV_10_I	N/A
+TC_SRC_REL_BV_01_I	INC
+TC_SRC_REL_BV_02_I	INC
+TC_SRC_SET_BV_01_I	INC
+TC_SRC_SET_BV_02_I	INC
+TC_SRC_SET_BV_03_I	INC
+TC_SRC_SET_BV_04_I	INC
+TC_SRC_SET_BV_05_I	INC
+TC_SRC_SET_BV_06_I	INC
+TC_SRC_SUS_BV_01_I	INC
+TC_SRC_SUS_BV_02_I	INC
+TC_SRC_SDP_BV_01_I	INC
+TC_SRC_AS_BV_01_I	INC
+-------------------------------------------------------------------------------
+
+
+		Sink (SNK)
+-------------------------------------------------------------------------------
+Test Name		Result	Notes
+-------------------------------------------------------------------------------
+TC_SNK_CC_BV_01_I	N/A
+TC_SNK_CC_BV_02_I	N/A
+TC_SNK_CC_BV_03_I	N/A
+TC_SNK_CC_BV_04_I	N/A
+TC_SNK_CC_BV_05_I	N/A
+TC_SNK_CC_BV_06_I	N/A
+TC_SNK_CC_BV_07_I	N/A
+TC_SNK_CC_BV_08_I	N/A
+TC_SNK_REL_BV_01_I	N/A
+TC_SNK_REL_BV_02_I	N/A
+TC_SNK_SET_BV_01_I	N/A
+TC_SNK_SET_BV_02_I	N/A
+TC_SNK_SET_BV_03_I	N/A
+TC_SNK_SET_BV_04_I	N/A
+TC_SNK_SET_BV_05_I	N/A
+TC_SNK_SET_BV_06_I	N/A
+TC_SNK_SUS_BV_01_I	N/A
+TC_SNK_SUS_BV_02_I	N/A
+TC_SNK_SDP_BV_02_I	N/A
+TC_SNK_AS_BV_01_I	N/A
+-------------------------------------------------------------------------------
-- 
1.8.5.2


^ permalink raw reply related

* Re: [PATCH v3 0/4] Regression fixes for rfcomm/tty.c
From: Alexander Holler @ 2014-01-20  8:34 UTC (permalink / raw)
  To: Marcel Holtmann, Gianluca Anzolin
  Cc: Gustavo F. Padovan, peter,
	linux-bluetooth@vger.kernel.org development, Greg KH, jslaby,
	stable
In-Reply-To: <53C8DDF7-94EA-4E01-A2A9-C366F9F85530@holtmann.org>

Am 06.01.2014 22:57, schrieb Marcel Holtmann:

> all 4 patches have been applied to bluetooth-next tree.

Maybe a bit late, but I've just seen they miss a Cc: 
stable@vger.kernel.org to automatically end up in 3.12 and 3.13 too.

Regards,

Alexander Holler

^ permalink raw reply

* Re: [PATCH 3/3] input: Add DualShock 4 detection
From: Frank Praznik @ 2014-01-20  4:37 UTC (permalink / raw)
  To: Szymon Janc, David Herrmann
  Cc: linux-bluetooth@vger.kernel.org, Simon Wood, Frank Praznik
In-Reply-To: <1572567.ZoR782tNKQ@athlon>

On 1/18/2014 10:13, Szymon Janc wrote:
> Hi,
>
> On Saturday 18 January 2014 16:05:26 David Herrmann wrote:
>> Hi
>>
>> @Simon and Frank:
>> This patch might help fix your DS4 issues.
>>
>> Cheers
>> David
> Just for clarification, this does not add DS4 support, just detection for it
> in input server. There is some problem with getting SDP records from DS4 by
> bluetoothd (works with sdptool) which prevents idev from being created.
>
> I'm working on fixing this, but no ETA yet.
>
With this and the IMTU patch I was able to get my controller paired.  I 
played around with it and from watching the traffic in btmon, there are 
still two issues that are stopping full two way communications:

1. The Dualshock 4 sends communications to the host on PSM 19, but will 
only receive packets on PSM 17.  Currently the bluetooth stack is trying 
to send data to the controller on PSM 19 so the data packets still 
aren't reaching the it.

2. The hidp layer always assigns a report type of 0xA2 (HIDP_TRANS_DATA 
| HIDP_DATA_RTYPE_OUTPUT) to every HIDP_OUTPUT_REPORT.  The Dualshock 4 
only accepts reports with type 0x52 (HIDP_TRANS_SEND_REPORT | 
HIDP_DATA_RTYPE_OUTPUT).  I was able to work around this with a kludge 
in net/bluetooth/hidp/core.c to catch the Dualshock 4 packets and use 
the value that the controller wants, but I don't think anyone wants a 
device-specific hack in a core protocol file.  Unfortunately, there 
seems to be no elegant way to work around this.

^ permalink raw reply


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