Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 2/6] android: Add pre-setup and post-teardown routines
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:42 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcin Kraglak
In-Reply-To: <1385631770-3858-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

From: Marcin Kraglak <marcin.kraglak@tieto.com>

This will add hciemu initialization and cleanup. These functions
will be called to create hci emulator and cleanup it.
---
 android/Makefile.am      |  10 ++-
 android/android-tester.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 179 insertions(+), 2 deletions(-)

diff --git a/android/Makefile.am b/android/Makefile.am
index 9390422..905032d 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -84,7 +84,15 @@ android_haltest_LDFLAGS = -pthread
 
 noinst_PROGRAMS += android/android-tester
 
-android_android_tester_SOURCES = android/android-tester.c
+android_android_tester_SOURCES = 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 \
+				android/android-tester.c
+
+android_android_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
 endif
 
diff --git a/android/android-tester.c b/android/android-tester.c
index f5c42b0..48e408d 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -15,7 +15,176 @@
  *
  */
 
+#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;
+	void *test_data;
+};
+
+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 *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	if (!tester_use_debug())
+		fclose(stderr);
+
+	data->mgmt = mgmt_new_default();
+	if (!data->mgmt) {
+		tester_warn("Failed to setup management interface");
+		tester_pre_setup_failed();
+		return;
+	}
+
+	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 pass_test(const void *test_data)
+{
+	tester_test_passed();
+}
+
+#define test_bredrle(name, data, test_setup, test, test_teardown) \
+	do { \
+		struct test_data *user; \
+		user = g_malloc0(sizeof(struct test_data)); \
+		if (!user) \
+			break; \
+		user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+		user->test_data = data; \
+		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[])
 {
-	return 0;
+	tester_init(&argc, &argv);
+
+	test_bredrle("test", NULL, NULL, pass_test, NULL);
+
+	return tester_run();
 }
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 1/6] android: Add android-tester
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:42 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcin Kraglak
In-Reply-To: <1385631770-3858-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

From: Marcin Kraglak <marcin.kraglak@tieto.com>

This commit add android-tester.c to tree and Makefile.am.
This will contain set of unit tests for testing android daemon.
---
 android/Makefile.am      |  4 ++++
 android/android-tester.c | 21 +++++++++++++++++++++
 2 files changed, 25 insertions(+)
 create mode 100644 android/android-tester.c

diff --git a/android/Makefile.am b/android/Makefile.am
index 94d231f..9390422 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -82,6 +82,10 @@ android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
 
 android_haltest_LDFLAGS = -pthread
 
+noinst_PROGRAMS += android/android-tester
+
+android_android_tester_SOURCES = android/android-tester.c
+
 endif
 
 EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README \
diff --git a/android/android-tester.c b/android/android-tester.c
new file mode 100644
index 0000000..f5c42b0
--- /dev/null
+++ b/android/android-tester.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+int main(int argc, char *argv[])
+{
+	return 0;
+}
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 0/6] android: initial code for automated tests
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:42 UTC (permalink / raw)
  To: linux-bluetooth

V2:
 - change-id removed
 - bogus patch removed from serie

from V1:

This serie adds initial code for automated android deamon and HAL library
tests. Skeleton and one initial test case is added.

-- 
Best regards,
Grzegorz

Grzegorz Kolodziejczyk (1):
  android: Add basic test and handle mgmt notifications, hal cb

Marcin Kraglak (4):
  android: Add android-tester
  android: Add pre-setup and post-teardown routines
  android: Start emulator in separate thread
  android: Add stack initialization of stack in setup

Szymon Janc (1):
  android: Make HAL logging wrapper print to stderr instead of stdout

 android/Makefile.am      |  18 ++
 android/android-tester.c | 592 +++++++++++++++++++++++++++++++++++++++++++++++
 android/hal-log.h        |   2 +-
 3 files changed, 611 insertions(+), 1 deletion(-)
 create mode 100644 android/android-tester.c

-- 
1.8.4.2


^ permalink raw reply

* [PATCH 6/6] android: Make HAL logging wrapper print to stderr instead of stdout
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1385631296-2856-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

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

This is used for testing and for user it makes no difference. This
will allow to switch on/off verbose logging from automated android
tester.
---
 android/hal-log.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/hal-log.h b/android/hal-log.h
index 9bd024d..63ff61b 100644
--- a/android/hal-log.h
+++ b/android/hal-log.h
@@ -25,7 +25,7 @@
 #define LOG_WARN " W"
 #define LOG_ERROR " E"
 #define LOG_DEBUG " D"
-#define ALOG(pri, tag, fmt, arg...) printf(tag pri": " fmt"\n", ##arg)
+#define ALOG(pri, tag, fmt, arg...) fprintf(stderr, tag pri": " fmt"\n", ##arg)
 #endif
 
 #define info(fmt, arg...) ALOG(LOG_INFO, LOG_TAG, fmt, ##arg)
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 5/6] android: Add basic test and handle mgmt notifications, hal cb
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1385631296-2856-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

This adds basic enable test case. Mgmt notifications and HAL callbacks
are now handled.

Change-Id: Icd222df3eb7093b291dbc83e462679f93e8114fc
---
 android/android-tester.c | 230 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 224 insertions(+), 6 deletions(-)

diff --git a/android/android-tester.c b/android/android-tester.c
index 5e5afe0..5c24dc4 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -40,16 +40,126 @@
 static pthread_cond_t emulator_cond = PTHREAD_COND_INITIALIZER;
 static pthread_mutex_t emulator_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+/*
+ * those are assigned to HAL methods and callbacks, we use ID later
+ * on mapped in switch-case due to different functions prototypes.
+ */
+
+enum hal_bluetooth_callbacks_id {
+	adapter_test_end,
+	adapter_state_changed_on,
+	adapter_state_changed_off,
+	adapter_prop_bdaddr,
+	adapter_prop_bdname,
+	adapter_prop_uuids,
+	adapter_prop_cod,
+	adapter_prop_scan_mode,
+	adapter_prop_disc_timeout,
+	adapter_prop_service_record,
+	adapter_prop_bonded_devices
+};
+
+struct generic_data {
+	uint32_t expect_settings_set;
+	uint8_t expected_hal_callbacks[];
+};
+
 struct test_data {
 	struct mgmt *mgmt;
 	uint16_t mgmt_index;
+	unsigned int mgmt_settings_id;
 	struct hciemu *hciemu;
 	enum hciemu_type hciemu_type;
-	void *test_data;
+	const struct generic_data *test_data;
 	pthread_t emulator_thread;
 	const bt_interface_t *if_bluetooth;
+
+	bool mgmt_settings_set;
+	bool hal_cb_called;
+
+	GSList *expected_callbacks;
 };
 
+static void test_update_state(void)
+{
+	struct test_data *data = tester_get_data();
+
+	if (data->mgmt_settings_set && data->hal_cb_called)
+		tester_test_passed();
+}
+
+static void test_mgmt_settings_set(struct test_data *data)
+{
+	data->mgmt_settings_set = true;
+
+	test_update_state();
+}
+
+static void command_generic_new_settings(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	uint32_t settings;
+
+	if (length != 4) {
+		tester_warn("Invalid parameter size for new settings event");
+		tester_test_failed();
+		return;
+	}
+
+	settings = bt_get_le32(param);
+
+	if ((settings & data->test_data->expect_settings_set) !=
+					data->test_data->expect_settings_set)
+		return;
+
+	test_mgmt_settings_set(data);
+	mgmt_unregister(data->mgmt, data->mgmt_settings_id);
+}
+
+static void hal_cb_init(void)
+{
+	struct test_data *data = tester_get_data();
+	unsigned int i = 0;
+
+	while (data->test_data->expected_hal_callbacks[i]) {
+						data->expected_callbacks =
+				g_slist_append(data->expected_callbacks,
+		GINT_TO_POINTER(data->test_data->expected_hal_callbacks[i]));
+		i++;
+	}
+}
+
+static void mgmt_cb_init(struct test_data *data)
+{
+	if (!data->test_data->expect_settings_set)
+		test_mgmt_settings_set(data);
+	else
+		data->mgmt_settings_id = mgmt_register(data->mgmt,
+					MGMT_EV_NEW_SETTINGS, data->mgmt_index,
+				command_generic_new_settings, NULL, NULL);
+}
+
+static int get_expected_hal_cb(void)
+{
+	struct test_data *data = tester_get_data();
+
+	return GPOINTER_TO_INT(data->expected_callbacks->data);
+}
+
+static void remove_expected_hal_cb(void)
+{
+	struct test_data *data = tester_get_data();
+
+	data->expected_callbacks = g_slist_remove(data->expected_callbacks,
+						data->expected_callbacks->data);
+
+	if (!data->expected_callbacks)
+		data->hal_cb_called = true;
+
+	test_update_state();
+}
+
 static void read_info_callback(uint8_t status, uint16_t length,
 					const void *param, void *user_data)
 {
@@ -257,10 +367,109 @@ static void *emulator(void *user_data)
 	return NULL;
 }
 
