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_advertising {
45 struct btd_adapter *adapter;
51 unsigned int instance_bitmap;
54 #define AD_TYPE_BROADCAST 0
55 #define AD_TYPE_PERIPHERAL 1
57 struct advertisement {
58 struct btd_advertising *manager;
64 uint8_t type; /* Advertising type */
65 bool include_tx_power;
70 struct dbus_obj_match {
75 static bool match_advertisement(const void *a, const void *b)
77 const struct advertisement *ad = a;
78 const struct dbus_obj_match *match = b;
80 if (match->owner && g_strcmp0(ad->owner, match->owner))
83 if (match->path && g_strcmp0(ad->path, match->path))
89 static void advertisement_free(void *data)
91 struct advertisement *ad = data;
94 g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
95 g_dbus_client_unref(ad->client);
98 bt_ad_unref(ad->data);
100 g_dbus_proxy_unref(ad->proxy);
111 static gboolean advertisement_free_idle_cb(void *data)
113 advertisement_free(data);
118 static void advertisement_release(void *data)
120 struct advertisement *ad = data;
121 DBusMessage *message;
123 DBG("Releasing advertisement %s, %s", ad->owner, ad->path);
125 message = dbus_message_new_method_call(ad->owner, ad->path,
126 LE_ADVERTISEMENT_IFACE,
130 error("Couldn't allocate D-Bus message");
134 g_dbus_send_message(btd_get_dbus_connection(), message);
137 static void advertisement_destroy(void *data)
139 advertisement_release(data);
140 advertisement_free(data);
143 static void advertisement_remove(void *data)
145 struct advertisement *ad = data;
146 struct mgmt_cp_remove_advertising cp;
148 g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
150 cp.instance = ad->instance;
152 mgmt_send(ad->manager->mgmt, MGMT_OP_REMOVE_ADVERTISING,
153 ad->manager->mgmt_index, sizeof(cp), &cp, NULL, NULL,
156 queue_remove(ad->manager->ads, ad);
158 util_clear_uid(&ad->manager->instance_bitmap, ad->instance);
160 g_idle_add(advertisement_free_idle_cb, ad);
163 static void client_disconnect_cb(DBusConnection *conn, void *user_data)
165 DBG("Client disconnected");
167 advertisement_remove(user_data);
170 static bool parse_advertising_type(GDBusProxy *proxy, uint8_t *type)
172 DBusMessageIter iter;
173 const char *msg_type;
175 if (!g_dbus_proxy_get_property(proxy, "Type", &iter))
178 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
181 dbus_message_iter_get_basic(&iter, &msg_type);
183 if (!g_strcmp0(msg_type, "broadcast")) {
184 *type = AD_TYPE_BROADCAST;
188 if (!g_strcmp0(msg_type, "peripheral")) {
189 *type = AD_TYPE_PERIPHERAL;
196 static bool parse_advertising_service_uuids(GDBusProxy *proxy,
199 DBusMessageIter iter, ariter;
201 if (!g_dbus_proxy_get_property(proxy, "ServiceUUIDs", &iter))
204 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
207 dbus_message_iter_recurse(&iter, &ariter);
209 bt_ad_clear_service_uuid(data);
211 while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
212 const char *uuid_str;
215 dbus_message_iter_get_basic(&ariter, &uuid_str);
217 DBG("Adding ServiceUUID: %s", uuid_str);
219 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
222 if (!bt_ad_add_service_uuid(data, &uuid))
225 dbus_message_iter_next(&ariter);
231 bt_ad_clear_service_uuid(data);
235 static bool parse_advertising_solicit_uuids(GDBusProxy *proxy,
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_advertising_manufacturer_data(GDBusProxy *proxy,
277 DBusMessageIter iter, entries;
279 if (!g_dbus_proxy_get_property(proxy, "ManufacturerData", &iter))
282 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
285 dbus_message_iter_recurse(&iter, &entries);
287 bt_ad_clear_manufacturer_data(data);
289 while (dbus_message_iter_get_arg_type(&entries)
290 == DBUS_TYPE_DICT_ENTRY) {
291 DBusMessageIter value, entry;
296 dbus_message_iter_recurse(&entries, &entry);
297 dbus_message_iter_get_basic(&entry, &manuf_id);
299 dbus_message_iter_next(&entry);
300 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
303 dbus_message_iter_recurse(&entry, &value);
305 if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
308 dbus_message_iter_get_fixed_array(&value, &manuf_data, &len);
310 DBG("Adding ManufacturerData for %04x", manuf_id);
312 if (!bt_ad_add_manufacturer_data(data, manuf_id, manuf_data,
316 dbus_message_iter_next(&entries);
322 bt_ad_clear_manufacturer_data(data);
326 static bool parse_advertising_service_data(GDBusProxy *proxy,
329 DBusMessageIter iter, entries;
331 if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
334 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
337 dbus_message_iter_recurse(&iter, &entries);
339 bt_ad_clear_service_data(data);
341 while (dbus_message_iter_get_arg_type(&entries)
342 == DBUS_TYPE_DICT_ENTRY) {
343 DBusMessageIter value, entry;
344 const char *uuid_str;
346 uint8_t *service_data;
349 dbus_message_iter_recurse(&entries, &entry);
350 dbus_message_iter_get_basic(&entry, &uuid_str);
352 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
355 dbus_message_iter_next(&entry);
356 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
359 dbus_message_iter_recurse(&entry, &value);
361 if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
364 dbus_message_iter_get_fixed_array(&value, &service_data, &len);
366 DBG("Adding ServiceData for %s", uuid_str);
368 if (!bt_ad_add_service_data(data, &uuid, service_data, len))
371 dbus_message_iter_next(&entries);
377 bt_ad_clear_service_data(data);
381 static bool parse_advertising_include_tx_power(GDBusProxy *proxy,
384 DBusMessageIter iter;
387 if (!g_dbus_proxy_get_property(proxy, "IncludeTxPower", &iter))
390 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
393 dbus_message_iter_get_basic(&iter, &b);
400 static void add_adverting_complete(struct advertisement *ad, uint8_t status)
405 error("Failed to add advertisement: %s (0x%02x)",
406 mgmt_errstr(status), status);
407 reply = btd_error_failed(ad->reg,
408 "Failed to register advertisement");
409 queue_remove(ad->manager->ads, ad);
410 g_idle_add(advertisement_free_idle_cb, ad);
413 reply = dbus_message_new_method_return(ad->reg);
415 g_dbus_send_message(btd_get_dbus_connection(), reply);
416 dbus_message_unref(ad->reg);
420 static void add_advertising_callback(uint8_t status, uint16_t length,
421 const void *param, void *user_data)
423 struct advertisement *ad = user_data;
424 const struct mgmt_rp_add_advertising *rp = param;
429 if (!param || length < sizeof(*rp)) {
430 status = MGMT_STATUS_FAILED;
434 ad->instance = rp->instance;
436 g_dbus_client_set_disconnect_watch(ad->client, client_disconnect_cb,
438 DBG("Advertisement registered: %s", ad->path);
441 add_adverting_complete(ad, status);
444 static size_t calc_max_adv_len(struct advertisement *ad, uint32_t flags)
446 size_t max = ad->manager->max_adv_len;
449 * Flags which reduce the amount of space available for advertising.
450 * See doc/mgmt-api.txt
452 if (flags & MGMT_ADV_FLAG_TX_POWER)
455 if (flags & (MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
456 MGMT_ADV_FLAG_MANAGED_FLAGS))
459 if (flags & MGMT_ADV_FLAG_APPEARANCE)
465 static DBusMessage *refresh_advertisement(struct advertisement *ad)
467 struct mgmt_cp_add_advertising *cp;
473 DBG("Refreshing advertisement: %s", ad->path);
475 if (ad->type == AD_TYPE_PERIPHERAL)
476 flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV;
478 if (ad->include_tx_power)
479 flags |= MGMT_ADV_FLAG_TX_POWER;
481 adv_data = bt_ad_generate(ad->data, &adv_data_len);
483 if (!adv_data || (adv_data_len > calc_max_adv_len(ad, flags))) {
484 error("Advertising data too long or couldn't be generated.");
486 return g_dbus_create_error(ad->reg, ERROR_INTERFACE
488 "Advertising data too long.");
491 param_len = sizeof(struct mgmt_cp_add_advertising) + adv_data_len;
493 cp = malloc0(param_len);
496 error("Couldn't allocate for MGMT!");
500 return btd_error_failed(ad->reg, "Failed");
504 cp->instance = ad->instance;
505 cp->adv_data_len = adv_data_len;
506 memcpy(cp->data, adv_data, adv_data_len);
510 if (!mgmt_send(ad->manager->mgmt, MGMT_OP_ADD_ADVERTISING,
511 ad->manager->mgmt_index, param_len, cp,
512 add_advertising_callback, ad, NULL)) {
513 error("Failed to add Advertising Data");
517 return btd_error_failed(ad->reg, "Failed");
525 static DBusMessage *parse_advertisement(struct advertisement *ad)
527 if (!parse_advertising_type(ad->proxy, &ad->type)) {
528 error("Failed to read \"Type\" property of advertisement");
532 if (!parse_advertising_service_uuids(ad->proxy, ad->data)) {
533 error("Property \"ServiceUUIDs\" failed to parse");
537 if (!parse_advertising_solicit_uuids(ad->proxy, ad->data)) {
538 error("Property \"SolicitUUIDs\" failed to parse");
542 if (!parse_advertising_manufacturer_data(ad->proxy, ad->data)) {
543 error("Property \"ManufacturerData\" failed to parse");
547 if (!parse_advertising_service_data(ad->proxy, ad->data)) {
548 error("Property \"ServiceData\" failed to parse");
552 if (!parse_advertising_include_tx_power(ad->proxy,
553 &ad->include_tx_power)) {
554 error("Property \"IncludeTxPower\" failed to parse");
558 return refresh_advertisement(ad);
561 return btd_error_failed(ad->reg, "Failed to parse advertisement.");
564 static void advertisement_proxy_added(GDBusProxy *proxy, void *data)
566 struct advertisement *ad = data;
569 reply = parse_advertisement(ad);
573 /* Failed to publish for some reason, remove. */
574 queue_remove(ad->manager->ads, ad);
576 g_idle_add(advertisement_free_idle_cb, ad);
578 g_dbus_send_message(btd_get_dbus_connection(), reply);
580 dbus_message_unref(ad->reg);
584 static struct advertisement *advertisement_create(DBusConnection *conn,
585 DBusMessage *msg, const char *path)
587 struct advertisement *ad;
588 const char *sender = dbus_message_get_sender(msg);
590 if (!path || !g_str_has_prefix(path, "/"))
593 ad = new0(struct advertisement, 1);
594 ad->client = g_dbus_client_new_full(conn, sender, path, path);
598 ad->owner = g_strdup(sender);
602 ad->path = g_strdup(path);
606 DBG("Adding proxy for %s", path);
607 ad->proxy = g_dbus_proxy_new(ad->client, path, LE_ADVERTISEMENT_IFACE);
611 g_dbus_client_set_proxy_handlers(ad->client, advertisement_proxy_added,
614 ad->reg = dbus_message_ref(msg);
616 ad->data = bt_ad_new();
623 advertisement_free(ad);
627 static DBusMessage *register_advertisement(DBusConnection *conn,
631 struct btd_advertising *manager = user_data;
632 DBusMessageIter args;
633 struct advertisement *ad;
634 struct dbus_obj_match match;
637 DBG("RegisterAdvertisement");
639 if (!dbus_message_iter_init(msg, &args))
640 return btd_error_invalid_args(msg);
642 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
643 return btd_error_invalid_args(msg);
645 dbus_message_iter_get_basic(&args, &match.path);
647 match.owner = dbus_message_get_sender(msg);
649 if (queue_find(manager->ads, match_advertisement, &match))
650 return btd_error_already_exists(msg);
652 instance = util_get_uid(&manager->instance_bitmap, manager->max_ads);
654 return btd_error_failed(msg, "Maximum advertisements reached");
656 dbus_message_iter_next(&args);
658 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
659 return btd_error_invalid_args(msg);
661 ad = advertisement_create(conn, msg, match.path);
663 return btd_error_failed(msg,
664 "Failed to register advertisement");
666 DBG("Registered advertisement at path %s", match.path);
668 ad->instance = instance;
669 ad->manager = manager;
671 queue_push_tail(manager->ads, ad);
676 static DBusMessage *unregister_advertisement(DBusConnection *conn,
680 struct btd_advertising *manager = user_data;
681 DBusMessageIter args;
682 struct advertisement *ad;
683 struct dbus_obj_match match;
685 DBG("UnregisterAdvertisement");
687 if (!dbus_message_iter_init(msg, &args))
688 return btd_error_invalid_args(msg);
690 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
691 return btd_error_invalid_args(msg);
693 dbus_message_iter_get_basic(&args, &match.path);
695 match.owner = dbus_message_get_sender(msg);
697 ad = queue_find(manager->ads, match_advertisement, &match);
699 return btd_error_does_not_exist(msg);
701 advertisement_remove(ad);
703 return dbus_message_new_method_return(msg);
706 static const GDBusMethodTable methods[] = {
707 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterAdvertisement",
708 GDBUS_ARGS({ "advertisement", "o" },
709 { "options", "a{sv}" }),
710 NULL, register_advertisement) },
711 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterAdvertisement",
712 GDBUS_ARGS({ "service", "o" }),
714 unregister_advertisement) },
718 static void advertising_manager_destroy(void *user_data)
720 struct btd_advertising *manager = user_data;
722 queue_destroy(manager->ads, advertisement_destroy);
724 mgmt_unref(manager->mgmt);
729 static void read_adv_features_callback(uint8_t status, uint16_t length,
730 const void *param, void *user_data)
732 struct btd_advertising *manager = user_data;
733 const struct mgmt_rp_read_adv_features *feat = param;
735 if (status || !param) {
736 error("Failed to read advertising features: %s (0x%02x)",
737 mgmt_errstr(status), status);
741 if (length < sizeof(*feat)) {
742 error("Wrong size of read adv features response");
746 manager->max_adv_len = feat->max_adv_data_len;
747 manager->max_ads = feat->max_instances;
749 if (manager->max_ads == 0)
752 if (!g_dbus_register_interface(btd_get_dbus_connection(),
753 adapter_get_path(manager->adapter),
754 LE_ADVERTISING_MGR_IFACE,
755 methods, NULL, NULL, manager, NULL))
756 error("Failed to register " LE_ADVERTISING_MGR_IFACE);
759 static struct btd_advertising *
760 advertising_manager_create(struct btd_adapter *adapter)
762 struct btd_advertising *manager;
764 manager = new0(struct btd_advertising, 1);
765 manager->adapter = adapter;
767 manager->mgmt = mgmt_new_default();
769 if (!manager->mgmt) {
770 error("Failed to access management interface");
775 manager->mgmt_index = btd_adapter_get_index(adapter);
777 if (!mgmt_send(manager->mgmt, MGMT_OP_READ_ADV_FEATURES,
778 manager->mgmt_index, 0, NULL,
779 read_adv_features_callback, manager, NULL)) {
780 error("Failed to read advertising features");
781 advertising_manager_destroy(manager);
785 manager->ads = queue_new();
790 struct btd_advertising *
791 btd_advertising_manager_new(struct btd_adapter *adapter)
793 struct btd_advertising *manager;
798 manager = advertising_manager_create(adapter);
802 DBG("LE Advertising Manager created for adapter: %s",
803 adapter_get_path(adapter));
808 void btd_advertising_manager_destroy(struct btd_advertising *manager)
813 g_dbus_unregister_interface(btd_get_dbus_connection(),
814 adapter_get_path(manager->adapter),
815 LE_ADVERTISING_MGR_IFACE);
817 advertising_manager_destroy(manager);