Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / src / advertising.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2015  Google Inc.
6  *
7  *
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.
12  *
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.
17  *
18  */
19
20 #include "advertising.h"
21
22 #include <stdint.h>
23 #include <stdbool.h>
24
25 #include <dbus/dbus.h>
26 #include <gdbus/gdbus.h>
27
28 #include "lib/bluetooth.h"
29 #include "lib/mgmt.h"
30 #include "lib/sdp.h"
31
32 #include "adapter.h"
33 #include "dbus-common.h"
34 #include "error.h"
35 #include "log.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"
40
41 #define LE_ADVERTISING_MGR_IFACE "org.bluez.LEAdvertisingManager1"
42 #define LE_ADVERTISEMENT_IFACE "org.bluez.LEAdvertisement1"
43
44 struct btd_advertising {
45         struct btd_adapter *adapter;
46         struct queue *ads;
47         struct mgmt *mgmt;
48         uint16_t mgmt_index;
49         uint8_t max_adv_len;
50         uint8_t max_ads;
51         unsigned int instance_bitmap;
52 };
53
54 #define AD_TYPE_BROADCAST 0
55 #define AD_TYPE_PERIPHERAL 1
56
57 struct advertisement {
58         struct btd_advertising *manager;
59         char *owner;
60         char *path;
61         GDBusClient *client;
62         GDBusProxy *proxy;
63         DBusMessage *reg;
64         uint8_t type; /* Advertising type */
65         bool include_tx_power;
66         struct bt_ad *data;
67         uint8_t instance;
68 };
69
70 struct dbus_obj_match {
71         const char *owner;
72         const char *path;
73 };
74
75 static bool match_advertisement(const void *a, const void *b)
76 {
77         const struct advertisement *ad = a;
78         const struct dbus_obj_match *match = b;
79
80         if (match->owner && g_strcmp0(ad->owner, match->owner))
81                 return false;
82
83         if (match->path && g_strcmp0(ad->path, match->path))
84                 return false;
85
86         return true;
87 }
88
89 static void advertisement_free(void *data)
90 {
91         struct advertisement *ad = data;
92
93         if (ad->client) {
94                 g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
95                 g_dbus_client_unref(ad->client);
96         }
97
98         bt_ad_unref(ad->data);
99
100         g_dbus_proxy_unref(ad->proxy);
101
102         if (ad->owner)
103                 g_free(ad->owner);
104
105         if (ad->path)
106                 g_free(ad->path);
107
108         free(ad);
109 }
110
111 static gboolean advertisement_free_idle_cb(void *data)
112 {
113         advertisement_free(data);
114
115         return FALSE;
116 }
117
118 static void advertisement_release(void *data)
119 {
120         struct advertisement *ad = data;
121         DBusMessage *message;
122
123         DBG("Releasing advertisement %s, %s", ad->owner, ad->path);
124
125         message = dbus_message_new_method_call(ad->owner, ad->path,
126                                                         LE_ADVERTISEMENT_IFACE,
127                                                         "Release");
128
129         if (!message) {
130                 error("Couldn't allocate D-Bus message");
131                 return;
132         }
133
134         g_dbus_send_message(btd_get_dbus_connection(), message);
135 }
136
137 static void advertisement_destroy(void *data)
138 {
139         advertisement_release(data);
140         advertisement_free(data);
141 }
142
143 static void advertisement_remove(void *data)
144 {
145         struct advertisement *ad = data;
146         struct mgmt_cp_remove_advertising cp;
147
148         g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
149
150         cp.instance = ad->instance;
151
152         mgmt_send(ad->manager->mgmt, MGMT_OP_REMOVE_ADVERTISING,
153                         ad->manager->mgmt_index, sizeof(cp), &cp, NULL, NULL,
154                         NULL);
155
156         queue_remove(ad->manager->ads, ad);
157
158         util_clear_uid(&ad->manager->instance_bitmap, ad->instance);
159
160         g_idle_add(advertisement_free_idle_cb, ad);
161 }
162
163 static void client_disconnect_cb(DBusConnection *conn, void *user_data)
164 {
165         DBG("Client disconnected");
166
167         advertisement_remove(user_data);
168 }
169
170 static bool parse_advertising_type(GDBusProxy *proxy, uint8_t *type)
171 {
172         DBusMessageIter iter;
173         const char *msg_type;
174
175         if (!g_dbus_proxy_get_property(proxy, "Type", &iter))
176                 return false;
177
178         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
179                 return false;
180
181         dbus_message_iter_get_basic(&iter, &msg_type);
182
183         if (!g_strcmp0(msg_type, "broadcast")) {
184                 *type = AD_TYPE_BROADCAST;
185                 return true;
186         }
187
188         if (!g_strcmp0(msg_type, "peripheral")) {
189                 *type = AD_TYPE_PERIPHERAL;
190                 return true;
191         }
192
193         return false;
194 }
195
196 static bool parse_advertising_service_uuids(GDBusProxy *proxy,
197                                         struct bt_ad *data)
198 {
199         DBusMessageIter iter, ariter;
200
201         if (!g_dbus_proxy_get_property(proxy, "ServiceUUIDs", &iter))
202                 return true;
203
204         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
205                 return false;
206
207         dbus_message_iter_recurse(&iter, &ariter);
208
209         bt_ad_clear_service_uuid(data);
210
211         while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
212                 const char *uuid_str;
213                 bt_uuid_t uuid;
214
215                 dbus_message_iter_get_basic(&ariter, &uuid_str);
216
217                 DBG("Adding ServiceUUID: %s", uuid_str);
218
219                 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
220                         goto fail;
221
222                 if (!bt_ad_add_service_uuid(data, &uuid))
223                         goto fail;
224
225                 dbus_message_iter_next(&ariter);
226         }
227
228         return true;
229
230 fail:
231         bt_ad_clear_service_uuid(data);
232         return false;
233 }
234
235 static bool parse_advertising_solicit_uuids(GDBusProxy *proxy,
236                                                         struct bt_ad *data)
237 {
238         DBusMessageIter iter, ariter;
239
240         if (!g_dbus_proxy_get_property(proxy, "SolicitUUIDs", &iter))
241                 return true;
242
243         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
244                 return false;
245
246         dbus_message_iter_recurse(&iter, &ariter);
247
248         bt_ad_clear_solicit_uuid(data);
249
250         while (dbus_message_iter_get_arg_type(&ariter) == DBUS_TYPE_STRING) {
251                 const char *uuid_str;
252                 bt_uuid_t uuid;
253
254                 dbus_message_iter_get_basic(&ariter, &uuid_str);
255
256                 DBG("Adding SolicitUUID: %s", uuid_str);
257
258                 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
259                         goto fail;
260
261                 if (!bt_ad_add_solicit_uuid(data, &uuid))
262                         goto fail;
263
264                 dbus_message_iter_next(&ariter);
265         }
266
267         return true;
268
269 fail:
270         bt_ad_clear_solicit_uuid(data);
271         return false;
272 }
273
274 static bool parse_advertising_manufacturer_data(GDBusProxy *proxy,
275                                                         struct bt_ad *data)
276 {
277         DBusMessageIter iter, entries;
278
279         if (!g_dbus_proxy_get_property(proxy, "ManufacturerData", &iter))
280                 return true;
281
282         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
283                 return false;
284
285         dbus_message_iter_recurse(&iter, &entries);
286
287         bt_ad_clear_manufacturer_data(data);
288
289         while (dbus_message_iter_get_arg_type(&entries)
290                                                 == DBUS_TYPE_DICT_ENTRY) {
291                 DBusMessageIter value, entry;
292                 uint16_t manuf_id;
293                 uint8_t *manuf_data;
294                 int len;
295
296                 dbus_message_iter_recurse(&entries, &entry);
297                 dbus_message_iter_get_basic(&entry, &manuf_id);
298
299                 dbus_message_iter_next(&entry);
300                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
301                         goto fail;
302
303                 dbus_message_iter_recurse(&entry, &value);
304
305                 if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
306                         goto fail;
307
308                 dbus_message_iter_get_fixed_array(&value, &manuf_data, &len);
309
310                 DBG("Adding ManufacturerData for %04x", manuf_id);
311
312                 if (!bt_ad_add_manufacturer_data(data, manuf_id, manuf_data,
313                                                                         len))
314                         goto fail;
315
316                 dbus_message_iter_next(&entries);
317         }
318
319         return true;
320
321 fail:
322         bt_ad_clear_manufacturer_data(data);
323         return false;
324 }
325
326 static bool parse_advertising_service_data(GDBusProxy *proxy,
327                                                         struct bt_ad *data)
328 {
329         DBusMessageIter iter, entries;
330
331         if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
332                 return true;
333
334         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
335                 return false;
336
337         dbus_message_iter_recurse(&iter, &entries);
338
339         bt_ad_clear_service_data(data);
340
341         while (dbus_message_iter_get_arg_type(&entries)
342                                                 == DBUS_TYPE_DICT_ENTRY) {
343                 DBusMessageIter value, entry;
344                 const char *uuid_str;
345                 bt_uuid_t uuid;
346                 uint8_t *service_data;
347                 int len;
348
349                 dbus_message_iter_recurse(&entries, &entry);
350                 dbus_message_iter_get_basic(&entry, &uuid_str);
351
352                 if (bt_string_to_uuid(&uuid, uuid_str) < 0)
353                         goto fail;
354
355                 dbus_message_iter_next(&entry);
356                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
357                         goto fail;
358
359                 dbus_message_iter_recurse(&entry, &value);
360
361                 if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE)
362                         goto fail;
363
364                 dbus_message_iter_get_fixed_array(&value, &service_data, &len);
365
366                 DBG("Adding ServiceData for %s", uuid_str);
367
368                 if (!bt_ad_add_service_data(data, &uuid, service_data, len))
369                         goto fail;
370
371                 dbus_message_iter_next(&entries);
372         }
373
374         return true;
375
376 fail:
377         bt_ad_clear_service_data(data);
378         return false;
379 }
380
381 static bool parse_advertising_include_tx_power(GDBusProxy *proxy,
382                                                         bool *included)
383 {
384         DBusMessageIter iter;
385         dbus_bool_t b;
386
387         if (!g_dbus_proxy_get_property(proxy, "IncludeTxPower", &iter))
388                 return true;
389
390         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
391                 return false;
392
393         dbus_message_iter_get_basic(&iter, &b);
394
395         *included = b;
396
397         return true;
398 }
399
400 static void add_adverting_complete(struct advertisement *ad, uint8_t status)
401 {
402         DBusMessage *reply;
403
404         if (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);
411
412         } else
413                 reply = dbus_message_new_method_return(ad->reg);
414
415         g_dbus_send_message(btd_get_dbus_connection(), reply);
416         dbus_message_unref(ad->reg);
417         ad->reg = NULL;
418 }
419
420 static void add_advertising_callback(uint8_t status, uint16_t length,
421                                           const void *param, void *user_data)
422 {
423         struct advertisement *ad = user_data;
424         const struct mgmt_rp_add_advertising *rp = param;
425
426         if (status)
427                 goto done;
428
429         if (!param || length < sizeof(*rp)) {
430                 status = MGMT_STATUS_FAILED;
431                 goto done;
432         }
433
434         ad->instance = rp->instance;
435
436         g_dbus_client_set_disconnect_watch(ad->client, client_disconnect_cb,
437                                                                         ad);
438         DBG("Advertisement registered: %s", ad->path);
439
440 done:
441         add_adverting_complete(ad, status);
442 }
443
444 static size_t calc_max_adv_len(struct advertisement *ad, uint32_t flags)
445 {
446         size_t max = ad->manager->max_adv_len;
447
448         /*
449          * Flags which reduce the amount of space available for advertising.
450          * See doc/mgmt-api.txt
451          */
452         if (flags & MGMT_ADV_FLAG_TX_POWER)
453                 max -= 3;
454
455         if (flags & (MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
456                                                 MGMT_ADV_FLAG_MANAGED_FLAGS))
457                 max -= 3;
458
459         if (flags & MGMT_ADV_FLAG_APPEARANCE)
460                 max -= 4;
461
462         return max;
463 }
464
465 static DBusMessage *refresh_advertisement(struct advertisement *ad)
466 {
467         struct mgmt_cp_add_advertising *cp;
468         uint8_t param_len;
469         uint8_t *adv_data;
470         size_t adv_data_len;
471         uint32_t flags = 0;
472
473         DBG("Refreshing advertisement: %s", ad->path);
474
475         if (ad->type == AD_TYPE_PERIPHERAL)
476                 flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV;
477
478         if (ad->include_tx_power)
479                 flags |= MGMT_ADV_FLAG_TX_POWER;
480
481         adv_data = bt_ad_generate(ad->data, &adv_data_len);
482
483         if (!adv_data || (adv_data_len > calc_max_adv_len(ad, flags))) {
484                 error("Advertising data too long or couldn't be generated.");
485
486                 return g_dbus_create_error(ad->reg, ERROR_INTERFACE
487                                                 ".InvalidLength",
488                                                 "Advertising data too long.");
489         }
490
491         param_len = sizeof(struct mgmt_cp_add_advertising) + adv_data_len;
492
493         cp = malloc0(param_len);
494
495         if (!cp) {
496                 error("Couldn't allocate for MGMT!");
497
498                 free(adv_data);
499
500                 return btd_error_failed(ad->reg, "Failed");
501         }
502
503         cp->flags = flags;
504         cp->instance = ad->instance;
505         cp->adv_data_len = adv_data_len;
506         memcpy(cp->data, adv_data, adv_data_len);
507
508         free(adv_data);
509
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");
514
515                 free(cp);
516
517                 return btd_error_failed(ad->reg, "Failed");
518         }
519
520         free(cp);
521
522         return NULL;
523 }
524
525 static DBusMessage *parse_advertisement(struct advertisement *ad)
526 {
527         if (!parse_advertising_type(ad->proxy, &ad->type)) {
528                 error("Failed to read \"Type\" property of advertisement");
529                 goto fail;
530         }
531
532         if (!parse_advertising_service_uuids(ad->proxy, ad->data)) {
533                 error("Property \"ServiceUUIDs\" failed to parse");
534                 goto fail;
535         }
536
537         if (!parse_advertising_solicit_uuids(ad->proxy, ad->data)) {
538                 error("Property \"SolicitUUIDs\" failed to parse");
539                 goto fail;
540         }
541
542         if (!parse_advertising_manufacturer_data(ad->proxy, ad->data)) {
543                 error("Property \"ManufacturerData\" failed to parse");
544                 goto fail;
545         }
546
547         if (!parse_advertising_service_data(ad->proxy, ad->data)) {
548                 error("Property \"ServiceData\" failed to parse");
549                 goto fail;
550         }
551
552         if (!parse_advertising_include_tx_power(ad->proxy,
553                                                 &ad->include_tx_power)) {
554                 error("Property \"IncludeTxPower\" failed to parse");
555                 goto fail;
556         }
557
558         return refresh_advertisement(ad);
559
560 fail:
561         return btd_error_failed(ad->reg, "Failed to parse advertisement.");
562 }
563
564 static void advertisement_proxy_added(GDBusProxy *proxy, void *data)
565 {
566         struct advertisement *ad = data;
567         DBusMessage *reply;
568
569         reply = parse_advertisement(ad);
570         if (!reply)
571                 return;
572
573         /* Failed to publish for some reason, remove. */
574         queue_remove(ad->manager->ads, ad);
575
576         g_idle_add(advertisement_free_idle_cb, ad);
577
578         g_dbus_send_message(btd_get_dbus_connection(), reply);
579
580         dbus_message_unref(ad->reg);
581         ad->reg = NULL;
582 }
583
584 static struct advertisement *advertisement_create(DBusConnection *conn,
585                                         DBusMessage *msg, const char *path)
586 {
587         struct advertisement *ad;
588         const char *sender = dbus_message_get_sender(msg);
589
590         if (!path || !g_str_has_prefix(path, "/"))
591                 return NULL;
592
593         ad = new0(struct advertisement, 1);
594         ad->client = g_dbus_client_new_full(conn, sender, path, path);
595         if (!ad->client)
596                 goto fail;
597
598         ad->owner = g_strdup(sender);
599         if (!ad->owner)
600                 goto fail;
601
602         ad->path = g_strdup(path);
603         if (!ad->path)
604                 goto fail;
605
606         DBG("Adding proxy for %s", path);
607         ad->proxy = g_dbus_proxy_new(ad->client, path, LE_ADVERTISEMENT_IFACE);
608         if (!ad->proxy)
609                 goto fail;
610
611         g_dbus_client_set_proxy_handlers(ad->client, advertisement_proxy_added,
612                                                                 NULL, NULL, ad);
613
614         ad->reg = dbus_message_ref(msg);
615
616         ad->data = bt_ad_new();
617         if (!ad->data)
618                 goto fail;
619
620         return ad;
621
622 fail:
623         advertisement_free(ad);
624         return NULL;
625 }
626
627 static DBusMessage *register_advertisement(DBusConnection *conn,
628                                                 DBusMessage *msg,
629                                                 void *user_data)
630 {
631         struct btd_advertising *manager = user_data;
632         DBusMessageIter args;
633         struct advertisement *ad;
634         struct dbus_obj_match match;
635         uint8_t instance;
636
637         DBG("RegisterAdvertisement");
638
639         if (!dbus_message_iter_init(msg, &args))
640                 return btd_error_invalid_args(msg);
641
642         if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
643                 return btd_error_invalid_args(msg);
644
645         dbus_message_iter_get_basic(&args, &match.path);
646
647         match.owner = dbus_message_get_sender(msg);
648
649         if (queue_find(manager->ads, match_advertisement, &match))
650                 return btd_error_already_exists(msg);
651
652         instance = util_get_uid(&manager->instance_bitmap, manager->max_ads);
653         if (!instance)
654                 return btd_error_failed(msg, "Maximum advertisements reached");
655
656         dbus_message_iter_next(&args);
657
658         if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
659                 return btd_error_invalid_args(msg);
660
661         ad = advertisement_create(conn, msg, match.path);
662         if (!ad)
663                 return btd_error_failed(msg,
664                                         "Failed to register advertisement");
665
666         DBG("Registered advertisement at path %s", match.path);
667
668         ad->instance = instance;
669         ad->manager = manager;
670
671         queue_push_tail(manager->ads, ad);
672
673         return NULL;
674 }
675
676 static DBusMessage *unregister_advertisement(DBusConnection *conn,
677                                                 DBusMessage *msg,
678                                                 void *user_data)
679 {
680         struct btd_advertising *manager = user_data;
681         DBusMessageIter args;
682         struct advertisement *ad;
683         struct dbus_obj_match match;
684
685         DBG("UnregisterAdvertisement");
686
687         if (!dbus_message_iter_init(msg, &args))
688                 return btd_error_invalid_args(msg);
689
690         if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
691                 return btd_error_invalid_args(msg);
692
693         dbus_message_iter_get_basic(&args, &match.path);
694
695         match.owner = dbus_message_get_sender(msg);
696
697         ad = queue_find(manager->ads, match_advertisement, &match);
698         if (!ad)
699                 return btd_error_does_not_exist(msg);
700
701         advertisement_remove(ad);
702
703         return dbus_message_new_method_return(msg);
704 }
705
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" }),
713                                                 NULL,
714                                                 unregister_advertisement) },
715         { }
716 };
717
718 static void advertising_manager_destroy(void *user_data)
719 {
720         struct btd_advertising *manager = user_data;
721
722         queue_destroy(manager->ads, advertisement_destroy);
723
724         mgmt_unref(manager->mgmt);
725
726         free(manager);
727 }
728
729 static void read_adv_features_callback(uint8_t status, uint16_t length,
730                                         const void *param, void *user_data)
731 {
732         struct btd_advertising *manager = user_data;
733         const struct mgmt_rp_read_adv_features *feat = param;
734
735         if (status || !param) {
736                 error("Failed to read advertising features: %s (0x%02x)",
737                                                 mgmt_errstr(status), status);
738                 return;
739         }
740
741         if (length < sizeof(*feat)) {
742                 error("Wrong size of read adv features response");
743                 return;
744         }
745
746         manager->max_adv_len = feat->max_adv_data_len;
747         manager->max_ads = feat->max_instances;
748
749         if (manager->max_ads == 0)
750                 return;
751
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);
757 }
758
759 static struct btd_advertising *
760 advertising_manager_create(struct btd_adapter *adapter)
761 {
762         struct btd_advertising *manager;
763
764         manager = new0(struct btd_advertising, 1);
765         manager->adapter = adapter;
766
767         manager->mgmt = mgmt_new_default();
768
769         if (!manager->mgmt) {
770                 error("Failed to access management interface");
771                 free(manager);
772                 return NULL;
773         }
774
775         manager->mgmt_index = btd_adapter_get_index(adapter);
776
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);
782                 return NULL;
783         }
784
785         manager->ads = queue_new();
786
787         return manager;
788 }
789
790 struct btd_advertising *
791 btd_advertising_manager_new(struct btd_adapter *adapter)
792 {
793         struct btd_advertising *manager;
794
795         if (!adapter)
796                 return NULL;
797
798         manager = advertising_manager_create(adapter);
799         if (!manager)
800                 return NULL;
801
802         DBG("LE Advertising Manager created for adapter: %s",
803                                                 adapter_get_path(adapter));
804
805         return manager;
806 }
807
808 void btd_advertising_manager_destroy(struct btd_advertising *manager)
809 {
810         if (!manager)
811                 return;
812
813         g_dbus_unregister_interface(btd_get_dbus_connection(),
814                                         adapter_get_path(manager->adapter),
815                                         LE_ADVERTISING_MGR_IFACE);
816
817         advertising_manager_destroy(manager);
818 }