+static void adapter_state_changed_cb(bt_state_t state)
+{
+	switch (get_expected_hal_cb()) {
+	case adapter_state_changed_on:
+		if (state == BT_STATE_ON)
+			remove_expected_hal_cb();
+		else
+			tester_test_failed();
+		break;
+	default:
+		break;
+	}
+}
+
+static void adapter_properties_cb(bt_status_t status, int num_properties,
+						bt_property_t *properties)
+{
+	enum hal_bluetooth_callbacks_id hal_cb;
+	int i;
+
+	for (i = 0; i < num_properties; i++) {
+		hal_cb = get_expected_hal_cb();
+		switch (properties[i].type) {
+		case BT_PROPERTY_BDADDR:
+			if (hal_cb != adapter_prop_bdaddr) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_BDNAME:
+			if (hal_cb != adapter_prop_bdname) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_UUIDS:
+			if (hal_cb != adapter_prop_uuids) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_CLASS_OF_DEVICE:
+			if (hal_cb != adapter_prop_cod) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_TYPE_OF_DEVICE:
+			if (hal_cb != adapter_prop_bdaddr) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_SERVICE_RECORD:
+			if (hal_cb != adapter_prop_service_record) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_ADAPTER_SCAN_MODE:
+			if (hal_cb != adapter_prop_scan_mode) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+			if (hal_cb != adapter_prop_bonded_devices) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+			if (hal_cb != adapter_prop_disc_timeout) {
+				tester_test_failed();
+				return;
+			}
+			remove_expected_hal_cb();
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static const struct generic_data bluetooth_enable_success_test = {
+	.expected_hal_callbacks = {adapter_prop_bdaddr, adapter_prop_bdname,
+			adapter_prop_uuids, adapter_prop_cod,
+			adapter_prop_scan_mode, adapter_prop_disc_timeout,
+			adapter_state_changed_on, adapter_test_end}
+};
+
 static bt_callbacks_t bt_callbacks = {
 	.size = sizeof(bt_callbacks),
-	.adapter_state_changed_cb = NULL,
-	.adapter_properties_cb = NULL,
+	.adapter_state_changed_cb = adapter_state_changed_cb,
+	.adapter_properties_cb = adapter_properties_cb,
 	.remote_device_properties_cb = NULL,
 	.device_found_cb = NULL,
 	.discovery_state_changed_cb = NULL,
@@ -343,12 +552,20 @@ static void teardown(const void *test_data)
 		data->emulator_thread = 0;
 	}
 
+	if (data->expected_callbacks)
+		g_slist_free(data->expected_callbacks);
+
 	tester_teardown_complete();
 }
 
-static void pass_test(const void *test_data)
+static void test_enable(const void *test_data)
 {
-	tester_test_passed();
+	struct test_data *data = tester_get_data();
+
+	hal_cb_init();
+	mgmt_cb_init(data);
+
+	data->if_bluetooth->enable();
 }
 
 #define test_bredrle(name, data, test_setup, test, test_teardown) \
@@ -368,7 +585,8 @@ int main(int argc, char *argv[])
 {
 	tester_init(&argc, &argv);
 
-	test_bredrle("test", NULL, setup, pass_test, teardown);
+	test_bredrle("Test Enable - Success", &bluetooth_enable_success_test,
+						setup, test_enable, teardown);
 
 	return tester_run();
 }
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 4/6] android: Add stack initialization of stack in setup
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcin Kraglak
In-Reply-To: <1385631296-2856-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

From: Marcin Kraglak <marcin.kraglak@tieto.com>

This add stack initialization and cleanup in setup/teardown.

Change-Id: I05c622b8e42a5d604e276d0a77d41c9bc7a6045e
---
 android/Makefile.am      |  8 ++++--
 android/android-tester.c | 69 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 71 insertions(+), 6 deletions(-)

diff --git a/android/Makefile.am b/android/Makefile.am
index b19ab4e..e71857e 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -90,9 +90,13 @@ android_android_tester_SOURCES = emulator/btdev.h emulator/btdev.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/android-tester.c
+				android/hal-utils.h android/hal-utils.c \
+				android/client/hwmodule.c android/android-tester.c
 
-android_android_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+android_android_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+
+android_android_tester_LDADD = lib/libbluetooth-internal.la \
+				android/libhal-internal.la @GLIB_LIBS@
 
 android_android_tester_LDFLAGS = -pthread
 
diff --git a/android/android-tester.c b/android/android-tester.c
index 16e8ec0..5e5afe0 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -32,6 +32,9 @@
 #include "src/shared/mgmt.h"
 #include "src/shared/hciemu.h"
 
+#include <hardware/hardware.h>
+#include <hardware/bluetooth.h>
+
 #define WAIT_FOR_CONDITION_TIME 2 /* in seconds */
 
 static pthread_cond_t emulator_cond = PTHREAD_COND_INITIALIZER;
@@ -44,6 +47,7 @@ struct test_data {
 	enum hciemu_type hciemu_type;
 	void *test_data;
 	pthread_t emulator_thread;
+	const bt_interface_t *if_bluetooth;
 };
 
 static void read_info_callback(uint8_t status, uint16_t length,
@@ -253,10 +257,30 @@ static void *emulator(void *user_data)
 	return NULL;
 }
 
+static bt_callbacks_t bt_callbacks = {
+	.size = sizeof(bt_callbacks),
+	.adapter_state_changed_cb = NULL,
+	.adapter_properties_cb = NULL,
+	.remote_device_properties_cb = NULL,
+	.device_found_cb = NULL,
+	.discovery_state_changed_cb = NULL,
+	.pin_request_cb = NULL,
+	.ssp_request_cb = NULL,
+	.bond_state_changed_cb = NULL,
+	.acl_state_changed_cb = NULL,
+	.thread_evt_cb = NULL,
+	.dut_mode_recv_cb = NULL,
+	.le_test_mode_cb = NULL
+};
+
 static void setup(const void *test_data)
 {
 	struct test_data *data = tester_get_data();
+	const hw_module_t *module;
+	hw_device_t *device;
+	bt_status_t status;
 	struct timespec ts;
+	int err;
 
 	clock_gettime(CLOCK_REALTIME, &ts);
 	ts.tv_sec += WAIT_FOR_CONDITION_TIME;
@@ -269,19 +293,56 @@ static void setup(const void *test_data)
 	}
 
 	if (pthread_cond_timedwait(&emulator_cond, &emulator_mutex,
-								&ts))
+								&ts)) {
 		tester_setup_failed();
-	else
-		tester_setup_complete();
+		pthread_mutex_unlock(&emulator_mutex);
+		return;
+	}
 
 	pthread_mutex_unlock(&emulator_mutex);
+
+	err = hw_get_module(BT_HARDWARE_MODULE_ID, &module);
+	if (err) {
+		tester_setup_failed();
+		return;
+	}
+
+	err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+	if (err) {
+		tester_setup_failed();
+		return;
+	}
+
+	data->if_bluetooth = ((bluetooth_device_t *)
+					device)->get_bluetooth_interface();
+	if (!data->if_bluetooth) {
+		tester_setup_failed();
+		return;
+	}
+
+	status = data->if_bluetooth->init(&bt_callbacks);
+	if (status != BT_STATUS_SUCCESS) {
+		data->if_bluetooth = NULL;
+		tester_setup_failed();
+	}
+
+	tester_setup_complete();
 }
 
 static void teardown(const void *test_data)
 {
 	struct test_data *data = tester_get_data();
 
-	pthread_join(data->emulator_thread, NULL);
+	if (data->if_bluetooth) {
+		data->if_bluetooth->cleanup();
+		data->if_bluetooth = NULL;
+	}
+
+	if (data->emulator_thread) {
+		pthread_join(data->emulator_thread, NULL);
+		data->emulator_thread = 0;
+	}
+
 	tester_teardown_complete();
 }
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 3/6] android: Start emulator in separate thread
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcin Kraglak
In-Reply-To: <1385631296-2856-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

From: Marcin Kraglak <marcin.kraglak@tieto.com>

This is needed because bluetooth->init call is blocking,
and we have to emulate normal behaviour of android environment.
That thread will exit if it won't receive any message in 2 sec
or when bluetoothd will exit. It will be joined in teardown.

