linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag
@ 2018-01-12 14:10 Grzegorz Kolodziejczyk
  2018-01-12 14:10 ` [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands Grzegorz Kolodziejczyk
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Grzegorz Kolodziejczyk @ 2018-01-12 14:10 UTC (permalink / raw)
  To: linux-bluetooth

Defined setting flag is presented as mask.
---
 tools/btpclient.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/btpclient.c b/tools/btpclient.c
index 806403f6a..a8a65fd51 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -368,9 +368,9 @@ static void btp_gap_set_connectable(uint8_t index, const void *param,
 	new_settings = adapter->current_settings;
 
 	if (cp->connectable)
-		new_settings |= 1 << BTP_GAP_SETTING_CONNECTABLE;
+		new_settings |= BTP_GAP_SETTING_CONNECTABLE;
 	else
-		new_settings &= ~(1 << BTP_GAP_SETTING_CONNECTABLE);
+		new_settings &= ~BTP_GAP_SETTING_CONNECTABLE;
 
 	update_current_settings(adapter, new_settings);
 
-- 
2.13.6


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

* [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands
  2018-01-12 14:10 [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Grzegorz Kolodziejczyk
@ 2018-01-12 14:10 ` Grzegorz Kolodziejczyk
  2018-01-15 13:21   ` Szymon Janc
  2018-01-12 14:10 ` [PATCH BlueZ v2 3/4] tools/btpclient: Add connect, disconnect commands Grzegorz Kolodziejczyk
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Grzegorz Kolodziejczyk @ 2018-01-12 14:10 UTC (permalink / raw)
  To: linux-bluetooth

This patch adds start and stop advertising commands for btp client.
---
 tools/btpclient.c | 651 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 650 insertions(+), 1 deletion(-)

diff --git a/tools/btpclient.c b/tools/btpclient.c
index a8a65fd51..3fb94b7f9 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -34,6 +34,19 @@
 
 #include "src/shared/btp.h"
 
+#define AD_PATH "/org/bluez/advertising"
+#define AD_IFACE "org.bluez.LEAdvertisement1"
+
+/* List of assigned numbers for advetising data and scan response */
+#define AD_TYPE_FLAGS				0x01
+#define AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST	0x02
+#define AD_TYPE_SHORT_NAME			0x08
+#define AD_TYPE_SERVICE_DATA_UUID16		0x16
+#define AD_TYPE_APPEARANCE			0x19
+#define AD_TYPE_MANUFACTURER_DATA		0xff
+
+static struct l_dbus *dbus;
+
 struct btp_adapter {
 	struct l_dbus_proxy *proxy;
 	struct l_dbus_proxy *ad_proxy;
@@ -53,12 +66,61 @@ static struct btp *btp;
 
 static bool gap_service_registered;
 
+struct ad_data {
+	uint8_t data[25];
+	uint8_t len;
+};
+
+struct service_data {
+	char *uuid;
+	struct ad_data data;
+};
+
+struct manufacturer_data {
+	uint16_t id;
+	struct ad_data data;
+};
+
+static struct ad {
+	bool registered;
+	char *type;
+	char *local_name;
+	uint16_t local_appearance;
+	uint16_t duration;
+	uint16_t timeout;
+	struct l_queue *uuids;
+	struct l_queue *services;
+	struct l_queue *manufacturers;
+	bool tx_power;
+	bool name;
+	bool appearance;
+} ad = {
+	.local_appearance = UINT16_MAX,
+};
+
 static bool str2addr(const char *str, uint8_t *addr)
 {
 	return sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[5], &addr[4],
 				&addr[3], &addr[2], &addr[1], &addr[0]) == 6;
 }
 
+static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
+{
+	switch (len) {
+	case 16:
+		return l_strdup_printf("%hhx%hhx", uuid[0], uuid[1]);
+	case 128:
+		return l_strdup_printf("%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx"
+					"%hhx%hhx%hhx%hhx%hhx%hhx%hhx", uuid[0],
+					uuid[1], uuid[2], uuid[3], uuid[4],
+					uuid[5], uuid[6], uuid[6], uuid[8],
+					uuid[7], uuid[10], uuid[11], uuid[12],
+					uuid[13], uuid[14], uuid[15]);
+	default:
+		return NULL;
+	}
+}
+
 static struct btp_adapter *find_adapter_by_proxy(struct l_dbus_proxy *proxy)
 {
 	const struct l_queue_entry *entry;
@@ -123,6 +185,8 @@ static void btp_gap_read_commands(uint8_t index, const void *param,
 	commands |= (1 << BTP_OP_GAP_SET_CONNECTABLE);
 	commands |= (1 << BTP_OP_GAP_SET_DISCOVERABLE);
 	commands |= (1 << BTP_OP_GAP_SET_BONDABLE);
+	commands |= (1 << BTP_OP_GAP_START_ADVERTISING);
+	commands |= (1 << BTP_OP_GAP_STOP_ADVERTISING);
 	commands |= (1 << BTP_OP_GAP_START_DISCOVERY);
 	commands |= (1 << BTP_OP_GAP_STOP_DISCOVERY);
 
@@ -234,6 +298,46 @@ static void remove_device_reply(struct l_dbus_proxy *proxy,
 	l_queue_remove(adapter->devices, device);
 }
 
+static void unreg_advertising_setup(struct l_dbus_message *message,
+								void *user_data)
+{
+	struct l_dbus_message_builder *builder;
+
+	builder = l_dbus_message_builder_new(message);
+	l_dbus_message_builder_append_basic(builder, 'o', AD_PATH);
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+}
+
+static void unreg_advertising_reply(struct l_dbus_proxy *proxy,
+						struct l_dbus_message *result,
+						void *user_data)
+{
+	const char *path = l_dbus_proxy_get_path(proxy);
+	struct btp_adapter *adapter = find_adapter_by_path(path);
+
+	if (!adapter)
+		return;
+
+	if (l_dbus_message_is_error(result)) {
+		const char *name;
+
+		l_dbus_message_get_error(result, &name, NULL);
+
+		l_error("Failed to stop advertising %s (%s)",
+					l_dbus_proxy_get_path(proxy), name);
+		return;
+	}
+
+	if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
+		l_info("Unable to remove ad instance");
+	if (!l_dbus_object_remove_interface(dbus, AD_PATH,
+						L_DBUS_INTERFACE_PROPERTIES))
+		l_info("Unable to remove propety instance");
+	if (!l_dbus_unregister_interface(dbus, AD_IFACE))
+		l_info("Unable to unregister ad interface");
+}
+
 static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
 								void *user_data)
 {
@@ -264,6 +368,16 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
 						NULL);
 	}
 
+	if (adapter->ad_proxy)
+		if (!l_dbus_proxy_method_call(adapter->ad_proxy,
+						"UnregisterAdvertisement",
+						unreg_advertising_setup,
+						unreg_advertising_reply,
+						NULL, NULL)) {
+			status = BTP_ERROR_FAIL;
+			goto failed;
+		}
+
 	/* TODO for we assume all went well */
 	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
 	return;
@@ -449,6 +563,529 @@ failed:
 	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
 }
 
