3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2015 Google Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
20 #include "advertising.h"
25 #include <dbus/dbus.h>
26 #include <gdbus/gdbus.h>
28 #include "lib/bluetooth.h"
33 #include "dbus-common.h"
36 #include "src/shared/ad.h"
37 #include "src/shared/mgmt.h"
38 #include "src/shared/queue.h"
39 #include "src/shared/util.h"
41 #define LE_ADVERTISING_MGR_IFACE "org.bluez.LEAdvertisingManager1"
42 #define LE_ADVERTISEMENT_IFACE "org.bluez.LEAdvertisement1"
44 struct btd_adv_manager {
45 struct btd_adapter *adapter;
46 struct queue *clients;
51 unsigned int instance_bitmap;
54 #define AD_TYPE_BROADCAST 0
55 #define AD_TYPE_PERIPHERAL 1
57 struct btd_adv_client {
58 struct btd_adv_manager *manager;
64 uint8_t type; /* Advertising type */
65 bool include_tx_power;
70 struct dbus_obj_match {
75 static bool match_client(const void *a, const void *b)
77 const struct btd_adv_client *client = a;
78 const struct dbus_obj_match *match = b;
80 if (match->owner && g_strcmp0(client->owner, match->owner))
83 if (match->path && g_strcmp0(client->path, match->path))
89 static void client_free(void *data)
91 struct btd_adv_client *client = data;
94 g_dbus_client_set_disconnect_watch(client->client, NULL, NULL);
95 g_dbus_client_unref(client->client);
99 util_clear_uid(&client->manager->instance_bitmap,
102 bt_ad_unref(client->data);
104 g_dbus_proxy_unref(client->proxy);
107 g_free(client->owner);
110 g_free(client->path);
115 static gboolean client_free_idle_cb(void *data)
122 static void client_release(void *data)
124 struct btd_adv_client *client = data;
125 DBusMessage *message;
127 DBG("Releasing advertisement %s, %s", client->owner, client->path);
129 message = dbus_message_new_method_call(client->owner, client->path,
130 LE_ADVERTISEMENT_IFACE,
134 error("Couldn't allocate D-Bus message");
138 g_dbus_send_message(btd_get_dbus_connection(), message);
141 static void client_destroy(void *data)
143 client_release(data);
147 static void client_remove(void *data)
149 struct btd_adv_client *client = data;
150 struct mgmt_cp_remove_advertising cp;
152 g_dbus_client_set_disconnect_watch(client->client, NULL, NULL);
154 cp.instance = client->instance;
156 mgmt_send(client->manager->mgmt, MGMT_OP_REMOVE_ADVERTISING,
157 client->manager->mgmt_index, sizeof(cp), &cp,
160 queue_remove(client->manager->clients, client);
162 g_idle_add(client_free_idle_cb, client);
165 static void client_disconnect_cb(DBusConnection *conn, void *user_data)
167 DBG("Client disconnected");
169 client_remove(user_data);
172 static bool parse_type(GDBusProxy *proxy, uint8_t *type)
174 DBusMessageIter iter;
175 const char *msg_type;
177 if (!g_dbus_proxy_get_property(proxy, "Type", &iter))
180 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
183 dbus_message_iter_get_basic(&iter, &msg_type);
185 if (!g_strcmp0(msg_type, "broadcast")) {
186 *type = AD_TYPE_BROADCAST;
190 if (!g_strcmp0(msg_type, "peripheral")) {
191 *type = AD_TYPE_PERIPHERAL;
198 static bool parse_service_uuids(GDBusProxy *proxy, struct bt_ad *data)
200 DBusMessageIter iter, ariter;
202 if (!g_dbus_proxy_get_property(proxy, "ServiceUUIDs", &iter))
205 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
208 dbus_message_iter_recurse(&iter, &ariter);
210 bt_ad_clear_service_uuid(data);
212 while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
213 const char *uuid_str;
216 dbus_message_iter_get_basic(&ariter, &uuid_str);
218 DBG("Adding ServiceUUID: %s", uuid_str);
220 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
223 if (!bt_ad_add_service_uuid(data, &uuid))
226 dbus_message_iter_next(&ariter);
232 bt_ad_clear_service_uuid(data);
236 static bool parse_solicit_uuids(GDBusProxy *proxy, struct bt_ad *data)
238 DBusMessageIter iter, ariter;
240 if (!g_dbus_proxy_get_property(proxy, "SolicitUUIDs", &iter))
243 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
246 dbus_message_iter_recurse(&iter, &ariter);
248 bt_ad_clear_solicit_uuid(data);
250 while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
251 const char *uuid_str;
254 dbus_message_iter_get_basic(&ariter, &uuid_str);
256 DBG("Adding SolicitUUID: %s", uuid_str);
258 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
261 if (!bt_ad_add_solicit_uuid(data, &uuid))
264 dbus_message_iter_next(&ariter);
270 bt_ad_clear_solicit_uuid(data);
274 static bool parse_manufacturer_data(GDBusProxy *proxy, struct bt_ad *data)
276 DBusMessageIter iter, entries;
278 if (!g_dbus_proxy_get_property(proxy, "ManufacturerData", &iter))
281 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
284 dbus_message_iter_recurse(&iter, &entries);
286 bt_ad_clear_manufacturer_data(data);
288 while (dbus_message_iter_get_arg_type(&entries)
289 == DBUS_TYPE_DICT_ENTRY) {
290 DBusMessageIter value, entry, array;
295 dbus_message_iter_recurse(&entries, &entry);
296 dbus_message_iter_get_basic(&entry, &manuf_id);
298 dbus_message_iter_next(&entry);
300 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
303 dbus_message_iter_recurse(&entry, &value);
305 if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
308 dbus_message_iter_recurse(&value, &array);
310 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
313 dbus_message_iter_get_fixed_array(&array, &manuf_data, &len);
315 DBG("Adding ManufacturerData for %04x", manuf_id);
317 if (!bt_ad_add_manufacturer_data(data, manuf_id, manuf_data,
321 dbus_message_iter_next(&entries);
327 bt_ad_clear_manufacturer_data(data);
331 static bool parse_service_data(GDBusProxy *proxy, struct bt_ad *data)
333 DBusMessageIter iter, entries;
335 if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
338 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
341 dbus_message_iter_recurse(&iter, &entries);
343 bt_ad_clear_service_data(data);
345 while (dbus_message_iter_get_arg_type(&entries)
346 == DBUS_TYPE_DICT_ENTRY) {
347 DBusMessageIter value, entry, array;
348 const char *uuid_str;
350 uint8_t *service_data;
353 dbus_message_iter_recurse(&entries, &entry);
354 dbus_message_iter_get_basic(&entry, &uuid_str);
356 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
359 dbus_message_iter_next(&entry);
361 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
364 dbus_message_iter_recurse(&entry, &value);
366 if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
369 dbus_message_iter_recurse(&value, &array);
371 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
374 dbus_message_iter_get_fixed_array(&array, &service_data, &len);
376 DBG("Adding ServiceData for %s", uuid_str);
378 if (!bt_ad_add_service_data(data, &uuid, service_data, len))
381 dbus_message_iter_next(&entries);
387 bt_ad_clear_service_data(data);
391 static bool parse_include_tx_power(GDBusProxy *proxy, bool *included)
393 DBusMessageIter iter;
396 if (!g_dbus_proxy_get_property(proxy, "IncludeTxPower", &iter))
399 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
402 dbus_message_iter_get_basic(&iter, &b);
409 static void add_client_complete(struct btd_adv_client *client, uint8_t status)
414 error("Failed to add advertisement: %s (0x%02x)",
415 mgmt_errstr(status), status);
416 reply = btd_error_failed(client->reg,
417 "Failed to register advertisement");
418 queue_remove(client->manager->clients, client);
419 g_idle_add(client_free_idle_cb, client);
422 reply = dbus_message_new_method_return(client->reg);
424 g_dbus_send_message(btd_get_dbus_connection(), reply);
425 dbus_message_unref(client->reg);
429 static void add_adv_callback(uint8_t status, uint16_t length,
430 const void *param, void *user_data)
432 struct btd_adv_client *client = user_data;
433 const struct mgmt_rp_add_advertising *rp = param;
438 if (!param || length < sizeof(*rp)) {
439 status = MGMT_STATUS_FAILED;
443 client->instance = rp->instance;
445 g_dbus_client_set_disconnect_watch(client->client, client_disconnect_cb,
447 DBG("Advertisement registered: %s", client->path);
450 add_client_complete(client, status);
453 static size_t calc_max_adv_len(struct btd_adv_client *client, uint32_t flags)
455 size_t max = client->manager->max_adv_len;
458 * Flags which reduce the amount of space available for advertising.
459 * See doc/mgmt-api.txt
461 if (flags & MGMT_ADV_FLAG_TX_POWER)
464 if (flags & (MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
465 MGMT_ADV_FLAG_MANAGED_FLAGS))
468 if (flags & MGMT_ADV_FLAG_APPEARANCE)
474 static DBusMessage *refresh_advertisement(struct btd_adv_client *client)
476 struct mgmt_cp_add_advertising *cp;
482 DBG("Refreshing advertisement: %s", client->path);
484 if (client->type == AD_TYPE_PERIPHERAL)
485 flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV;
487 if (client->include_tx_power)
488 flags |= MGMT_ADV_FLAG_TX_POWER;
490 adv_data = bt_ad_generate(client->data, &adv_data_len);
492 if (!adv_data || (adv_data_len > calc_max_adv_len(client, flags))) {
493 error("Advertising data too long or couldn't be generated.");
495 return g_dbus_create_error(client->reg, ERROR_INTERFACE
497 "Advertising data too long.");
500 param_len = sizeof(struct mgmt_cp_add_advertising) + adv_data_len;
502 cp = malloc0(param_len);
505 error("Couldn't allocate for MGMT!");
509 return btd_error_failed(client->reg, "Failed");
512 cp->flags = htobl(flags);
513 cp->instance = client->instance;
514 cp->adv_data_len = adv_data_len;
515 memcpy(cp->data, adv_data, adv_data_len);
519 if (!mgmt_send(client->manager->mgmt, MGMT_OP_ADD_ADVERTISING,
520 client->manager->mgmt_index, param_len, cp,
521 add_adv_callback, client, NULL)) {
522 error("Failed to add Advertising Data");
526 return btd_error_failed(client->reg, "Failed");
534 static DBusMessage *parse_advertisement(struct btd_adv_client *client)
536 if (!parse_type(client->proxy, &client->type)) {
537 error("Failed to read \"Type\" property of advertisement");
541 if (!parse_service_uuids(client->proxy, client->data)) {
542 error("Property \"ServiceUUIDs\" failed to parse");
546 if (!parse_solicit_uuids(client->proxy, client->data)) {
547 error("Property \"SolicitUUIDs\" failed to parse");
551 if (!parse_manufacturer_data(client->proxy, client->data)) {
552 error("Property \"ManufacturerData\" failed to parse");
556 if (!parse_service_data(client->proxy, client->data)) {
557 error("Property \"ServiceData\" failed to parse");
561 if (!parse_include_tx_power(client->proxy, &client->include_tx_power)) {
562 error("Property \"IncludeTxPower\" failed to parse");
566 return refresh_advertisement(client);
569 return btd_error_failed(client->reg, "Failed to parse advertisement.");
572 static void client_proxy_added(GDBusProxy *proxy, void *data)
574 struct btd_adv_client *client = data;
577 reply = parse_advertisement(client);
581 /* Failed to publish for some reason, remove. */
582 queue_remove(client->manager->clients, client);
584 g_idle_add(client_free_idle_cb, client);
586 g_dbus_send_message(btd_get_dbus_connection(), reply);
588 dbus_message_unref(client->reg);
592 static struct btd_adv_client *client_create(struct btd_adv_manager *manager,
593 DBusConnection *conn,
594 DBusMessage *msg, const char *path)
596 struct btd_adv_client *client;
597 const char *sender = dbus_message_get_sender(msg);
599 if (!path || !g_str_has_prefix(path, "/"))
602 client = new0(struct btd_adv_client, 1);
603 client->client = g_dbus_client_new_full(conn, sender, path, path);
607 client->owner = g_strdup(sender);
611 client->path = g_strdup(path);
615 DBG("Adding proxy for %s", path);
616 client->proxy = g_dbus_proxy_new(client->client, path,
617 LE_ADVERTISEMENT_IFACE);
621 g_dbus_client_set_proxy_handlers(client->client, client_proxy_added,
624 client->reg = dbus_message_ref(msg);
626 client->data = bt_ad_new();
630 client->instance = util_get_uid(&manager->instance_bitmap,
632 if (!client->instance)
635 client->manager = manager;
644 static DBusMessage *register_advertisement(DBusConnection *conn,
648 struct btd_adv_manager *manager = user_data;
649 DBusMessageIter args;
650 struct btd_adv_client *client;
651 struct dbus_obj_match match;
653 DBG("RegisterAdvertisement");
655 if (!dbus_message_iter_init(msg, &args))
656 return btd_error_invalid_args(msg);
658 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
659 return btd_error_invalid_args(msg);
661 dbus_message_iter_get_basic(&args, &match.path);
663 match.owner = dbus_message_get_sender(msg);
665 if (queue_find(manager->clients, match_client, &match))
666 return btd_error_already_exists(msg);
668 dbus_message_iter_next(&args);
670 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
671 return btd_error_invalid_args(msg);
673 client = client_create(manager, conn, msg, match.path);
675 return btd_error_failed(msg,
676 "Failed to register advertisement");
678 DBG("Registered advertisement at path %s", match.path);
680 queue_push_tail(manager->clients, client);
685 static DBusMessage *unregister_advertisement(DBusConnection *conn,
689 struct btd_adv_manager *manager = user_data;
690 DBusMessageIter args;
691 struct btd_adv_client *client;
692 struct dbus_obj_match match;
694 DBG("UnregisterAdvertisement");
696 if (!dbus_message_iter_init(msg, &args))
697 return btd_error_invalid_args(msg);
699 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
700 return btd_error_invalid_args(msg);
702 dbus_message_iter_get_basic(&args, &match.path);
704 match.owner = dbus_message_get_sender(msg);
706 client = queue_find(manager->clients, match_client, &match);
708 return btd_error_does_not_exist(msg);
710 client_remove(client);
712 return dbus_message_new_method_return(msg);
715 static const GDBusMethodTable methods[] = {
716 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterAdvertisement",
717 GDBUS_ARGS({ "advertisement", "o" },
718 { "options", "a{sv}" }),
719 NULL, register_advertisement) },
720 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterAdvertisement",
721 GDBUS_ARGS({ "service", "o" }),
723 unregister_advertisement) },
727 static void manager_destroy(void *user_data)
729 struct btd_adv_manager *manager = user_data;
731 queue_destroy(manager->clients, client_destroy);
733 mgmt_unref(manager->mgmt);
738 static void read_adv_features_callback(uint8_t status, uint16_t length,
739 const void *param, void *user_data)
741 struct btd_adv_manager *manager = user_data;
742 const struct mgmt_rp_read_adv_features *feat = param;
744 if (status || !param) {
745 error("Failed to read advertising features: %s (0x%02x)",
746 mgmt_errstr(status), status);
750 if (length < sizeof(*feat)) {
751 error("Wrong size of read adv features response");
755 manager->max_adv_len = feat->max_adv_data_len;
756 manager->max_ads = feat->max_instances;
758 if (manager->max_ads == 0)
761 if (!g_dbus_register_interface(btd_get_dbus_connection(),
762 adapter_get_path(manager->adapter),
763 LE_ADVERTISING_MGR_IFACE,
764 methods, NULL, NULL, manager, NULL))
765 error("Failed to register " LE_ADVERTISING_MGR_IFACE);
768 static struct btd_adv_manager *manager_create(struct btd_adapter *adapter)
770 struct btd_adv_manager *manager;
772 manager = new0(struct btd_adv_manager, 1);
773 manager->adapter = adapter;
775 manager->mgmt = mgmt_new_default();
777 if (!manager->mgmt) {
778 error("Failed to access management interface");
783 manager->mgmt_index = btd_adapter_get_index(adapter);
785 if (!mgmt_send(manager->mgmt, MGMT_OP_READ_ADV_FEATURES,
786 manager->mgmt_index, 0, NULL,
787 read_adv_features_callback, manager, NULL)) {
788 error("Failed to read advertising features");
789 manager_destroy(manager);
793 manager->clients = queue_new();
798 struct btd_adv_manager *btd_adv_manager_new(struct btd_adapter *adapter)
800 struct btd_adv_manager *manager;
805 manager = manager_create(adapter);
809 DBG("LE Advertising Manager created for adapter: %s",
810 adapter_get_path(adapter));
815 void btd_adv_manager_destroy(struct btd_adv_manager *manager)
820 g_dbus_unregister_interface(btd_get_dbus_connection(),
821 adapter_get_path(manager->adapter),
822 LE_ADVERTISING_MGR_IFACE);
824 manager_destroy(manager);