Change-Id: I72ebad714cf1b9ca6792c817c0b3ab7d42630998
---
 android/Makefile.am      |   2 +
 android/android-tester.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 126 insertions(+), 1 deletion(-)

diff --git a/android/Makefile.am b/android/Makefile.am
index 905032d..b19ab4e 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -94,6 +94,8 @@ android_android_tester_SOURCES = emulator/btdev.h emulator/btdev.c \
 
 android_android_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
+android_android_tester_LDFLAGS = -pthread
+
 endif
 
 EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README \
diff --git a/android/android-tester.c b/android/android-tester.c
index 48e408d..16e8ec0 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -15,9 +15,15 @@
  *
  */
 
+#include <stdlib.h>
 #include <unistd.h>
 
 #include <glib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <pthread.h>
 
 #include "lib/bluetooth.h"
 #include "lib/mgmt.h"
@@ -26,12 +32,18 @@
 #include "src/shared/mgmt.h"
 #include "src/shared/hciemu.h"
 
+#define WAIT_FOR_CONDITION_TIME 2 /* in seconds */
+
+static pthread_cond_t emulator_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t emulator_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 struct test_data {
 	struct mgmt *mgmt;
 	uint16_t mgmt_index;
 	struct hciemu *hciemu;
 	enum hciemu_type hciemu_type;
 	void *test_data;
+	pthread_t emulator_thread;
 };
 
 static void read_info_callback(uint8_t status, uint16_t length,
@@ -162,6 +174,117 @@ static void test_post_teardown(const void *test_data)
 	data->hciemu = NULL;
 }
 
+static void bluetoothd_start(void)
+{
+	struct test_data *data = tester_get_data();
+	char prg_name[PATH_MAX + 1];
+	char index[8];
+	char *prg_argv[4];
+	pid_t pid;
+	int status;
+
+	snprintf(prg_name, sizeof(prg_name), "%s/%s", "android", "bluetoothd");
+	snprintf(index, sizeof(index), "%d", data->mgmt_index);
+
+	prg_argv[0] = prg_name;
+	prg_argv[1] = "-i";
+	prg_argv[2] = index;
+	prg_argv[3] = NULL;
+
+	pid = fork();
+	if (pid < 0) {
+		perror("Failed to fork new process");
+		return;
+	}
+
+	if (pid == 0) {
+		if (!tester_use_debug())
+			fclose(stderr);
+
+		execve(prg_argv[0], prg_argv, NULL);
+		exit(0);
+	}
+
+	pid = waitpid(-1, &status, 0);
+}
+
+static void *emulator(void *user_data)
+{
+	static const char SYSTEM_SOCKET_PATH[] = "\0android_system";
+	char buf[4096];
+	struct sockaddr_un addr;
+	struct timeval tv;
+	int fd;
+	ssize_t len;
+
+	fd = socket(PF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (fd < 0)
+		return NULL;
+
+	tv.tv_sec = WAIT_FOR_CONDITION_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");
+		close(fd);
+		pthread_exit(NULL);
+		return NULL;
+	}
+
+	pthread_mutex_lock(&emulator_mutex);
+	pthread_cond_signal(&emulator_cond);
+	pthread_mutex_unlock(&emulator_mutex);
+
+	len = read(fd, buf, sizeof(buf));
+	if (len <= 0 || (strcmp(buf, "ctl.start=bluetoothd"))) {
+		close(fd);
+		pthread_exit(NULL);
+		return NULL;
+	}
+
+	close(fd);
+	bluetoothd_start();
+	pthread_exit(NULL);
+	return NULL;
+}
+
+static void setup(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	struct timespec ts;
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += WAIT_FOR_CONDITION_TIME;
+
+	pthread_mutex_lock(&emulator_mutex);
+
+	if (pthread_create(&data->emulator_thread, NULL, emulator, NULL)) {
+		tester_setup_failed();
+		return;
+	}
+
+	if (pthread_cond_timedwait(&emulator_cond, &emulator_mutex,
+								&ts))
+		tester_setup_failed();
+	else
+		tester_setup_complete();
+
+	pthread_mutex_unlock(&emulator_mutex);
+}
+
+static void teardown(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	pthread_join(data->emulator_thread, NULL);
+	tester_teardown_complete();
+}
+
 static void pass_test(const void *test_data)
 {
 	tester_test_passed();
@@ -184,7 +307,7 @@ int main(int argc, char *argv[])
 {
 	tester_init(&argc, &argv);
 
-	test_bredrle("test", NULL, NULL, pass_test, NULL);
+	test_bredrle("test", NULL, setup, pass_test, teardown);
 
 	return tester_run();
 }
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 2/6] android: Add pre-setup and post-teardown routines
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcin Kraglak
In-Reply-To: <1385631296-2856-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

From: Marcin Kraglak <marcin.kraglak@tieto.com>

This will add hciemu initialization and cleanup. These functions
will be called to create hci emulator and cleanup it.

Change-Id: Id9e32ee725948ac1d313041ab136f02d17d00fed
---
 android/Makefile.am      |  10 ++-
 android/android-tester.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 179 insertions(+), 2 deletions(-)

diff --git a/android/Makefile.am b/android/Makefile.am
index 9390422..905032d 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -84,7 +84,15 @@ android_haltest_LDFLAGS = -pthread
 
 noinst_PROGRAMS += android/android-tester
 
-android_android_tester_SOURCES = android/android-tester.c
+android_android_tester_SOURCES = 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 \
+				android/android-tester.c
+
+android_android_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
 endif
 
diff --git a/android/android-tester.c b/android/android-tester.c
index f5c42b0..48e408d 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -15,7 +15,176 @@
  *
  */
 
+#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;
+	void *test_data;
+};
+
+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 *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	if (!tester_use_debug())
+		fclose(stderr);
+
+	data->mgmt = mgmt_new_default();
+	if (!data->mgmt) {
+		tester_warn("Failed to setup management interface");
+		tester_pre_setup_failed();
+		return;
+	}
+
+	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 pass_test(const void *test_data)
+{
+	tester_test_passed();
+}
+
+#define test_bredrle(name, data, test_setup, test, test_teardown) \
+	do { \
+		struct test_data *user; \
+		user = g_malloc0(sizeof(struct test_data)); \
+		if (!user) \
+			break; \
+		user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+		user->test_data = data; \
+		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[])
 {
-	return 0;
+	tester_init(&argc, &argv);
+
+	test_bredrle("test", NULL, NULL, pass_test, NULL);
+
+	return tester_run();
 }
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH] Whitespace characters
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1385631296-2856-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

---
 android/bt-hal-tester.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/android/bt-hal-tester.c b/android/bt-hal-tester.c
index 8bcb901..fab987b 100644
--- a/android/bt-hal-tester.c
+++ b/android/bt-hal-tester.c
@@ -86,7 +86,7 @@ static void read_info_callback(uint8_t status, uint16_t length,
 		tester_pre_setup_failed();
 		return;
 	}
-	
+
 	tester_pre_setup_complete();
 }
 
@@ -275,24 +275,24 @@ static void setup(const void *test_data)
 	bt_status_t status;
 	const hw_module_t *module;
 	hw_device_t *device;
-	
+
 	clock_gettime(CLOCK_REALTIME, &ts);
 	ts.tv_sec += WAIT_FOR_CONDITION_TIME;
 
 	pthread_mutex_lock(&emulator_mutex);
-	
+
 	if (pthread_create(&data->emulator_thread, NULL, emulator, NULL)) {
 		tester_setup_failed();
 		return;
 	}
 	if (pthread_cond_timedwait(&emulator_started_cond, &emulator_mutex, &ts)
-																	< 0) {
+									< 0) {
 		tester_setup_failed();
 		return;
 	} else {
 		data->emulator_started = true;
 	}
-	
+
 	pthread_mutex_unlock(&emulator_mutex);
 
 	err = hw_get_module(BT_HARDWARE_MODULE_ID, &module);
@@ -320,14 +320,14 @@ static void setup(const void *test_data)
 		data->if_bluetooth = NULL;
 		tester_setup_failed();
 	}
-	
+
 	tester_setup_complete();
 }
 
 static void teardown(const void *test_data)
 {
 	struct test_data *data = tester_get_data();
-	
+
 	if (data->if_bluetooth)
 		data->if_bluetooth->cleanup();
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 1/6] android: Add android-tester
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcin Kraglak
In-Reply-To: <1385631296-2856-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

From: Marcin Kraglak <marcin.kraglak@tieto.com>

This commit add android-tester.c to tree and Makefile.am.
This will contain set of unit tests for testing android daemon.