+static void ad_cleanup_service(void *service)
+{
+	struct service_data *s = service;
+
+	l_free(s->uuid);
+	l_free(s);
+}
+
+static void ad_cleanup()
+{
+	l_free(ad.local_name);
+	l_queue_destroy(ad.uuids, l_free);
+	l_queue_destroy(ad.services, ad_cleanup_service);
+	l_queue_destroy(ad.manufacturers, l_free);
+}
+
+static struct l_dbus_message *ad_release_call(struct l_dbus *dbus,
+						struct l_dbus_message *message,
+						void *user_data)
+{
+	struct l_dbus_message *reply;
+
+	l_dbus_unregister_object(dbus, AD_PATH);
+	l_dbus_unregister_interface(dbus, AD_IFACE);
+
+	reply = l_dbus_message_new_method_return(message);
+	l_dbus_message_set_arguments(reply, "");
+
+	ad_cleanup();
+
+	return reply;
+}
+
+static bool ad_type_getter(struct l_dbus *dbus, struct l_dbus_message *message,
+				struct l_dbus_message_builder *builder,
+				void *user_data)
+{
+	l_dbus_message_builder_append_basic(builder, 's', ad.type);
+
+	return true;
+}
+
+static bool ad_serviceuuids_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	const struct l_queue_entry *entry;
+
+	if (l_queue_isempty(ad.uuids))
+		return false;
+
+	l_dbus_message_builder_enter_array(builder, "s");
+
+	for (entry = l_queue_get_entries(ad.uuids); entry; entry = entry->next)
+		l_dbus_message_builder_append_basic(builder, 's', entry->data);
+
+	l_dbus_message_builder_leave_array(builder);
+
+	return true;
+}
+
+static bool ad_servicedata_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	const struct l_queue_entry *entry;
+	size_t i;
+
+	if (l_queue_isempty(ad.services))
+		return false;
+
+	l_dbus_message_builder_enter_array(builder, "{sv}");
+
+	for (entry = l_queue_get_entries(ad.services); entry;
+							entry = entry->next) {
+		struct service_data *sd = entry->data;
+
+		l_dbus_message_builder_enter_dict(builder, "sv");
+		l_dbus_message_builder_append_basic(builder, 's', sd->uuid);
+		l_dbus_message_builder_enter_variant(builder, "ay");
+		l_dbus_message_builder_enter_array(builder, "y");
+
+		for (i = 0; i < sd->data.len; i++)
+			l_dbus_message_builder_append_basic(builder, 'y',
+							&(sd->data.data[i]));
+
+		l_dbus_message_builder_leave_array(builder);
+		l_dbus_message_builder_leave_variant(builder);
+		l_dbus_message_builder_leave_dict(builder);
+	}
+	l_dbus_message_builder_leave_array(builder);
+
+	return true;
+}
+
+static bool ad_manufacturerdata_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	const struct l_queue_entry *entry;
+	size_t i;
+
+	if (l_queue_isempty(ad.manufacturers))
+		return false;
+
+	l_dbus_message_builder_enter_array(builder, "{qv}");
+
+	for (entry = l_queue_get_entries(ad.manufacturers); entry;
+							entry = entry->next) {
+		struct manufacturer_data *md = entry->data;
+
+		l_dbus_message_builder_enter_dict(builder, "qv");
+		l_dbus_message_builder_append_basic(builder, 'q', &md->id);
+		l_dbus_message_builder_enter_variant(builder, "ay");
+		l_dbus_message_builder_enter_array(builder, "y");
+
+		for (i = 0; i < md->data.len; i++)
+			l_dbus_message_builder_append_basic(builder, 'y',
+							&(md->data.data[i]));
+
+		l_dbus_message_builder_leave_array(builder);
+		l_dbus_message_builder_leave_variant(builder);
+		l_dbus_message_builder_leave_dict(builder);
+	}
+	l_dbus_message_builder_leave_array(builder);
+
+	return true;
+}
+
+static bool ad_includes_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	l_dbus_message_builder_enter_array(builder, "s");
+
+	if (!(ad.tx_power || ad.name || ad.appearance))
+		return false;
+
+	if (ad.tx_power) {
+		const char *str = "tx-power";
+
+		l_dbus_message_builder_append_basic(builder, 's', &str);
+	}
+
+	if (ad.name) {
+		const char *str = "local-name";
+
+		l_dbus_message_builder_append_basic(builder, 's', &str);
+	}
+
+	if (ad.appearance) {
+		const char *str = "appearance";
+
+		l_dbus_message_builder_append_basic(builder, 's', &str);
+	}
+
+	l_dbus_message_builder_leave_array(builder);
+
+	return true;
+}
+
+static bool ad_localname_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	if (!ad.local_name)
+		return false;
+
+	l_dbus_message_builder_append_basic(builder, 's', ad.local_name);
+
+	return true;
+}
+
+static bool ad_appearance_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	if (!ad.local_appearance)
+		return false;
+
+	l_dbus_message_builder_append_basic(builder, 'q', &ad.local_appearance);
+
+	return true;
+}
+
+static bool ad_duration_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	if (!ad.duration)
+		return false;
+
+	l_dbus_message_builder_append_basic(builder, 'q', &ad.duration);
+
+	return true;
+}
+
+static bool ad_timeout_getter(struct l_dbus *dbus,
+					struct l_dbus_message *message,
+					struct l_dbus_message_builder *builder,
+					void *user_data)
+{
+	if (!ad.timeout)
+		return false;
+
+	l_dbus_message_builder_append_basic(builder, 'q', &ad.timeout);
+
+	return true;
+}
+
+static void setup_ad_interface(struct l_dbus_interface *interface)
+{
+	l_dbus_interface_method(interface, "Release",
+						L_DBUS_METHOD_FLAG_NOREPLY,
+						ad_release_call, "", "");
+	l_dbus_interface_property(interface, "Type", 0, "s", ad_type_getter,
+									NULL);
+	l_dbus_interface_property(interface, "ServiceUUIDs", 0, "as",
+						ad_serviceuuids_getter, NULL);
+	l_dbus_interface_property(interface, "ServiceData", 0, "a{sv}",
+						ad_servicedata_getter, NULL);
+	l_dbus_interface_property(interface, "ManufacturerServiceData", 0,
+					"a{qv}", ad_manufacturerdata_getter,
+					NULL);
+	l_dbus_interface_property(interface, "Includes", 0, "as",
+						ad_includes_getter, NULL);
+	l_dbus_interface_property(interface, "LocalName", 0, "s",
+						ad_localname_getter, NULL);
+	l_dbus_interface_property(interface, "Appearance", 0, "q",
+						ad_appearance_getter, NULL);
+	l_dbus_interface_property(interface, "Duration", 0, "q",
+						ad_duration_getter, NULL);
+	l_dbus_interface_property(interface, "Timeout", 0, "q",
+						ad_timeout_getter, NULL);
+}
+
+static void start_advertising_reply(struct l_dbus_proxy *proxy,
+						struct l_dbus_message *result,
+						void *user_data)
+{
+	const char *path = l_dbus_proxy_get_path(proxy);
+	struct btp_adapter *adapter = find_adapter_by_path(path);
+	uint32_t new_settings;
+
+	if (!adapter) {
+		btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
+								BTP_ERROR_FAIL);
+		return;
+	}
+
+	if (l_dbus_message_is_error(result)) {
+		const char *name, *desc;
+
+		l_dbus_message_get_error(result, &name, &desc);
+		l_error("Failed to start advertising (%s), %s", name, desc);
+
+		btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
+								BTP_ERROR_FAIL);
+		return;
+	}
+
+	new_settings = adapter->current_settings;
+	new_settings |= BTP_GAP_SETTING_ADVERTISING;
+	update_current_settings(adapter, new_settings);
+
+	ad.registered = true;
+
+	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_ADVERTISING,
+					adapter->index, sizeof(new_settings),
+					&new_settings);
+}
+
+static void create_advertising_data(uint8_t adv_data_len, const uint8_t *data)
+{
+	const uint8_t *ad_data;
+	uint8_t ad_type, ad_len;
+	uint8_t remaining_data_len = adv_data_len;
+
+	while (remaining_data_len) {
+		ad_type = data[adv_data_len - remaining_data_len];
+		ad_len = data[adv_data_len - remaining_data_len + 1];
+		ad_data = &data[adv_data_len - remaining_data_len + 2];
+
+		switch (ad_type) {
+		case AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST:
+		{
+			char *uuid = dupuuid2str(ad_data, 16);
+			l_queue_push_tail(ad.uuids, uuid);
+
+			break;
+		}
+		case AD_TYPE_SHORT_NAME:
+			ad.local_name = malloc(ad_len + 1);
+			memcpy(ad.local_name, ad_data, ad_len);
+			ad.local_name[ad_len] = '\0';
+
+			break;
+		case AD_TYPE_SERVICE_DATA_UUID16:
+		{
+			struct service_data *sd;
+
+			sd = l_new(struct service_data, 1);
+			sd->uuid = dupuuid2str(ad_data, 16);
+			sd->data.len = ad_len - 2;
+			memcpy(sd->data.data, ad_data + 2, sd->data.len);
+
+			l_queue_push_tail(ad.services, sd);
+
+			break;
+		}
+		case AD_TYPE_APPEARANCE:
+			memcpy(&ad.local_appearance, ad_data, ad_len);
+
+			break;
+		case AD_TYPE_MANUFACTURER_DATA:
+		{
+			struct manufacturer_data *md;
+
+			md = l_new(struct manufacturer_data, 1);
+			/* The first 2 octets contain the Company Identifier
+			 * Code followed by additional manufacturer specific
+			 * data.
+			 */
+			memcpy(&md->id, ad_data, 2);
+			md->data.len = ad_len - 2;
+			memcpy(md->data.data, ad_data + 2, md->data.len);
+
+			l_queue_push_tail(ad.manufacturers, md);
+
+			break;
+		}
+		default:
+			l_info("Unsupported advertising data type");
+
+			break;
+		}
+		/* Advertising entity data len + advertising entity header
+		 * (type, len)
+		 */
+		remaining_data_len -= ad_len + 2;
+	}
+}
+
+static void create_scan_response(uint8_t scan_rsp_len, const uint8_t *data)
+{
+	/* TODO */
+}
+
+static void start_advertising_setup(struct l_dbus_message *message,
+							void *user_data)
+{
+	struct l_dbus_message_builder *builder;
+
+	builder = l_dbus_message_builder_new(message);
+	l_dbus_message_builder_append_basic(builder, 'o', AD_PATH);
+	l_dbus_message_builder_enter_array(builder, "{sv}");
+	l_dbus_message_builder_enter_dict(builder, "sv");
+	l_dbus_message_builder_leave_dict(builder);
+	l_dbus_message_builder_leave_array(builder);
+	l_dbus_message_builder_finalize(builder);
+	l_dbus_message_builder_destroy(builder);
+}
+
+static void btp_gap_start_advertising(uint8_t index, const void *param,
+					uint16_t length, void *user_data)
+{
+	struct btp_adapter *adapter = find_adapter_by_index(index);
+	const struct btp_gap_start_adv_cp *cp = param;
+	uint8_t status = BTP_ERROR_FAIL;
+	bool prop;
+
+	if (!adapter) {
+		status = BTP_ERROR_INVALID_INDEX;
+		goto failed;
+	}
+
+	/* Adapter needs to be powered to be able to remove devices */
+	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+							!prop || ad.registered)
+		goto failed;
+
+	if (!l_dbus_register_interface(dbus, AD_IFACE, setup_ad_interface, NULL,
+									false)) {
+		l_info("Unable to register ad interface");
+		goto failed;
+	}
+
+	if (!l_dbus_object_add_interface(dbus, AD_PATH, AD_IFACE, NULL)) {
+		l_info("Unable to instantiate ad interface");
+
+		if (!l_dbus_unregister_interface(dbus, AD_IFACE))
+			l_info("Unable to unregister ad interface");
+
+		goto failed;
+	}
+
+	if (!l_dbus_object_add_interface(dbus, AD_PATH,
+						L_DBUS_INTERFACE_PROPERTIES,
+						NULL)) {
+		l_info("Unable to instantiate the properties interface");
+
+		if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
+			l_info("Unable to remove ad instance");
+		if (!l_dbus_unregister_interface(dbus, AD_IFACE))
+			l_info("Unable to unregister ad interface");
+
+		goto failed;
+	}
+
+	ad.uuids = l_queue_new();
+	ad.services = l_queue_new();
+	ad.manufacturers = l_queue_new();
+
+	if (adapter->current_settings & BTP_GAP_SETTING_CONNECTABLE)
+		ad.type = l_strdup("peripheral");
+	else
+		ad.type = l_strdup("broadcast");
+
+	if (cp->adv_data_len > 0)
+		create_advertising_data(cp->adv_data_len, cp->data);
+	if (cp->scan_rsp_len > 0)
+		create_scan_response(cp->scan_rsp_len,
+						cp->data + cp->scan_rsp_len);
+
+	if (!l_dbus_proxy_method_call(adapter->ad_proxy,
+							"RegisterAdvertisement",
+							start_advertising_setup,
+							start_advertising_reply,
+							NULL, NULL)) {
+		if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
+			l_info("Unable to remove ad instance");
+		if (!l_dbus_unregister_interface(dbus, AD_IFACE))
+			l_info("Unable to unregister ad interface");
+
+		goto failed;
+	}
+
+	return;
+
+failed:
+	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
+static void stop_advertising_reply(struct l_dbus_proxy *proxy,
+						struct l_dbus_message *result,
+						void *user_data)
+{
+	const char *path = l_dbus_proxy_get_path(proxy);
+	struct btp_adapter *adapter = find_adapter_by_path(path);
+	uint32_t new_settings;
+
+	if (!adapter)
+		return;
+
+	if (l_dbus_message_is_error(result)) {
+		const char *name;
+
+		l_dbus_message_get_error(result, &name, NULL);
+
+		l_error("Failed to stop advertising %s (%s)",
+					l_dbus_proxy_get_path(proxy), name);
+		return;
+	}
+
+	if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
+		l_info("Unable to remove ad instance");
+	if (!l_dbus_object_remove_interface(dbus, AD_PATH,
+						L_DBUS_INTERFACE_PROPERTIES))
+		l_info("Unable to remove propety instance");
+	if (!l_dbus_unregister_interface(dbus, AD_IFACE))
+		l_info("Unable to unregister ad interface");
+
+	new_settings = adapter->current_settings;
+	new_settings &= ~BTP_GAP_SETTING_ADVERTISING;
+	update_current_settings(adapter, new_settings);
+
+	ad_cleanup();
+
+	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_STOP_ADVERTISING,
+					adapter->index, sizeof(new_settings),
+					&new_settings);
+}
+
+static void btp_gap_stop_advertising(uint8_t index, const void *param,
+					uint16_t length, void *user_data)
+{
+	struct btp_adapter *adapter = find_adapter_by_index(index);
+	uint8_t status = BTP_ERROR_FAIL;
+	bool prop;
+
+	if (!adapter) {
+		status = BTP_ERROR_INVALID_INDEX;
+		goto failed;
+	}
+
+	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+							!prop || !ad.registered)
+		goto failed;
+
+	if (adapter->ad_proxy) {
+		if (!l_dbus_proxy_method_call(adapter->ad_proxy,
+						"UnregisterAdvertisement",
+						unreg_advertising_setup,
+						stop_advertising_reply,
+						NULL, NULL)) {
+			status = BTP_ERROR_FAIL;
+			goto failed;
+		}
+	}
+
+	return;
+
+failed:
+	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
 static void start_discovery_reply(struct l_dbus_proxy *proxy,
 						struct l_dbus_message *result,
 						void *user_data)
@@ -728,6 +1365,12 @@ static void register_gap_service(void)
 	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_BONDABLE,
 					btp_gap_set_bondable, NULL, NULL);
 
+	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_ADVERTISING,
+					btp_gap_start_advertising, NULL, NULL);
+
+	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_STOP_ADVERTISING,
+					btp_gap_stop_advertising, NULL, NULL);
+
 	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_DISCOVERY,
 					btp_gap_start_discovery, NULL, NULL);
 
