3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2015 Google Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library 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 GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "src/shared/ad.h"
27 #include "src/shared/queue.h"
28 #include "src/shared/util.h"
30 #define MAX_ADV_DATA_LEN 31
34 struct queue *service_uuids;
35 struct queue *manufacturer_data;
36 struct queue *solicit_uuids;
37 struct queue *service_data;
40 struct bt_ad *bt_ad_new(void)
44 ad = new0(struct bt_ad, 1);
45 ad->service_uuids = queue_new();
46 ad->manufacturer_data = queue_new();
47 ad->solicit_uuids = queue_new();
48 ad->service_data = queue_new();
53 struct bt_ad *bt_ad_ref(struct bt_ad *ad)
62 static void uuid_destroy(void *data)
64 struct bt_ad_service_data *uuid_data = data;
66 free(uuid_data->data);
70 static bool uuid_data_match(const void *data, const void *elem)
72 const struct bt_ad_service_data *uuid_data = elem;
73 const bt_uuid_t *uuid = data;
75 return !bt_uuid_cmp(&uuid_data->uuid, uuid);
78 static void manuf_destroy(void *data)
80 struct bt_ad_manufacturer_data *manuf = data;
86 static bool manuf_match(const void *data, const void *elem)
88 const struct bt_ad_manufacturer_data *manuf = elem;
89 uint16_t manuf_id = PTR_TO_UINT(elem);
91 return manuf->manufacturer_id == manuf_id;
94 void bt_ad_unref(struct bt_ad *ad)
99 if (__sync_sub_and_fetch(&ad->ref_count, 1))
102 queue_destroy(ad->service_uuids, free);
104 queue_destroy(ad->manufacturer_data, manuf_destroy);
106 queue_destroy(ad->solicit_uuids, free);
108 queue_destroy(ad->service_data, uuid_destroy);
113 static size_t uuid_list_length(struct queue *uuid_queue)
115 bool uuid16_included = false;
116 bool uuid32_included = false;
117 bool uuid128_included = false;
119 const struct queue_entry *entry;
121 entry = queue_get_entries(uuid_queue);
124 bt_uuid_t *uuid = entry->data;
126 length += bt_uuid_len(uuid);
128 if (uuid->type == BT_UUID16)
129 uuid16_included = true;
130 else if (uuid->type == BT_UUID32)
131 uuid32_included = true;
133 uuid128_included = true;
144 if (uuid128_included)
150 static size_t mfg_data_length(struct queue *manuf_data)
153 const struct queue_entry *entry;
155 entry = queue_get_entries(manuf_data);
158 struct bt_ad_manufacturer_data *data = entry->data;
160 length += 2 + sizeof(uint16_t) + data->len;
168 static size_t uuid_data_length(struct queue *uuid_data)
171 const struct queue_entry *entry;
173 entry = queue_get_entries(uuid_data);
176 struct bt_ad_service_data *data = entry->data;
178 length += 2 + bt_uuid_len(&data->uuid) + data->len;
186 static size_t calculate_length(struct bt_ad *ad)
190 length += uuid_list_length(ad->service_uuids);
192 length += uuid_list_length(ad->solicit_uuids);
194 length += mfg_data_length(ad->manufacturer_data);
196 length += uuid_data_length(ad->service_data);
201 static void serialize_uuids(struct queue *uuids, uint8_t uuid_type,
202 uint8_t ad_type, uint8_t *buf,
205 const struct queue_entry *entry = queue_get_entries(uuids);
207 uint8_t length_pos = 0;
210 bt_uuid_t *uuid = entry->data;
212 if (uuid->type == uuid_type) {
214 length_pos = (*pos)++;
215 buf[(*pos)++] = ad_type;
219 if (uuid_type != BT_UUID32)
220 bt_uuid_to_le(uuid, buf + *pos);
222 bt_put_le32(uuid->value.u32, buf + *pos);
224 *pos += bt_uuid_len(uuid);
231 buf[length_pos] = *pos - length_pos - 1;
234 static void serialize_service_uuids(struct queue *uuids, uint8_t *buf,
237 serialize_uuids(uuids, BT_UUID16, EIR_UUID16_ALL, buf, pos);
239 serialize_uuids(uuids, BT_UUID32, EIR_UUID32_ALL, buf, pos);
241 serialize_uuids(uuids, BT_UUID128, EIR_UUID128_ALL, buf, pos);
244 static void serialize_solicit_uuids(struct queue *uuids, uint8_t *buf,
247 serialize_uuids(uuids, BT_UUID16, EIR_SOLICIT16, buf, pos);
249 serialize_uuids(uuids, BT_UUID32, EIR_SOLICIT32, buf, pos);
251 serialize_uuids(uuids, BT_UUID128, EIR_SOLICIT128, buf, pos);
254 static void serialize_manuf_data(struct queue *manuf_data, uint8_t *buf,
257 const struct queue_entry *entry = queue_get_entries(manuf_data);
260 struct bt_ad_manufacturer_data *data = entry->data;
262 buf[(*pos)++] = data->len + 2 + 1;
264 buf[(*pos)++] = EIR_MANUFACTURER_DATA;
266 bt_put_le16(data->manufacturer_id, buf + (*pos));
270 memcpy(buf + *pos, data->data, data->len);
278 static void serialize_service_data(struct queue *service_data, uint8_t *buf,
281 const struct queue_entry *entry = queue_get_entries(service_data);
284 struct bt_ad_service_data *data = entry->data;
285 int uuid_len = bt_uuid_len(&data->uuid);
287 buf[(*pos)++] = uuid_len + data->len + 1;
291 buf[(*pos)++] = EIR_SVC_DATA16;
294 buf[(*pos)++] = EIR_SVC_DATA32;
297 buf[(*pos)++] = EIR_SVC_DATA128;
302 bt_uuid_to_le(&data->uuid, buf + *pos);
304 bt_put_le32(data->uuid.value.u32, buf + *pos);
308 memcpy(buf + *pos, data->data, data->len);
316 uint8_t *bt_ad_generate(struct bt_ad *ad, size_t *length)
324 *length = calculate_length(ad);
326 if (*length > MAX_ADV_DATA_LEN)
329 adv_data = malloc0(*length);
333 serialize_service_uuids(ad->service_uuids, adv_data, &pos);
335 serialize_solicit_uuids(ad->solicit_uuids, adv_data, &pos);
337 serialize_manuf_data(ad->manufacturer_data, adv_data, &pos);
339 serialize_service_data(ad->service_data, adv_data, &pos);
344 static bool queue_add_uuid(struct queue *queue, const bt_uuid_t *uuid)
351 new_uuid = new0(bt_uuid_t, 1);
355 if (queue_push_tail(queue, new_uuid))
363 static bool uuid_match(const void *data, const void *elem)
365 const bt_uuid_t *match_uuid = data;
366 const bt_uuid_t *uuid = elem;
368 return bt_uuid_cmp(match_uuid, uuid);
371 static bool queue_remove_uuid(struct queue *queue, bt_uuid_t *uuid)
378 removed = queue_remove_if(queue, uuid_match, uuid);
388 bool bt_ad_add_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid)
393 return queue_add_uuid(ad->service_uuids, uuid);
396 bool bt_ad_remove_service_uuid(struct bt_ad *ad, bt_uuid_t *uuid)
401 return queue_remove_uuid(ad->service_uuids, uuid);
404 void bt_ad_clear_service_uuid(struct bt_ad *ad)
409 queue_remove_all(ad->service_uuids, NULL, NULL, free);
412 static bool manufacturer_id_data_match(const void *data, const void *user_data)
414 const struct bt_ad_manufacturer_data *m = data;
415 uint16_t id = PTR_TO_UINT(user_data);
417 return m->manufacturer_id == id;
420 bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id,
421 void *data, size_t len)
423 struct bt_ad_manufacturer_data *new_data;
428 if (len > (MAX_ADV_DATA_LEN - 2 - sizeof(uint16_t)))
431 new_data = queue_find(ad->manufacturer_data, manufacturer_id_data_match,
432 UINT_TO_PTR(manufacturer_id));
434 if (new_data->len == len && !memcmp(new_data->data, data, len))
436 new_data->data = realloc(new_data->data, len);
437 memcpy(new_data->data, data, len);
442 new_data = new0(struct bt_ad_manufacturer_data, 1);
443 new_data->manufacturer_id = manufacturer_id;
445 new_data->data = malloc(len);
446 if (!new_data->data) {
451 memcpy(new_data->data, data, len);
455 if (queue_push_tail(ad->manufacturer_data, new_data))
458 manuf_destroy(new_data);
463 static bool manufacturer_data_match(const void *data, const void *user_data)
465 const struct bt_ad_manufacturer_data *m1 = data;
466 const struct bt_ad_manufacturer_data *m2 = user_data;
468 if (m1->manufacturer_id != m2->manufacturer_id)
471 if (m1->len != m2->len)
474 return !memcmp(m1->data, m2->data, m1->len);
477 bool bt_ad_has_manufacturer_data(struct bt_ad *ad,
478 const struct bt_ad_manufacturer_data *data)
484 return !queue_isempty(ad->manufacturer_data);
486 return queue_find(ad->manufacturer_data, manufacturer_data_match, data);
489 void bt_ad_foreach_manufacturer_data(struct bt_ad *ad, bt_ad_func_t func,
495 queue_foreach(ad->manufacturer_data, func, user_data);
498 bool bt_ad_remove_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id)
500 struct bt_ad_manufacturer_data *data;
505 data = queue_remove_if(ad->manufacturer_data, manuf_match,
506 UINT_TO_PTR(manufacturer_id));
516 void bt_ad_clear_manufacturer_data(struct bt_ad *ad)
521 queue_remove_all(ad->manufacturer_data, NULL, NULL, manuf_destroy);
524 bool bt_ad_add_solicit_uuid(struct bt_ad *ad, const bt_uuid_t *uuid)
529 return queue_add_uuid(ad->solicit_uuids, uuid);
532 bool bt_ad_remove_solicit_uuid(struct bt_ad *ad, bt_uuid_t *uuid)
537 return queue_remove_uuid(ad->solicit_uuids, uuid);
540 void bt_ad_clear_solicit_uuid(struct bt_ad *ad)
545 queue_remove_all(ad->solicit_uuids, NULL, NULL, free);
549 static bool service_uuid_match(const void *data, const void *user_data)
551 const struct bt_ad_service_data *s = data;
552 const bt_uuid_t *uuid = user_data;
554 return !bt_uuid_cmp(&s->uuid, uuid);
557 bool bt_ad_add_service_data(struct bt_ad *ad, const bt_uuid_t *uuid, void *data,
560 struct bt_ad_service_data *new_data;
565 if (len > (MAX_ADV_DATA_LEN - 2 - (size_t)bt_uuid_len(uuid)))
568 new_data = queue_find(ad->service_data, service_uuid_match, uuid);
570 if (new_data->len == len && !memcmp(new_data->data, data, len))
572 new_data->data = realloc(new_data->data, len);
573 memcpy(new_data->data, data, len);
578 new_data = new0(struct bt_ad_service_data, 1);
580 new_data->uuid = *uuid;
582 new_data->data = malloc(len);
583 if (!new_data->data) {
588 memcpy(new_data->data, data, len);
592 if (queue_push_tail(ad->service_data, new_data))
595 uuid_destroy(new_data);
600 static bool service_data_match(const void *data, const void *user_data)
602 const struct bt_ad_service_data *s1 = data;
603 const struct bt_ad_service_data *s2 = user_data;
605 if (bt_uuid_cmp(&s1->uuid, &s2->uuid))
608 if (s1->len != s2->len)
611 return !memcmp(s1->data, s2->data, s1->len);
614 bool bt_ad_has_service_data(struct bt_ad *ad,
615 const struct bt_ad_service_data *data)
621 return !queue_isempty(ad->service_data);
623 return queue_find(ad->service_data, service_data_match, data);
626 void bt_ad_foreach_service_data(struct bt_ad *ad, bt_ad_func_t func,
632 queue_foreach(ad->service_data, func, user_data);
635 bool bt_ad_remove_service_data(struct bt_ad *ad, bt_uuid_t *uuid)
637 struct bt_ad_service_data *data;
642 data = queue_remove_if(ad->service_data, uuid_data_match, uuid);
652 void bt_ad_clear_service_data(struct bt_ad *ad)
657 queue_remove_all(ad->service_data, NULL, NULL, uuid_destroy);