Change-Id: I0acf021aa33a0d7531f1e9faae8cd0b68d6b0438
---
 android/Makefile.am      |  4 ++++
 android/android-tester.c | 21 +++++++++++++++++++++
 2 files changed, 25 insertions(+)
 create mode 100644 android/android-tester.c

diff --git a/android/Makefile.am b/android/Makefile.am
index 94d231f..9390422 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -82,6 +82,10 @@ android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
 
 android_haltest_LDFLAGS = -pthread
 
+noinst_PROGRAMS += android/android-tester
+
+android_android_tester_SOURCES = android/android-tester.c
+
 endif
 
 EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README \
diff --git a/android/android-tester.c b/android/android-tester.c
new file mode 100644
index 0000000..f5c42b0
--- /dev/null
+++ b/android/android-tester.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+int main(int argc, char *argv[])
+{
+	return 0;
+}
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 0/6] android: initial code for automated tests
From: Grzegorz Kolodziejczyk @ 2013-11-28  9:34 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

This serie adds initial code for automated android deamon and HAL library
tests. Skeleton and one initial test case is added.

-- 
Best regards,
Grzegorz

Grzegorz Kolodziejczyk (1):
  android: Add basic test and handle mgmt notifications, hal cb

Marcin Kraglak (4):
  android: Add android-tester
  android: Add pre-setup and post-teardown routines
  android: Start emulator in separate thread
  android: Add stack initialization of stack in setup

Szymon Janc (1):
  android: Make HAL logging wrapper print to stderr instead of stdout

 android/Makefile.am      |  18 ++
 android/android-tester.c | 592 +++++++++++++++++++++++++++++++++++++++++++++++
 android/hal-log.h        |   2 +-
 3 files changed, 611 insertions(+), 1 deletion(-)
 create mode 100644 android/android-tester.c

-- 
1.8.4.2


^ permalink raw reply

* [PATCH] android/pics: Add PTS PICS for OPP
From: Jakub Tyszkowski @ 2013-11-28  8:04 UTC (permalink / raw)
  To: linux-bluetooth

PTS PICS for OPP, targeting Android 4.4.

---
 android/Makefile.am  |   3 +-
 android/pics-opp.txt | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+), 1 deletion(-)
 create mode 100644 android/pics-opp.txt

diff --git a/android/Makefile.am b/android/Makefile.am
index 94d231f..38aa00a 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -86,4 +86,5 @@ endif
 
 EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README \
 		android/pics-gap.txt android/pics-hid.txt \
-		android/pics-pan.txt android/pics-did.txt
+		android/pics-pan.txt android/pics-did.txt \
+		android/pics-opp.txt
diff --git a/android/pics-opp.txt b/android/pics-opp.txt
new file mode 100644
index 0000000..c0f2ad6
--- /dev/null
+++ b/android/pics-opp.txt
@@ -0,0 +1,184 @@
+OPP PICS for the PTS tool.
+
+* - different than PTS defaults
+# - not yet implemented/supported
+
+M - mandatory
+O - optional
+
+		Roles
+-------------------------------------------------------------------------------
+Parameter Name	Selected	Description
+-------------------------------------------------------------------------------
+TSPC_OPP_1_1	True (*)	Role: Object Push Client.
+TSPC_OPP_1_2	True (*)	Role: Object Push Server.
+-------------------------------------------------------------------------------
+C.1: It is Mandatory to Support at least one of the defined roles.
+-------------------------------------------------------------------------------
+
+
+		Client Profile Version
+-------------------------------------------------------------------------------
+Parameter Name	Selected	Description
+-------------------------------------------------------------------------------
+TSPC_OPP_1b_1	True		Client supports OPP version 1.1. (C.1)
+TSPC_OPP_1b_2	False		Client supports OPP version 1.2. (C.1)
+-------------------------------------------------------------------------------
+C.1: It is mandatory to support at least one of the profile versions.
+-------------------------------------------------------------------------------
+
+
+		Client Application Features
+-------------------------------------------------------------------------------
+Parameter Name	Selected	Description
+-------------------------------------------------------------------------------
+TSPC_OPP_2_1	True		Client: Perform Service Discovery request.
+					(M.1)
+TSPC_OPP_2_2	True		Client: Authentication/PIN exchange supported.
+					(M.1)
+TSPC_OPP_2_2a	True (*)	Client: Require Authentication/PIN by default.
+					(O)
+TSPC_OPP_2_3	True		Client: Object Push is supported. (M.1)
+TSPC_OPP_2_4	True (*)	Client: vCard 2.1 format is supported for
+					Object Push. (C.3)
+TSPC_OPP_2_5	False		Client: vCalender 1.0 format is supported for
+					Object Push. (O)
+TSPC_OPP_2_6	False		Client: vMsg as defined in IrMC 1.1 is supported
+					for Object Push. (O)
+TSPC_OPP_2_7	False		Client: vNote as defined in IrMC 1.1 is
+					supported for Object Push. (O)
+TSPC_OPP_2_8	True (*)	Client: Support content formats other than those
+					declared in TSPC_OPP_2_44 through
+					TSPC_OPP_2_7. (O)
+TSPC_OPP_2_8a	False		Client: Support specific set of other content
+					formats. (C.4)
+TSPC_OPP_2_8b	True (*)	Client: Support all content formats. (C.4)
+TSPC_OPP_2_9	True (*)	Client: Push multiple vCard objects. (O)
+TSPC_OPP_2_9a	False		Client: Push multiple vCard objects using
+					different PUT operations. (C.5)
+TSPC_OPP_2_9b	True (*)	Client: Push multiple vCard objects using the
+					same PUT operation. (C.5)
+TSPC_OPP_2_10	False		Client: Push multiple vCalender objects. (O)
+TSPC_OPP_2_10a	False		Client: Push multiple vMsg objects using
+					different PUT operations. (C.6)
+TSPC_OPP_2_10b	False		Client: Push multiple vMsg objects using the
+					same PUT operation. (C.6)
+TSPC_OPP_2_11	False		Client: Push multiple vMsg objects. (O)
+TSPC_OPP_2_11a	False		Client: Push multiple vMsg objects using
+					different PUT operations. (C.7)
+TSPC_OPP_2_11b	False		Client: Push multiple vMsg objects using the
+					same PUT operation. (C.7)
+TSPC_OPP_2_12	False		Client: Push multiple vNote objects. (O)
+TSPC_OPP_2_12a	False		Client: Push multiple vNote objects using
+					different PUT operations. (C.8)
+TSPC_OPP_2_12b	False		Client: Push multiple vNote objects using the
+					same PUT operation. (C.8)
+TSPC_OPP_2_13	False		Client: Pull business card is supported. (O)
+TSPC_OPP_2_14	False		Client: vCard 2.1 format is supported for
+					Business Card Pull. (C.1)
+TSPC_OPP_2_15	False		Client: Exchange business card is supported. (O)
+TSPC_OPP_2_16	False		Client: vCard 2.1 format is supported for
+					Business Card Exchange (C.2)
+-------------------------------------------------------------------------------
+C.1: Mandatory to Support IF (TSPC_OPP_2_13) Business Card Pull is supported.
+C.2: Mandatory to Support IF (TSPC_OPP_2_15) Business Card Exchange is
+	supported.
+M.1: Mandatory to Support IF (TSPC_OPP_1_1) supported.
+C.3: vCard 2.1 support is required for devices containing phonebook
+	applications. vCard 2.1 support optional for other devices.
+C.4: Mandatory to support one of TSPC_OPP_2_8a or TSPC_OPP_2_8b if TSPC_OPP_2_8
+	is supported. Otherwise, both items are excluded.
+C.5: Mandatory to support at least one of TSPC_OPP_2_9a and TSPC_OPP_2_9b if
+	TSPC_OPP_2_9 is supported. Otherwise, both items are excluded.
+C.6: Mandatory to support at least one of TSPC_OPP_2_10a and TSPC_OPP_2_10b if
+	TSPC_OPP_2_10 is supported. Otherwise, both items are excluded.
+C.7: Mandatory to support at least one of TSPC_OPP_2_11a and TSPC_OPP_2_11b if
+	TSPC_OPP_2_11 is supported. Otherwise, both items are excluded.
+C.8: Mandatory to support at least one of TSPC_OPP_2_12a and TSPC_OPP_2_12b if
+	TSPC_OPP_2_12 is supported. Otherwise, both items are excluded.
+-------------------------------------------------------------------------------
+
+
+		Server Profile Version
+-------------------------------------------------------------------------------
+Parameter Name	Selected	Description
+-------------------------------------------------------------------------------
+TSPC_OPP_2b_1	True		Server supports OPP version 1.1.
+TSPC_OPP_2b_2	False		Server supports OPP version 1.2.
+-------------------------------------------------------------------------------
+C.1: It is mandatory to support at least one of the profile versions.
+-------------------------------------------------------------------------------
+
+
+		Server Application Features
+-------------------------------------------------------------------------------
+Parameter Name	Selected	Description
+-------------------------------------------------------------------------------
+TSPC_OPP_3_1	True		Server: Provide information on supported
+					contents type on service discovery
+					request. (M)
+TSPC_OPP_3_2	True		Server: Authentication/PIN exchange supported.
+					(M)
+TSPC_OPP_3_3	True		Server: Object Push is supported. (M)
+TSPC_OPP_3_3a	True (*)	Server: Receive multiple objects in the same
+					PUT operation. (O)
+TSPC_OPP_3_4	True (*)	Server: vCard 2.1 format is supported for Object
+					Push. (C.3)
+TSPC_OPP_3_5	False		Server: vCalender 1.0 format is supported for
+					Object Push. (O)
+TSPC_OPP_3_6	False		Server: vMsg as defined in IrMC 1.1 is supported
+					for Object Push. (O)
+TSPC_OPP_3_7	False		Server: vNote as defined in IrMC 1.1 is
+					supported for Object Push. (O)
+TSPC_OPP_3_8	True (*)	Server: Support content formats other than those
+					declared in TSPC_OPP_3_4 through
+					TSPC_OPP_3_7. (O)
+TSPC_OPP_3_8a	False		Server: Support specific set of other content
+					formats. (C.4)
+TSPC_OPP_3_8b	True (*)	Server: Support all content formats. (C.4)
+TSPC_OPP_3_9	True (*)	Server: Object Push vCard reject. (O)
+TSPC_OPP_3_10	False		Server: Object Push vCal rejectt. (O)
+TSPC_OPP_3_11	False		Server: Object Push vMsg reject. (O)
+TSPC_OPP_3_12	False		Server: Object Push vNote reject. (O)
+TSPC_OPP_3_13	False		Server: Business card pull is supported. (O.1)
+TSPC_OPP_3_14	False		Server: vCard 2.1 format is supported for
+					Business Card Pull. (C.1)
+TSPC_OPP_3_15	False		Server: Business card pull reject. (O)
+TSPC_OPP_3_16	False		Server: Business card exchange is supported.
+					(O.2)
+TSPC_OPP_3_17	False		Server: vCard 2.1 format is supported for
+					Business Card Exchange (C.2)
+TSPC_OPP_3_18	False		Server: Business card exchange reject. (O)
+-------------------------------------------------------------------------------
+M.1: Mandatory to Support IF (TSPC_OPP_1_2) supported.
+C.2: Mandatory to Support IF (TSPC_OPP_3_16) Business Card Exchange is
+	supported.
+O.1: IF NOT Supported, an error message must be sent on request for Business
+	Card Pull.
+O.2: IF NOT Supported, an error message must be sent on request for Business
+	Card Exchange.
+C.1: Mandatory to Support IF (TSPC_OPP_3_13) Business Card Pull is supported.
+C.3: vCard 2.1 support is required for devices containing phonebook
+	applications. vCard 2.1 support optional for other devices.
+C.4: Mandatory to support one of TSPC_OPP_3_8a or TSPC_OPP_3_8b if TSPC_OPP_3_8
+	is supported. Otherwise, both items are excluded.
+-------------------------------------------------------------------------------
+
+
+		Additional OPP Capabilities
+-------------------------------------------------------------------------------
+Parameter Name	Selected	Description
+-------------------------------------------------------------------------------
+TSPC_OPP_4_1	False		Abort-Push Operation is supported. (O)
+TSPC_OPP_4_2	False		Disconnect of OBEX session should be tested.
+TSPC_OPP_4_3	False		Multiple vCards transferred as a single vObject
+					is supported. (C.1)
+TSPC_OPP_4_4	False		Multiple vCards transfer is supported. (C.1)
+TSPC_OPP_4_5	False		vCards with multiple Phone Number Fields is
+					supported. (C.1)
+TSPC_OPP_4_6	False		Server supports Push vCal to Different Time
+					Zone. (C.1)
+TSPC_ALL	False		Turn on all test cases.
+-------------------------------------------------------------------------------
+C.1: Optional if TSPC_OPP_1_2 is supported, otherwise excluded.
+-------------------------------------------------------------------------------
-- 
1.8.4.1