@@ -1124,6 +1767,12 @@ static void client_ready(struct l_dbus_client *client, void *user_data)
 					BTP_INDEX_NON_CONTROLLER, 0, NULL);
 }
 
+static void ready_callback(void *user_data)
+{
+	if (!l_dbus_object_manager_enable(dbus))
+		l_info("Unable to register the ObjectManager");
+}
+
 static void usage(void)
 {
 	l_info("btpclient - Bluetooth tester");
@@ -1148,7 +1797,6 @@ int main(int argc, char *argv[])
 {
 	struct l_dbus_client *client;
 	struct l_signal *signal;
-	struct l_dbus *dbus;
 	sigset_t mask;
 	int opt;
 
@@ -1192,6 +1840,7 @@ int main(int argc, char *argv[])
 	signal = l_signal_create(&mask, signal_handler, NULL, NULL);
 
 	dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS);
+	l_dbus_set_ready_handler(dbus, ready_callback, NULL, NULL);
 	client = l_dbus_client_new(dbus, "org.bluez", "/org/bluez");
 
 	l_dbus_client_set_connect_handler(client, client_connected, NULL, NULL);
-- 
2.13.6


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

* [PATCH BlueZ v2 3/4] tools/btpclient: Add connect, disconnect commands
  2018-01-12 14:10 [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Grzegorz Kolodziejczyk
  2018-01-12 14:10 ` [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands Grzegorz Kolodziejczyk
@ 2018-01-12 14:10 ` Grzegorz Kolodziejczyk
  2018-01-12 14:10 ` [PATCH BlueZ v2 4/4] tools/btpclient: Add connected, disconnected event Grzegorz Kolodziejczyk
  2018-01-15 13:50 ` [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Szymon Janc
  3 siblings, 0 replies; 7+ messages in thread
From: Grzegorz Kolodziejczyk @ 2018-01-12 14:10 UTC (permalink / raw)
  To: linux-bluetooth

This patch adds start and stop connect, disconnect commands for btp
client.
---
 tools/btpclient.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 175 insertions(+)

diff --git a/tools/btpclient.c b/tools/btpclient.c
index 3fb94b7f9..7492872c0 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -104,6 +104,13 @@ static bool str2addr(const char *str, uint8_t *addr)
 				&addr[3], &addr[2], &addr[1], &addr[0]) == 6;
 }
 
+static bool addr2str(const uint8_t *addr, char *str)
+{
+	return snprintf(str, 18, "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX",
+			addr[5], addr[4], addr[3], addr[2], addr[1], addr[0])
+			== 17;
+}
+
 static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
 {
 	switch (len) {
@@ -121,6 +128,17 @@ static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
 	}
 }
 
+static bool match_dev_addr_type(const char *addr_type_str, uint8_t addr_type)
+{
+	if (addr_type == BTP_GAP_ADDR_PUBLIC && strcmp(addr_type_str, "public"))
+		return false;
+
+	if (addr_type == BTP_GAP_ADDR_RANDOM && strcmp(addr_type_str, "random"))
+		return false;
+
+	return true;
+}
+
 static struct btp_adapter *find_adapter_by_proxy(struct l_dbus_proxy *proxy)
 {
 	const struct l_queue_entry *entry;
@@ -166,6 +184,34 @@ static struct btp_adapter *find_adapter_by_path(const char *path)
 	return NULL;
 }
 
+static struct btp_device *find_device_by_address(struct btp_adapter *adapter,
+							const uint8_t *addr,
+							uint8_t addr_type)
+{
+	const struct l_queue_entry *entry;
+	const char *str;
+	char addr_str[18];
+
+	if (!addr2str(addr, addr_str))
+		return NULL;
+
+	for (entry = l_queue_get_entries(adapter->devices); entry;
+							entry = entry->next) {
+		struct btp_device *device = entry->data;
+
+		l_dbus_proxy_get_property(device->proxy, "Address", "s", &str);
+		if (strcmp(str, addr_str))
+			continue;
+
+		l_dbus_proxy_get_property(device->proxy, "AddressType", "s",
+									&str);
+		if (match_dev_addr_type(str, addr_type))
+			return device;
+	}
+
+	return NULL;
+}
+
 static void btp_gap_read_commands(uint8_t index, const void *param,
 					uint16_t length, void *user_data)
 {
@@ -189,6 +235,8 @@ static void btp_gap_read_commands(uint8_t index, const void *param,
 	commands |= (1 << BTP_OP_GAP_STOP_ADVERTISING);
 	commands |= (1 << BTP_OP_GAP_START_DISCOVERY);
 	commands |= (1 << BTP_OP_GAP_STOP_DISCOVERY);
+	commands |= (1 << BTP_OP_GAP_CONNECT);
+	commands |= (1 << BTP_OP_GAP_DISCONNECT);
 
 	commands = L_CPU_TO_LE16(commands);
 
@@ -1304,6 +1352,127 @@ static void btp_gap_stop_discovery(uint8_t index, const void *param,
 					stop_discovery_reply, NULL, NULL);
 }
 
+static void connect_reply(struct l_dbus_proxy *proxy,
+				struct l_dbus_message *result, void *user_data)
+{
+	uint8_t adapter_index = L_PTR_TO_UINT(user_data);
+	struct btp_adapter *adapter = find_adapter_by_index(adapter_index);
+
+	if (!adapter) {
+		btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
+								BTP_ERROR_FAIL);
+		return;
+	}
+
+	if (l_dbus_message_is_error(result)) {
+		const char *name, *desc;
+
+		l_dbus_message_get_error(result, &name, &desc);
+		l_error("Failed to connect (%s), %s", name, desc);
+
+		btp_send_error(btp, BTP_GAP_SERVICE, adapter_index,
+								BTP_ERROR_FAIL);
+		return;
+	}
+
+	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_CONNECT, adapter_index, 0,
+									NULL);
+}
+
+static void btp_gap_connect(uint8_t index, const void *param, uint16_t length,
+								void *user_data)
+{
+	struct btp_adapter *adapter = find_adapter_by_index(index);
+	const struct btp_gap_connect_cp *cp = param;
+	struct btp_device *device;
+	bool prop;
+	uint8_t status = BTP_ERROR_FAIL;
+
+	if (!adapter) {
+		status = BTP_ERROR_INVALID_INDEX;
+		goto failed;
+	}
+
+	/* Adapter needs to be powered to be able to connect */
+	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+									!prop)
+		goto failed;
+
+	device = find_device_by_address(adapter, cp->address, cp->address_type);
+
+	if (!device)
+		goto failed;
+
+	l_dbus_proxy_method_call(device->proxy, "Connect", NULL, connect_reply,
+					L_UINT_TO_PTR(adapter->index), NULL);
+
+	return;
+
+failed:
+	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
+static void disconnect_reply(struct l_dbus_proxy *proxy,
+				struct l_dbus_message *result, void *user_data)
+{
+	uint8_t adapter_index = L_PTR_TO_UINT(user_data);
+	struct btp_adapter *adapter = find_adapter_by_index(adapter_index);
+
+	if (!adapter) {
+		btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
+								BTP_ERROR_FAIL);
+		return;
+	}
+
+	if (l_dbus_message_is_error(result)) {
+		const char *name, *desc;
+
+		l_dbus_message_get_error(result, &name, &desc);
+		l_error("Failed to disconnect (%s), %s", name, desc);
+
+		btp_send_error(btp, BTP_GAP_SERVICE, adapter_index,
+								BTP_ERROR_FAIL);
+		return;
+	}
+
+	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_DISCONNECT, adapter_index, 0,
+									NULL);
+}
+
+static void btp_gap_disconnect(uint8_t index, const void *param,
+					uint16_t length, void *user_data)
+{
+	struct btp_adapter *adapter = find_adapter_by_index(index);
+	const struct btp_gap_disconnect_cp *cp = param;
+	uint8_t status = BTP_ERROR_FAIL;
+	struct btp_device *device;
+	bool prop;
+
+	if (!adapter) {
+		status = BTP_ERROR_INVALID_INDEX;
+		goto failed;
+	}
+
+	/* Adapter needs to be powered to be able to connect */
+	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+									!prop)
+		goto failed;
+
+	device = find_device_by_address(adapter, cp->address, cp->address_type);
+
+	if (!device)
+		goto failed;
+
+	l_dbus_proxy_method_call(device->proxy, "Disconnect", NULL,
+					disconnect_reply,
+					L_UINT_TO_PTR(adapter->index), NULL);
+
+	return;
+
+failed:
+	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
 static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
 {
 	struct btp_device_found_ev ev;
@@ -1376,6 +1545,12 @@ static void register_gap_service(void)
 
 	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_STOP_DISCOVERY,
 					btp_gap_stop_discovery, NULL, NULL);
+
+	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_CONNECT, btp_gap_connect,
+								NULL, NULL);
+
+	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_DISCONNECT,
+						btp_gap_disconnect, NULL, NULL);
 }
 
 static void btp_core_read_commands(uint8_t index, const void *param,
-- 
2.13.6


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

* [PATCH BlueZ v2 4/4] tools/btpclient: Add connected, disconnected event
  2018-01-12 14:10 [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Grzegorz Kolodziejczyk
  2018-01-12 14:10 ` [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands Grzegorz Kolodziejczyk
  2018-01-12 14:10 ` [PATCH BlueZ v2 3/4] tools/btpclient: Add connect, disconnect commands Grzegorz Kolodziejczyk
@ 2018-01-12 14:10 ` Grzegorz Kolodziejczyk
  2018-01-15 13:50 ` [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Szymon Janc
  3 siblings, 0 replies; 7+ messages in thread
From: Grzegorz Kolodziejczyk @ 2018-01-12 14:10 UTC (permalink / raw)
  To: linux-bluetooth

This patch adds conntected, disconnected events for btp client.
---
 tools/btpclient.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/tools/btpclient.c b/tools/btpclient.c
index 7492872c0..c0ecb3f06 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -212,6 +212,26 @@ static struct btp_device *find_device_by_address(struct btp_adapter *adapter,
 	return NULL;
 }
 
+static bool match_proxies(const void *proxy_a, const void *proxy_b)
+{
+	return proxy_a == proxy_b;
+}
+
+static struct btp_adapter *find_adapter_by_dev_proxy(struct l_dbus_proxy *proxy)
+{
+	const struct l_queue_entry *entry;
+
+	for (entry = l_queue_get_entries(adapters); entry;
+							entry = entry->next) {
+		struct btp_adapter *adapter = entry->data;
+
+		if (l_queue_find(adapter->devices, match_proxies, proxy))
+			return adapter;
+	}
+
+	return NULL;
+}
+
 static void btp_gap_read_commands(uint8_t index, const void *param,
 					uint16_t length, void *user_data)
 {
@@ -1507,6 +1527,49 @@ static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
 						sizeof(ev) + ev.eir_len, &ev);
 }
 
+static void btp_gap_device_connection_ev(struct l_dbus_proxy *proxy,
+								bool connected)
+{
+	struct btp_adapter *adapter;
+	const char *str_addr, *str_addr_type;
+	uint8_t address_type;
+
+
+	adapter = find_adapter_by_dev_proxy(proxy);
+
+	if (!adapter)
+		return;
+
+	if (!l_dbus_proxy_get_property(proxy, "Address", "s", &str_addr))
+		return;
+
+
+	if (!l_dbus_proxy_get_property(proxy, "AddressType", "s",
+								&str_addr_type))
+		return;
+
+	address_type = strcmp(str_addr_type, "public") ? BTP_GAP_ADDR_RANDOM :
+							BTP_GAP_ADDR_PUBLIC;
+
+	if (connected) {
+		struct btp_gap_device_connected_ev ev;
+
+		str2addr(str_addr, ev.address);
+		ev.address_type = address_type;
+
+		btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_DEVICE_CONNECTED,
+					adapter->index, sizeof(ev), &ev);
+	} else {
+		struct btp_gap_device_disconnected_ev ev;
+
+		str2addr(str_addr, ev.address);
+		ev.address_type = address_type;
+
+		btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_DEVICE_DISCONNECTED,
+					adapter->index, sizeof(ev), &ev);
+	}
+}
+
 static void register_gap_service(void)
 {
 	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_READ_SUPPORTED_COMMANDS,
@@ -1910,6 +1973,13 @@ static void property_changed(struct l_dbus_proxy *proxy, const char *name,
 				return;
 
 			btp_gap_device_found_ev(proxy);
+		} else if (!strcmp(name, "Connected")) {
+			bool prop;
+
+			if (!l_dbus_message_get_arguments(msg, "b", &prop))
+				return;
+
+			btp_gap_device_connection_ev(proxy, prop);
 		}
 	}
 }
