ble_gatt_client
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
gatt-helpers.c
Go to the documentation of this file.
1 
10 /*
11  *
12  * BlueZ - Bluetooth protocol stack for Linux
13  *
14  * Copyright (C) 2014 Google Inc.
15  *
16  *
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  *
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25  * Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30  *
31  */
32 
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include "queue.h"
39 #include "att.h"
40 #include "bluetooth.h"
41 #include "uuid.h"
42 #include "gatt-helpers.h"
43 #include "util.h"
44 
45 #ifndef MIN
46 #define MIN(a, b) ((a) < (b) ? (a) : (b))
47 #endif
48 
50  uint8_t opcode;
51  void *pdu;
52  uint16_t pdu_len;
53  uint16_t data_len;
54 
55  void *op; /* Discovery operation data */
56 
58 };
59 
60 static struct bt_gatt_result *result_create(uint8_t opcode, const void *pdu,
61  uint16_t pdu_len,
62  uint16_t data_len,
63  void *op)
64 {
65  struct bt_gatt_result *result;
66 
67  result = new0(struct bt_gatt_result, 1);
68  if (!result)
69  return NULL;
70 
71  result->pdu = malloc(pdu_len);
72  if (!result->pdu) {
73  free(result);
74  return NULL;
75  }
76 
77  result->opcode = opcode;
78  result->pdu_len = pdu_len;
79  result->data_len = data_len;
80  result->op = op;
81 
82  memcpy(result->pdu, pdu, pdu_len);
83 
84  return result;
85 }
86 
87 static void result_destroy(struct bt_gatt_result *result)
88 {
89  struct bt_gatt_result *next;
90 
91  while (result) {
92  next = result->next;
93 
94  free(result->pdu);
95  free(result);
96 
97  result = next;
98  }
99 }
100 
101 static unsigned int result_element_count(struct bt_gatt_result *result)
102 {
103  unsigned int count = 0;
104  struct bt_gatt_result *cur;
105 
106  cur = result;
107 
108  while (cur) {
109  count += cur->pdu_len / cur->data_len;
110  cur = cur->next;
111  }
112 
113  return count;
114 }
115 
116 unsigned int bt_gatt_result_service_count(struct bt_gatt_result *result)
117 {
118  if (!result)
119  return 0;
120 
121  if (result->opcode != BT_ATT_OP_READ_BY_GRP_TYPE_RSP &&
123  return 0;
124 
125  return result_element_count(result);
126 }
127 
129 {
130  if (!result)
131  return 0;
132 
133  if (result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
134  return 0;
135 
136  /*
137  * Data length contains 7 or 21 octets:
138  * 2 octets: Attribute handle
139  * 1 octet: Characteristic properties
140  * 2 octets: Characteristic value handle
141  * 2 or 16 octets: characteristic UUID
142  */
143  if (result->data_len != 21 && result->data_len != 7)
144  return 0;
145 
146  return result_element_count(result);
147 }
148 
150 {
151  if (!result)
152  return 0;
153 
154  if (result->opcode != BT_ATT_OP_FIND_INFO_RSP)
155  return 0;
156 
157  return result_element_count(result);
158 }
159 
160 unsigned int bt_gatt_result_included_count(struct bt_gatt_result *result)
161 {
162  struct bt_gatt_result *cur;
163  unsigned int count = 0;
164 
165  if (!result)
166  return 0;
167 
168  if (result->opcode != BT_ATT_OP_READ_BY_TYPE_RSP)
169  return 0;
170 
171  /*
172  * Data length can be of length 6 or 8 octets:
173  * 2 octets - include service handle
174  * 2 octets - start handle of included service
175  * 2 octets - end handle of included service
176  * 2 octets (optionally) - 16 bit Bluetooth UUID
177  */
178  if (result->data_len != 6 && result->data_len != 8)
179  return 0;
180 
181  for (cur = result; cur; cur = cur->next)
183  count += cur->pdu_len / cur->data_len;
184 
185  return count;
186 }
187 
188 bool bt_gatt_iter_init(struct bt_gatt_iter *iter, struct bt_gatt_result *result)
189 {
190  if (!iter || !result)
191  return false;
192 
193  iter->result = result;
194  iter->pos = 0;
195 
196  return true;
197 }
198 
199 static const uint8_t bt_base_uuid[16] = {
200  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
201  0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
202 };
203 
204 static bool convert_uuid_le(const uint8_t *src, size_t len, uint8_t dst[16])
205 {
206  if (len == 16) {
207  bswap_128(src, dst);
208  return true;
209  }
210 
211  if (len != 2)
212  return false;
213 
214  memcpy(dst, bt_base_uuid, sizeof(bt_base_uuid));
215  dst[2] = src[1];
216  dst[3] = src[0];
217 
218  return true;
219 }
220 
222  struct bt_att *att;
223  unsigned int id;
224  uint16_t start_handle;
225  uint16_t end_handle;
228  uint16_t service_type;
232  void *user_data;
234 };
235 
236 static struct bt_gatt_result *result_append(uint8_t opcode, const void *pdu,
237  uint16_t pdu_len,
238  uint16_t data_len,
239  struct bt_gatt_request *op)
240 {
241  struct bt_gatt_result *result;
242 
243  result = result_create(opcode, pdu, pdu_len, data_len, op);
244  if (!result)
245  return NULL;
246 
247  if (!op->result_head)
248  op->result_head = op->result_tail = result;
249  else {
250  op->result_tail->next = result;
251  op->result_tail = result;
252  }
253 
254  return result;
255 }
256 
258  uint16_t *handle, uint16_t *start_handle,
259  uint16_t *end_handle, uint8_t uuid[16])
260 {
261  struct bt_gatt_result *read_result;
262  struct bt_gatt_request *op;
263  const void *pdu_ptr;
264  int i = 0;
265 
266  if (!iter || !iter->result || !handle || !start_handle || !end_handle
267  || !uuid)
268  return false;
269 
270 
272  return false;
273 
274  /* UUID in discovery_op is set in read_by_type and service_discovery */
275  op = iter->result->op;
276  if (op->uuid.type != BT_UUID_UNSPEC)
277  return false;
278  /*
279  * iter->result points to READ_BY_TYPE_RSP with data length containing:
280  * 2 octets - include service handle
281  * 2 octets - start handle of included service
282  * 2 octets - end handle of included service
283  * optional 2 octets - Bluetooth UUID
284  */
285  if (iter->result->data_len != 8 && iter->result->data_len != 6)
286  return false;
287 
288  pdu_ptr = iter->result->pdu + iter->pos;
289 
290  /* This result contains 16 bit UUID */
291  if (iter->result->data_len == 8) {
292  *handle = get_le16(pdu_ptr);
293  *start_handle = get_le16(pdu_ptr + 2);
294  *end_handle = get_le16(pdu_ptr + 4);
295  convert_uuid_le(pdu_ptr + 6, 2, uuid);
296 
297  iter->pos += iter->result->data_len;
298 
299  if (iter->pos == iter->result->pdu_len) {
300  iter->result = iter->result->next;
301  iter->pos = 0;
302  }
303 
304  return true;
305  }
306 
307  *handle = get_le16(pdu_ptr);
308  *start_handle = get_le16(pdu_ptr + 2);
309  *end_handle = get_le16(pdu_ptr + 4);
310  read_result = iter->result;
311 
312  /*
313  * Find READ_RSP with include service UUID.
314  * If number of current data set in READ_BY_TYPE_RSP is n, then we must
315  * go to n'th PDU next to current item->result
316  */
317  for (read_result = read_result->next; read_result; i++) {
318  if (i >= (iter->pos / iter->result->data_len))
319  break;
320 
321  read_result = read_result->next;
322  }
323 
324  if (!read_result)
325  return false;
326 
327  convert_uuid_le(read_result->pdu, read_result->data_len, uuid);
328  iter->pos += iter->result->data_len;
329  if (iter->pos == iter->result->pdu_len) {
330  iter->result = read_result->next;
331  iter->pos = 0;
332  }
333 
334  return true;
335 }
336 
338  uint16_t *start_handle, uint16_t *end_handle,
339  uint8_t uuid[16])
340 {
341  struct bt_gatt_request *op;
342  const void *pdu_ptr;
343  bt_uuid_t tmp;
344 
345  if (!iter || !iter->result || !start_handle || !end_handle || !uuid)
346  return false;
347 
348  op = iter->result->op;
349  pdu_ptr = iter->result->pdu + iter->pos;
350 
351  switch (iter->result->opcode) {
353  *start_handle = get_le16(pdu_ptr);
354  *end_handle = get_le16(pdu_ptr + 2);
355  convert_uuid_le(pdu_ptr + 4, iter->result->data_len - 4, uuid);
356  break;
358  *start_handle = get_le16(pdu_ptr);
359  *end_handle = get_le16(pdu_ptr + 2);
360 
361  bt_uuid_to_uuid128(&op->uuid, &tmp);
362  memcpy(uuid, tmp.value.u128.data, 16);
363  break;
364  default:
365  return false;
366  }
367 
368 
369  iter->pos += iter->result->data_len;
370  if (iter->pos == iter->result->pdu_len) {
371  iter->result = iter->result->next;
372  iter->pos = 0;
373  }
374 
375  return true;
376 }
377 
379  uint16_t *start_handle, uint16_t *end_handle,
380  uint16_t *value_handle, uint8_t *properties,
381  uint8_t uuid[16])
382 {
383  struct bt_gatt_request *op;
384  const void *pdu_ptr;
385 
386  if (!iter || !iter->result || !start_handle || !end_handle ||
387  !value_handle || !properties || !uuid)
388  return false;
389 
391  return false;
392 
393  /* UUID in discovery_op is set in read_by_type and service_discovery */
394  op = iter->result->op;
395  if (op->uuid.type != BT_UUID_UNSPEC)
396  return false;
397  /*
398  * Data length contains 7 or 21 octets:
399  * 2 octets: Attribute handle
400  * 1 octet: Characteristic properties
401  * 2 octets: Characteristic value handle
402  * 2 or 16 octets: characteristic UUID
403  */
404  if (iter->result->data_len != 21 && iter->result->data_len != 7)
405  return false;
406 
407  pdu_ptr = iter->result->pdu + iter->pos;
408 
409  *start_handle = get_le16(pdu_ptr);
410  *properties = ((uint8_t *) pdu_ptr)[2];
411  *value_handle = get_le16(pdu_ptr + 3);
412  convert_uuid_le(pdu_ptr + 5, iter->result->data_len - 5, uuid);
413 
414  iter->pos += iter->result->data_len;
415  if (iter->pos == iter->result->pdu_len) {
416  iter->result = iter->result->next;
417  iter->pos = 0;
418  }
419 
420  if (!iter->result) {
421  *end_handle = op->end_handle;
422  return true;
423  }
424 
425  *end_handle = get_le16(iter->result->pdu + iter->pos) - 1;
426 
427  return true;
428 }
429 
430 bool bt_gatt_iter_next_descriptor(struct bt_gatt_iter *iter, uint16_t *handle,
431  uint8_t uuid[16])
432 {
433  const void *pdu_ptr;
434 
435  if (!iter || !iter->result || !handle || !uuid)
436  return false;
437 
438  if (iter->result->opcode != BT_ATT_OP_FIND_INFO_RSP)
439  return false;
440 
441  pdu_ptr = iter->result->pdu + iter->pos;
442 
443  *handle = get_le16(pdu_ptr);
444  convert_uuid_le(pdu_ptr + 2, iter->result->data_len - 2, uuid);
445 
446  iter->pos += iter->result->data_len;
447  if (iter->pos == iter->result->pdu_len) {
448  iter->result = iter->result->next;
449  iter->pos = 0;
450  }
451 
452  return true;
453 }
454 
456  uint16_t *handle, uint16_t *length,
457  const uint8_t **value)
458 {
459  struct bt_gatt_request *op;
460  const void *pdu_ptr;
461 
462  if (!iter || !iter->result || !handle || !length || !value)
463  return false;
464 
466  return false;
467 
468  /*
469  * Check if UUID is set, otherwise results can contain characteristic
470  * discovery service or included service discovery results
471  */
472  op = iter->result->op;
473  if (op->uuid.type == BT_UUID_UNSPEC)
474  return false;
475 
476  pdu_ptr = iter->result->pdu + iter->pos;
477 
478  *handle = get_le16(pdu_ptr);
479  *length = iter->result->data_len - 2;
480  *value = pdu_ptr + 2;
481 
482  iter->pos += iter->result->data_len;
483  if (iter->pos == iter->result->pdu_len) {
484  iter->result = iter->result->next;
485  iter->pos = 0;
486  }
487 
488  return true;
489 }
490 
491 struct mtu_op {
492  struct bt_att *att;
493  uint16_t client_rx_mtu;
495  void *user_data;
497 };
498 
499 static void destroy_mtu_op(void *user_data)
500 {
501  struct mtu_op *op = user_data;
502 
503  if (op->destroy)
504  op->destroy(op->user_data);
505 
506  free(op);
507 }
508 
509 static uint8_t process_error(const void *pdu, uint16_t length)
510 {
511  const struct bt_att_pdu_error_rsp *error_pdu;
512 
513  if (!pdu || length != sizeof(struct bt_att_pdu_error_rsp))
514  return 0;
515 
516  error_pdu = pdu;
517 
518  return error_pdu->ecode;
519 }
520 
528 static void mtu_cb(uint8_t opcode, const void *pdu, uint16_t length,
529  void *user_data)
530 {
531  struct mtu_op *op = user_data;
532  bool success = true;
533  uint8_t att_ecode = 0;
534  uint16_t server_rx_mtu;
535 
536  if (opcode == BT_ATT_OP_ERROR_RSP) {
537  success = false;
538  att_ecode = process_error(pdu, length);
539  goto done;
540  }
541 
542  if (opcode != BT_ATT_OP_MTU_RSP || !pdu || length != 2) {
543  success = false;
544  goto done;
545  }
546 
547  server_rx_mtu = get_le16(pdu);
548  bt_att_set_mtu(op->att, MIN(op->client_rx_mtu, server_rx_mtu));
549 
550 done:
551  if (op->callback)
552  op->callback(success, att_ecode, op->user_data);
553 }
554 
582 unsigned int bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
584  void *user_data,
586 {
587  struct mtu_op *op;
588  uint8_t pdu[2];
589  unsigned int id;
590 
591  if (!att || !client_rx_mtu)
592  return false;
593 
594  op = new0(struct mtu_op, 1);
595  if (!op)
596  return false;
597 
598  op->att = att;
600  op->callback = callback;
601  op->user_data = user_data;
602  op->destroy = destroy;
603 
604  put_le16(client_rx_mtu, pdu);
605 
606  id = bt_att_send(att, BT_ATT_OP_MTU_REQ, pdu, sizeof(pdu), mtu_cb, op,
608  if (!id)
609  free(op);
610 
611  return id;
612 }
613 
614 static inline int get_uuid_len(const bt_uuid_t *uuid)
615 {
616  if (!uuid)
617  return 0;
618 
619  return (uuid->type == BT_UUID16) ? 2 : 16;
620 }
621 
623 {
624  if (!req)
625  return NULL;
626 
627  __sync_fetch_and_add(&req->ref_count, 1);
628 
629  return req;
630 }
631 
633 {
634  if (!req)
635  return;
636 
637  if (__sync_sub_and_fetch(&req->ref_count, 1))
638  return;
639 
641 
642  if (req->destroy)
643  req->destroy(req->user_data);
644 
646 
647  free(req);
648 }
649 
651 {
652  if (!req)
653  return;
654 
655  if (!req->id)
656  return;
657 
658  bt_att_cancel(req->att, req->id);
659  req->id = 0;
660 }
661 
662 static void async_req_unref(void *data)
663 {
664  struct bt_gatt_request *req = data;
665 
667 }
668 
669 static void discovery_op_complete(struct bt_gatt_request *op, bool success,
670  uint8_t ecode)
671 {
672  /* Reset success if there is some result to report */
673  if (ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND && op->result_head)
674  success = true;
675 
676  if (op->callback)
677  op->callback(success, ecode, success ? op->result_head : NULL,
678  op->user_data);
679 
680  if (!op->id)
681  async_req_unref(op);
682  else
683  op->id = 0;
684 
685 }
686 
687 static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
688  uint16_t length, void *user_data)
689 {
690  struct bt_gatt_request *op = user_data;
691  bool success;
692  uint8_t att_ecode = 0;
693  struct bt_gatt_result *cur_result;
694  size_t data_length;
695  size_t list_length;
696  uint16_t last_end;
697 
698  if (opcode == BT_ATT_OP_ERROR_RSP) {
699  success = false;
700  att_ecode = process_error(pdu, length);
701  goto done;
702  }
703 
704  /* PDU must contain at least the following (sans opcode):
705  * - Attr Data Length (1 octet)
706  * - Attr Data List (at least 6 octets):
707  * -- 2 octets: Attribute handle
708  * -- 2 octets: End group handle
709  * -- 2 or 16 octets: service UUID
710  */
711  if (opcode != BT_ATT_OP_READ_BY_GRP_TYPE_RSP || !pdu || length < 7) {
712  success = false;
713  goto done;
714  }
715 
716  data_length = ((uint8_t *) pdu)[0];
717  list_length = length - 1;
718 
719  if ((data_length != 6 && data_length != 20) ||
720  (list_length % data_length)) {
721  success = false;
722  goto done;
723  }
724 
725  /* PDU is correctly formatted. Get the last end handle to process the
726  * next request and store the PDU.
727  */
728  cur_result = result_append(opcode, pdu + 1, list_length, data_length,
729  op);
730  if (!cur_result) {
731  success = false;
732  goto done;
733  }
734 
735  last_end = get_le16(pdu + length - data_length + 2);
736 
737  /*
738  * If last handle is lower from previous start handle then it is smth
739  * wrong. Let's stop search, otherwise we might enter infinite loop.
740  */
741  if (last_end < op->start_handle) {
742  success = false;
743  goto done;
744  }
745 
746  op->start_handle = last_end + 1;
747 
748  if (last_end < op->end_handle) {
749  uint8_t pdu[6];
750 
751  put_le16(op->start_handle, pdu);
752  put_le16(op->end_handle, pdu + 2);
753  put_le16(op->service_type, pdu + 4);
754 
756  pdu, sizeof(pdu),
760  if (op->id)
761  return;
762 
763  success = false;
764  goto done;
765  }
766 
767  /* Some devices incorrectly return 0xffff as the end group handle when
768  * the read-by-group-type request is performed within a smaller range.
769  * Manually set the end group handle that we report in the result to the
770  * end handle in the original request.
771  */
772  if (last_end == 0xffff && last_end != op->end_handle)
773  put_le16(op->end_handle,
774  cur_result->pdu + length - data_length + 1);
775 
776  success = true;
777 
778 done:
779  discovery_op_complete(op, success, att_ecode);
780 }
781 
782 static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
783  uint16_t length, void *user_data)
784 {
785  struct bt_gatt_request *op = user_data;
786  bool success;
787  uint8_t att_ecode = 0;
788  uint16_t last_end;
789 
790  if (opcode == BT_ATT_OP_ERROR_RSP) {
791  success = false;
792  att_ecode = process_error(pdu, length);
793  goto done;
794  }
795 
796  /* PDU must contain 4 bytes and it must be a multiple of 4, where each
797  * 4 bytes contain the 16-bit attribute and group end handles.
798  */
799  if (opcode != BT_ATT_OP_FIND_BY_TYPE_VAL_RSP || !pdu || !length ||
800  length % 4) {
801  success = false;
802  goto done;
803  }
804 
805  if (!result_append(opcode, pdu, length, 4, op)) {
806  success = false;
807  goto done;
808  }
809 
810  /*
811  * Each data set contains:
812  * 2 octets with start handle
813  * 2 octets with end handle
814  * last_end is end handle of last data set
815  */
816  last_end = get_le16(pdu + length - 2);
817 
818  /*
819  * If last handle is lower from previous start handle then it is smth
820  * wrong. Let's stop search, otherwise we might enter infinite loop.
821  */
822  if (last_end < op->start_handle) {
823  success = false;
824  goto done;
825  }
826 
827  op->start_handle = last_end + 1;
828 
829  if (last_end < op->end_handle) {
830  uint8_t pdu[6 + get_uuid_len(&op->uuid)];
831 
832  put_le16(op->start_handle, pdu);
833  put_le16(op->end_handle, pdu + 2);
834  put_le16(op->service_type, pdu + 4);
835  bt_uuid_to_le(&op->uuid, pdu + 6);
836 
838  pdu, sizeof(pdu),
842  if (op->id)
843  return;
844 
845  success = false;
846  goto done;
847  }
848 
849  success = false;
850 
851 done:
852  discovery_op_complete(op, success, att_ecode);
853 }
854 
856  bt_uuid_t *uuid,
857  uint16_t start, uint16_t end,
859  void *user_data,
861  bool primary)
862 {
863  struct bt_gatt_request *op;
864 
865  if (!att)
866  return NULL;
867 
868  op = new0(struct bt_gatt_request, 1);
869  if (!op)
870  return NULL;
871 
872  op->att = att;
873  op->start_handle = start;
874  op->end_handle = end;
875  op->callback = callback;
876  op->user_data = user_data;
877  op->destroy = destroy;
878  /* set service uuid to primary or secondary */
880 
881  /* If UUID is NULL, then discover all primary services */
882  if (!uuid) {
883  uint8_t pdu[6];
884 
885  put_le16(start, pdu);
886  put_le16(end, pdu + 2);
887  put_le16(op->service_type, pdu + 4);
888 
890  pdu, sizeof(pdu),
894  } else {
895  uint8_t pdu[6 + get_uuid_len(uuid)];
896 
897  if (uuid->type == BT_UUID_UNSPEC) {
898  free(op);
899  return NULL;
900  }
901 
902  /* Discover by UUID */
903  op->uuid = *uuid;
904 
905  put_le16(start, pdu);
906  put_le16(end, pdu + 2);
907  put_le16(op->service_type, pdu + 4);
908  bt_uuid_to_le(&op->uuid, pdu + 6);
909 
911  pdu, sizeof(pdu),
915  }
916 
917  if (!op->id) {
918  free(op);
919  return NULL;
920  }
921 
922  return bt_gatt_request_ref(op);
923 }
924 
926  struct bt_att *att, bt_uuid_t *uuid,
928  void *user_data,
930 {
931  return bt_gatt_discover_primary_services(att, uuid, 0x0001, 0xffff,
932  callback, user_data,
933  destroy);
934 }
935 
937  struct bt_att *att, bt_uuid_t *uuid,
938  uint16_t start, uint16_t end,
940  void *user_data,
942 {
943  return discover_services(att, uuid, start, end, callback, user_data,
944  destroy, true);
945 }
946 
948  struct bt_att *att, bt_uuid_t *uuid,
949  uint16_t start, uint16_t end,
951  void *user_data,
953 {
954  return discover_services(att, uuid, start, end, callback, user_data,
955  destroy, false);
956 }
957 
961  int pos;
963 };
964 
966 {
967  struct read_incl_data *data;
968 
969  data = new0(struct read_incl_data, 1);
970  if (!data)
971  return NULL;
972 
973  data->op = bt_gatt_request_ref(res->op);
974  data->result = res;
975 
976  return data;
977 };
978 
979 static struct read_incl_data *read_included_ref(struct read_incl_data *data)
980 {
981  __sync_fetch_and_add(&data->ref_count, 1);
982 
983  return data;
984 }
985 
986 static void read_included_unref(void *data)
987 {
988  struct read_incl_data *read_data = data;
989 
990  if (__sync_sub_and_fetch(&read_data->ref_count, 1))
991  return;
992 
993  async_req_unref(read_data->op);
994 
995  free(read_data);
996 }
997 
998 static void discover_included_cb(uint8_t opcode, const void *pdu,
999  uint16_t length, void *user_data);
1000 
1001 static void read_included_cb(uint8_t opcode, const void *pdu,
1002  uint16_t length, void *user_data)
1003 {
1004  struct read_incl_data *data = user_data;
1005  struct bt_gatt_request *op = data->op;
1006  uint8_t att_ecode = 0;
1007  uint8_t read_pdu[2];
1008  bool success;
1009 
1010  if (opcode == BT_ATT_OP_ERROR_RSP) {
1011  success = false;
1012  att_ecode = process_error(pdu, length);
1013  goto done;
1014  }
1015 
1016  if (opcode != BT_ATT_OP_READ_RSP || (!pdu && length)) {
1017  success = false;
1018  goto done;
1019  }
1020 
1021  /*
1022  * UUID should be in 128 bit format, as it couldn't be read in
1023  * READ_BY_TYPE request
1024  */
1025  if (length != 16) {
1026  success = false;
1027  goto done;
1028  }
1029 
1030  if (!result_append(opcode, pdu, length, length, op)) {
1031  success = false;
1032  goto done;
1033  }
1034 
1035  if (data->pos == data->result->pdu_len) {
1036  uint16_t last_handle;
1037  uint8_t pdu[6];
1038 
1039  last_handle = get_le16(data->result->pdu + data->pos -
1040  data->result->data_len);
1041  if (last_handle == op->end_handle) {
1042  success = true;
1043  goto done;
1044  }
1045 
1046  put_le16(last_handle + 1, pdu);
1047  put_le16(op->end_handle, pdu + 2);
1048  put_le16(GATT_INCLUDE_UUID, pdu + 4);
1049 
1051  pdu, sizeof(pdu),
1053  bt_gatt_request_ref(op),
1054  async_req_unref);
1055  if (op->id)
1056  return;
1057 
1058  success = false;
1059  goto done;
1060  }
1061 
1062  memcpy(read_pdu, data->result->pdu + data->pos + 2, sizeof(uint16_t));
1063 
1064  data->pos += data->result->data_len;
1065 
1066  if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, read_pdu, sizeof(read_pdu),
1069  return;
1070 
1071  read_included_unref(data);
1072  success = false;
1073 
1074 done:
1075  discovery_op_complete(op, success, att_ecode);
1076 }
1077 
1078 static void read_included(struct read_incl_data *data)
1079 {
1080  struct bt_gatt_request *op = data->op;
1081  uint8_t pdu[2];
1082 
1083  memcpy(pdu, data->result->pdu + 2, sizeof(uint16_t));
1084 
1085  data->pos += data->result->data_len;
1086 
1087  if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, pdu, sizeof(pdu),
1089  read_included_ref(data),
1091  return;
1092 
1093  if (op->callback)
1094  op->callback(false, 0, NULL, data->op->user_data);
1095 
1096  read_included_unref(data);
1097 }
1098 
1099 static void discover_included_cb(uint8_t opcode, const void *pdu,
1100  uint16_t length, void *user_data)
1101 {
1102  struct bt_gatt_request *op = user_data;
1103  struct bt_gatt_result *cur_result;
1104  uint8_t att_ecode = 0;
1105  uint16_t last_handle;
1106  size_t data_length;
1107  bool success;
1108 
1109  if (opcode == BT_ATT_OP_ERROR_RSP) {
1110  att_ecode = process_error(pdu, length);
1111  success = false;
1112  goto failed;
1113  }
1114 
1115  if (opcode != BT_ATT_OP_READ_BY_TYPE_RSP || !pdu || length < 6) {
1116  success = false;
1117  goto failed;
1118  }
1119 
1120  data_length = ((const uint8_t *) pdu)[0];
1121 
1122  /*
1123  * Check if PDU contains data sets with length declared in the beginning
1124  * of frame and if this length is correct.
1125  * Data set length may be 6 or 8 octets:
1126  * 2 octets - include service handle
1127  * 2 octets - start handle of included service
1128  * 2 octets - end handle of included service
1129  * optional 2 octets - Bluetooth UUID of included service
1130  */
1131  if ((data_length != 8 && data_length != 6) ||
1132  (length - 1) % data_length) {
1133  success = false;
1134  goto failed;
1135  }
1136 
1137  cur_result = result_append(opcode, pdu + 1, length - 1, data_length,
1138  op);
1139  if (!cur_result) {
1140  success = false;
1141  goto failed;
1142  }
1143 
1144  if (data_length == 6) {
1145  struct read_incl_data *data;
1146 
1147  data = new_read_included(cur_result);
1148  if (!data) {
1149  success = false;
1150  goto failed;
1151  }
1152 
1153  read_included(data);
1154  return;
1155  }
1156 
1157  last_handle = get_le16(pdu + length - data_length);
1158 
1159  /*
1160  * If last handle is lower from previous start handle then it is smth
1161  * wrong. Let's stop search, otherwise we might enter infinite loop.
1162  */
1163  if (last_handle < op->start_handle) {
1164  success = false;
1165  goto failed;
1166  }
1167 
1168  op->start_handle = last_handle + 1;
1169  if (last_handle != op->end_handle) {
1170  uint8_t pdu[6];
1171 
1172  put_le16(op->start_handle, pdu);
1173  put_le16(op->end_handle, pdu + 2);
1174  put_le16(GATT_INCLUDE_UUID, pdu + 4);
1175 
1177  pdu, sizeof(pdu),
1179  bt_gatt_request_ref(op),
1180  async_req_unref);
1181  if (op->id)
1182  return;
1183 
1184  success = false;
1185  goto failed;
1186  }
1187 
1188  success = true;
1189 
1190 failed:
1191  discovery_op_complete(op, success, att_ecode);
1192 }
1193 
1195  uint16_t start, uint16_t end,
1197  void *user_data,
1199 {
1200  struct bt_gatt_request *op;
1201  uint8_t pdu[6];
1202 
1203  if (!att)
1204  return false;
1205 
1206  op = new0(struct bt_gatt_request, 1);
1207  if (!op)
1208  return false;
1209 
1210  op->att = att;
1211  op->callback = callback;
1212  op->user_data = user_data;
1213  op->destroy = destroy;
1214  op->start_handle = start;
1215  op->end_handle = end;
1216 
1217  put_le16(start, pdu);
1218  put_le16(end, pdu + 2);
1219  put_le16(GATT_INCLUDE_UUID, pdu + 4);
1220 
1221  op->id = bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
1223  async_req_unref);
1224  if (!op->id) {
1225  free(op);
1226  return NULL;
1227  }
1228 
1229  return bt_gatt_request_ref(op);
1230 }
1231 
1232 static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
1233  uint16_t length, void *user_data)
1234 {
1235  struct bt_gatt_request *op = user_data;
1236  bool success;
1237  uint8_t att_ecode = 0;
1238  size_t data_length;
1239  uint16_t last_handle;
1240 
1241  if (opcode == BT_ATT_OP_ERROR_RSP) {
1242  success = false;
1243  att_ecode = process_error(pdu, length);
1244  goto done;
1245  }
1246 
1247  /* PDU must contain at least the following (sans opcode):
1248  * - Attr Data Length (1 octet)
1249  * - Attr Data List (at least 7 octets):
1250  * -- 2 octets: Attribute handle
1251  * -- 1 octet: Characteristic properties
1252  * -- 2 octets: Characteristic value handle
1253  * -- 2 or 16 octets: characteristic UUID
1254  */
1255  if (opcode != BT_ATT_OP_READ_BY_TYPE_RSP || !pdu || length < 8) {
1256  success = false;
1257  goto done;
1258  }
1259 
1260  data_length = ((uint8_t *) pdu)[0];
1261 
1262  if ((data_length != 7 && data_length != 21) ||
1263  ((length - 1) % data_length)) {
1264  success = false;
1265  goto done;
1266  }
1267 
1268  if (!result_append(opcode, pdu + 1, length - 1,
1269  data_length, op)) {
1270  success = false;
1271  goto done;
1272  }
1273  last_handle = get_le16(pdu + length - data_length);
1274 
1275  /*
1276  * If last handle is lower from previous start handle then it is smth
1277  * wrong. Let's stop search, otherwise we might enter infinite loop.
1278  */
1279  if (last_handle < op->start_handle) {
1280  success = false;
1281  goto done;
1282  }
1283 
1284  op->start_handle = last_handle + 1;
1285 
1286  if (last_handle != op->end_handle) {
1287  uint8_t pdu[6];
1288 
1289  put_le16(op->start_handle, pdu);
1290  put_le16(op->end_handle, pdu + 2);
1291  put_le16(GATT_CHARAC_UUID, pdu + 4);
1292 
1294  pdu, sizeof(pdu),
1296  bt_gatt_request_ref(op),
1297  async_req_unref);
1298  if (op->id)
1299  return;
1300 
1301  success = false;
1302  goto done;
1303  }
1304 
1305  success = true;
1306 
1307 done:
1308  discovery_op_complete(op, success, att_ecode);
1309 }
1310 
1312  uint16_t start, uint16_t end,
1314  void *user_data,
1316 {
1317  struct bt_gatt_request *op;
1318  uint8_t pdu[6];
1319 
1320  if (!att)
1321  return false;
1322 
1323  op = new0(struct bt_gatt_request, 1);
1324  if (!op)
1325  return false;
1326 
1327  op->att = att;
1328  op->callback = callback;
1329  op->user_data = user_data;
1330  op->destroy = destroy;
1331  op->start_handle = start;
1332  op->end_handle = end;
1333 
1334  put_le16(start, pdu);
1335  put_le16(end, pdu + 2);
1336  put_le16(GATT_CHARAC_UUID, pdu + 4);
1337 
1338  op->id = bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
1340  async_req_unref);
1341  if (!op->id) {
1342  free(op);
1343  return NULL;
1344  }
1345 
1346  return bt_gatt_request_ref(op);
1347 }
1348 
1349 static void read_by_type_cb(uint8_t opcode, const void *pdu,
1350  uint16_t length, void *user_data)
1351 {
1352  struct bt_gatt_request *op = user_data;
1353  bool success;
1354  uint8_t att_ecode = 0;
1355  size_t data_length;
1356  uint16_t last_handle;
1357 
1358  if (opcode == BT_ATT_OP_ERROR_RSP) {
1359  att_ecode = process_error(pdu, length);
1360  success = false;
1361  goto done;
1362  }
1363 
1364  if (opcode != BT_ATT_OP_READ_BY_TYPE_RSP || !pdu) {
1365  success = false;
1366  att_ecode = 0;
1367  goto done;
1368  }
1369 
1370  data_length = ((uint8_t *) pdu)[0];
1371  if (((length - 1) % data_length)) {
1372  success = false;
1373  att_ecode = 0;
1374  goto done;
1375  }
1376 
1377  if (!result_append(opcode, pdu + 1, length - 1, data_length, op)) {
1378  success = false;
1379  att_ecode = 0;
1380  goto done;
1381  }
1382 
1383  last_handle = get_le16(pdu + length - data_length);
1384 
1385  /*
1386  * If last handle is lower from previous start handle then it is smth
1387  * wrong. Let's stop search, otherwise we might enter infinite loop.
1388  */
1389  if (last_handle < op->start_handle) {
1390  success = false;
1391  goto done;
1392  }
1393 
1394  op->start_handle = last_handle + 1;
1395 
1396  if (last_handle != op->end_handle) {
1397  uint8_t pdu[4 + get_uuid_len(&op->uuid)];
1398 
1399  put_le16(op->start_handle, pdu);
1400  put_le16(op->end_handle, pdu + 2);
1401  bt_uuid_to_le(&op->uuid, pdu + 4);
1402 
1404  pdu, sizeof(pdu),
1406  bt_gatt_request_ref(op),
1407  async_req_unref);
1408  if (op->id)
1409  return;
1410 
1411  success = false;
1412  goto done;
1413  }
1414 
1415  success = true;
1416 
1417 done:
1418  discovery_op_complete(op, success, att_ecode);
1419 }
1420 
1421 bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
1422  const bt_uuid_t *uuid,
1424  void *user_data,
1426 {
1427  struct bt_gatt_request *op;
1428  uint8_t pdu[4 + get_uuid_len(uuid)];
1429 
1430  if (!att || !uuid || uuid->type == BT_UUID_UNSPEC)
1431  return false;
1432 
1433  op = new0(struct bt_gatt_request, 1);
1434  if (!op)
1435  return false;
1436 
1437  op->att = att;
1438  op->callback = callback;
1439  op->user_data = user_data;
1440  op->destroy = destroy;
1441  op->start_handle = start;
1442  op->end_handle = end;
1443  op->uuid = *uuid;
1444 
1445  put_le16(start, pdu);
1446  put_le16(end, pdu + 2);
1447  bt_uuid_to_le(uuid, pdu + 4);
1448 
1449  op->id = bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
1451  bt_gatt_request_ref(op),
1452  async_req_unref);
1453  if (op->id)
1454  return true;
1455 
1456  free(op);
1457  return false;
1458 }
1459 
1460 static void discover_descs_cb(uint8_t opcode, const void *pdu,
1461  uint16_t length, void *user_data)
1462 {
1463  struct bt_gatt_request *op = user_data;
1464  bool success;
1465  uint8_t att_ecode = 0;
1466  uint8_t format;
1467  uint16_t last_handle;
1468  size_t data_length;
1469 
1470  if (opcode == BT_ATT_OP_ERROR_RSP) {
1471  success = false;
1472  att_ecode = process_error(pdu, length);
1473  goto done;
1474  }
1475 
1476  /* The PDU should contain the following data (sans opcode):
1477  * - Format (1 octet)
1478  * - Attr Data List (at least 4 octets):
1479  * -- 2 octets: Attribute handle
1480  * -- 2 or 16 octets: UUID.
1481  */
1482  if (opcode != BT_ATT_OP_FIND_INFO_RSP || !pdu || length < 5) {
1483  success = false;
1484  goto done;
1485  }
1486 
1487  format = ((uint8_t *) pdu)[0];
1488 
1489  if (format == 0x01)
1490  data_length = 4;
1491  else if (format == 0x02)
1492  data_length = 18;
1493  else {
1494  success = false;
1495  goto done;
1496  }
1497 
1498  if ((length - 1) % data_length) {
1499  success = false;
1500  goto done;
1501  }
1502 
1503  if (!result_append(opcode, pdu + 1, length - 1, data_length, op)) {
1504  success = false;
1505  goto done;
1506  }
1507 
1508  last_handle = get_le16(pdu + length - data_length);
1509 
1510  /*
1511  * If last handle is lower from previous start handle then it is smth
1512  * wrong. Let's stop search, otherwise we might enter infinite loop.
1513  */
1514  if (last_handle < op->start_handle) {
1515  success = false;
1516  goto done;
1517  }
1518 
1519  op->start_handle = last_handle + 1;
1520 
1521  if (last_handle != op->end_handle) {
1522  uint8_t pdu[4];
1523 
1524  put_le16(op->start_handle, pdu);
1525  put_le16(op->end_handle, pdu + 2);
1526 
1528  pdu, sizeof(pdu),
1530  bt_gatt_request_ref(op),
1531  async_req_unref);
1532  if (op->id)
1533  return;
1534 
1535  success = false;
1536  }
1537 
1538  success = true;
1539 
1540 done:
1541  discovery_op_complete(op, success, att_ecode);
1542 }
1543 
1545  uint16_t start, uint16_t end,
1547  void *user_data,
1549 {
1550  struct bt_gatt_request *op;
1551  uint8_t pdu[4];
1552 
1553  if (!att)
1554  return false;
1555 
1556  op = new0(struct bt_gatt_request, 1);
1557  if (!op)
1558  return false;
1559 
1560  op->att = att;
1561  op->callback = callback;
1562  op->user_data = user_data;
1563  op->destroy = destroy;
1564  op->start_handle = start;
1565  op->end_handle = end;
1566 
1567  put_le16(start, pdu);
1568  put_le16(end, pdu + 2);
1569 
1570  op->id = bt_att_send(att, BT_ATT_OP_FIND_INFO_REQ, pdu, sizeof(pdu),
1572  bt_gatt_request_ref(op),
1573  async_req_unref);
1574  if (!op->id) {
1575  free(op);
1576  return NULL;
1577  }
1578 
1579  return bt_gatt_request_ref(op);
1580 }
uint128_t u128
Definition: uuid.h:152
#define BT_ATT_OP_READ_BY_TYPE_REQ
Definition: att-types.h:47
static struct bt_gatt_result * result_append(uint8_t opcode, const void *pdu, uint16_t pdu_len, uint16_t data_len, struct bt_gatt_request *op)
Definition: gatt-helpers.c:236
void bt_gatt_request_unref(struct bt_gatt_request *req)
Definition: gatt-helpers.c:632
static unsigned int result_element_count(struct bt_gatt_result *result)
Definition: gatt-helpers.c:101
#define BT_ATT_OP_READ_RSP
Definition: att-types.h:50
#define BT_ATT_OP_READ_BY_TYPE_RSP
Definition: att-types.h:48
bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, const bt_uuid_t *uuid, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
void(* bt_gatt_request_callback_t)(bool success, uint8_t att_ecode, struct bt_gatt_result *result, void *user_data)
Definition: gatt-helpers.h:64
struct bt_gatt_result * result_tail
Definition: gatt-helpers.c:230
bt_gatt_result_callback_t callback
Definition: gatt-helpers.c:494
struct bt_gatt_result * result
Definition: gatt-helpers.h:34
uint8_t data[16]
Definition: bluetooth.h:343
static void async_req_unref(void *data)
Definition: gatt-helpers.c:662
static void discovery_op_complete(struct bt_gatt_request *op, bool success, uint8_t ecode)
Definition: gatt-helpers.c:669
uint16_t data_len
Definition: gatt-helpers.c:53
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
Definition: uuid.c:85
#define GATT_PRIM_SVC_UUID
Definition: uuid.h:110
struct bt_gatt_request * bt_gatt_discover_characteristics(struct bt_att *att, uint16_t start, uint16_t end, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
#define GATT_INCLUDE_UUID
Definition: uuid.h:112
struct bt_gatt_request * bt_gatt_discover_included_services(struct bt_att *att, uint16_t start, uint16_t end, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
static void destroy_mtu_op(void *user_data)
Definition: gatt-helpers.c:499
unsigned int id
Definition: gatt-helpers.c:223
void(* bt_gatt_result_callback_t)(bool success, uint8_t att_ecode, void *user_data)
Definition: gatt-helpers.h:62
bool bt_gatt_iter_next_characteristic(struct bt_gatt_iter *iter, uint16_t *start_handle, uint16_t *end_handle, uint16_t *value_handle, uint8_t *properties, uint8_t uuid[16])
Definition: gatt-helpers.c:378
void * user_data
Definition: gatt-helpers.c:495
union bt_uuid_t::@8 value
#define BT_ATT_OP_MTU_REQ
Definition: att-types.h:41
struct bt_gatt_result * next
Definition: gatt-helpers.c:57
struct bt_gatt_result * result_head
Definition: gatt-helpers.c:229
static void discover_included_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
static void put_le16(uint16_t val, void *dst)
Definition: util.h:130
void(* bt_gatt_destroy_func_t)(void *user_data)
Definition: gatt-helpers.h:60
#define BT_ATT_OP_FIND_INFO_RSP
Definition: att-types.h:44
struct bt_gatt_request * bt_gatt_discover_descriptors(struct bt_att *att, uint16_t start, uint16_t end, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
struct bt_gatt_request * op
Definition: gatt-helpers.c:959
static void read_included_unref(void *data)
Definition: gatt-helpers.c:986
static void read_by_grp_type_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
Definition: gatt-helpers.c:687
struct bt_gatt_request * bt_gatt_request_ref(struct bt_gatt_request *req)
Definition: gatt-helpers.c:622
uint16_t end_handle
Definition: gatt-helpers.c:225
uint16_t pos
Definition: gatt-helpers.h:35
bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu)
Definition: att.c:1119
static struct read_incl_data * new_read_included(struct bt_gatt_result *res)
Definition: gatt-helpers.c:965
enum bt_uuid_t::@7 type
bt_gatt_request_callback_t callback
Definition: gatt-helpers.c:231
bt_uuid_t uuid
Definition: gatt-helpers.c:227
static void discover_chrcs_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
static bool convert_uuid_le(const uint8_t *src, size_t len, uint8_t dst[16])
Definition: gatt-helpers.c:204
bool bt_att_cancel(struct bt_att *att, unsigned int id)
Definition: att.c:1278
struct bt_att * att
Definition: gatt-helpers.c:222
bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter, uint16_t *handle, uint16_t *start_handle, uint16_t *end_handle, uint8_t uuid[16])
Definition: gatt-helpers.c:257
#define BT_ATT_OP_MTU_RSP
Definition: att-types.h:42
static void mtu_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
Definition: gatt-helpers.c:528
#define BT_ATT_OP_READ_BY_GRP_TYPE_REQ
Definition: att-types.h:55
#define BT_ATT_OP_ERROR_RSP
Definition: att-types.h:40
bool bt_gatt_iter_init(struct bt_gatt_iter *iter, struct bt_gatt_result *result)
Definition: gatt-helpers.c:188
static void bswap_128(const void *src, void *dst)
Definition: bluetooth.h:346
#define BT_ATT_OP_FIND_BY_TYPE_VAL_REQ
Definition: att-types.h:45
#define BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND
Definition: att-types.h:90
static void find_by_type_val_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
Definition: gatt-helpers.c:782
struct bt_gatt_result * result
Definition: gatt-helpers.c:960
struct bt_gatt_request * bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid, uint16_t start, uint16_t end, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
Definition: gatt-helpers.c:947
uint8_t opcode
Definition: gatt-helpers.c:50
uint16_t start_handle
Definition: gatt-helpers.c:224
unsigned int bt_gatt_result_descriptor_count(struct bt_gatt_result *result)
Definition: gatt-helpers.c:149
struct bt_att * att
Definition: gatt-helpers.c:492
#define BT_ATT_OP_READ_BY_GRP_TYPE_RSP
Definition: att-types.h:56
static void discover_descs_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
Definition: att.c:64
static void result_destroy(struct bt_gatt_result *result)
Definition: gatt-helpers.c:87
static struct bt_gatt_request * discover_services(struct bt_att *att, bt_uuid_t *uuid, uint16_t start, uint16_t end, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy, bool primary)
Definition: gatt-helpers.c:855
static int get_uuid_len(const bt_uuid_t *uuid)
Definition: gatt-helpers.c:614
#define BT_ATT_OP_FIND_BY_TYPE_VAL_RSP
Definition: att-types.h:46
int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
Definition: uuid.c:304
unsigned int bt_gatt_result_characteristic_count(struct bt_gatt_result *result)
Definition: gatt-helpers.c:128
struct bt_gatt_request * bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid, uint16_t start, uint16_t end, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
Definition: gatt-helpers.c:936
bool bt_gatt_iter_next_descriptor(struct bt_gatt_iter *iter, uint16_t *handle, uint8_t uuid[16])
Definition: gatt-helpers.c:430
static void read_by_type_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
static const uint8_t bt_base_uuid[16]
Definition: gatt-helpers.c:199
bool bt_gatt_iter_next_service(struct bt_gatt_iter *iter, uint16_t *start_handle, uint16_t *end_handle, uint8_t uuid[16])
Definition: gatt-helpers.c:337
static uint16_t get_le16(const void *ptr)
Definition: util.h:100
static void read_included_cb(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
static uint8_t process_error(const void *pdu, uint16_t length)
Definition: gatt-helpers.c:509
#define new0(t, n)
Definition: util.h:82
#define MIN(a, b)
Definition: gatt-helpers.c:46
unsigned int bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu, bt_gatt_result_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
Definition: gatt-helpers.c:582
bt_gatt_destroy_func_t destroy
Definition: gatt-helpers.c:233
#define BT_ATT_OP_READ_REQ
Definition: att-types.h:49
#define BT_ATT_OP_FIND_INFO_REQ
Definition: att-types.h:43
static struct bt_gatt_result * result_create(uint8_t opcode, const void *pdu, uint16_t pdu_len, uint16_t data_len, void *op)
Definition: gatt-helpers.c:60
uint8_t opcode
Definition: att.c:140
static struct read_incl_data * read_included_ref(struct read_incl_data *data)
Definition: gatt-helpers.c:979
void bt_gatt_request_cancel(struct bt_gatt_request *req)
Definition: gatt-helpers.c:650
unsigned int bt_gatt_result_service_count(struct bt_gatt_result *result)
Definition: gatt-helpers.c:116
unsigned int bt_att_send(struct bt_att *att, uint8_t opcode, const void *pdu, uint16_t length, bt_att_response_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
Definition: att.c:1220
unsigned int bt_gatt_result_included_count(struct bt_gatt_result *result)
Definition: gatt-helpers.c:160
#define GATT_SND_SVC_UUID
Definition: uuid.h:111
uint16_t pdu_len
Definition: gatt-helpers.c:52
bt_gatt_destroy_func_t destroy
Definition: gatt-helpers.c:496
uint16_t client_rx_mtu
Definition: gatt-helpers.c:493
#define GATT_CHARAC_UUID
Definition: uuid.h:113
bool bt_gatt_iter_next_read_by_type(struct bt_gatt_iter *iter, uint16_t *handle, uint16_t *length, const uint8_t **value)
Definition: gatt-helpers.c:455
static void read_included(struct read_incl_data *data)
struct bt_gatt_request * bt_gatt_discover_all_primary_services(struct bt_att *att, bt_uuid_t *uuid, bt_gatt_request_callback_t callback, void *user_data, bt_gatt_destroy_func_t destroy)
Definition: gatt-helpers.c:925
uint16_t service_type
Definition: gatt-helpers.c:228