^ permalink raw reply related

* Re: [RFC] build: Force GLib version check while building in maintainer mode
From: Johan Hedberg @ 2013-11-28  7:44 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1385567096-27261-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Wed, Nov 27, 2013, Szymon Janc wrote:
> This will allow to catch up build errors introduced by using GLib API
> introduced in newer GLib than minimal required even if building with
> newer version.
> ---
>  acinclude.m4 | 2 ++
>  1 file changed, 2 insertions(+)

Seems like a good idea. Applied. Thanks.

Johan

^ permalink raw reply

* [PATCH] Bluetooth: Add support for Toshiba Bluetooth device [0930:0220]
From: Marco Piazza @ 2013-11-27 23:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marco Piazza

This patch adds support for new Toshiba Bluetooth device.

T:  Bus=05 Lev=01 Prnt=01 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
D:  Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=0930 ProdID=0220 Rev=00.02
C:  #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
I:  If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb

Signed-off-by: Marco Piazza <mpiazza@gmail.com>
---
 drivers/bluetooth/ath3k.c | 2 ++
 drivers/bluetooth/btusb.c | 1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index d3fdc32..106d1d8 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = {
 	{ USB_DEVICE(0x0CF3, 0xE004) },
 	{ USB_DEVICE(0x0CF3, 0xE005) },
 	{ USB_DEVICE(0x0930, 0x0219) },
+	{ USB_DEVICE(0x0930, 0x0220) },
 	{ USB_DEVICE(0x0489, 0xe057) },
 	{ USB_DEVICE(0x13d3, 0x3393) },
 	{ USB_DEVICE(0x0489, 0xe04e) },
@@ -132,6 +133,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index bfbcc5a..9f7e539 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -155,6 +155,7 @@ static const struct usb_device_id blacklist_table[] = {
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
-- 
1.8.4.rc3


^ permalink raw reply related

* [RFC BlueZ v0 17/17] bluetooth.conf: Add ObjectManager interface
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

---
 src/bluetooth.conf | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 0495200..ad8891a 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -18,6 +18,7 @@
     <allow send_interface="org.bluez.Profile1"/>
     <allow send_interface="org.bluez.HeartRateWatcher1"/>
     <allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
+    <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
   </policy>
 
   <policy at_console="true">
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 16/17] gatttool: Add unix socket support for interactive mode
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

This patch allows running GATT operations over unix socket on
interactive mode.
---
 attrib/interactive.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 5bd27af..d89b494 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -84,7 +84,7 @@ static char *get_prompt(void)
 	if (opt_dst)
 		g_string_append_printf(prompt, "[%17s]", opt_dst);
 	else
-		g_string_append_printf(prompt, "[%17s]", "");
+		g_string_append_printf(prompt, "[LOCAL]");
 
 	if (conn_state == STATE_CONNECTED)
 		g_string_append(prompt, COLOR_OFF);
@@ -406,15 +406,17 @@ static void cmd_connect(int argcp, char **argvp)
 			opt_dst_type = g_strdup("public");
 	}
 
-	if (opt_dst == NULL) {
-		error("Remote Bluetooth address required\n");
-		return;
+	if (opt_dst) {
+
+		rl_printf("Attempting to connect to %s\n", opt_dst);
+		set_state(STATE_CONNECTING);
+		iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
+				opt_psm, opt_mtu, connect_cb, &gerr);
+	} else {
+		rl_printf("Local connection\n");
+		iochannel = unix_connect(connect_cb, &gerr);
 	}
 
-	rl_printf("Attempting to connect to %s\n", opt_dst);
-	set_state(STATE_CONNECTING);
-	iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
-					opt_psm, opt_mtu, connect_cb, &gerr);
 	if (iochannel == NULL) {
 		set_state(STATE_DISCONNECTED);
 		error("%s\n", gerr->message);
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 15/17] gatttool: Add unix socket connect
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the initial support for GATT procedures over unix
socket transport on command line mode (one-shot command). Temporary
solution to allow local GATT procedures testing.
---
 attrib/gatttool.c | 27 ++++++++++++++++++++-------
 attrib/gatttool.h |  1 +
 attrib/utils.c    | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 7 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index f211dcd..65fba19 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -29,7 +29,6 @@
 #include <errno.h>
 #include <glib.h>
 #include <stdlib.h>