-- 
2.13.6


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

* Re: [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands
  2018-01-12 14:10 ` [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands Grzegorz Kolodziejczyk
@ 2018-01-15 13:21   ` Szymon Janc
  2018-01-16  9:26     ` Grzegorz Kołodziejczyk
  0 siblings, 1 reply; 7+ messages in thread
From: Szymon Janc @ 2018-01-15 13:21 UTC (permalink / raw)
  To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth

Hi Grzegorz,

On Friday, 12 January 2018 15:10:10 CET Grzegorz Kolodziejczyk wrote:
> This patch adds start and stop advertising commands for btp client.
> ---
>  tools/btpclient.c | 651
> +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 650
> insertions(+), 1 deletion(-)
> 
> diff --git a/tools/btpclient.c b/tools/btpclient.c
> index a8a65fd51..3fb94b7f9 100644
> --- a/tools/btpclient.c
> +++ b/tools/btpclient.c
> @@ -34,6 +34,19 @@
> 
>  #include "src/shared/btp.h"
> 
> +#define AD_PATH "/org/bluez/advertising"
> +#define AD_IFACE "org.bluez.LEAdvertisement1"
> +
> +/* List of assigned numbers for advetising data and scan response */
> +#define AD_TYPE_FLAGS				0x01
> +#define AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST	0x02
> +#define AD_TYPE_SHORT_NAME			0x08
> +#define AD_TYPE_SERVICE_DATA_UUID16		0x16
> +#define AD_TYPE_APPEARANCE			0x19
> +#define AD_TYPE_MANUFACTURER_DATA		0xff
> +
> +static struct l_dbus *dbus;
> +
>  struct btp_adapter {
>  	struct l_dbus_proxy *proxy;
>  	struct l_dbus_proxy *ad_proxy;
> @@ -53,12 +66,61 @@ static struct btp *btp;
> 
>  static bool gap_service_registered;
> 
> +struct ad_data {
> +	uint8_t data[25];
> +	uint8_t len;
> +};
> +
> +struct service_data {
> +	char *uuid;
> +	struct ad_data data;
> +};
> +
> +struct manufacturer_data {
> +	uint16_t id;
> +	struct ad_data data;
> +};
> +
> +static struct ad {
> +	bool registered;
> +	char *type;
> +	char *local_name;
> +	uint16_t local_appearance;
> +	uint16_t duration;
> +	uint16_t timeout;
> +	struct l_queue *uuids;
> +	struct l_queue *services;
> +	struct l_queue *manufacturers;
> +	bool tx_power;
> +	bool name;
> +	bool appearance;
> +} ad = {
> +	.local_appearance = UINT16_MAX,
> +};
> +
>  static bool str2addr(const char *str, uint8_t *addr)
>  {
>  	return sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[5], &addr[4],
>  				&addr[3], &addr[2], &addr[1], &addr[0]) == 6;
>  }
> 
> +static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
> +{
> +	switch (len) {
> +	case 16:
> +		return l_strdup_printf("%hhx%hhx", uuid[0], uuid[1]);
> +	case 128:
> +		return l_strdup_printf("%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx"
> +					"%hhx%hhx%hhx%hhx%hhx%hhx%hhx", uuid[0],
> +					uuid[1], uuid[2], uuid[3], uuid[4],
> +					uuid[5], uuid[6], uuid[6], uuid[8],
> +					uuid[7], uuid[10], uuid[11], uuid[12],
> +					uuid[13], uuid[14], uuid[15]);
> +	default:
> +		return NULL;
> +	}
> +}
> +
>  static struct btp_adapter *find_adapter_by_proxy(struct l_dbus_proxy
> *proxy) {
>  	const struct l_queue_entry *entry;
> @@ -123,6 +185,8 @@ static void btp_gap_read_commands(uint8_t index, const
> void *param, commands |= (1 << BTP_OP_GAP_SET_CONNECTABLE);
>  	commands |= (1 << BTP_OP_GAP_SET_DISCOVERABLE);
>  	commands |= (1 << BTP_OP_GAP_SET_BONDABLE);
> +	commands |= (1 << BTP_OP_GAP_START_ADVERTISING);
> +	commands |= (1 << BTP_OP_GAP_STOP_ADVERTISING);
>  	commands |= (1 << BTP_OP_GAP_START_DISCOVERY);
>  	commands |= (1 << BTP_OP_GAP_STOP_DISCOVERY);
> 
> @@ -234,6 +298,46 @@ static void remove_device_reply(struct l_dbus_proxy
> *proxy, l_queue_remove(adapter->devices, device);
>  }
> 
> +static void unreg_advertising_setup(struct l_dbus_message *message,
> +								void *user_data)
> +{
> +	struct l_dbus_message_builder *builder;
> +
> +	builder = l_dbus_message_builder_new(message);
> +	l_dbus_message_builder_append_basic(builder, 'o', AD_PATH);
> +	l_dbus_message_builder_finalize(builder);
> +	l_dbus_message_builder_destroy(builder);
> +}
> +
> +static void unreg_advertising_reply(struct l_dbus_proxy *proxy,
> +						struct l_dbus_message *result,
> +						void *user_data)
> +{
> +	const char *path = l_dbus_proxy_get_path(proxy);
> +	struct btp_adapter *adapter = find_adapter_by_path(path);
> +
> +	if (!adapter)
> +		return;
> +
> +	if (l_dbus_message_is_error(result)) {
> +		const char *name;
> +
> +		l_dbus_message_get_error(result, &name, NULL);
> +
> +		l_error("Failed to stop advertising %s (%s)",
> +					l_dbus_proxy_get_path(proxy), name);
> +		return;
> +	}
> +
> +	if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
> +		l_info("Unable to remove ad instance");
> +	if (!l_dbus_object_remove_interface(dbus, AD_PATH,
> +						L_DBUS_INTERFACE_PROPERTIES))
> +		l_info("Unable to remove propety instance");
> +	if (!l_dbus_unregister_interface(dbus, AD_IFACE))
> +		l_info("Unable to unregister ad interface");
> +}
> +
>  static void btp_gap_reset(uint8_t index, const void *param, uint16_t
> length, void *user_data)
>  {
> @@ -264,6 +368,16 @@ static void btp_gap_reset(uint8_t index, const void
> *param, uint16_t length, NULL);
>  	}
> 
> +	if (adapter->ad_proxy)
> +		if (!l_dbus_proxy_method_call(adapter->ad_proxy,
> +						"UnregisterAdvertisement",
> +						unreg_advertising_setup,
> +						unreg_advertising_reply,
> +						NULL, NULL)) {
> +			status = BTP_ERROR_FAIL;
> +			goto failed;
> +		}
> +
>  	/* TODO for we assume all went well */
>  	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
>  	return;
> @@ -449,6 +563,529 @@ failed:
>  	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>  }
> 
> +static void ad_cleanup_service(void *service)
> +{
> +	struct service_data *s = service;
> +
> +	l_free(s->uuid);
> +	l_free(s);
> +}
> +
> +static void ad_cleanup()

(void) is missing

> +{
> +	l_free(ad.local_name);
> +	l_queue_destroy(ad.uuids, l_free);
> +	l_queue_destroy(ad.services, ad_cleanup_service);
> +	l_queue_destroy(ad.manufacturers, l_free);

type free is missing here, and I'd also memset ad here.

> +}
> +
> +static struct l_dbus_message *ad_release_call(struct l_dbus *dbus,
> +						struct l_dbus_message *message,
> +						void *user_data)
> +{
> +	struct l_dbus_message *reply;
> +
> +	l_dbus_unregister_object(dbus, AD_PATH);
> +	l_dbus_unregister_interface(dbus, AD_IFACE);
> +
> +	reply = l_dbus_message_new_method_return(message);
> +	l_dbus_message_set_arguments(reply, "");
> +
> +	ad_cleanup();
> +
> +	return reply;
> +}
> +
> +static bool ad_type_getter(struct l_dbus *dbus, struct l_dbus_message
> *message, +				struct l_dbus_message_builder *builder,
> +				void *user_data)
> +{
> +	l_dbus_message_builder_append_basic(builder, 's', ad.type);
> +
> +	return true;
> +}
> +
> +static bool ad_serviceuuids_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	const struct l_queue_entry *entry;
> +
> +	if (l_queue_isempty(ad.uuids))
> +		return false;
> +
> +	l_dbus_message_builder_enter_array(builder, "s");
> +
> +	for (entry = l_queue_get_entries(ad.uuids); entry; entry = entry->next)
> +		l_dbus_message_builder_append_basic(builder, 's', entry->data);
> +
> +	l_dbus_message_builder_leave_array(builder);
> +
> +	return true;
> +}
> +
> +static bool ad_servicedata_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	const struct l_queue_entry *entry;
> +	size_t i;
> +
> +	if (l_queue_isempty(ad.services))
> +		return false;
> +
> +	l_dbus_message_builder_enter_array(builder, "{sv}");
> +
> +	for (entry = l_queue_get_entries(ad.services); entry;
> +							entry = entry->next) {
> +		struct service_data *sd = entry->data;
> +
> +		l_dbus_message_builder_enter_dict(builder, "sv");
> +		l_dbus_message_builder_append_basic(builder, 's', sd->uuid);
> +		l_dbus_message_builder_enter_variant(builder, "ay");
> +		l_dbus_message_builder_enter_array(builder, "y");
> +
> +		for (i = 0; i < sd->data.len; i++)
> +			l_dbus_message_builder_append_basic(builder, 'y',
> +							&(sd->data.data[i]));
> +
> +		l_dbus_message_builder_leave_array(builder);
> +		l_dbus_message_builder_leave_variant(builder);
> +		l_dbus_message_builder_leave_dict(builder);
> +	}
> +	l_dbus_message_builder_leave_array(builder);
> +
> +	return true;
> +}
> +
> +static bool ad_manufacturerdata_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	const struct l_queue_entry *entry;
> +	size_t i;
> +
> +	if (l_queue_isempty(ad.manufacturers))
> +		return false;
> +
> +	l_dbus_message_builder_enter_array(builder, "{qv}");
> +
> +	for (entry = l_queue_get_entries(ad.manufacturers); entry;
> +							entry = entry->next) {
> +		struct manufacturer_data *md = entry->data;
> +
> +		l_dbus_message_builder_enter_dict(builder, "qv");
> +		l_dbus_message_builder_append_basic(builder, 'q', &md->id);
> +		l_dbus_message_builder_enter_variant(builder, "ay");
> +		l_dbus_message_builder_enter_array(builder, "y");
> +
> +		for (i = 0; i < md->data.len; i++)
> +			l_dbus_message_builder_append_basic(builder, 'y',
> +							&(md->data.data[i]));
> +
> +		l_dbus_message_builder_leave_array(builder);
> +		l_dbus_message_builder_leave_variant(builder);
> +		l_dbus_message_builder_leave_dict(builder);
> +	}
> +	l_dbus_message_builder_leave_array(builder);
> +
> +	return true;
> +}
> +
> +static bool ad_includes_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	l_dbus_message_builder_enter_array(builder, "s");
> +
> +	if (!(ad.tx_power || ad.name || ad.appearance))
> +		return false;
> +
> +	if (ad.tx_power) {
> +		const char *str = "tx-power";
> +
> +		l_dbus_message_builder_append_basic(builder, 's', &str);
> +	}
> +
> +	if (ad.name) {
> +		const char *str = "local-name";
> +
> +		l_dbus_message_builder_append_basic(builder, 's', &str);
> +	}
> +
> +	if (ad.appearance) {
> +		const char *str = "appearance";
> +
> +		l_dbus_message_builder_append_basic(builder, 's', &str);
> +	}
> +
> +	l_dbus_message_builder_leave_array(builder);
> +
> +	return true;
> +}
> +
> +static bool ad_localname_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	if (!ad.local_name)
> +		return false;
> +
> +	l_dbus_message_builder_append_basic(builder, 's', ad.local_name);
> +
> +	return true;
> +}
> +
> +static bool ad_appearance_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	if (!ad.local_appearance)
> +		return false;
> +
> +	l_dbus_message_builder_append_basic(builder, 'q', &ad.local_appearance);
> +
> +	return true;
> +}
> +
> +static bool ad_duration_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	if (!ad.duration)
> +		return false;
> +
> +	l_dbus_message_builder_append_basic(builder, 'q', &ad.duration);
> +
> +	return true;
> +}
> +
> +static bool ad_timeout_getter(struct l_dbus *dbus,
> +					struct l_dbus_message *message,
> +					struct l_dbus_message_builder *builder,
> +					void *user_data)
> +{
> +	if (!ad.timeout)
> +		return false;
> +
> +	l_dbus_message_builder_append_basic(builder, 'q', &ad.timeout);
> +
> +	return true;
> +}
> +
> +static void setup_ad_interface(struct l_dbus_interface *interface)
> +{
> +	l_dbus_interface_method(interface, "Release",
> +						L_DBUS_METHOD_FLAG_NOREPLY,
> +						ad_release_call, "", "");
> +	l_dbus_interface_property(interface, "Type", 0, "s", ad_type_getter,
> +									NULL);
> +	l_dbus_interface_property(interface, "ServiceUUIDs", 0, "as",
> +						ad_serviceuuids_getter, NULL);
> +	l_dbus_interface_property(interface, "ServiceData", 0, "a{sv}",
> +						ad_servicedata_getter, NULL);
> +	l_dbus_interface_property(interface, "ManufacturerServiceData", 0,
> +					"a{qv}", ad_manufacturerdata_getter,
> +					NULL);
> +	l_dbus_interface_property(interface, "Includes", 0, "as",
> +						ad_includes_getter, NULL);
> +	l_dbus_interface_property(interface, "LocalName", 0, "s",
> +						ad_localname_getter, NULL);
> +	l_dbus_interface_property(interface, "Appearance", 0, "q",
> +						ad_appearance_getter, NULL);
> +	l_dbus_interface_property(interface, "Duration", 0, "q",
> +						ad_duration_getter, NULL);
> +	l_dbus_interface_property(interface, "Timeout", 0, "q",
> +						ad_timeout_getter, NULL);
> +}
> +
> +static void start_advertising_reply(struct l_dbus_proxy *proxy,
> +						struct l_dbus_message *result,
> +						void *user_data)
> +{
> +	const char *path = l_dbus_proxy_get_path(proxy);
> +	struct btp_adapter *adapter = find_adapter_by_path(path);
> +	uint32_t new_settings;
> +
> +	if (!adapter) {
> +		btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
> +								BTP_ERROR_FAIL);
> +		return;
> +	}
> +
> +	if (l_dbus_message_is_error(result)) {
> +		const char *name, *desc;
> +
> +		l_dbus_message_get_error(result, &name, &desc);
> +		l_error("Failed to start advertising (%s), %s", name, desc);
> +
> +		btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
> +								BTP_ERROR_FAIL);
> +		return;
> +	}
> +
> +	new_settings = adapter->current_settings;
> +	new_settings |= BTP_GAP_SETTING_ADVERTISING;
> +	update_current_settings(adapter, new_settings);
> +
> +	ad.registered = true;
> +
> +	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_ADVERTISING,
> +					adapter->index, sizeof(new_settings),
> +					&new_settings);
> +}
> +
> +static void create_advertising_data(uint8_t adv_data_len, const uint8_t
> *data) +{
> +	const uint8_t *ad_data;
> +	uint8_t ad_type, ad_len;
> +	uint8_t remaining_data_len = adv_data_len;
> +
> +	while (remaining_data_len) {
> +		ad_type = data[adv_data_len - remaining_data_len];
> +		ad_len = data[adv_data_len - remaining_data_len + 1];
> +		ad_data = &data[adv_data_len - remaining_data_len + 2];
> +
> +		switch (ad_type) {
> +		case AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST:
> +		{
> +			char *uuid = dupuuid2str(ad_data, 16);

Empty line here.

> +			l_queue_push_tail(ad.uuids, uuid);
> +
> +			break;
> +		}
> +		case AD_TYPE_SHORT_NAME:
> +			ad.local_name = malloc(ad_len + 1);
> +			memcpy(ad.local_name, ad_data, ad_len);
> +			ad.local_name[ad_len] = '\0';
> +
> +			break;
> +		case AD_TYPE_SERVICE_DATA_UUID16:
> +		{
> +			struct service_data *sd;
> +
> +			sd = l_new(struct service_data, 1);
> +			sd->uuid = dupuuid2str(ad_data, 16);
> +			sd->data.len = ad_len - 2;
> +			memcpy(sd->data.data, ad_data + 2, sd->data.len);
> +
> +			l_queue_push_tail(ad.services, sd);
> +
> +			break;
> +		}
> +		case AD_TYPE_APPEARANCE:
> +			memcpy(&ad.local_appearance, ad_data, ad_len);
> +
> +			break;
> +		case AD_TYPE_MANUFACTURER_DATA:
> +		{
> +			struct manufacturer_data *md;
> +
> +			md = l_new(struct manufacturer_data, 1);
> +			/* The first 2 octets contain the Company Identifier
> +			 * Code followed by additional manufacturer specific
> +			 * data.
> +			 */
> +			memcpy(&md->id, ad_data, 2);
> +			md->data.len = ad_len - 2;
> +			memcpy(md->data.data, ad_data + 2, md->data.len);
> +
> +			l_queue_push_tail(ad.manufacturers, md);
> +
> +			break;
> +		}
> +		default:
> +			l_info("Unsupported advertising data type");
> +
> +			break;
> +		}
> +		/* Advertising entity data len + advertising entity header
> +		 * (type, len)
> +		 */
> +		remaining_data_len -= ad_len + 2;
> +	}
> +}
> +
> +static void create_scan_response(uint8_t scan_rsp_len, const uint8_t *data)
> +{
> +	/* TODO */
> +}
> +
> +static void start_advertising_setup(struct l_dbus_message *message,
> +							void *user_data)
> +{
> +	struct l_dbus_message_builder *builder;
> +
> +	builder = l_dbus_message_builder_new(message);
> +	l_dbus_message_builder_append_basic(builder, 'o', AD_PATH);
> +	l_dbus_message_builder_enter_array(builder, "{sv}");
> +	l_dbus_message_builder_enter_dict(builder, "sv");
> +	l_dbus_message_builder_leave_dict(builder);
> +	l_dbus_message_builder_leave_array(builder);
> +	l_dbus_message_builder_finalize(builder);
> +	l_dbus_message_builder_destroy(builder);
> +}
> +
> +static void btp_gap_start_advertising(uint8_t index, const void *param,
> +					uint16_t length, void *user_data)
> +{
> +	struct btp_adapter *adapter = find_adapter_by_index(index);
> +	const struct btp_gap_start_adv_cp *cp = param;
> +	uint8_t status = BTP_ERROR_FAIL;
> +	bool prop;
> +
> +	if (!adapter) {
> +		status = BTP_ERROR_INVALID_INDEX;
> +		goto failed;
> +	}
> +
> +	/* Adapter needs to be powered to be able to remove devices */
> +	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
> +							!prop || ad.registered)
> +		goto failed;
> +
> +	if (!l_dbus_register_interface(dbus, AD_IFACE, setup_ad_interface, NULL,
> +									false)) {
> +		l_info("Unable to register ad interface");
> +		goto failed;
> +	}
> +
> +	if (!l_dbus_object_add_interface(dbus, AD_PATH, AD_IFACE, NULL)) {
> +		l_info("Unable to instantiate ad interface");
> +
> +		if (!l_dbus_unregister_interface(dbus, AD_IFACE))
> +			l_info("Unable to unregister ad interface");
> +
> +		goto failed;
> +	}
> +
> +	if (!l_dbus_object_add_interface(dbus, AD_PATH,
> +						L_DBUS_INTERFACE_PROPERTIES,
> +						NULL)) {
> +		l_info("Unable to instantiate the properties interface");
> +
> +		if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
> +			l_info("Unable to remove ad instance");
> +		if (!l_dbus_unregister_interface(dbus, AD_IFACE))
> +			l_info("Unable to unregister ad interface");
> +
> +		goto failed;
> +	}
> +
> +	ad.uuids = l_queue_new();
> +	ad.services = l_queue_new();
> +	ad.manufacturers = l_queue_new();

Put this into helper eg ad_init(), also set appearance to default value.

> +
> +	if (adapter->current_settings & BTP_GAP_SETTING_CONNECTABLE)
> +		ad.type = l_strdup("peripheral");
> +	else
> +		ad.type = l_strdup("broadcast");

No need to dup those string, just assing them with constants.

> +
> +	if (cp->adv_data_len > 0)
> +		create_advertising_data(cp->adv_data_len, cp->data);
> +	if (cp->scan_rsp_len > 0)
> +		create_scan_response(cp->scan_rsp_len,
> +						cp->data + cp->scan_rsp_len);
> +
> +	if (!l_dbus_proxy_method_call(adapter->ad_proxy,
> +							"RegisterAdvertisement",
> +							start_advertising_setup,
> +							start_advertising_reply,
> +							NULL, NULL)) {
> +		if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
> +			l_info("Unable to remove ad instance");
> +		if (!l_dbus_unregister_interface(dbus, AD_IFACE))
> +			l_info("Unable to unregister ad interface");
> +
> +		goto failed;
> +	}
> +
> +	return;
> +
> +failed:
> +	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> +}
> +
> +static void stop_advertising_reply(struct l_dbus_proxy *proxy,
> +						struct l_dbus_message *result,
> +						void *user_data)
> +{
> +	const char *path = l_dbus_proxy_get_path(proxy);
> +	struct btp_adapter *adapter = find_adapter_by_path(path);
> +	uint32_t new_settings;
> +
> +	if (!adapter)
> +		return;
> +
> +	if (l_dbus_message_is_error(result)) {
> +		const char *name;
> +
> +		l_dbus_message_get_error(result, &name, NULL);
> +
> +		l_error("Failed to stop advertising %s (%s)",
> +					l_dbus_proxy_get_path(proxy), name);
> +		return;
> +	}
> +
> +	if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
> +		l_info("Unable to remove ad instance");
> +	if (!l_dbus_object_remove_interface(dbus, AD_PATH,
> +						L_DBUS_INTERFACE_PROPERTIES))
> +		l_info("Unable to remove propety instance");
> +	if (!l_dbus_unregister_interface(dbus, AD_IFACE))
> +		l_info("Unable to unregister ad interface");
> +
> +	new_settings = adapter->current_settings;
> +	new_settings &= ~BTP_GAP_SETTING_ADVERTISING;
> +	update_current_settings(adapter, new_settings);
> +
> +	ad_cleanup();
> +
> +	btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_STOP_ADVERTISING,
> +					adapter->index, sizeof(new_settings),
> +					&new_settings);
> +}
> +
> +static void btp_gap_stop_advertising(uint8_t index, const void *param,
> +					uint16_t length, void *user_data)
> +{
> +	struct btp_adapter *adapter = find_adapter_by_index(index);
> +	uint8_t status = BTP_ERROR_FAIL;
> +	bool prop;
> +
> +	if (!adapter) {
> +		status = BTP_ERROR_INVALID_INDEX;
> +		goto failed;
> +	}
> +
> +	if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
> +							!prop || !ad.registered)
> +		goto failed;
> +
> +	if (adapter->ad_proxy) {
> +		if (!l_dbus_proxy_method_call(adapter->ad_proxy,
> +						"UnregisterAdvertisement",
> +						unreg_advertising_setup,
> +						stop_advertising_reply,
> +						NULL, NULL)) {
> +			status = BTP_ERROR_FAIL;
> +			goto failed;
> +		}
> +	}
> +
> +	return;
> +
> +failed:
> +	btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> +}
> +
>  static void start_discovery_reply(struct l_dbus_proxy *proxy,
>  						struct l_dbus_message *result,
>  						void *user_data)
> @@ -728,6 +1365,12 @@ static void register_gap_service(void)
>  	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_BONDABLE,
>  					btp_gap_set_bondable, NULL, NULL);
> 
> +	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_ADVERTISING,
> +					btp_gap_start_advertising, NULL, NULL);
> +
> +	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_STOP_ADVERTISING,
> +					btp_gap_stop_advertising, NULL, NULL);
> +
>  	btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_DISCOVERY,
>  					btp_gap_start_discovery, NULL, NULL);
> 
> @@ -1124,6 +1767,12 @@ static void client_ready(struct l_dbus_client
> *client, void *user_data) BTP_INDEX_NON_CONTROLLER, 0, NULL);
>  }
> 
> +static void ready_callback(void *user_data)
> +{
> +	if (!l_dbus_object_manager_enable(dbus))
> +		l_info("Unable to register the ObjectManager");
> +}
> +
>  static void usage(void)
>  {
>  	l_info("btpclient - Bluetooth tester");
> @@ -1148,7 +1797,6 @@ int main(int argc, char *argv[])
>  {
>  	struct l_dbus_client *client;
>  	struct l_signal *signal;
> -	struct l_dbus *dbus;
>  	sigset_t mask;
>  	int opt;
> 
> @@ -1192,6 +1840,7 @@ int main(int argc, char *argv[])
>  	signal = l_signal_create(&mask, signal_handler, NULL, NULL);
> 
>  	dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS);
> +	l_dbus_set_ready_handler(dbus, ready_callback, NULL, NULL);
>  	client = l_dbus_client_new(dbus, "org.bluez", "/org/bluez");
> 
>  	l_dbus_client_set_connect_handler(client, client_connected, NULL, NULL);


-- 
pozdrawiam
Szymon Janc



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

* Re: [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag
  2018-01-12 14:10 [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Grzegorz Kolodziejczyk
                   ` (2 preceding siblings ...)
  2018-01-12 14:10 ` [PATCH BlueZ v2 4/4] tools/btpclient: Add connected, disconnected event Grzegorz Kolodziejczyk
@ 2018-01-15 13:50 ` Szymon Janc
  3 siblings, 0 replies; 7+ messages in thread
From: Szymon Janc @ 2018-01-15 13:50 UTC (permalink / raw)
  To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth

Hi Grzegorz,

On Friday, 12 January 2018 15:10:09 CET Grzegorz Kolodziejczyk wrote:
> Defined setting flag is presented as mask.
> ---
>  tools/btpclient.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/btpclient.c b/tools/btpclient.c
> index 806403f6a..a8a65fd51 100644
> --- a/tools/btpclient.c
> +++ b/tools/btpclient.c
> @@ -368,9 +368,9 @@ static void btp_gap_set_connectable(uint8_t index, const
> void *param, new_settings = adapter->current_settings;
> 
>  	if (cp->connectable)
> -		new_settings |= 1 << BTP_GAP_SETTING_CONNECTABLE;
> +		new_settings |= BTP_GAP_SETTING_CONNECTABLE;
>  	else
> -		new_settings &= ~(1 << BTP_GAP_SETTING_CONNECTABLE);
> +		new_settings &= ~BTP_GAP_SETTING_CONNECTABLE;
> 
>  	update_current_settings(adapter, new_settings);

This patch is now applied, thanks.

-- 
pozdrawiam
Szymon Janc



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

* Re: [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands
  2018-01-15 13:21   ` Szymon Janc
@ 2018-01-16  9:26     ` Grzegorz Kołodziejczyk
  0 siblings, 0 replies; 7+ messages in thread
From: Grzegorz Kołodziejczyk @ 2018-01-16  9:26 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth

Hi Szymon,

2018-01-15 14:21 GMT+01:00 Szymon Janc <szymon.janc@codecoup.pl>:
> Hi Grzegorz,
>
> On Friday, 12 January 2018 15:10:10 CET Grzegorz Kolodziejczyk wrote:
>> This patch adds start and stop advertising commands for btp client.
>> ---
>>  tools/btpclient.c | 651
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 6=
50
>> insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/btpclient.c b/tools/btpclient.c
>> index a8a65fd51..3fb94b7f9 100644
>> --- a/tools/btpclient.c
>> +++ b/tools/btpclient.c
>> @@ -34,6 +34,19 @@
>>
>>  #include "src/shared/btp.h"
>>
>> +#define AD_PATH "/org/bluez/advertising"
>> +#define AD_IFACE "org.bluez.LEAdvertisement1"
>> +
>> +/* List of assigned numbers for advetising data and scan response */
>> +#define AD_TYPE_FLAGS                                0x01
>> +#define AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST       0x02
>> +#define AD_TYPE_SHORT_NAME                   0x08
>> +#define AD_TYPE_SERVICE_DATA_UUID16          0x16
>> +#define AD_TYPE_APPEARANCE                   0x19
>> +#define AD_TYPE_MANUFACTURER_DATA            0xff
>> +
>> +static struct l_dbus *dbus;
>> +
>>  struct btp_adapter {
>>       struct l_dbus_proxy *proxy;
>>       struct l_dbus_proxy *ad_proxy;
>> @@ -53,12 +66,61 @@ static struct btp *btp;
>>
>>  static bool gap_service_registered;
>>
>> +struct ad_data {
>> +     uint8_t data[25];
>> +     uint8_t len;
>> +};
>> +
>> +struct service_data {
>> +     char *uuid;
>> +     struct ad_data data;
>> +};
>> +
>> +struct manufacturer_data {
>> +     uint16_t id;
>> +     struct ad_data data;
>> +};
>> +
>> +static struct ad {
>> +     bool registered;
>> +     char *type;
>> +     char *local_name;
>> +     uint16_t local_appearance;
>> +     uint16_t duration;
>> +     uint16_t timeout;
>> +     struct l_queue *uuids;
>> +     struct l_queue *services;
>> +     struct l_queue *manufacturers;
>> +     bool tx_power;
>> +     bool name;
>> +     bool appearance;
>> +} ad =3D {
>> +     .local_appearance =3D UINT16_MAX,
>> +};
>> +
>>  static bool str2addr(const char *str, uint8_t *addr)
>>  {
>>       return sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[5], &add=
r[4],
>>                               &addr[3], &addr[2], &addr[1], &addr[0]) =
=3D=3D 6;
>>  }
>>
>> +static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
>> +{
>> +     switch (len) {
>> +     case 16:
>> +             return l_strdup_printf("%hhx%hhx", uuid[0], uuid[1]);
>> +     case 128:
>> +             return l_strdup_printf("%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx%h=
hx"
>> +                                     "%hhx%hhx%hhx%hhx%hhx%hhx%hhx", uu=
id[0],
>> +                                     uuid[1], uuid[2], uuid[3], uuid[4]=
,
>> +                                     uuid[5], uuid[6], uuid[6], uuid[8]=
,
>> +                                     uuid[7], uuid[10], uuid[11], uuid[=
12],
>> +                                     uuid[13], uuid[14], uuid[15]);
>> +     default:
>> +             return NULL;
>> +     }
>> +}
>> +
>>  static struct btp_adapter *find_adapter_by_proxy(struct l_dbus_proxy
>> *proxy) {
>>       const struct l_queue_entry *entry;
>> @@ -123,6 +185,8 @@ static void btp_gap_read_commands(uint8_t index, con=
st
>> void *param, commands |=3D (1 << BTP_OP_GAP_SET_CONNECTABLE);
>>       commands |=3D (1 << BTP_OP_GAP_SET_DISCOVERABLE);
>>       commands |=3D (1 << BTP_OP_GAP_SET_BONDABLE);
>> +     commands |=3D (1 << BTP_OP_GAP_START_ADVERTISING);
>> +     commands |=3D (1 << BTP_OP_GAP_STOP_ADVERTISING);
>>       commands |=3D (1 << BTP_OP_GAP_START_DISCOVERY);
>>       commands |=3D (1 << BTP_OP_GAP_STOP_DISCOVERY);
>>
>> @@ -234,6 +298,46 @@ static void remove_device_reply(struct l_dbus_proxy
>> *proxy, l_queue_remove(adapter->devices, device);
>>  }
>>
>> +static void unreg_advertising_setup(struct l_dbus_message *message,
>> +                                                             void *user=
_data)
>> +{
>> +     struct l_dbus_message_builder *builder;
>> +
>> +     builder =3D l_dbus_message_builder_new(message);
>> +     l_dbus_message_builder_append_basic(builder, 'o', AD_PATH);
>> +     l_dbus_message_builder_finalize(builder);
>> +     l_dbus_message_builder_destroy(builder);
>> +}
>> +
>> +static void unreg_advertising_reply(struct l_dbus_proxy *proxy,
>> +                                             struct l_dbus_message *res=
ult,
>> +                                             void *user_data)
>> +{
>> +     const char *path =3D l_dbus_proxy_get_path(proxy);
>> +     struct btp_adapter *adapter =3D find_adapter_by_path(path);
>> +
>> +     if (!adapter)
>> +             return;
>> +
>> +     if (l_dbus_message_is_error(result)) {
>> +             const char *name;
>> +
>> +             l_dbus_message_get_error(result, &name, NULL);
>> +
>> +             l_error("Failed to stop advertising %s (%s)",
>> +                                     l_dbus_proxy_get_path(proxy), name=
);
>> +             return;
>> +     }
>> +
>> +     if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
>> +             l_info("Unable to remove ad instance");
>> +     if (!l_dbus_object_remove_interface(dbus, AD_PATH,
>> +                                             L_DBUS_INTERFACE_PROPERTIE=
S))
>> +             l_info("Unable to remove propety instance");
>> +     if (!l_dbus_unregister_interface(dbus, AD_IFACE))
>> +             l_info("Unable to unregister ad interface");
>> +}
>> +
>>  static void btp_gap_reset(uint8_t index, const void *param, uint16_t
>> length, void *user_data)
>>  {
>> @@ -264,6 +368,16 @@ static void btp_gap_reset(uint8_t index, const void
>> *param, uint16_t length, NULL);
>>       }
>>
>> +     if (adapter->ad_proxy)
>> +             if (!l_dbus_proxy_method_call(adapter->ad_proxy,
>> +                                             "UnregisterAdvertisement",
>> +                                             unreg_advertising_setup,
>> +                                             unreg_advertising_reply,
>> +                                             NULL, NULL)) {
>> +                     status =3D BTP_ERROR_FAIL;
>> +                     goto failed;
>> +             }
>> +
>>       /* TODO for we assume all went well */
>>       btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
>>       return;
>> @@ -449,6 +563,529 @@ failed:
>>       btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>>  }
>>
>> +static void ad_cleanup_service(void *service)
>> +{
>> +     struct service_data *s =3D service;
>> +
>> +     l_free(s->uuid);
>> +     l_free(s);
>> +}
>> +
>> +static void ad_cleanup()
>
> (void) is missing
>
>> +{
>> +     l_free(ad.local_name);
>> +     l_queue_destroy(ad.uuids, l_free);
>> +     l_queue_destroy(ad.services, ad_cleanup_service);
>> +     l_queue_destroy(ad.manufacturers, l_free);
>
> type free is missing here, and I'd also memset ad here.
Right, I'll fix it.
>
>> +}
>> +
>> +static struct l_dbus_message *ad_release_call(struct l_dbus *dbus,
>> +                                             struct l_dbus_message *mes=
sage,
>> +                                             void *user_data)
>> +{
>> +     struct l_dbus_message *reply;
>> +
>> +     l_dbus_unregister_object(dbus, AD_PATH);
>> +     l_dbus_unregister_interface(dbus, AD_IFACE);
>> +
>> +     reply =3D l_dbus_message_new_method_return(message);
>> +     l_dbus_message_set_arguments(reply, "");
>> +
>> +     ad_cleanup();
>> +
>> +     return reply;
>> +}
>> +
>> +static bool ad_type_getter(struct l_dbus *dbus, struct l_dbus_message
>> *message, +                           struct l_dbus_message_builder *bui=
lder,
>> +                             void *user_data)
>> +{
>> +     l_dbus_message_builder_append_basic(builder, 's', ad.type);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_serviceuuids_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     const struct l_queue_entry *entry;
>> +
>> +     if (l_queue_isempty(ad.uuids))
>> +             return false;
>> +
>> +     l_dbus_message_builder_enter_array(builder, "s");
>> +
>> +     for (entry =3D l_queue_get_entries(ad.uuids); entry; entry =3D ent=
ry->next)
>> +             l_dbus_message_builder_append_basic(builder, 's', entry->d=
ata);
>> +
>> +     l_dbus_message_builder_leave_array(builder);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_servicedata_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     const struct l_queue_entry *entry;
>> +     size_t i;
>> +
>> +     if (l_queue_isempty(ad.services))
>> +             return false;
>> +
>> +     l_dbus_message_builder_enter_array(builder, "{sv}");
>> +
>> +     for (entry =3D l_queue_get_entries(ad.services); entry;
>> +                                                     entry =3D entry->n=
ext) {
>> +             struct service_data *sd =3D entry->data;
>> +
>> +             l_dbus_message_builder_enter_dict(builder, "sv");
>> +             l_dbus_message_builder_append_basic(builder, 's', sd->uuid=
);
>> +             l_dbus_message_builder_enter_variant(builder, "ay");
>> +             l_dbus_message_builder_enter_array(builder, "y");
>> +
>> +             for (i =3D 0; i < sd->data.len; i++)
>> +                     l_dbus_message_builder_append_basic(builder, 'y',
>> +                                                     &(sd->data.data[i]=
));
>> +
>> +             l_dbus_message_builder_leave_array(builder);
>> +             l_dbus_message_builder_leave_variant(builder);
>> +             l_dbus_message_builder_leave_dict(builder);
>> +     }
>> +     l_dbus_message_builder_leave_array(builder);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_manufacturerdata_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     const struct l_queue_entry *entry;
>> +     size_t i;
>> +
>> +     if (l_queue_isempty(ad.manufacturers))
>> +             return false;
>> +
>> +     l_dbus_message_builder_enter_array(builder, "{qv}");
>> +
>> +     for (entry =3D l_queue_get_entries(ad.manufacturers); entry;
>> +                                                     entry =3D entry->n=
ext) {
>> +             struct manufacturer_data *md =3D entry->data;
>> +
>> +             l_dbus_message_builder_enter_dict(builder, "qv");
>> +             l_dbus_message_builder_append_basic(builder, 'q', &md->id)=
;
>> +             l_dbus_message_builder_enter_variant(builder, "ay");
>> +             l_dbus_message_builder_enter_array(builder, "y");
>> +
>> +             for (i =3D 0; i < md->data.len; i++)
>> +                     l_dbus_message_builder_append_basic(builder, 'y',
>> +                                                     &(md->data.data[i]=
));
>> +
>> +             l_dbus_message_builder_leave_array(builder);
>> +             l_dbus_message_builder_leave_variant(builder);
>> +             l_dbus_message_builder_leave_dict(builder);
>> +     }
>> +     l_dbus_message_builder_leave_array(builder);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_includes_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     l_dbus_message_builder_enter_array(builder, "s");
>> +
>> +     if (!(ad.tx_power || ad.name || ad.appearance))
>> +             return false;
>> +
>> +     if (ad.tx_power) {
>> +             const char *str =3D "tx-power";
>> +
>> +             l_dbus_message_builder_append_basic(builder, 's', &str);
>> +     }
>> +
>> +     if (ad.name) {
>> +             const char *str =3D "local-name";
>> +
>> +             l_dbus_message_builder_append_basic(builder, 's', &str);
>> +     }
>> +
>> +     if (ad.appearance) {
>> +             const char *str =3D "appearance";
>> +
>> +             l_dbus_message_builder_append_basic(builder, 's', &str);
>> +     }
>> +
>> +     l_dbus_message_builder_leave_array(builder);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_localname_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     if (!ad.local_name)
>> +             return false;
>> +
>> +     l_dbus_message_builder_append_basic(builder, 's', ad.local_name);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_appearance_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     if (!ad.local_appearance)
>> +             return false;
>> +
>> +     l_dbus_message_builder_append_basic(builder, 'q', &ad.local_appear=
ance);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_duration_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     if (!ad.duration)
>> +             return false;
>> +
>> +     l_dbus_message_builder_append_basic(builder, 'q', &ad.duration);
>> +
>> +     return true;
>> +}
>> +
>> +static bool ad_timeout_getter(struct l_dbus *dbus,
>> +                                     struct l_dbus_message *message,
>> +                                     struct l_dbus_message_builder *bui=
lder,
>> +                                     void *user_data)
>> +{
>> +     if (!ad.timeout)
>> +             return false;
>> +
>> +     l_dbus_message_builder_append_basic(builder, 'q', &ad.timeout);
>> +
>> +     return true;
>> +}
>> +
>> +static void setup_ad_interface(struct l_dbus_interface *interface)
>> +{
>> +     l_dbus_interface_method(interface, "Release",
>> +                                             L_DBUS_METHOD_FLAG_NOREPLY=
,
>> +                                             ad_release_call, "", "");
>> +     l_dbus_interface_property(interface, "Type", 0, "s", ad_type_gette=
r,
>> +                                                                     NU=
LL);
>> +     l_dbus_interface_property(interface, "ServiceUUIDs", 0, "as",
>> +                                             ad_serviceuuids_getter, NU=
LL);
>> +     l_dbus_interface_property(interface, "ServiceData", 0, "a{sv}",
>> +                                             ad_servicedata_getter, NUL=
L);
>> +     l_dbus_interface_property(interface, "ManufacturerServiceData", 0,
>> +                                     "a{qv}", ad_manufacturerdata_gette=
r,
>> +                                     NULL);
>> +     l_dbus_interface_property(interface, "Includes", 0, "as",
>> +                                             ad_includes_getter, NULL);
>> +     l_dbus_interface_property(interface, "LocalName", 0, "s",
>> +                                             ad_localname_getter, NULL)=
;
>> +     l_dbus_interface_property(interface, "Appearance", 0, "q",
>> +                                             ad_appearance_getter, NULL=
);
>> +     l_dbus_interface_property(interface, "Duration", 0, "q",
>> +                                             ad_duration_getter, NULL);
>> +     l_dbus_interface_property(interface, "Timeout", 0, "q",
>> +                                             ad_timeout_getter, NULL);
>> +}
>> +
>> +static void start_advertising_reply(struct l_dbus_proxy *proxy,
>> +                                             struct l_dbus_message *res=
ult,
>> +                                             void *user_data)
>> +{
>> +     const char *path =3D l_dbus_proxy_get_path(proxy);
>> +     struct btp_adapter *adapter =3D find_adapter_by_path(path);
>> +     uint32_t new_settings;
>> +
>> +     if (!adapter) {
>> +             btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROL=
LER,
>> +                                                             BTP_ERROR_=
FAIL);
>> +             return;
>> +     }
>> +
>> +     if (l_dbus_message_is_error(result)) {
>> +             const char *name, *desc;
>> +
>> +             l_dbus_message_get_error(result, &name, &desc);
>> +             l_error("Failed to start advertising (%s), %s", name, desc=
);
>> +
>> +             btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
>> +                                                             BTP_ERROR_=
FAIL);
>> +             return;
>> +     }
>> +
>> +     new_settings =3D adapter->current_settings;
>> +     new_settings |=3D BTP_GAP_SETTING_ADVERTISING;
>> +     update_current_settings(adapter, new_settings);
>> +
>> +     ad.registered =3D true;
>> +
>> +     btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_ADVERTISING,
>> +                                     adapter->index, sizeof(new_setting=
s),
>> +                                     &new_settings);
>> +}
>> +
>> +static void create_advertising_data(uint8_t adv_data_len, const uint8_t
>> *data) +{
>> +     const uint8_t *ad_data;
>> +     uint8_t ad_type, ad_len;
>> +     uint8_t remaining_data_len =3D adv_data_len;
>> +
>> +     while (remaining_data_len) {
>> +             ad_type =3D data[adv_data_len - remaining_data_len];
>> +             ad_len =3D data[adv_data_len - remaining_data_len + 1];
>> +             ad_data =3D &data[adv_data_len - remaining_data_len + 2];
>> +
>> +             switch (ad_type) {
>> +             case AD_TYPE_INCOMPLETE_UUID16_SERVICE_LIST:
>> +             {
>> +                     char *uuid =3D dupuuid2str(ad_data, 16);
>
> Empty line here.
Ok.
>
>> +                     l_queue_push_tail(ad.uuids, uuid);
>> +
>> +                     break;
>> +             }
>> +             case AD_TYPE_SHORT_NAME:
>> +                     ad.local_name =3D malloc(ad_len + 1);
>> +                     memcpy(ad.local_name, ad_data, ad_len);
>> +                     ad.local_name[ad_len] =3D '\0';
>> +
>> +                     break;
>> +             case AD_TYPE_SERVICE_DATA_UUID16:
>> +             {
>> +                     struct service_data *sd;
>> +
>> +                     sd =3D l_new(struct service_data, 1);
>> +                     sd->uuid =3D dupuuid2str(ad_data, 16);
>> +                     sd->data.len =3D ad_len - 2;
>> +                     memcpy(sd->data.data, ad_data + 2, sd->data.len);
>> +
>> +                     l_queue_push_tail(ad.services, sd);
>> +
>> +                     break;
>> +             }
>> +             case AD_TYPE_APPEARANCE:
>> +                     memcpy(&ad.local_appearance, ad_data, ad_len);
>> +
>> +                     break;
>> +             case AD_TYPE_MANUFACTURER_DATA:
>> +             {
>> +                     struct manufacturer_data *md;
>> +
>> +                     md =3D l_new(struct manufacturer_data, 1);
>> +                     /* The first 2 octets contain the Company Identifi=
er
>> +                      * Code followed by additional manufacturer specif=
ic
>> +                      * data.
>> +                      */
>> +                     memcpy(&md->id, ad_data, 2);
>> +                     md->data.len =3D ad_len - 2;
>> +                     memcpy(md->data.data, ad_data + 2, md->data.len);
>> +
>> +                     l_queue_push_tail(ad.manufacturers, md);
>> +
>> +                     break;
>> +             }
>> +             default:
>> +                     l_info("Unsupported advertising data type");
>> +
>> +                     break;
>> +             }
>> +             /* Advertising entity data len + advertising entity header
>> +              * (type, len)
>> +              */
>> +             remaining_data_len -=3D ad_len + 2;
>> +     }
>> +}
>> +
>> +static void create_scan_response(uint8_t scan_rsp_len, const uint8_t *d=
ata)
>> +{
>> +     /* TODO */
>> +}
>> +
>> +static void start_advertising_setup(struct l_dbus_message *message,
>> +                                                     void *user_data)
>> +{
>> +     struct l_dbus_message_builder *builder;
>> +
>> +     builder =3D l_dbus_message_builder_new(message);
>> +     l_dbus_message_builder_append_basic(builder, 'o', AD_PATH);
>> +     l_dbus_message_builder_enter_array(builder, "{sv}");
>> +     l_dbus_message_builder_enter_dict(builder, "sv");
>> +     l_dbus_message_builder_leave_dict(builder);
>> +     l_dbus_message_builder_leave_array(builder);
>> +     l_dbus_message_builder_finalize(builder);
>> +     l_dbus_message_builder_destroy(builder);
>> +}
>> +
>> +static void btp_gap_start_advertising(uint8_t index, const void *param,
>> +                                     uint16_t length, void *user_data)
>> +{
>> +     struct btp_adapter *adapter =3D find_adapter_by_index(index);
>> +     const struct btp_gap_start_adv_cp *cp =3D param;
>> +     uint8_t status =3D BTP_ERROR_FAIL;
>> +     bool prop;
>> +
>> +     if (!adapter) {
>> +             status =3D BTP_ERROR_INVALID_INDEX;
>> +             goto failed;
>> +     }
>> +
>> +     /* Adapter needs to be powered to be able to remove devices */
>> +     if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &pr=
op) ||
>> +                                                     !prop || ad.regist=
ered)
>> +             goto failed;
>> +
>> +     if (!l_dbus_register_interface(dbus, AD_IFACE, setup_ad_interface,=
 NULL,
>> +                                                                     fa=
lse)) {
>> +             l_info("Unable to register ad interface");
>> +             goto failed;
>> +     }
>> +
>> +     if (!l_dbus_object_add_interface(dbus, AD_PATH, AD_IFACE, NULL)) {
>> +             l_info("Unable to instantiate ad interface");
>> +
>> +             if (!l_dbus_unregister_interface(dbus, AD_IFACE))
>> +                     l_info("Unable to unregister ad interface");
>> +
>> +             goto failed;
>> +     }
>> +
>> +     if (!l_dbus_object_add_interface(dbus, AD_PATH,
>> +                                             L_DBUS_INTERFACE_PROPERTIE=
S,
>> +                                             NULL)) {
>> +             l_info("Unable to instantiate the properties interface");
>> +
>> +             if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFAC=
E))
>> +                     l_info("Unable to remove ad instance");
>> +             if (!l_dbus_unregister_interface(dbus, AD_IFACE))
>> +                     l_info("Unable to unregister ad interface");
>> +
>> +             goto failed;
>> +     }
>> +
>> +     ad.uuids =3D l_queue_new();
>> +     ad.services =3D l_queue_new();
>> +     ad.manufacturers =3D l_queue_new();
>
> Put this into helper eg ad_init(), also set appearance to default value.
Ok.
>
>> +
>> +     if (adapter->current_settings & BTP_GAP_SETTING_CONNECTABLE)
>> +             ad.type =3D l_strdup("peripheral");
>> +     else
>> +             ad.type =3D l_strdup("broadcast");
>
> No need to dup those string, just assing them with constants.
Right.
>
>> +
>> +     if (cp->adv_data_len > 0)
>> +             create_advertising_data(cp->adv_data_len, cp->data);
>> +     if (cp->scan_rsp_len > 0)
>> +             create_scan_response(cp->scan_rsp_len,
>> +                                             cp->data + cp->scan_rsp_le=
n);
>> +
>> +     if (!l_dbus_proxy_method_call(adapter->ad_proxy,
>> +                                                     "RegisterAdvertise=
ment",
>> +                                                     start_advertising_=
setup,
>> +                                                     start_advertising_=
reply,
>> +                                                     NULL, NULL)) {
>> +             if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFAC=
E))
>> +                     l_info("Unable to remove ad instance");
>> +             if (!l_dbus_unregister_interface(dbus, AD_IFACE))
>> +                     l_info("Unable to unregister ad interface");
>> +
>> +             goto failed;
>> +     }
>> +
>> +     return;
>> +
>> +failed:
>> +     btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> +}
>> +
>> +static void stop_advertising_reply(struct l_dbus_proxy *proxy,
>> +                                             struct l_dbus_message *res=
ult,
>> +                                             void *user_data)
>> +{
>> +     const char *path =3D l_dbus_proxy_get_path(proxy);
>> +     struct btp_adapter *adapter =3D find_adapter_by_path(path);
>> +     uint32_t new_settings;
>> +
>> +     if (!adapter)
>> +             return;
>> +
>> +     if (l_dbus_message_is_error(result)) {
>> +             const char *name;
>> +
>> +             l_dbus_message_get_error(result, &name, NULL);
>> +
>> +             l_error("Failed to stop advertising %s (%s)",
>> +                                     l_dbus_proxy_get_path(proxy), name=
);
>> +             return;
>> +     }
>> +
>> +     if (!l_dbus_object_remove_interface(dbus, AD_PATH, AD_IFACE))
>> +             l_info("Unable to remove ad instance");
>> +     if (!l_dbus_object_remove_interface(dbus, AD_PATH,
>> +                                             L_DBUS_INTERFACE_PROPERTIE=
S))
>> +             l_info("Unable to remove propety instance");
>> +     if (!l_dbus_unregister_interface(dbus, AD_IFACE))
>> +             l_info("Unable to unregister ad interface");
>> +
>> +     new_settings =3D adapter->current_settings;
>> +     new_settings &=3D ~BTP_GAP_SETTING_ADVERTISING;
>> +     update_current_settings(adapter, new_settings);
>> +
>> +     ad_cleanup();
>> +
>> +     btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_STOP_ADVERTISING,
>> +                                     adapter->index, sizeof(new_setting=
s),
>> +                                     &new_settings);
>> +}
>> +
>> +static void btp_gap_stop_advertising(uint8_t index, const void *param,
>> +                                     uint16_t length, void *user_data)
>> +{
>> +     struct btp_adapter *adapter =3D find_adapter_by_index(index);
>> +     uint8_t status =3D BTP_ERROR_FAIL;
>> +     bool prop;
>> +
>> +     if (!adapter) {
>> +             status =3D BTP_ERROR_INVALID_INDEX;
>> +             goto failed;
>> +     }
>> +
>> +     if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &pr=
op) ||
>> +                                                     !prop || !ad.regis=
tered)
>> +             goto failed;
>> +
>> +     if (adapter->ad_proxy) {
>> +             if (!l_dbus_proxy_method_call(adapter->ad_proxy,
>> +                                             "UnregisterAdvertisement",
>> +                                             unreg_advertising_setup,
>> +                                             stop_advertising_reply,
>> +                                             NULL, NULL)) {
>> +                     status =3D BTP_ERROR_FAIL;
>> +                     goto failed;
>> +             }
>> +     }
>> +
>> +     return;
>> +
>> +failed:
>> +     btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> +}
>> +
>>  static void start_discovery_reply(struct l_dbus_proxy *proxy,
>>                                               struct l_dbus_message *res=
ult,
>>                                               void *user_data)
>> @@ -728,6 +1365,12 @@ static void register_gap_service(void)
>>       btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_BONDABLE,
>>                                       btp_gap_set_bondable, NULL, NULL);
>>
>> +     btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_ADVERTISING,
>> +                                     btp_gap_start_advertising, NULL, N=
ULL);
>> +
>> +     btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_STOP_ADVERTISING,
>> +                                     btp_gap_stop_advertising, NULL, NU=
LL);
>> +
>>       btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_START_DISCOVERY,
>>                                       btp_gap_start_discovery, NULL, NUL=
L);
>>
>> @@ -1124,6 +1767,12 @@ static void client_ready(struct l_dbus_client
>> *client, void *user_data) BTP_INDEX_NON_CONTROLLER, 0, NULL);
>>  }
>>
>> +static void ready_callback(void *user_data)
>> +{
>> +     if (!l_dbus_object_manager_enable(dbus))
>> +             l_info("Unable to register the ObjectManager");
>> +}
>> +
>>  static void usage(void)
>>  {
>>       l_info("btpclient - Bluetooth tester");
>> @@ -1148,7 +1797,6 @@ int main(int argc, char *argv[])
>>  {
>>       struct l_dbus_client *client;
>>       struct l_signal *signal;
>> -     struct l_dbus *dbus;
>>       sigset_t mask;
>>       int opt;
>>
>> @@ -1192,6 +1840,7 @@ int main(int argc, char *argv[])
>>       signal =3D l_signal_create(&mask, signal_handler, NULL, NULL);
>>
>>       dbus =3D l_dbus_new_default(L_DBUS_SYSTEM_BUS);
>> +     l_dbus_set_ready_handler(dbus, ready_callback, NULL, NULL);
>>       client =3D l_dbus_client_new(dbus, "org.bluez", "/org/bluez");
>>
>>       l_dbus_client_set_connect_handler(client, client_connected, NULL, =
NULL);
>
>
> --
> pozdrawiam
> Szymon Janc
>
>
pozdrawiam,
Grzegorz Ko=C5=82odziejczyk

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

end of thread, other threads:[~2018-01-16  9:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-01-12 14:10 [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Grzegorz Kolodziejczyk
2018-01-12 14:10 ` [PATCH BlueZ v2 2/4] tools/btpclient: Add start, stop advertising commands Grzegorz Kolodziejczyk
2018-01-15 13:21   ` Szymon Janc
2018-01-16  9:26     ` Grzegorz Kołodziejczyk
2018-01-12 14:10 ` [PATCH BlueZ v2 3/4] tools/btpclient: Add connect, disconnect commands Grzegorz Kolodziejczyk
2018-01-12 14:10 ` [PATCH BlueZ v2 4/4] tools/btpclient: Add connected, disconnected event Grzegorz Kolodziejczyk
2018-01-15 13:50 ` [PATCH BlueZ v2 1/4] tools/btpclient: Fix setting/reseting connectable flag Szymon Janc

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).