-#include <unistd.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
@@ -53,6 +52,7 @@ static int opt_end = 0xffff;
 static int opt_handle = -1;
 static int opt_mtu = 0;
 static int opt_psm = 0;
+static gboolean opt_local = FALSE;
 static gboolean opt_primary = FALSE;
 static gboolean opt_characteristics = FALSE;
 static gboolean opt_char_read = FALSE;
@@ -512,6 +512,8 @@ static GOptionEntry options[] = {
 		"Specify local adapter interface", "hciX" },
 	{ "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
 		"Specify remote Bluetooth address", "MAC" },
+	{ "local", 'L', 0, G_OPTION_ARG_NONE, &opt_local,
+		"Use unix socket transport (local communication)", NULL },
 	{ "addr-type", 't', 0, G_OPTION_ARG_STRING, &opt_dst_type,
 		"Set LE address type. Default: public", "[public | random]"},
 	{ "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
@@ -564,6 +566,11 @@ int main(int argc, char *argv[])
 		g_clear_error(&gerr);
 	}
 
+	if (opt_local) {
+		opt_src = NULL;
+		opt_dst = NULL;
+	}
+
 	if (opt_interactive) {
 		interactive(opt_src, opt_dst, opt_dst_type, opt_psm);
 		goto done;
@@ -589,14 +596,20 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
-	if (opt_dst == NULL) {
-		g_print("Remote Bluetooth address required\n");
-		got_error = TRUE;
-		goto done;
+	if (opt_local)
+		chan = unix_connect(connect_cb, &gerr);
+	else {
+		if (opt_dst == NULL) {
+			g_print("Remote Bluetooth address required\n");
+			got_error = TRUE;
+			goto done;
+		}
+
+		chan = gatt_connect(opt_src, opt_dst, opt_dst_type,
+					opt_sec_level, opt_psm, opt_mtu,
+					connect_cb, &gerr);
 	}
 
-	chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
-					opt_psm, opt_mtu, connect_cb, &gerr);
 	if (chan == NULL) {
 		g_printerr("%s\n", gerr->message);
 		g_clear_error(&gerr);
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 8f0913c..be8e236 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -27,4 +27,5 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
 			const char *dst_type, const char *sec_level,
 			int psm, int mtu, BtIOConnect connect_cb,
 			GError **gerr);
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr);
 size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
diff --git a/attrib/utils.c b/attrib/utils.c
index 77bab27..de7b00a 100644
--- a/attrib/utils.c
+++ b/attrib/utils.c
@@ -25,7 +25,12 @@
 #include "config.h"
 #endif
 
+#include <errno.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
 #include <glib.h>
 
 #include <bluetooth/bluetooth.h>
@@ -101,6 +106,55 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
 	return chan;
 }
 
+static gboolean unix_connect_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	BtIOConnect connect_cb = user_data;
+	GError *gerr;
+
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		gerr = g_error_new_literal(G_IO_CHANNEL_ERROR,
+						G_IO_CHANNEL_ERROR_FAILED,
+						"connection attempt failed");
+		connect_cb(io, gerr, user_data);
+		g_clear_error(&gerr);
+	} else {
+		connect_cb(io, NULL, user_data);
+	}
+
+	return FALSE;
+}
+
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr)
+{
+	GIOChannel *io;
+	struct sockaddr_un uaddr  = {
+		.sun_family	= AF_UNIX,
+		.sun_path	= "\0/bluetooth/unix_att",
+	};
+	int sk;
+
+	sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC , 0);
+	if (sk < 0) {
+		g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+				G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+		return NULL;
+	}
+
+	if (connect(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+		g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+				G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+		close(sk);
+		return NULL;
+	}
+
+	io = g_io_channel_unix_new(sk);
+	g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+						unix_connect_cb, connect_cb);
+
+	return io;
+}
+
 size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
 {
 	char tmp[3];
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 14/17] test: Add registering external service
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

This patch extends gatt-service to call RegisterService() when org.bluez
service gets connected to the system bus.
---
 test/gatt-service.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/test/gatt-service.c b/test/gatt-service.c
index 06719b4..c26a5be 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -114,6 +114,65 @@ static void create_services(DBusConnection *conn)
 	printf("Registered service: %s\n", service_path);
 }
 
+static void register_external_service_reply(DBusPendingCall *call,
+							void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	dbus_set_error_from_message(&derr, reply);
+
+	if (dbus_error_is_set(&derr))
+		fprintf(stderr, "RegisterService: %s\n", derr.message);
+	else
+		printf("RegisterService: OK\n");
+
+	dbus_message_unref(reply);
+	dbus_error_free(&derr);
+}
+
+static void register_external_service(gpointer a, gpointer b)
+{
+	DBusConnection *conn = b;
+	const char *path = a;
+	DBusMessage *msg;
+	DBusPendingCall *call;
+	DBusMessageIter iter, dict;
+
+	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+					SERVICE_MGR_IFACE, "RegisterService");
+	if (msg == NULL) {
+		fprintf(stderr, "Couldn't allocate D-Bus message\n");
+		return;
+	}
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+	/* TODO: Add options dictionary */
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return;
+	}
+
+	dbus_pending_call_set_notify(call, register_external_service_reply,
+								NULL, NULL);
+
+	dbus_pending_call_unref(call);
+}
+
+static void connect_handler(DBusConnection *conn, void *user_data)
+{
+	g_slist_foreach(services, register_external_service, conn);
+}
+
 static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
 							gpointer user_data)
 {
@@ -159,6 +218,7 @@ static guint setup_signalfd(void)
 
 int main(int argc, char *argv[])
 {
+	GDBusClient *client;
 	DBusConnection *dbus_conn;
 	guint signal;
 
@@ -177,8 +237,14 @@ int main(int argc, char *argv[])
 
 	create_services(dbus_conn);
 
+	client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+	g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+
 	g_main_loop_run(main_loop);
 
+	g_dbus_client_unref(client);
+
 	g_source_remove(signal);
 
 	g_slist_free_full(services, g_free);
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 13/17] test: Add signal handling for gatt-service
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

This patch implements signal handling to run cleanup tasks before
exiting.
---
 test/gatt-service.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/test/gatt-service.c b/test/gatt-service.c
index 31aa06b..06719b4 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -27,12 +27,14 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <sys/signalfd.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 #include <gdbus/gdbus.h>
 
 #define SERVICE_IFACE			"org.bluez.Service1"
+#define SERVICE_MGR_IFACE		"org.bluez.ServiceManager1"
 
 /* Immediate Alert Service UUID */
 #define IAS_UUID			"00001802-0000-1000-8000-00805f9b34fb"
@@ -112,9 +114,57 @@ static void create_services(DBusConnection *conn)
 	printf("Registered service: %s\n", service_path);
 }
 
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+							gpointer user_data)
+{
+	g_main_loop_quit(main_loop);
+
+	return FALSE;
+}
+
+static guint setup_signalfd(void)
+{
+	GIOChannel *channel;
+	guint source;
+	sigset_t mask;
+	int fd;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGINT);
+	sigaddset(&mask, SIGTERM);
+
+	if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+		perror("Failed to set signal mask");
+		return 0;
+	}
+
+	fd = signalfd(-1, &mask, 0);
+	if (fd < 0) {
+		perror("Failed to create signal descriptor");
+		return 0;
+	}
+
+	channel = g_io_channel_unix_new(fd);
+
+	g_io_channel_set_close_on_unref(channel, TRUE);
+
+	source = g_io_add_watch(channel,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				signal_handler, NULL);
+
+	g_io_channel_unref(channel);
+
+	return source;
+}
+
 int main(int argc, char *argv[])
 {
 	DBusConnection *dbus_conn;
+	guint signal;
+
+	signal = setup_signalfd();
+	if (signal == 0)
+		return -errno;
 
 	dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
 
@@ -129,6 +179,8 @@ int main(int argc, char *argv[])
 
 	g_main_loop_run(main_loop);
 
+	g_source_remove(signal);
+
 	g_slist_free_full(services, g_free);
 	dbus_connection_unref(dbus_conn);
 
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 12/17] test: Add external service GATT skeleton
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the initial code for an external GATT service example.
It implements the API defined at doc/gatt-api.txt
---
 Makefile.tools      |   5 ++
 test/gatt-service.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 141 insertions(+)
 create mode 100644 test/gatt-service.c

diff --git a/Makefile.tools b/Makefile.tools
index 78034f5..7eaf03d 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -292,3 +292,8 @@ test_scripts += test/sap_client.py test/bluezutils.py \
 		test/service-ftp.xml test/simple-player test/test-nap \
 		test/test-heartrate test/test-alert test/test-hfp \
 		test/test-cyclingspeed
+
+test_gatt_service_SOURCES = test/gatt-service.c
+test_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
+
+noinst_PROGRAMS += test/gatt-service
diff --git a/test/gatt-service.c b/test/gatt-service.c
new file mode 100644
index 0000000..31aa06b
--- /dev/null
+++ b/test/gatt-service.c
@@ -0,0 +1,136 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  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 <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#define SERVICE_IFACE			"org.bluez.Service1"
+
+/* Immediate Alert Service UUID */
+#define IAS_UUID			"00001802-0000-1000-8000-00805f9b34fb"
+
+static GMainLoop *main_loop;
+static GSList *services;
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	const char *uuid = user_data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+	return TRUE;
+}
+
+static gboolean service_get_includes(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	return TRUE;
+}
+
+static gboolean service_exist_includes(const GDBusPropertyTable *property,
+							void *user_data)
+{
+	return FALSE;
+}
+
+static DBusMessage *service_release(DBusConnection *conn,
+				DBusMessage *msg, void *user_data)
+{
+	fprintf(stderr, "Terminating...\n");
+
+	g_main_loop_quit(main_loop);
+
+	return NULL;
+};
+
+static const GDBusMethodTable service_methods[] = {
+	{ GDBUS_NOREPLY_METHOD("Release", NULL, NULL, service_release) },
+	{ }
+};
+
+static const GDBusPropertyTable service_properties[] = {
+	{ "UUID", "s", service_get_uuid },
+	{ "Includes", "ao", service_get_includes, NULL,
+					service_exist_includes },
+	{ }
+};
+
+static char *register_service(DBusConnection *conn, const char *uuid)
+{
+	static int id = 1;
+	char *path;
+
+	path = g_strdup_printf("/service%d", id++);
+	if (g_dbus_register_interface(conn, path, SERVICE_IFACE,
+				service_methods, NULL, service_properties,
+				g_strdup(uuid), g_free) == FALSE) {
+		fprintf(stderr, "Couldn't register service interface\n");
+		g_free(path);
+		return NULL;
+	}
+
+	return path;
+}
+
+static void create_services(DBusConnection *conn)
+{
+	char *service_path;
+
+	service_path = register_service(conn, IAS_UUID);
+
+	services = g_slist_prepend(services, service_path);
+
+	printf("Registered service: %s\n", service_path);
+}
+
+int main(int argc, char *argv[])
+{
+	DBusConnection *dbus_conn;
+
+	dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+	main_loop = g_main_loop_new(NULL, FALSE);
+
+	g_dbus_attach_object_manager(dbus_conn);
+
+	printf("gatt-service unique name: %s\n",
+				dbus_bus_get_unique_name(dbus_conn));
+
+	create_services(dbus_conn);
+
+	g_main_loop_run(main_loop);
+
+	g_slist_free_full(services, g_free);
+	dbus_connection_unref(dbus_conn);
+
+	return 0;
+}
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 11/17] gatt: Add Discover All Primary Services
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch adds ATT Read By Group request handling to the attribute
server. It is the primitive to implement Discover All Primary Services
procedure.
---
 src/gatt.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 128 insertions(+), 1 deletion(-)

diff --git a/src/gatt.c b/src/gatt.c
index fcb7b56..1dc8bde 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -100,6 +100,130 @@ static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
 	g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
 }
 
+static void read_by_group_resp(GAttrib *attrib, uint16_t start,
+					uint16_t end, bt_uuid_t *pattern)
+{
+	uint8_t opdu[ATT_DEFAULT_LE_MTU];
+	GList *list;
+	struct btd_attribute *last = NULL;
+	uint8_t *group_start, *group_end = NULL, *group_uuid;
+	unsigned int uuid_type = BT_UUID_UNSPEC;
+	size_t group_len = 0, plen = 0;
+
+	/*
+	 * Read By Group Type Response format:
+	 *    Attribute Opcode: 1 byte
+	 *    Length: 1 byte (size of each group)
+	 *    Group: start | end | <<UUID>>
+	 */
+
+	opdu[0] = ATT_OP_READ_BY_GROUP_RESP;
+	group_start = &opdu[2];
+	group_uuid = &opdu[6];
+
+	for (list = local_attribute_db; list;
+			last = list->data, list = g_list_next(list)) {
+		struct btd_attribute *attr = list->data;
+
+		if (attr->handle < start)
+			continue;
+
+		if (attr->handle > end)
+			break;
+
+		if (bt_uuid_cmp(&attr->type, pattern) != 0)
+			continue;
+
+		if (uuid_type != BT_UUID_UNSPEC &&
+						uuid_type != attr->type.type) {
+			/*
+			 * Groups should contain the same length: UUID16 and
+			 * UUID128 should be sent on different ATT PDUs
+			 */
+			break;
+		}
+
+		/*
+		 * MTU checking should not be shifted up, otherwise the
+		 * handle of last end group will not be set properly.
+		 */
+		if ((plen + group_len) >= ATT_DEFAULT_LE_MTU)
+			break;
+
+		/* Start Grouping handle */
+		att_put_u16(attr->handle, group_start);
+
+		/* Grouping <<UUID>>: Value is little endian */
+		memcpy(group_uuid, attr->value, attr->value_len);
+
+		if (last && group_end) {
+			att_put_u16(last->handle, group_end);
+			group_end += group_len;
+			plen += group_len;
+		}
+
+		/* Grouping initial settings: First grouping */
+		if (uuid_type == BT_UUID_UNSPEC) {
+			uuid_type = attr->type.type;
+
+			/* start(0xXXXX) | end(0xXXXX) | <<UUID>> */
+			group_len = 2 + 2 + bt_uuid_len(&attr->type);
+
+			/* 2: ATT Opcode and Length */
+			plen = 2 + group_len;
+
+			/* Size of each Attribute Data */
+			opdu[1] = group_len;
+
+			group_end = &opdu[4];
+		}
+
+		group_start += group_len;
+		group_uuid += group_len;
+	}
+
+	if (plen == 0) {
+		send_error(attrib, ATT_OP_READ_BY_GROUP_REQ, start,
+						ATT_ECODE_ATTR_NOT_FOUND);
+		return;
+	}
+
+	if (group_end)
+		att_put_u16(last->handle, group_end);
+
+	g_attrib_send(attrib, 0, opdu, plen, NULL, NULL, NULL);
+}
+
+static void read_by_group(GAttrib *attrib, const uint8_t *ipdu, size_t ilen)
+{
+	uint16_t decoded, start, end;
+	bt_uuid_t pattern;
+
+	decoded = dec_read_by_grp_req(ipdu, ilen, &start, &end, &pattern);
+	if (decoded == 0) {
+		send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_INVALID_PDU);
+		return;
+	}
+
+	if (start > end || start == 0x0000) {
+		send_error(attrib, ipdu[0], start, ATT_ECODE_INVALID_HANDLE);
+		return;
+	}
+
+	 /*
+	  * Restricting Read By Group Type to <<Primary>>.
+	  * Removing the checking below requires changes to support
+	  * dynamic values(defined in the upper layer) and additional
+	  * security verification.
+	  */
+	if (bt_uuid_cmp(&pattern, &primary_uuid) != 0) {
+		send_error(attrib, ipdu[0], start, ATT_ECODE_UNSUPP_GRP_TYPE);
+		return;
+	}
+
+	read_by_group_resp(attrib, start, end, &pattern);
+}
+
 static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
 							gpointer user_data)
 {
@@ -121,11 +245,14 @@ static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
 	case ATT_OP_READ_MULTI_REQ:
 	case ATT_OP_PREP_WRITE_REQ:
 	case ATT_OP_EXEC_WRITE_REQ:
-	case ATT_OP_READ_BY_GROUP_REQ:
 	case ATT_OP_SIGNED_WRITE_CMD:
 		send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
 		break;
 
+	case ATT_OP_READ_BY_GROUP_REQ:
+		read_by_group(attrib, ipdu, ilen);
+		break;
+
 	/* Responses */
 	case ATT_OP_MTU_RESP:
 	case ATT_OP_FIND_INFO_RESP:
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 10/17] gatt: Register ATT command/event handler
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch registers the ATT channel handler to manage incoming ATT
commands and events.
---
 src/gatt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/src/gatt.c b/src/gatt.c
index bbd44f0..fcb7b56 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -38,6 +38,7 @@
 #include "log.h"
 #include "lib/uuid.h"
 #include "attrib/att.h"
+#include "attrib/gattrib.h"
 
 #include "gatt-dbus.h"
 #include "gatt.h"
@@ -88,12 +89,83 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	return attr;
 }
 
+static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
+								uint8_t ecode)
+{
+	uint8_t pdu[ATT_DEFAULT_LE_MTU];
+	size_t plen;
+
+	plen = enc_error_resp(opcode, handle, ecode, pdu, sizeof(pdu));
+
+	g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
+}
+
+static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
+							gpointer user_data)
+{
+	GAttrib *attrib = user_data;
+
+	switch (ipdu[0]) {
+	case ATT_OP_ERROR:
+		break;
+
+	/* Requests */
+	case ATT_OP_WRITE_CMD:
+	case ATT_OP_WRITE_REQ:
+	case ATT_OP_READ_REQ:
+	case ATT_OP_READ_BY_TYPE_REQ:
+	case ATT_OP_MTU_REQ:
+	case ATT_OP_FIND_INFO_REQ:
+	case ATT_OP_FIND_BY_TYPE_REQ:
+	case ATT_OP_READ_BLOB_REQ:
+	case ATT_OP_READ_MULTI_REQ:
+	case ATT_OP_PREP_WRITE_REQ:
+	case ATT_OP_EXEC_WRITE_REQ:
+	case ATT_OP_READ_BY_GROUP_REQ:
+	case ATT_OP_SIGNED_WRITE_CMD:
+		send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
+		break;
+
+	/* Responses */
+	case ATT_OP_MTU_RESP:
+	case ATT_OP_FIND_INFO_RESP:
+	case ATT_OP_FIND_BY_TYPE_RESP:
+	case ATT_OP_READ_BY_TYPE_RESP:
+	case ATT_OP_READ_RESP:
+	case ATT_OP_READ_BLOB_RESP:
+	case ATT_OP_READ_MULTI_RESP:
+	case ATT_OP_READ_BY_GROUP_RESP:
+	case ATT_OP_WRITE_RESP:
+	case ATT_OP_PREP_WRITE_RESP:
+	case ATT_OP_EXEC_WRITE_RESP:
+	case ATT_OP_HANDLE_CNF:
+		break;
+
+	/* Notification & Indication */
+	case ATT_OP_HANDLE_NOTIFY:
+	case ATT_OP_HANDLE_IND:
+		break;
+	}
+}
+
+static gboolean unix_hup_cb(GIOChannel *io, GIOCondition cond,
+						gpointer user_data)
+{
+	GAttrib *attrib = user_data;
+
+	g_attrib_unregister_all(attrib);
+	g_attrib_unref(attrib);
+
+	return FALSE;
+}
+
 static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
 	struct sockaddr_un uaddr;
 	socklen_t len = sizeof(uaddr);
 	GIOChannel *nio;
+	GAttrib *attrib;
 	int err, nsk, sk;
 
 	sk = g_io_channel_unix_get_fd(io);
@@ -108,6 +180,14 @@ static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
 	nio = g_io_channel_unix_new(nsk);
 	g_io_channel_set_close_on_unref(nio, TRUE);
 	DBG("ATT UNIX socket: %p new client", nio);
+
+	attrib = g_attrib_new(nio);
+
+	g_attrib_register(attrib, GATTRIB_ALL_EVENTS, GATTRIB_ALL_HANDLES,
+					channel_handler_cb, attrib, NULL);
+
+	g_io_add_watch(nio, G_IO_HUP, unix_hup_cb, attrib);
+
 	g_io_channel_unref(nio);
 
 	return TRUE;
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 09/17] gattrib: Use default ATT LE MTU for non-standard sockets
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

This patch forces the MTU to 23 (default ATT MTU) if the transport
is not Bluetooth. This is a development purpose change to allow
testing GATT procedures over non-Bluetooth sockets.
---
 attrib/gattrib.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index 609b908..fccb2bf 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -468,18 +468,18 @@ GAttrib *g_attrib_new(GIOChannel *io)
 	struct _GAttrib *attrib;
 	uint16_t imtu;
 	uint16_t att_mtu;
-	uint16_t cid;
-	GError *gerr = NULL;
+	uint16_t cid = 0;
 
 	g_io_channel_set_encoding(io, NULL, NULL);
 	g_io_channel_set_buffered(io, FALSE);
 
-	bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu,
-				BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);
-	if (gerr) {
-		error("%s", gerr->message);
-		g_error_free(gerr);
-		return NULL;
+	if (bt_io_get(io, NULL, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_CID, &cid,
+						BT_IO_OPT_INVALID) == FALSE) {
+		/*
+		 * Use default ATT LE MTU for non-standard transports. Used
+		 * for testing purpose only. eg: Unix sockets
+		 */
+		imtu = ATT_DEFAULT_LE_MTU;
 	}
 
 	attrib = g_try_new0(struct _GAttrib, 1);
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 08/17] gatt: Add server unix socket
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds a server unix socket to handle local ATT traffic. This
is a development purpose feature used to allow local testing without
breaking the current attribute server.
---
 src/gatt.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/src/gatt.c b/src/gatt.c
index 86023a4..bbd44f0 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,6 +25,11 @@
 #include <config.h>
 #endif
 
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
 #include <glib.h>
 
 #include "adapter.h"
@@ -50,6 +55,7 @@ struct btd_attribute {
 
 static GList *local_attribute_db = NULL;
 static uint16_t next_handle = 0x0001;
+static guint unix_watch;
 
 static int local_database_add(uint16_t handle, struct btd_attribute *attr)
 {
@@ -82,11 +88,71 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	return attr;
 }
 
+static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct sockaddr_un uaddr;
+	socklen_t len = sizeof(uaddr);
+	GIOChannel *nio;
+	int err, nsk, sk;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	nsk = accept(sk, (struct sockaddr *) &uaddr, &len);
+	if (nsk < 0) {
+		err = errno;
+		error("ATT UNIX socket accept: %s(%d)", strerror(err), err);
+		return TRUE;
+	}
+
+	nio = g_io_channel_unix_new(nsk);
+	g_io_channel_set_close_on_unref(nio, TRUE);
+	DBG("ATT UNIX socket: %p new client", nio);
+	g_io_channel_unref(nio);
+
+	return TRUE;
+}
+
 void gatt_init(void)
 {
+	struct sockaddr_un uaddr  = {
+		.sun_family     = AF_UNIX,
+		.sun_path       = "\0/bluetooth/unix_att",
+	};
+	GIOChannel *io;
+	int sk, err;
+
 	DBG("Starting GATT server");
 
 	gatt_dbus_manager_register();
+
+	sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC , 0);
+	if (sk < 0) {
+		err = errno;
+		error("ATT UNIX socket: %s(%d)", strerror(err), err);
+		return;
+	}
+
+	if (bind(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+		err = errno;
+		error("binding ATT UNIX socket: %s(%d)", strerror(err), err);
+		close(sk);
+		return;
+	}
+
+	if (listen(sk, 5) < 0) {
+		err = errno;
+		error("listen ATT UNIX socket: %s(%d)", strerror(err), err);
+		close(sk);
+		return;
+	}
+
+	io = g_io_channel_unix_new(sk);
+	g_io_channel_set_close_on_unref(io, TRUE);
+	unix_watch = g_io_add_watch(io,
+				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+				unix_accept_cb, NULL);
+	g_io_channel_unref(io);
 }
 
 void gatt_cleanup(void)
@@ -94,4 +160,5 @@ void gatt_cleanup(void)
 	DBG("Stopping GATT server");
 
 	gatt_dbus_manager_unregister();
+	g_source_remove(unix_watch);
 }
-- 
1.8.3.1


^ permalink raw reply related

* [RFC BlueZ v0 07/17] gatt: Implement UnregisterService
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch implements UnregisterService method of ServiceManager1.
External applications may call this method to unregister a given
service without leaving the system bus.
---
 src/gatt-dbus.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index a53eed2..a7424d5 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -243,6 +243,31 @@ invalid:
 static DBusMessage *unregister_service(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
+	struct external_app *eapp = user_data;
+	DBusMessageIter iter;
+	const char *path;
+	GSList *list;
+
+	DBG("Unregistering GATT Service");
+
+	if (dbus_message_iter_init(msg, &iter) == false)
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&iter, &path);
+
+	list = g_slist_find_custom(external_apps, path, external_app_path_cmp);
+	if (list == NULL)
+		return btd_error_does_not_exist(msg);
+
+	eapp = list->data;
+	if (g_strcmp0(dbus_message_get_sender(msg), eapp->owner) != 0)
+		return btd_error_does_not_exist(msg);
+
+	g_dbus_remove_watch(conn, eapp->watch);
+
 	return dbus_message_new_method_return(msg);
 }
 
-- 
1.8.3.1


^ permalink raw reply related


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