• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /**
21  * GATT client - Generic Attribute Profile; client operations.
22  *
23  * Design overview:
24  *
25  * GATT client procedures are initiated by the application via function calls.
26  * Such functions return when either of the following happens:
27  *
28  * (1) The procedure completes (success or failure).
29  * (2) The procedure cannot proceed until a BLE peer responds.
30  *
31  * For (1), the result of the procedure if fully indicated by the function
32  * return code.
33  * For (2), the procedure result is indicated by an application-configured
34  * callback.  The callback is executed when the procedure completes.
35  *
36  * Notes on thread-safety:
37  * 1. The ble_hs mutex must never be locked when an application callback is
38  *    executed.  A callback is free to initiate additional host procedures.
39  * 2. The only resource protected by the mutex is the list of active procedures
40  *    (ble_gattc_procs).  Thread-safety is achieved by locking the mutex during
41  *    removal and insertion operations.  Procedure objects are only modified
42  *    while they are not in the list.  This is sufficient, as the host parent
43  *    task is the only task which inspects or modifies individual procedure
44  *    entries.  Tasks have the following permissions regarding procedure
45  *    entries:
46  *
47  *                | insert  | remove    | inspect   | modify
48  *    ------------+---------+-----------|-----------|---------
49  *    parent task | X       | X         | X         | X
50  *    other tasks | X       |           |           |
51  */
52 
53 #include <stddef.h>
54 #include <stdlib.h>
55 #include <errno.h>
56 #include <string.h>
57 #include "securec.h"
58 #include "os/os_mempool.h"
59 #include "nimble/ble.h"
60 #include "host/ble_uuid.h"
61 #include "host/ble_gap.h"
62 #include "ble_hs_priv.h"
63 
64 /*****************************************************************************
65  * $definitions / declarations                                               *
66  *****************************************************************************/
67 
68 /**
69  * The maximum time to wait for a single ATT response.  The spec defines this
70  * as the ATT transaction time (Vol. 3, Part F, 3.3.3)
71  */
72 #define BLE_GATTC_UNRESPONSIVE_TIMEOUT_MS       30000 /* ms */
73 
74 #define BLE_GATT_OP_NONE                        UINT8_MAX
75 #define BLE_GATT_OP_MTU                         0
76 #define BLE_GATT_OP_DISC_ALL_SVCS               1
77 #define BLE_GATT_OP_DISC_SVC_UUID               2
78 #define BLE_GATT_OP_FIND_INC_SVCS               3
79 #define BLE_GATT_OP_DISC_ALL_CHRS               4
80 #define BLE_GATT_OP_DISC_CHR_UUID               5
81 #define BLE_GATT_OP_DISC_ALL_DSCS               6
82 #define BLE_GATT_OP_READ                        7
83 #define BLE_GATT_OP_READ_UUID                   8
84 #define BLE_GATT_OP_READ_LONG                   9
85 #define BLE_GATT_OP_READ_MULT                   10
86 #define BLE_GATT_OP_WRITE                       11
87 #define BLE_GATT_OP_WRITE_LONG                  12
88 #define BLE_GATT_OP_WRITE_RELIABLE              13
89 #define BLE_GATT_OP_INDICATE                    14
90 #define BLE_GATT_OP_CNT                         15
91 
92 /** Procedure stalled due to resource exhaustion. */
93 #define BLE_GATTC_PROC_F_STALLED                0x01
94 
95 /** Represents an in-progress GATT procedure. */
96 struct ble_gattc_proc {
97     STAILQ_ENTRY(ble_gattc_proc) next;
98 
99     uint32_t exp_os_ticks;
100     uint16_t conn_handle;
101     uint8_t op;
102     uint8_t flags;
103 
104     union {
105         struct {
106             ble_gatt_mtu_fn *cb;
107             void *cb_arg;
108         } mtu;
109 
110         struct {
111             uint16_t prev_handle;
112             ble_gatt_disc_svc_fn *cb;
113             void *cb_arg;
114         } disc_all_svcs;
115 
116         struct {
117             ble_uuid_any_t service_uuid;
118             uint16_t prev_handle;
119             ble_gatt_disc_svc_fn *cb;
120             void *cb_arg;
121         } disc_svc_uuid;
122 
123         struct {
124             uint16_t prev_handle;
125             uint16_t end_handle;
126 
127             uint16_t cur_start;
128             uint16_t cur_end;
129 
130             ble_gatt_disc_svc_fn *cb;
131             void *cb_arg;
132         } find_inc_svcs;
133 
134         struct {
135             uint16_t prev_handle;
136             uint16_t end_handle;
137             ble_gatt_chr_fn *cb;
138             void *cb_arg;
139         } disc_all_chrs;
140 
141         struct {
142             ble_uuid_any_t chr_uuid;
143             uint16_t prev_handle;
144             uint16_t end_handle;
145             ble_gatt_chr_fn *cb;
146             void *cb_arg;
147         } disc_chr_uuid;
148 
149         struct {
150             uint16_t chr_val_handle;
151             uint16_t prev_handle;
152             uint16_t end_handle;
153             ble_gatt_dsc_fn *cb;
154             void *cb_arg;
155         } disc_all_dscs;
156 
157         struct {
158             uint16_t handle;
159             ble_gatt_attr_fn *cb;
160             void *cb_arg;
161         } read;
162 
163         struct {
164             ble_uuid_any_t chr_uuid;
165             uint16_t start_handle;
166             uint16_t end_handle;
167             ble_gatt_attr_fn *cb;
168             void *cb_arg;
169         } read_uuid;
170 
171         struct {
172             uint16_t handle;
173             uint16_t offset;
174             ble_gatt_attr_fn *cb;
175             void *cb_arg;
176         } read_long;
177 
178         struct {
179             uint16_t handles[MYNEWT_VAL(BLE_GATT_READ_MAX_ATTRS)];
180             uint8_t num_handles;
181             ble_gatt_attr_fn *cb;
182             void *cb_arg;
183         } read_mult;
184 
185         struct {
186             uint16_t att_handle;
187             ble_gatt_attr_fn *cb;
188             void *cb_arg;
189         } write;
190 
191         struct {
192             struct ble_gatt_attr attr;
193             uint16_t length;
194             ble_gatt_attr_fn *cb;
195             void *cb_arg;
196         } write_long;
197 
198         struct {
199             struct ble_gatt_attr attrs[MYNEWT_VAL(BLE_GATT_WRITE_MAX_ATTRS)];
200             uint8_t num_attrs;
201             uint8_t cur_attr;
202             uint16_t length;
203             ble_gatt_reliable_attr_fn *cb;
204             void *cb_arg;
205         } write_reliable;
206 
207         struct {
208             uint16_t chr_val_handle;
209         } indicate;
210     };
211 };
212 
213 STAILQ_HEAD(ble_gattc_proc_list, ble_gattc_proc);
214 
215 /**
216  * Error functions - these handle an incoming ATT error response and apply it
217  * to the appropriate active GATT procedure.
218  */
219 typedef void ble_gattc_err_fn(struct ble_gattc_proc *proc, int status,
220                               uint16_t att_handle);
221 static ble_gattc_err_fn ble_gattc_mtu_err;
222 static ble_gattc_err_fn ble_gattc_disc_all_svcs_err;
223 static ble_gattc_err_fn ble_gattc_disc_svc_uuid_err;
224 static ble_gattc_err_fn ble_gattc_find_inc_svcs_err;
225 static ble_gattc_err_fn ble_gattc_disc_all_chrs_err;
226 static ble_gattc_err_fn ble_gattc_disc_chr_uuid_err;
227 static ble_gattc_err_fn ble_gattc_disc_all_dscs_err;
228 static ble_gattc_err_fn ble_gattc_read_err;
229 static ble_gattc_err_fn ble_gattc_read_uuid_err;
230 static ble_gattc_err_fn ble_gattc_read_long_err;
231 static ble_gattc_err_fn ble_gattc_read_mult_err;
232 static ble_gattc_err_fn ble_gattc_write_err;
233 static ble_gattc_err_fn ble_gattc_write_long_err;
234 static ble_gattc_err_fn ble_gattc_write_reliable_err;
235 static ble_gattc_err_fn ble_gattc_indicate_err;
236 
237 static ble_gattc_err_fn *const ble_gattc_err_dispatch[BLE_GATT_OP_CNT] = {
238     [BLE_GATT_OP_MTU]               = ble_gattc_mtu_err,
239     [BLE_GATT_OP_DISC_ALL_SVCS]     = ble_gattc_disc_all_svcs_err,
240     [BLE_GATT_OP_DISC_SVC_UUID]     = ble_gattc_disc_svc_uuid_err,
241     [BLE_GATT_OP_FIND_INC_SVCS]     = ble_gattc_find_inc_svcs_err,
242     [BLE_GATT_OP_DISC_ALL_CHRS]     = ble_gattc_disc_all_chrs_err,
243     [BLE_GATT_OP_DISC_CHR_UUID]     = ble_gattc_disc_chr_uuid_err,
244     [BLE_GATT_OP_DISC_ALL_DSCS]     = ble_gattc_disc_all_dscs_err,
245     [BLE_GATT_OP_READ]              = ble_gattc_read_err,
246     [BLE_GATT_OP_READ_UUID]         = ble_gattc_read_uuid_err,
247     [BLE_GATT_OP_READ_LONG]         = ble_gattc_read_long_err,
248     [BLE_GATT_OP_READ_MULT]         = ble_gattc_read_mult_err,
249     [BLE_GATT_OP_WRITE]             = ble_gattc_write_err,
250     [BLE_GATT_OP_WRITE_LONG]        = ble_gattc_write_long_err,
251     [BLE_GATT_OP_WRITE_RELIABLE]    = ble_gattc_write_reliable_err,
252     [BLE_GATT_OP_INDICATE]          = ble_gattc_indicate_err,
253 };
254 
255 /**
256  * Resume functions - these handle periodic retries of procedures that have
257  * stalled due to memory exhaustion.
258  */
259 typedef int ble_gattc_resume_fn(struct ble_gattc_proc *proc);
260 
261 static ble_gattc_resume_fn ble_gattc_disc_all_svcs_resume;
262 static ble_gattc_resume_fn ble_gattc_disc_svc_uuid_resume;
263 static ble_gattc_resume_fn ble_gattc_find_inc_svcs_resume;
264 static ble_gattc_resume_fn ble_gattc_disc_all_chrs_resume;
265 static ble_gattc_resume_fn ble_gattc_disc_chr_uuid_resume;
266 static ble_gattc_resume_fn ble_gattc_disc_all_dscs_resume;
267 static ble_gattc_resume_fn ble_gattc_read_long_resume;
268 static ble_gattc_resume_fn ble_gattc_write_long_resume;
269 static ble_gattc_resume_fn ble_gattc_write_reliable_resume;
270 
271 static ble_gattc_resume_fn *const
272 ble_gattc_resume_dispatch[BLE_GATT_OP_CNT] = {
273     [BLE_GATT_OP_MTU]               = NULL,
274     [BLE_GATT_OP_DISC_ALL_SVCS]     = ble_gattc_disc_all_svcs_resume,
275     [BLE_GATT_OP_DISC_SVC_UUID]     = ble_gattc_disc_svc_uuid_resume,
276     [BLE_GATT_OP_FIND_INC_SVCS]     = ble_gattc_find_inc_svcs_resume,
277     [BLE_GATT_OP_DISC_ALL_CHRS]     = ble_gattc_disc_all_chrs_resume,
278     [BLE_GATT_OP_DISC_CHR_UUID]     = ble_gattc_disc_chr_uuid_resume,
279     [BLE_GATT_OP_DISC_ALL_DSCS]     = ble_gattc_disc_all_dscs_resume,
280     [BLE_GATT_OP_READ]              = NULL,
281     [BLE_GATT_OP_READ_UUID]         = NULL,
282     [BLE_GATT_OP_READ_LONG]         = ble_gattc_read_long_resume,
283     [BLE_GATT_OP_READ_MULT]         = NULL,
284     [BLE_GATT_OP_WRITE]             = NULL,
285     [BLE_GATT_OP_WRITE_LONG]        = ble_gattc_write_long_resume,
286     [BLE_GATT_OP_WRITE_RELIABLE]    = ble_gattc_write_reliable_resume,
287     [BLE_GATT_OP_INDICATE]          = NULL,
288 };
289 
290 /**
291  * Timeout functions - these notify the application that a GATT procedure has
292  * timed out while waiting for a response.
293  */
294 typedef void ble_gattc_tmo_fn(struct ble_gattc_proc *proc);
295 
296 static ble_gattc_tmo_fn ble_gattc_mtu_tmo;
297 static ble_gattc_tmo_fn ble_gattc_disc_all_svcs_tmo;
298 static ble_gattc_tmo_fn ble_gattc_disc_svc_uuid_tmo;
299 static ble_gattc_tmo_fn ble_gattc_find_inc_svcs_tmo;
300 static ble_gattc_tmo_fn ble_gattc_disc_all_chrs_tmo;
301 static ble_gattc_tmo_fn ble_gattc_disc_chr_uuid_tmo;
302 static ble_gattc_tmo_fn ble_gattc_disc_all_dscs_tmo;
303 static ble_gattc_tmo_fn ble_gattc_read_tmo;
304 static ble_gattc_tmo_fn ble_gattc_read_uuid_tmo;
305 static ble_gattc_tmo_fn ble_gattc_read_long_tmo;
306 static ble_gattc_tmo_fn ble_gattc_read_mult_tmo;
307 static ble_gattc_tmo_fn ble_gattc_write_tmo;
308 static ble_gattc_tmo_fn ble_gattc_write_long_tmo;
309 static ble_gattc_tmo_fn ble_gattc_write_reliable_tmo;
310 static ble_gattc_tmo_fn ble_gattc_indicate_tmo;
311 
312 static ble_gattc_tmo_fn *const
313 ble_gattc_tmo_dispatch[BLE_GATT_OP_CNT] = {
314     [BLE_GATT_OP_MTU]               = ble_gattc_mtu_tmo,
315     [BLE_GATT_OP_DISC_ALL_SVCS]     = ble_gattc_disc_all_svcs_tmo,
316     [BLE_GATT_OP_DISC_SVC_UUID]     = ble_gattc_disc_svc_uuid_tmo,
317     [BLE_GATT_OP_FIND_INC_SVCS]     = ble_gattc_find_inc_svcs_tmo,
318     [BLE_GATT_OP_DISC_ALL_CHRS]     = ble_gattc_disc_all_chrs_tmo,
319     [BLE_GATT_OP_DISC_CHR_UUID]     = ble_gattc_disc_chr_uuid_tmo,
320     [BLE_GATT_OP_DISC_ALL_DSCS]     = ble_gattc_disc_all_dscs_tmo,
321     [BLE_GATT_OP_READ]              = ble_gattc_read_tmo,
322     [BLE_GATT_OP_READ_UUID]         = ble_gattc_read_uuid_tmo,
323     [BLE_GATT_OP_READ_LONG]         = ble_gattc_read_long_tmo,
324     [BLE_GATT_OP_READ_MULT]         = ble_gattc_read_mult_tmo,
325     [BLE_GATT_OP_WRITE]             = ble_gattc_write_tmo,
326     [BLE_GATT_OP_WRITE_LONG]        = ble_gattc_write_long_tmo,
327     [BLE_GATT_OP_WRITE_RELIABLE]    = ble_gattc_write_reliable_tmo,
328     [BLE_GATT_OP_INDICATE]          = ble_gattc_indicate_tmo,
329 };
330 
331 /**
332  * Receive functions - these handle specific incoming responses and apply them
333  * to the appropriate active GATT procedure.
334  */
335 typedef int ble_gattc_rx_adata_fn(struct ble_gattc_proc *proc,
336                                   struct ble_att_read_type_adata *adata);
337 
338 typedef int ble_gattc_rx_prep_fn(struct ble_gattc_proc *proc, int status,
339                                  uint16_t handle, uint16_t offset,
340                                  struct os_mbuf **om);
341 
342 typedef int ble_gattc_rx_attr_fn(struct ble_gattc_proc *proc, int status,
343                                  struct os_mbuf **om);
344 
345 typedef int ble_gattc_rx_complete_fn(struct ble_gattc_proc *proc, int status);
346 typedef int ble_gattc_rx_exec_fn(struct ble_gattc_proc *proc, int status);
347 
348 static ble_gattc_rx_adata_fn ble_gattc_find_inc_svcs_rx_adata;
349 static ble_gattc_rx_complete_fn ble_gattc_find_inc_svcs_rx_complete;
350 static ble_gattc_rx_attr_fn ble_gattc_find_inc_svcs_rx_read_rsp;
351 static ble_gattc_rx_adata_fn ble_gattc_disc_all_chrs_rx_adata;
352 static ble_gattc_rx_complete_fn ble_gattc_disc_all_chrs_rx_complete;
353 static ble_gattc_rx_adata_fn ble_gattc_disc_chr_uuid_rx_adata;
354 static ble_gattc_rx_complete_fn ble_gattc_disc_chr_uuid_rx_complete;
355 static ble_gattc_rx_attr_fn ble_gattc_read_rx_read_rsp;
356 static ble_gattc_rx_attr_fn ble_gattc_read_long_rx_read_rsp;
357 static ble_gattc_rx_adata_fn ble_gattc_read_uuid_rx_adata;
358 static ble_gattc_rx_complete_fn ble_gattc_read_uuid_rx_complete;
359 static ble_gattc_rx_prep_fn ble_gattc_write_long_rx_prep;
360 static ble_gattc_rx_exec_fn ble_gattc_write_long_rx_exec;
361 static ble_gattc_rx_prep_fn ble_gattc_write_reliable_rx_prep;
362 static ble_gattc_rx_exec_fn ble_gattc_write_reliable_rx_exec;
363 
364 static const struct ble_gattc_rx_adata_entry {
365     uint8_t op;
366     ble_gattc_rx_adata_fn *cb;
367 } ble_gattc_rx_read_type_elem_entries[] = {
368     { BLE_GATT_OP_FIND_INC_SVCS,    ble_gattc_find_inc_svcs_rx_adata },
369     { BLE_GATT_OP_DISC_ALL_CHRS,    ble_gattc_disc_all_chrs_rx_adata },
370     { BLE_GATT_OP_DISC_CHR_UUID,    ble_gattc_disc_chr_uuid_rx_adata },
371     { BLE_GATT_OP_READ_UUID,        ble_gattc_read_uuid_rx_adata },
372 };
373 
374 static const struct ble_gattc_rx_complete_entry {
375     uint8_t op;
376     ble_gattc_rx_complete_fn *cb;
377 } ble_gattc_rx_read_type_complete_entries[] = {
378     { BLE_GATT_OP_FIND_INC_SVCS,    ble_gattc_find_inc_svcs_rx_complete },
379     { BLE_GATT_OP_DISC_ALL_CHRS,    ble_gattc_disc_all_chrs_rx_complete },
380     { BLE_GATT_OP_DISC_CHR_UUID,    ble_gattc_disc_chr_uuid_rx_complete },
381     { BLE_GATT_OP_READ_UUID,        ble_gattc_read_uuid_rx_complete },
382 };
383 
384 static const struct ble_gattc_rx_attr_entry {
385     uint8_t op;
386     ble_gattc_rx_attr_fn *cb;
387 } ble_gattc_rx_read_rsp_entries[] = {
388     { BLE_GATT_OP_READ,             ble_gattc_read_rx_read_rsp },
389     { BLE_GATT_OP_READ_LONG,        ble_gattc_read_long_rx_read_rsp },
390     { BLE_GATT_OP_FIND_INC_SVCS,    ble_gattc_find_inc_svcs_rx_read_rsp },
391 };
392 
393 static const struct ble_gattc_rx_prep_entry {
394     uint8_t op;
395     ble_gattc_rx_prep_fn *cb;
396 } ble_gattc_rx_prep_entries[] = {
397     { BLE_GATT_OP_WRITE_LONG,       ble_gattc_write_long_rx_prep },
398     { BLE_GATT_OP_WRITE_RELIABLE,   ble_gattc_write_reliable_rx_prep },
399 };
400 
401 static const struct ble_gattc_rx_exec_entry {
402     uint8_t op;
403     ble_gattc_rx_exec_fn *cb;
404 } ble_gattc_rx_exec_entries[] = {
405     { BLE_GATT_OP_WRITE_LONG,       ble_gattc_write_long_rx_exec },
406     { BLE_GATT_OP_WRITE_RELIABLE,   ble_gattc_write_reliable_rx_exec },
407 };
408 
409 static os_membuf_t ble_gattc_proc_mem[
410                  OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_GATT_MAX_PROCS),
411                                  sizeof(struct ble_gattc_proc))
412 ];
413 
414 static struct os_mempool ble_gattc_proc_pool;
415 
416 /* The list of active GATT client procedures. */
417 static struct ble_gattc_proc_list ble_gattc_procs;
418 
419 /* The time when we should attempt to resume stalled procedures, in OS ticks.
420  * A value of 0 indicates no stalled procedures.
421  */
422 static ble_npl_time_t ble_gattc_resume_at;
423 
424 /* Statistics. */
425 STATS_SECT_DECL(ble_gattc_stats) ble_gattc_stats;
426 STATS_NAME_START(ble_gattc_stats)
STATS_NAME(ble_gattc_stats,mtu)427 STATS_NAME(ble_gattc_stats, mtu)
428 STATS_NAME(ble_gattc_stats, mtu_fail)
429 STATS_NAME(ble_gattc_stats, disc_all_svcs)
430 STATS_NAME(ble_gattc_stats, disc_all_svcs_fail)
431 STATS_NAME(ble_gattc_stats, disc_svc_uuid)
432 STATS_NAME(ble_gattc_stats, disc_svc_uuid_fail)
433 STATS_NAME(ble_gattc_stats, find_inc_svcs)
434 STATS_NAME(ble_gattc_stats, find_inc_svcs_fail)
435 STATS_NAME(ble_gattc_stats, disc_all_chrs)
436 STATS_NAME(ble_gattc_stats, disc_all_chrs_fail)
437 STATS_NAME(ble_gattc_stats, disc_chrs_uuid)
438 STATS_NAME(ble_gattc_stats, disc_chrs_uuid_fail)
439 STATS_NAME(ble_gattc_stats, disc_all_dscs)
440 STATS_NAME(ble_gattc_stats, disc_all_dscs_fail)
441 STATS_NAME(ble_gattc_stats, read)
442 STATS_NAME(ble_gattc_stats, read_fail)
443 STATS_NAME(ble_gattc_stats, read_uuid)
444 STATS_NAME(ble_gattc_stats, read_uuid_fail)
445 STATS_NAME(ble_gattc_stats, read_long)
446 STATS_NAME(ble_gattc_stats, read_long_fail)
447 STATS_NAME(ble_gattc_stats, read_mult)
448 STATS_NAME(ble_gattc_stats, read_mult_fail)
449 STATS_NAME(ble_gattc_stats, write_no_rsp)
450 STATS_NAME(ble_gattc_stats, write_no_rsp_fail)
451 STATS_NAME(ble_gattc_stats, write)
452 STATS_NAME(ble_gattc_stats, write_fail)
453 STATS_NAME(ble_gattc_stats, write_long)
454 STATS_NAME(ble_gattc_stats, write_long_fail)
455 STATS_NAME(ble_gattc_stats, write_reliable)
456 STATS_NAME(ble_gattc_stats, write_reliable_fail)
457 STATS_NAME(ble_gattc_stats, notify)
458 STATS_NAME(ble_gattc_stats, notify_fail)
459 STATS_NAME(ble_gattc_stats, indicate)
460 STATS_NAME(ble_gattc_stats, indicate_fail)
461 STATS_NAME(ble_gattc_stats, proc_timeout)
462 STATS_NAME_END(ble_gattc_stats)
463 
464 /*****************************************************************************
465  * $debug                                                                    *
466  *****************************************************************************/
467 
468 static void ble_gattc_dbg_assert_proc_not_inserted(struct ble_gattc_proc *proc)
469 {
470 #if MYNEWT_VAL(BLE_HS_DEBUG)
471     struct ble_gattc_proc *cur;
472     ble_hs_lock();
473     STAILQ_FOREACH(cur, &ble_gattc_procs, next) {
474         BLE_HS_DBG_ASSERT(cur != proc);
475     }
476     ble_hs_unlock();
477 #endif
478 }
479 
480 /*****************************************************************************
481  * $log                                                                      *
482  *****************************************************************************/
483 
ble_gattc_log_proc_init(const char * name)484 static void ble_gattc_log_proc_init(const char *name)
485 {
486     BLE_HS_LOG(INFO, "GATT procedure initiated: %s", name);
487 }
488 
ble_gattc_log_uuid(const ble_uuid_t * uuid)489 static void ble_gattc_log_uuid(const ble_uuid_t *uuid)
490 {
491     char buf[BLE_UUID_STR_LEN];
492     ble_uuid_to_str(uuid, buf);
493     BLE_HS_LOG(INFO, "%s", buf);
494 }
495 
ble_gattc_log_disc_svc_uuid(struct ble_gattc_proc * proc)496 static void ble_gattc_log_disc_svc_uuid(struct ble_gattc_proc *proc)
497 {
498     ble_gattc_log_proc_init("discover service by uuid; uuid=");
499     ble_gattc_log_uuid(&proc->disc_svc_uuid.service_uuid.u);
500     BLE_HS_LOG(INFO, "\n");
501 }
502 
ble_gattc_log_find_inc_svcs(struct ble_gattc_proc * proc)503 static void ble_gattc_log_find_inc_svcs(struct ble_gattc_proc *proc)
504 {
505     ble_gattc_log_proc_init("find included services; ");
506     BLE_HS_LOG(INFO, "start_handle=%d end_handle=%d\n",
507                proc->find_inc_svcs.prev_handle + 1,
508                proc->find_inc_svcs.end_handle);
509 }
510 
ble_gattc_log_disc_all_chrs(struct ble_gattc_proc * proc)511 static void ble_gattc_log_disc_all_chrs(struct ble_gattc_proc *proc)
512 {
513     ble_gattc_log_proc_init("discover all characteristics; ");
514     BLE_HS_LOG(INFO, "start_handle=%d end_handle=%d\n",
515                proc->disc_all_chrs.prev_handle + 1,
516                proc->disc_all_chrs.end_handle);
517 }
518 
ble_gattc_log_disc_chr_uuid(struct ble_gattc_proc * proc)519 static void ble_gattc_log_disc_chr_uuid(struct ble_gattc_proc *proc)
520 {
521     ble_gattc_log_proc_init("discover characteristics by uuid; ");
522     BLE_HS_LOG(INFO, "start_handle=%d end_handle=%d uuid=",
523                proc->disc_chr_uuid.prev_handle + 1,
524                proc->disc_chr_uuid.end_handle);
525     ble_gattc_log_uuid(&proc->disc_chr_uuid.chr_uuid.u);
526     BLE_HS_LOG(INFO, "\n");
527 }
528 
ble_gattc_log_disc_all_dscs(struct ble_gattc_proc * proc)529 static void ble_gattc_log_disc_all_dscs(struct ble_gattc_proc *proc)
530 {
531     ble_gattc_log_proc_init("discover all descriptors; ");
532     BLE_HS_LOG(INFO, "chr_val_handle=%d end_handle=%d\n",
533                proc->disc_all_dscs.chr_val_handle,
534                proc->disc_all_dscs.end_handle);
535 }
536 
ble_gattc_log_read(uint16_t att_handle)537 static void ble_gattc_log_read(uint16_t att_handle)
538 {
539     ble_gattc_log_proc_init("read; ");
540     BLE_HS_LOG(INFO, "att_handle=%d\n", att_handle);
541 }
542 
ble_gattc_log_read_uuid(uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid)543 static void ble_gattc_log_read_uuid(uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid)
544 {
545     ble_gattc_log_proc_init("read by uuid; ");
546     BLE_HS_LOG(INFO, "start_handle=%d end_handle=%d uuid=",
547                start_handle, end_handle);
548     ble_gattc_log_uuid(uuid);
549     BLE_HS_LOG(INFO, "\n");
550 }
551 
ble_gattc_log_read_long(struct ble_gattc_proc * proc)552 static void ble_gattc_log_read_long(struct ble_gattc_proc *proc)
553 {
554     ble_gattc_log_proc_init("read long; ");
555     BLE_HS_LOG(INFO, "att_handle=%d\n", proc->read_long.handle);
556 }
557 
ble_gattc_log_read_mult(const uint16_t * handles,uint8_t num_handles)558 static void ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles)
559 {
560     int i;
561     ble_gattc_log_proc_init("read multiple; ");
562     BLE_HS_LOG(INFO, "att_handles=");
563 
564     for (i = 0; i < num_handles; i++) {
565         BLE_HS_LOG(INFO, "%s%d", i != 0 ? "," : "", handles[i]);
566     }
567 
568     BLE_HS_LOG(INFO, "\n");
569 }
570 
ble_gattc_log_write(uint16_t att_handle,uint16_t len,int expecting_rsp)571 static void ble_gattc_log_write(uint16_t att_handle, uint16_t len, int expecting_rsp)
572 {
573     const char *name;
574 
575     if (expecting_rsp) {
576         name = "write; ";
577     } else {
578         name = "write no rsp; ";
579     }
580 
581     ble_gattc_log_proc_init(name);
582     BLE_HS_LOG(INFO, "att_handle=%d len=%d\n", att_handle, len);
583 }
584 
ble_gattc_log_write_long(struct ble_gattc_proc * proc)585 static void ble_gattc_log_write_long(struct ble_gattc_proc *proc)
586 {
587     ble_gattc_log_proc_init("write long; ");
588     BLE_HS_LOG(INFO, "att_handle=%d len=%d\n",
589                proc->write_long.attr.handle,
590                OS_MBUF_PKTLEN(proc->write_long.attr.om));
591 }
592 
ble_gattc_log_write_reliable(struct ble_gattc_proc * proc)593 static void ble_gattc_log_write_reliable(struct ble_gattc_proc *proc)
594 {
595     int i;
596     ble_gattc_log_proc_init("write reliable; ");
597     BLE_HS_LOG(INFO, "att_handles=");
598 
599     for (i = 0; i < proc->write_reliable.num_attrs; i++) {
600         BLE_HS_LOG(INFO, "%s%d", i != 0 ? "," : "",
601                    proc->write_reliable.attrs[i].handle);
602     }
603 
604     BLE_HS_LOG(INFO, "\r\n");
605 }
606 
ble_gattc_log_notify(uint16_t att_handle)607 static void ble_gattc_log_notify(uint16_t att_handle)
608 {
609     ble_gattc_log_proc_init("notify; ");
610     BLE_HS_LOG(INFO, "att_handle=%d\r\n", att_handle);
611 }
612 
ble_gattc_log_indicate(uint16_t att_handle)613 static void ble_gattc_log_indicate(uint16_t att_handle)
614 {
615     ble_gattc_log_proc_init("indicate; ");
616     BLE_HS_LOG(INFO, "att_handle=%d\r\n", att_handle);
617 }
618 
619 /*****************************************************************************
620  * $rx entry                                                                 *
621  *****************************************************************************/
622 
ble_gattc_rx_entry_find(uint8_t op,const void * rx_entries,int num_entries)623 static const void *ble_gattc_rx_entry_find(uint8_t op, const void *rx_entries, int num_entries)
624 {
625     struct gen_entry {
626         uint8_t op;
627         void (*cb)(void);
628     };
629     const struct gen_entry *entries;
630     int i;
631     entries = rx_entries;
632 
633     for (i = 0; i < num_entries; i++) {
634         if (entries[i].op == op) {
635             return entries + i;
636         }
637     }
638 
639     return NULL;
640 }
641 
642 /*****************************************************************************
643  * $proc                                                                    *
644  *****************************************************************************/
645 
646 /**
647  * Allocates a proc entry.
648  *
649  * @return                      An entry on success; null on failure.
650  */
ble_gattc_proc_alloc(void)651 static struct ble_gattc_proc *ble_gattc_proc_alloc(void)
652 {
653     struct ble_gattc_proc *proc;
654     proc = os_memblock_get(&ble_gattc_proc_pool);
655     if (proc != NULL) {
656         memset_s(proc, sizeof(*proc), 0, sizeof(*proc));
657     }
658 
659     return proc;
660 }
661 
662 /**
663  * Frees the specified proc entry.  No-op if passed a null pointer.
664  */
ble_gattc_proc_free(struct ble_gattc_proc * proc)665 static void ble_gattc_proc_free(struct ble_gattc_proc *proc)
666 {
667     if (proc != NULL) {
668         ble_gattc_dbg_assert_proc_not_inserted(proc);
669 
670         switch (proc->op) {
671             case BLE_GATT_OP_WRITE_LONG:
672                 os_mbuf_free_chain(proc->write_long.attr.om);
673                 break;
674 
675             case BLE_GATT_OP_WRITE_RELIABLE:
676                 for (int i = 0; i < proc->write_reliable.num_attrs; i++) {
677                     os_mbuf_free_chain(proc->write_reliable.attrs[i].om);
678                 }
679 
680                 break;
681 
682             default:
683                 break;
684         }
685 
686 #if MYNEWT_VAL(BLE_HS_DEBUG)
687         memset_s(proc, sizeof(*proc), 0xff, sizeof(*proc));
688 #endif
689         int rc = os_memblock_put(&ble_gattc_proc_pool, proc);
690         BLE_HS_DBG_ASSERT_EVAL(rc == 0);
691     }
692 }
693 
ble_gattc_proc_insert(struct ble_gattc_proc * proc)694 static void ble_gattc_proc_insert(struct ble_gattc_proc *proc)
695 {
696     ble_gattc_dbg_assert_proc_not_inserted(proc);
697     ble_hs_lock();
698     STAILQ_INSERT_TAIL(&ble_gattc_procs, proc, next);
699     ble_hs_unlock();
700 }
701 
ble_gattc_proc_set_exp_timer(struct ble_gattc_proc * proc)702 static void ble_gattc_proc_set_exp_timer(struct ble_gattc_proc *proc)
703 {
704     proc->exp_os_ticks = ble_npl_time_get() +
705                          ble_npl_time_ms_to_ticks32(BLE_GATTC_UNRESPONSIVE_TIMEOUT_MS);
706 }
707 
ble_gattc_proc_set_resume_timer(struct ble_gattc_proc * proc)708 static void ble_gattc_proc_set_resume_timer(struct ble_gattc_proc *proc)
709 {
710     proc->flags |= BLE_GATTC_PROC_F_STALLED;
711 
712     /* Don't overwrite resume time if it is already set; piggyback on it
713      * instead.
714      */
715     if (ble_gattc_resume_at == 0) {
716         ble_gattc_resume_at = ble_npl_time_get() +
717                               ble_npl_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE));
718         /* A value of 0 indicates the timer is unset.  Disambiguate this. */
719         if (ble_gattc_resume_at == 0) {
720             ble_gattc_resume_at++;
721         }
722     }
723 }
724 
ble_gattc_process_status(struct ble_gattc_proc * proc,int status)725 static void ble_gattc_process_status(struct ble_gattc_proc *proc, int status)
726 {
727     switch (status) {
728         case 0:
729             if (!(proc->flags & BLE_GATTC_PROC_F_STALLED)) {
730                 ble_gattc_proc_set_exp_timer(proc);
731             }
732 
733             ble_gattc_proc_insert(proc);
734             ble_hs_timer_resched();
735             break;
736 
737         default:
738             ble_gattc_proc_free(proc);
739             break;
740     }
741 }
742 
743 /**
744  * Processes the return code that results from an attempt to resume a
745  * procedure.  If the resume attempt failed due to memory exhaustion at a lower
746  * layer, the procedure is marked as stalled but still in progress.  Otherwise,
747  * the resume error code is unmodified.
748  */
ble_gattc_process_resume_status(struct ble_gattc_proc * proc,int status)749 static int ble_gattc_process_resume_status(struct ble_gattc_proc *proc, int status)
750 {
751     switch (status) {
752         case 0:
753             return 0;
754 
755         case BLE_HS_ENOMEM:
756             ble_gattc_proc_set_resume_timer(proc);
757             return 0;
758 
759         default:
760             return status;
761     }
762 }
763 
764 /*****************************************************************************
765  * $util                                                                     *
766  *****************************************************************************/
767 
768 /**
769  * Retrieves the error dispatch entry with the specified op code.
770  */
ble_gattc_err_dispatch_get(uint8_t op)771 static ble_gattc_err_fn *ble_gattc_err_dispatch_get(uint8_t op)
772 {
773     BLE_HS_DBG_ASSERT(op < BLE_GATT_OP_CNT);
774     return ble_gattc_err_dispatch[op];
775 }
776 
777 /**
778  * Retrieves the error dispatch entry with the specified op code.
779  */
ble_gattc_resume_dispatch_get(uint8_t op)780 static ble_gattc_resume_fn *ble_gattc_resume_dispatch_get(uint8_t op)
781 {
782     BLE_HS_DBG_ASSERT(op < BLE_GATT_OP_CNT);
783     return ble_gattc_resume_dispatch[op];
784 }
785 
ble_gattc_tmo_dispatch_get(uint8_t op)786 static ble_gattc_tmo_fn *ble_gattc_tmo_dispatch_get(uint8_t op)
787 {
788     BLE_HS_DBG_ASSERT(op < BLE_GATT_OP_CNT);
789     return ble_gattc_tmo_dispatch[op];
790 }
791 
792 typedef int ble_gattc_match_fn(struct ble_gattc_proc *proc, void *arg);
793 
794 struct ble_gattc_criteria_conn_op {
795     uint16_t conn_handle;
796     uint8_t op;
797 };
798 
799 /**
800  * Tests if a proc entry fits the specified criteria.
801  *
802  * @param proc                  The procedure to test.
803  * @param conn_handle           The connection handle to match against.
804  * @param op                    The op code to match against, or
805  *                                  BLE_GATT_OP_NONE to ignore this criterion.
806  *
807  * @return                      1 if the proc matches; 0 otherwise.
808  */
ble_gattc_proc_matches_conn_op(struct ble_gattc_proc * proc,void * arg)809 static int ble_gattc_proc_matches_conn_op(struct ble_gattc_proc *proc, void *arg)
810 {
811     const struct ble_gattc_criteria_conn_op *criteria;
812     criteria = arg;
813     if (criteria->conn_handle != proc->conn_handle) {
814         return 0;
815     }
816 
817     if (criteria->op != proc->op && criteria->op != BLE_GATT_OP_NONE) {
818         return 0;
819     }
820 
821     return 1;
822 }
823 
824 struct ble_gattc_criteria_exp {
825     ble_npl_time_t now;
826     int32_t next_exp_in;
827 };
828 
ble_gattc_proc_matches_expired(struct ble_gattc_proc * proc,void * arg)829 static int ble_gattc_proc_matches_expired(struct ble_gattc_proc *proc, void *arg)
830 {
831     struct ble_gattc_criteria_exp *criteria;
832     int32_t time_diff;
833     criteria = arg;
834     time_diff = proc->exp_os_ticks - criteria->now;
835     if (time_diff <= 0) {
836         /* Procedure is expired. */
837         return 1;
838     }
839 
840     /* Procedure isn't expired; determine if it is the next to expire. */
841     if (time_diff < criteria->next_exp_in) {
842         criteria->next_exp_in = time_diff;
843     }
844 
845     return 0;
846 }
847 
848 struct ble_gattc_criteria_conn_rx_entry {
849     uint16_t conn_handle;
850     const void *rx_entries;
851     int num_rx_entries;
852     const void *matching_rx_entry;
853 };
854 
ble_gattc_proc_matches_conn_rx_entry(struct ble_gattc_proc * proc,void * arg)855 static int ble_gattc_proc_matches_conn_rx_entry(struct ble_gattc_proc *proc, void *arg)
856 {
857     struct ble_gattc_criteria_conn_rx_entry *criteria;
858     criteria = arg;
859     if (criteria->conn_handle != BLE_HS_CONN_HANDLE_NONE &&
860             criteria->conn_handle != proc->conn_handle) {
861         return 0;
862     }
863 
864     /* Entry matches; indicate corresponding rx entry. */
865     criteria->matching_rx_entry = ble_gattc_rx_entry_find(proc->op, criteria->rx_entries, criteria->num_rx_entries);
866     return (criteria->matching_rx_entry != NULL);
867 }
868 
ble_gattc_extract(ble_gattc_match_fn * cb,void * arg,int max_procs,struct ble_gattc_proc_list * dst_list)869 static void ble_gattc_extract(ble_gattc_match_fn *cb, void *arg, int max_procs, struct ble_gattc_proc_list *dst_list)
870 {
871     struct ble_gattc_proc *proc;
872     struct ble_gattc_proc *prev;
873     struct ble_gattc_proc *next;
874     int num_extracted;
875     /* Only the parent task is allowed to remove entries from the list. */
876     BLE_HS_DBG_ASSERT(ble_hs_is_parent_task());
877     STAILQ_INIT(dst_list);
878     num_extracted = 0;
879     ble_hs_lock();
880     prev = NULL;
881     proc = STAILQ_FIRST(&ble_gattc_procs);
882     while (proc != NULL) {
883         next = STAILQ_NEXT(proc, next);
884 
885         if (cb(proc, arg)) {
886             if (prev == NULL) {
887                 STAILQ_REMOVE_HEAD(&ble_gattc_procs, next);
888             } else {
889                 STAILQ_REMOVE_AFTER(&ble_gattc_procs, prev, next);
890             }
891 
892             STAILQ_INSERT_TAIL(dst_list, proc, next);
893 
894             if (max_procs > 0) {
895                 num_extracted++;
896 
897                 if (num_extracted >= max_procs) {
898                     break;
899                 }
900             }
901         } else {
902             prev = proc;
903         }
904 
905         proc = next;
906     }
907 
908     ble_hs_unlock();
909 }
910 
ble_gattc_extract_one(ble_gattc_match_fn * cb,void * arg)911 static struct ble_gattc_proc *ble_gattc_extract_one(ble_gattc_match_fn *cb, void *arg)
912 {
913     struct ble_gattc_proc_list dst_list;
914     ble_gattc_extract(cb, arg, 1, &dst_list);
915     return STAILQ_FIRST(&dst_list);
916 }
917 
ble_gattc_extract_by_conn_op(uint16_t conn_handle,uint8_t op,int max_procs,struct ble_gattc_proc_list * dst_list)918 static void ble_gattc_extract_by_conn_op(uint16_t conn_handle, uint8_t op, int max_procs,
919                                          struct ble_gattc_proc_list *dst_list)
920 {
921     struct ble_gattc_criteria_conn_op criteria;
922     criteria.conn_handle = conn_handle;
923     criteria.op = op;
924     ble_gattc_extract(ble_gattc_proc_matches_conn_op, &criteria, max_procs, dst_list);
925 }
926 
ble_gattc_extract_first_by_conn_op(uint16_t conn_handle,uint8_t op)927 static struct ble_gattc_proc *ble_gattc_extract_first_by_conn_op(uint16_t conn_handle, uint8_t op)
928 {
929     struct ble_gattc_proc_list dst_list;
930     ble_gattc_extract_by_conn_op(conn_handle, op, 1, &dst_list);
931     return STAILQ_FIRST(&dst_list);
932 }
933 
ble_gattc_proc_matches_stalled(struct ble_gattc_proc * proc,void * unused)934 static int ble_gattc_proc_matches_stalled(struct ble_gattc_proc *proc, void *unused)
935 {
936     return proc->flags & BLE_GATTC_PROC_F_STALLED;
937 }
938 
ble_gattc_extract_stalled(struct ble_gattc_proc_list * dst_list)939 static void ble_gattc_extract_stalled(struct ble_gattc_proc_list *dst_list)
940 {
941     ble_gattc_extract(ble_gattc_proc_matches_stalled, NULL, 0, dst_list);
942 }
943 
944 /**
945  * @return                      The number of ticks until the next expiration
946  *                                  occurs.
947  */
ble_gattc_extract_expired(struct ble_gattc_proc_list * dst_list)948 static int32_t ble_gattc_extract_expired(struct ble_gattc_proc_list *dst_list)
949 {
950     struct ble_gattc_criteria_exp criteria;
951     criteria.now = ble_npl_time_get();
952     criteria.next_exp_in = BLE_HS_FOREVER;
953     STAILQ_INIT(dst_list);
954     ble_gattc_extract(ble_gattc_proc_matches_expired, &criteria, 0, dst_list);
955     return criteria.next_exp_in;
956 }
957 
ble_gattc_extract_with_rx_entry(uint16_t conn_handle,const void * rx_entries,int num_rx_entries,const void ** out_rx_entry)958 static struct ble_gattc_proc *ble_gattc_extract_with_rx_entry(uint16_t conn_handle,
959     const void *rx_entries, int num_rx_entries,
960     const void **out_rx_entry)
961 {
962     struct ble_gattc_criteria_conn_rx_entry criteria;
963     struct ble_gattc_proc *proc;
964     criteria.conn_handle = conn_handle;
965     criteria.rx_entries = rx_entries;
966     criteria.num_rx_entries = num_rx_entries;
967     criteria.matching_rx_entry = NULL;
968     proc = ble_gattc_extract_one(ble_gattc_proc_matches_conn_rx_entry,
969                                  &criteria);
970     *out_rx_entry = criteria.matching_rx_entry;
971     return proc;
972 }
973 
974 /**
975  * Searches the main proc list for an entry whose connection handle and op code
976  * match those specified.  If a matching entry is found, it is removed from the
977  * list and returned.
978  *
979  * @param conn_handle           The connection handle to match against.
980  * @param rx_entries            The array of rx entries corresponding to the
981  *                                  op code of the incoming response.
982  * @param out_rx_entry          On success, the address of the matching rx
983  *                                  entry is written to this pointer.
984  *
985  * @return                      The matching proc entry on success;
986  *                                  null on failure.
987  */
988 #define BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, rx_entries, out_rx_entry)  \
989     ble_gattc_extract_with_rx_entry(                                          \
990     (conn_handle), (rx_entries),                                              \
991     sizeof (rx_entries) / sizeof (rx_entries)[0],                             \
992     (const void **)(out_rx_entry))
993 
994 /**
995  * Causes all GATT procedures matching the specified criteria to fail with the
996  * specified status code.
997  */
ble_gattc_fail_procs(uint16_t conn_handle,uint8_t op,int status)998 static void ble_gattc_fail_procs(uint16_t conn_handle, uint8_t op, int status)
999 {
1000     struct ble_gattc_proc_list temp_list;
1001     struct ble_gattc_proc *proc;
1002 
1003     /* Remove all procs with the specified conn handle-op-pair and insert them
1004      * into the temporary list.
1005      */
1006     ble_gattc_extract_by_conn_op(conn_handle, op, 0, &temp_list);
1007 
1008     /* Notify application of failed procedures and free the corresponding proc
1009      * entries.
1010      */
1011     while ((proc = STAILQ_FIRST(&temp_list)) != NULL) {
1012         ble_gattc_err_fn *err_cb = ble_gattc_err_dispatch_get(proc->op);
1013         err_cb(proc, status, 0);
1014         STAILQ_REMOVE_HEAD(&temp_list, next);
1015         ble_gattc_proc_free(proc);
1016     }
1017 }
1018 
ble_gattc_resume_procs(void)1019 static void ble_gattc_resume_procs(void)
1020 {
1021     struct ble_gattc_proc_list stall_list;
1022     struct ble_gattc_proc *proc;
1023     ble_gattc_resume_fn *resume_cb;
1024 
1025     /* Cancel resume timer since it is being serviced. */
1026     ble_gattc_resume_at = 0;
1027     ble_gattc_extract_stalled(&stall_list);
1028     STAILQ_FOREACH(proc, &stall_list, next) {
1029         resume_cb = ble_gattc_resume_dispatch_get(proc->op);
1030         BLE_HS_DBG_ASSERT(resume_cb != NULL);
1031         proc->flags &= ~BLE_GATTC_PROC_F_STALLED;
1032         int rc = resume_cb(proc);
1033         ble_gattc_process_status(proc, rc);
1034     }
1035 }
1036 
ble_gattc_ticks_until_resume(void)1037 static int32_t ble_gattc_ticks_until_resume(void)
1038 {
1039     ble_npl_time_t now;
1040     int32_t diff;
1041 
1042     /* Resume timer not set. */
1043     if (ble_gattc_resume_at == 0) {
1044         return BLE_HS_FOREVER;
1045     }
1046 
1047     now = ble_npl_time_get();
1048     diff = ble_gattc_resume_at - now;
1049     if (diff <= 0) {
1050         /* Timer already expired; resume immediately. */
1051         return 0;
1052     }
1053 
1054     return diff;
1055 }
1056 
ble_gattc_proc_timeout(struct ble_gattc_proc * proc)1057 static void ble_gattc_proc_timeout(struct ble_gattc_proc *proc)
1058 {
1059     ble_gattc_tmo_fn *cb;
1060     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1061     ble_gattc_dbg_assert_proc_not_inserted(proc);
1062     cb = ble_gattc_tmo_dispatch_get(proc->op);
1063     if (cb != NULL) {
1064         cb(proc);
1065     }
1066 }
1067 
1068 /**
1069  * Times out expired GATT client procedures.
1070  *
1071  * @return                      The number of ticks until this function should
1072  *                                  be called again.
1073  */
ble_gattc_timer(void)1074 int32_t ble_gattc_timer(void)
1075 {
1076     struct ble_gattc_proc_list exp_list;
1077     struct ble_gattc_proc *proc;
1078     int32_t ticks_until_resume;
1079     int32_t ticks_until_exp;
1080     /* Remove timed-out procedures from the main list and insert them into a
1081      * temporary list.  This function also calculates the number of ticks until
1082      * the next expiration will occur.
1083      */
1084     ticks_until_exp = ble_gattc_extract_expired(&exp_list);
1085 
1086     /* Terminate the connection associated with each timed-out procedure. */
1087     while ((proc = STAILQ_FIRST(&exp_list)) != NULL) {
1088         STATS_INC(ble_gattc_stats, proc_timeout);
1089         ble_gattc_proc_timeout(proc);
1090         ble_gap_terminate(proc->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
1091         STAILQ_REMOVE_HEAD(&exp_list, next);
1092         ble_gattc_proc_free(proc);
1093     }
1094 
1095     /* If there are stalled procedures, the GATT client will need to wake up to
1096      * resume them.
1097      */
1098     ticks_until_resume = ble_gattc_ticks_until_resume();
1099     if (ticks_until_resume == 0) {
1100         ble_gattc_resume_procs();
1101         ticks_until_resume = ble_gattc_ticks_until_resume();
1102     }
1103 
1104     return min(ticks_until_exp, ticks_until_resume);
1105 }
1106 
1107 /**
1108  * Returns a pointer to a GATT error object with the specified fields.  The
1109  * returned object is statically allocated, so this function is not reentrant.
1110  * This function should only ever be called by the ble_hs task.
1111  */
ble_gattc_error(int status,uint16_t att_handle)1112 static struct ble_gatt_error *ble_gattc_error(int status, uint16_t att_handle)
1113 {
1114     static struct ble_gatt_error error;
1115     uint16_t att_handle_tmp = att_handle;
1116     /* For consistency, always indicate a handle of 0 on success. */
1117     if (status == 0 || status == BLE_HS_EDONE) {
1118         att_handle_tmp = 0;
1119     }
1120 
1121     error.status = status;
1122     error.att_handle = att_handle_tmp;
1123     return &error;
1124 }
1125 
1126 /*****************************************************************************
1127  * $mtu                                                                      *
1128  *****************************************************************************/
1129 
1130 /**
1131  * Calls an mtu-exchange proc's callback with the specified parameters.  If the
1132  * proc has no callback, this function is a no-op.
1133  *
1134  * @return                      The return code of the callback (or 0 if there
1135  *                                  is no callback).
1136  */
ble_gattc_mtu_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,uint16_t mtu)1137 static int ble_gattc_mtu_cb(struct ble_gattc_proc *proc, int status, uint16_t att_handle, uint16_t mtu)
1138 {
1139     int rc;
1140     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1141     ble_gattc_dbg_assert_proc_not_inserted(proc);
1142 
1143     if (status != 0 && status != BLE_HS_EDONE) {
1144         STATS_INC(ble_gattc_stats, mtu_fail);
1145     }
1146 
1147     if (proc->mtu.cb == NULL) {
1148         rc = 0;
1149     } else {
1150         rc = proc->mtu.cb(proc->conn_handle,
1151                           ble_gattc_error(status, att_handle),
1152                           mtu, proc->mtu.cb_arg);
1153     }
1154 
1155     return rc;
1156 }
1157 
ble_gattc_mtu_tmo(struct ble_gattc_proc * proc)1158 static void ble_gattc_mtu_tmo(struct ble_gattc_proc *proc)
1159 {
1160     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1161     ble_gattc_dbg_assert_proc_not_inserted(proc);
1162     ble_gattc_mtu_cb(proc, BLE_HS_ETIMEOUT, 0, 0);
1163 }
1164 
1165 /**
1166  * Handles an incoming ATT error response for the specified mtu-exchange proc.
1167  */
ble_gattc_mtu_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)1168 static void ble_gattc_mtu_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
1169 {
1170     ble_gattc_dbg_assert_proc_not_inserted(proc);
1171     ble_gattc_mtu_cb(proc, status, att_handle, 0);
1172 }
1173 
ble_gattc_mtu_tx(struct ble_gattc_proc * proc)1174 static int ble_gattc_mtu_tx(struct ble_gattc_proc *proc)
1175 {
1176     struct ble_l2cap_chan *chan;
1177     struct ble_hs_conn *conn;
1178     uint16_t mtu;
1179     int rc;
1180     ble_hs_lock();
1181     rc = ble_att_conn_chan_find(proc->conn_handle, &conn, &chan);
1182     if (rc == 0) {
1183         mtu = chan->my_mtu;
1184     }
1185 
1186     ble_hs_unlock();
1187 
1188     if (rc == 0) {
1189         rc = ble_att_clt_tx_mtu(proc->conn_handle, mtu);
1190     }
1191 
1192     return rc;
1193 }
1194 
ble_gattc_exchange_mtu(uint16_t conn_handle,ble_gatt_mtu_fn * cb,void * cb_arg)1195 int ble_gattc_exchange_mtu(uint16_t conn_handle, ble_gatt_mtu_fn *cb, void *cb_arg)
1196 {
1197     struct ble_gattc_proc *proc;
1198     int rc;
1199     STATS_INC(ble_gattc_stats, mtu);
1200     proc = ble_gattc_proc_alloc();
1201     if (proc == NULL) {
1202         rc = BLE_HS_ENOMEM;
1203         goto done;
1204     }
1205 
1206     proc->op = BLE_GATT_OP_MTU;
1207     proc->conn_handle = conn_handle;
1208     proc->mtu.cb = cb;
1209     proc->mtu.cb_arg = cb_arg;
1210     ble_gattc_log_proc_init("exchange mtu\n");
1211     rc = ble_gattc_mtu_tx(proc);
1212     if (rc != 0) {
1213         goto done;
1214     }
1215 
1216 done:
1217 
1218     if (rc != 0) {
1219         STATS_INC(ble_gattc_stats, mtu_fail);
1220     }
1221 
1222     ble_gattc_process_status(proc, rc);
1223     return rc;
1224 }
1225 
1226 /*****************************************************************************
1227  * $discover all services                                                    *
1228  *****************************************************************************/
1229 
1230 /**
1231  * Calls a discover-all-services proc's callback with the specified parameters.
1232  * If the proc has no callback, this function is a no-op.
1233  *
1234  * @return                      The return code of the callback (or 0 if there
1235  *                                  is no callback).
1236  */
ble_gattc_disc_all_svcs_cb(struct ble_gattc_proc * proc,uint16_t status,uint16_t att_handle,struct ble_gatt_svc * service)1237 static int ble_gattc_disc_all_svcs_cb(struct ble_gattc_proc *proc,
1238                                       uint16_t status, uint16_t att_handle,
1239                                       struct ble_gatt_svc *service)
1240 {
1241     int rc;
1242     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1243     BLE_HS_DBG_ASSERT(service != NULL || status != 0);
1244     ble_gattc_dbg_assert_proc_not_inserted(proc);
1245 
1246     if (status != 0 && status != BLE_HS_EDONE) {
1247         STATS_INC(ble_gattc_stats, disc_all_svcs_fail);
1248     }
1249 
1250     if (proc->disc_all_svcs.cb == NULL) {
1251         rc = 0;
1252     } else {
1253         rc = proc->disc_all_svcs.cb(proc->conn_handle,
1254                                     ble_gattc_error(status, att_handle),
1255                                     service, proc->disc_all_svcs.cb_arg);
1256     }
1257 
1258     return rc;
1259 }
1260 
ble_gattc_disc_all_svcs_tmo(struct ble_gattc_proc * proc)1261 static void ble_gattc_disc_all_svcs_tmo(struct ble_gattc_proc *proc)
1262 {
1263     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1264     ble_gattc_dbg_assert_proc_not_inserted(proc);
1265     ble_gattc_disc_all_svcs_cb(proc, BLE_HS_ETIMEOUT, 0, 0);
1266 }
1267 
1268 /**
1269  * Triggers a pending transmit for the specified discover-all-services proc.
1270  */
ble_gattc_disc_all_svcs_tx(struct ble_gattc_proc * proc)1271 static int ble_gattc_disc_all_svcs_tx(struct ble_gattc_proc *proc)
1272 {
1273     ble_uuid16_t uuid = BLE_UUID16_INIT(BLE_ATT_UUID_PRIMARY_SERVICE);
1274     int rc;
1275     ble_gattc_dbg_assert_proc_not_inserted(proc);
1276     rc = ble_att_clt_tx_read_group_type(proc->conn_handle,
1277                                         proc->disc_all_svcs.prev_handle + 1,
1278                                         0xffff, &uuid.u);
1279     if (rc != 0) {
1280         return rc;
1281     }
1282 
1283     return 0;
1284 }
1285 
ble_gattc_disc_all_svcs_resume(struct ble_gattc_proc * proc)1286 static int ble_gattc_disc_all_svcs_resume(struct ble_gattc_proc *proc)
1287 {
1288     int status;
1289     int rc;
1290     status = ble_gattc_disc_all_svcs_tx(proc);
1291     rc = ble_gattc_process_resume_status(proc, status);
1292     if (rc != 0) {
1293         ble_gattc_disc_all_svcs_cb(proc, rc, 0, NULL);
1294         return rc;
1295     }
1296 
1297     return 0;
1298 }
1299 
1300 /**
1301  * Handles an incoming ATT error response for the specified
1302  * discover-all-services proc.
1303  */
ble_gattc_disc_all_svcs_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)1304 static void ble_gattc_disc_all_svcs_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
1305 {
1306     ble_gattc_dbg_assert_proc_not_inserted(proc);
1307 
1308     if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) {
1309         /* Discovery is complete. */
1310         status = BLE_HS_EDONE;
1311     }
1312 
1313     ble_gattc_disc_all_svcs_cb(proc, status, att_handle, NULL);
1314 }
1315 
1316 /**
1317  * Handles an incoming attribute data entry from a read-group-type response for
1318  * the specified discover-all-services proc.
1319  */
ble_gattc_disc_all_svcs_rx_adata(struct ble_gattc_proc * proc,struct ble_att_read_group_type_adata * adata)1320 static int ble_gattc_disc_all_svcs_rx_adata(struct ble_gattc_proc *proc, struct ble_att_read_group_type_adata *adata)
1321 {
1322     struct ble_gatt_svc service;
1323     int cbrc;
1324     int rc;
1325     ble_gattc_dbg_assert_proc_not_inserted(proc);
1326 
1327     switch (adata->value_len) {
1328         case 2: // 2:case value
1329         case 16: // 16:case value
1330             rc = ble_uuid_init_from_att_buf(&service.uuid, adata->value,
1331                                             adata->value_len);
1332             if (rc != 0) {
1333                 rc = BLE_HS_EBADDATA;
1334                 goto done;
1335             }
1336 
1337             break;
1338 
1339         default:
1340             rc = BLE_HS_EBADDATA;
1341             goto done;
1342     }
1343 
1344     if (adata->end_group_handle <= proc->disc_all_svcs.prev_handle) {
1345         /* Peer sent services out of order; terminate procedure. */
1346         rc = BLE_HS_EBADDATA;
1347         goto done;
1348     }
1349 
1350     proc->disc_all_svcs.prev_handle = adata->end_group_handle;
1351     service.start_handle = adata->att_handle;
1352     service.end_handle = adata->end_group_handle;
1353     rc = 0;
1354 done:
1355     cbrc = ble_gattc_disc_all_svcs_cb(proc, rc, 0, &service);
1356 
1357     if (rc != 0 || cbrc != 0) {
1358         return BLE_HS_EDONE;
1359     } else {
1360         return 0;
1361     }
1362 }
1363 
1364 /**
1365  * Handles a notification that an incoming read-group-type response has been
1366  * fully processed.
1367  */
ble_gattc_disc_all_svcs_rx_complete(struct ble_gattc_proc * proc,int status)1368 static int ble_gattc_disc_all_svcs_rx_complete(struct ble_gattc_proc *proc, int status)
1369 {
1370     int rc;
1371     ble_gattc_dbg_assert_proc_not_inserted(proc);
1372 
1373     if (status != 0) {
1374         ble_gattc_disc_all_svcs_cb(proc, status, 0, NULL);
1375         return BLE_HS_EDONE;
1376     }
1377 
1378     if (proc->disc_all_svcs.prev_handle == 0xffff) {
1379         /* Service discovery complete. */
1380         ble_gattc_disc_all_svcs_cb(proc, BLE_HS_EDONE, 0, NULL);
1381         return BLE_HS_EDONE;
1382     }
1383 
1384     /* Send follow-up request. */
1385     rc = ble_gattc_disc_all_svcs_resume(proc);
1386     if (rc != 0) {
1387         return BLE_HS_EDONE;
1388     }
1389 
1390     return 0;
1391 }
1392 
ble_gattc_disc_all_svcs(uint16_t conn_handle,ble_gatt_disc_svc_fn * cb,void * cb_arg)1393 int ble_gattc_disc_all_svcs(uint16_t conn_handle, ble_gatt_disc_svc_fn *cb, void *cb_arg)
1394 {
1395 #if !MYNEWT_VAL(BLE_GATT_DISC_ALL_SVCS)
1396     return BLE_HS_ENOTSUP;
1397 #endif
1398     struct ble_gattc_proc *proc;
1399     int rc;
1400     STATS_INC(ble_gattc_stats, disc_all_svcs);
1401     proc = ble_gattc_proc_alloc();
1402     if (proc == NULL) {
1403         rc = BLE_HS_ENOMEM;
1404         goto done;
1405     }
1406 
1407     proc->op = BLE_GATT_OP_DISC_ALL_SVCS;
1408     proc->conn_handle = conn_handle;
1409     proc->disc_all_svcs.prev_handle = 0x0000;
1410     proc->disc_all_svcs.cb = cb;
1411     proc->disc_all_svcs.cb_arg = cb_arg;
1412     ble_gattc_log_proc_init("discover all services\n");
1413     rc = ble_gattc_disc_all_svcs_tx(proc);
1414     if (rc != 0) {
1415         goto done;
1416     }
1417 
1418 done:
1419 
1420     if (rc != 0) {
1421         STATS_INC(ble_gattc_stats, disc_all_svcs_fail);
1422     }
1423 
1424     ble_gattc_process_status(proc, rc);
1425     return rc;
1426 }
1427 
1428 /*****************************************************************************
1429  * $discover service by uuid                                                 *
1430  *****************************************************************************/
1431 
1432 /**
1433  * Calls a discover-service-by-uuid proc's callback with the specified
1434  * parameters.  If the proc has no callback, this function is a no-op.
1435  *
1436  * @return                      The return code of the callback (or 0 if there
1437  *                                  is no callback).
1438  */
ble_gattc_disc_svc_uuid_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_svc * service)1439 static int ble_gattc_disc_svc_uuid_cb(struct ble_gattc_proc *proc, int status,
1440                                       uint16_t att_handle,
1441                                       struct ble_gatt_svc *service)
1442 {
1443     int rc;
1444     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1445     BLE_HS_DBG_ASSERT(service != NULL || status != 0);
1446     ble_gattc_dbg_assert_proc_not_inserted(proc);
1447 
1448     if (status != 0 && status != BLE_HS_EDONE) {
1449         STATS_INC(ble_gattc_stats, disc_svc_uuid_fail);
1450     }
1451 
1452     if (proc->disc_svc_uuid.cb == NULL) {
1453         rc = 0;
1454     } else {
1455         rc = proc->disc_svc_uuid.cb(proc->conn_handle,
1456                                     ble_gattc_error(status, att_handle),
1457                                     service, proc->disc_svc_uuid.cb_arg);
1458     }
1459 
1460     return rc;
1461 }
1462 
ble_gattc_disc_svc_uuid_tmo(struct ble_gattc_proc * proc)1463 static void ble_gattc_disc_svc_uuid_tmo(struct ble_gattc_proc *proc)
1464 {
1465     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1466     ble_gattc_dbg_assert_proc_not_inserted(proc);
1467     ble_gattc_disc_svc_uuid_cb(proc, BLE_HS_ETIMEOUT, 0, 0);
1468 }
1469 
1470 /**
1471  * Triggers a pending transmit for the specified discover-service-by-uuid proc.
1472  */
ble_gattc_disc_svc_uuid_tx(struct ble_gattc_proc * proc)1473 static int ble_gattc_disc_svc_uuid_tx(struct ble_gattc_proc *proc)
1474 {
1475     uint8_t val[16];
1476     int rc;
1477     ble_gattc_dbg_assert_proc_not_inserted(proc);
1478     ble_uuid_flat(&proc->disc_svc_uuid.service_uuid.u, val);
1479     rc = ble_att_clt_tx_find_type_value(proc->conn_handle,
1480                                         proc->disc_svc_uuid.prev_handle + 1,
1481                                         0xffff, BLE_ATT_UUID_PRIMARY_SERVICE,
1482                                         val,
1483                                         ble_uuid_length(&proc->disc_svc_uuid.service_uuid.u));
1484     if (rc != 0) {
1485         return rc;
1486     }
1487 
1488     return 0;
1489 }
1490 
ble_gattc_disc_svc_uuid_resume(struct ble_gattc_proc * proc)1491 static int ble_gattc_disc_svc_uuid_resume(struct ble_gattc_proc *proc)
1492 {
1493     int status;
1494     int rc;
1495     status = ble_gattc_disc_svc_uuid_tx(proc);
1496     rc = ble_gattc_process_resume_status(proc, status);
1497     if (rc != 0) {
1498         ble_gattc_disc_svc_uuid_cb(proc, rc, 0, NULL);
1499         return rc;
1500     }
1501 
1502     return 0;
1503 }
1504 
1505 /**
1506  * Handles an incoming ATT error response for the specified
1507  * discover-service-by-uuid proc.
1508  */
ble_gattc_disc_svc_uuid_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)1509 static void ble_gattc_disc_svc_uuid_err(struct ble_gattc_proc *proc, int status,
1510                                         uint16_t att_handle)
1511 {
1512     ble_gattc_dbg_assert_proc_not_inserted(proc);
1513 
1514     if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) {
1515         /* Discovery is complete. */
1516         status = BLE_HS_EDONE;
1517     }
1518 
1519     ble_gattc_disc_svc_uuid_cb(proc, status, att_handle, NULL);
1520 }
1521 
1522 /**
1523  * Handles an incoming "handles info" entry from a find-type-value response for
1524  * the specified discover-service-by-uuid proc.
1525  */
ble_gattc_disc_svc_uuid_rx_hinfo(struct ble_gattc_proc * proc,struct ble_att_find_type_value_hinfo * hinfo)1526 static int ble_gattc_disc_svc_uuid_rx_hinfo(struct ble_gattc_proc *proc,
1527                                             struct ble_att_find_type_value_hinfo *hinfo)
1528 {
1529     struct ble_gatt_svc service;
1530     int cbrc;
1531     int rc;
1532     ble_gattc_dbg_assert_proc_not_inserted(proc);
1533 
1534     if (hinfo->group_end_handle <= proc->disc_svc_uuid.prev_handle) {
1535         /* Peer sent services out of order; terminate procedure. */
1536         rc = BLE_HS_EBADDATA;
1537         goto done;
1538     }
1539 
1540     proc->disc_svc_uuid.prev_handle = hinfo->group_end_handle;
1541     service.start_handle = hinfo->attr_handle;
1542     service.end_handle = hinfo->group_end_handle;
1543     service.uuid = proc->disc_svc_uuid.service_uuid;
1544     rc = 0;
1545 done:
1546     cbrc = ble_gattc_disc_svc_uuid_cb(proc, rc, 0, &service);
1547 
1548     if (rc != 0 || cbrc != 0) {
1549         return BLE_HS_EDONE;
1550     } else {
1551         return 0;
1552     }
1553 }
1554 
1555 /**
1556  * Handles a notification that a find-type-value response has been fully
1557  * processed for the specified discover-service-by-uuid proc.
1558  */
ble_gattc_disc_svc_uuid_rx_complete(struct ble_gattc_proc * proc,int status)1559 static int ble_gattc_disc_svc_uuid_rx_complete(struct ble_gattc_proc *proc, int status)
1560 {
1561     int rc;
1562     ble_gattc_dbg_assert_proc_not_inserted(proc);
1563 
1564     if (status != 0) {
1565         ble_gattc_disc_svc_uuid_cb(proc, status, 0, NULL);
1566         return BLE_HS_EDONE;
1567     }
1568 
1569     if (proc->disc_svc_uuid.prev_handle == 0xffff) {
1570         /* Service discovery complete. */
1571         ble_gattc_disc_svc_uuid_cb(proc, BLE_HS_EDONE, 0, NULL);
1572         return BLE_HS_EDONE;
1573     }
1574 
1575     /* Send follow-up request. */
1576     rc = ble_gattc_disc_svc_uuid_resume(proc);
1577     if (rc != 0) {
1578         return BLE_HS_EDONE;
1579     }
1580 
1581     return 0;
1582 }
1583 
ble_gattc_disc_svc_by_uuid(uint16_t conn_handle,const ble_uuid_t * uuid,ble_gatt_disc_svc_fn * cb,void * cb_arg)1584 int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid,
1585                                ble_gatt_disc_svc_fn *cb, void *cb_arg)
1586 {
1587 #if !MYNEWT_VAL(BLE_GATT_DISC_SVC_UUID)
1588     return BLE_HS_ENOTSUP;
1589 #endif
1590     struct ble_gattc_proc *proc;
1591     int rc;
1592     STATS_INC(ble_gattc_stats, disc_svc_uuid);
1593     proc = ble_gattc_proc_alloc();
1594     if (proc == NULL) {
1595         rc = BLE_HS_ENOMEM;
1596         goto done;
1597     }
1598 
1599     proc->op = BLE_GATT_OP_DISC_SVC_UUID;
1600     proc->conn_handle = conn_handle;
1601     ble_uuid_to_any(uuid, &proc->disc_svc_uuid.service_uuid);
1602     proc->disc_svc_uuid.prev_handle = 0x0000;
1603     proc->disc_svc_uuid.cb = cb;
1604     proc->disc_svc_uuid.cb_arg = cb_arg;
1605     ble_gattc_log_disc_svc_uuid(proc);
1606     rc = ble_gattc_disc_svc_uuid_tx(proc);
1607     if (rc != 0) {
1608         goto done;
1609     }
1610 
1611 done:
1612 
1613     if (rc != 0) {
1614         STATS_INC(ble_gattc_stats, disc_svc_uuid_fail);
1615     }
1616 
1617     ble_gattc_process_status(proc, rc);
1618     return rc;
1619 }
1620 
1621 /*****************************************************************************
1622  * $find included svcs                                                       *
1623  *****************************************************************************/
1624 
1625 /**
1626  * Calls a find-included-services proc's callback with the specified
1627  * parameters.  If the proc has no callback, this function is a no-op.
1628  *
1629  * @return                      The return code of the callback (or 0 if there
1630  *                                  is no callback).
1631  */
ble_gattc_find_inc_svcs_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_svc * service)1632 static int ble_gattc_find_inc_svcs_cb(struct ble_gattc_proc *proc, int status,
1633                                       uint16_t att_handle,
1634                                       struct ble_gatt_svc *service)
1635 {
1636     int rc;
1637     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1638     BLE_HS_DBG_ASSERT(service != NULL || status != 0);
1639     ble_gattc_dbg_assert_proc_not_inserted(proc);
1640 
1641     if (status != 0 && status != BLE_HS_EDONE) {
1642         STATS_INC(ble_gattc_stats, find_inc_svcs_fail);
1643     }
1644 
1645     if (proc->find_inc_svcs.cb == NULL) {
1646         rc = 0;
1647     } else {
1648         rc = proc->find_inc_svcs.cb(proc->conn_handle,
1649                                     ble_gattc_error(status, att_handle),
1650                                     service, proc->find_inc_svcs.cb_arg);
1651     }
1652 
1653     return rc;
1654 }
1655 
ble_gattc_find_inc_svcs_tmo(struct ble_gattc_proc * proc)1656 static void ble_gattc_find_inc_svcs_tmo(struct ble_gattc_proc *proc)
1657 {
1658     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1659     ble_gattc_dbg_assert_proc_not_inserted(proc);
1660     ble_gattc_find_inc_svcs_cb(proc, BLE_HS_ETIMEOUT, 0, 0);
1661 }
1662 
1663 /**
1664  * Triggers a pending transmit for the specified find-included-services proc.
1665  */
ble_gattc_find_inc_svcs_tx(struct ble_gattc_proc * proc)1666 static int ble_gattc_find_inc_svcs_tx(struct ble_gattc_proc *proc)
1667 {
1668     ble_uuid16_t uuid = BLE_UUID16_INIT(BLE_ATT_UUID_INCLUDE);
1669     int rc;
1670     ble_gattc_dbg_assert_proc_not_inserted(proc);
1671 
1672     if (proc->find_inc_svcs.cur_start == 0) {
1673         /* Find the next included service. */
1674         rc = ble_att_clt_tx_read_type(proc->conn_handle,
1675                                       proc->find_inc_svcs.prev_handle + 1,
1676                                       proc->find_inc_svcs.end_handle, &uuid.u);
1677         if (rc != 0) {
1678             return rc;
1679         }
1680     } else {
1681         /* Read the UUID of the previously found service. */
1682         rc = ble_att_clt_tx_read(proc->conn_handle,
1683                                  proc->find_inc_svcs.cur_start);
1684         if (rc != 0) {
1685             return rc;
1686         }
1687     }
1688 
1689     return 0;
1690 }
1691 
ble_gattc_find_inc_svcs_resume(struct ble_gattc_proc * proc)1692 static int ble_gattc_find_inc_svcs_resume(struct ble_gattc_proc *proc)
1693 {
1694     int status;
1695     int rc;
1696     status = ble_gattc_find_inc_svcs_tx(proc);
1697     rc = ble_gattc_process_resume_status(proc, status);
1698     if (rc != 0) {
1699         ble_gattc_find_inc_svcs_cb(proc, rc, 0, NULL);
1700         return rc;
1701     }
1702 
1703     return 0;
1704 }
1705 
1706 /**
1707  * Handles an incoming ATT error response for the specified
1708  * find-included-services proc.
1709  */
ble_gattc_find_inc_svcs_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)1710 static void ble_gattc_find_inc_svcs_err(struct ble_gattc_proc *proc, int status,
1711                                         uint16_t att_handle)
1712 {
1713     ble_gattc_dbg_assert_proc_not_inserted(proc);
1714 
1715     if (proc->find_inc_svcs.cur_start == 0 &&
1716             status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) {
1717         /* Discovery is complete. */
1718         status = BLE_HS_EDONE;
1719     }
1720 
1721     ble_gattc_find_inc_svcs_cb(proc, status, att_handle, NULL);
1722 }
1723 
1724 /**
1725  * Handles an incoming read-response for the specified find-included-services
1726  * proc.
1727  */
ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc * proc,int status,struct os_mbuf ** om)1728 static int ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc *proc, int status,
1729                                                struct os_mbuf **om)
1730 {
1731     struct ble_gatt_svc service;
1732     int rc;
1733     ble_gattc_dbg_assert_proc_not_inserted(proc);
1734     rc = ble_uuid_init_from_att_mbuf(&service.uuid, *om, 0, 16); // 16:len
1735     os_mbuf_free_chain(*om);
1736     *om = NULL;
1737 
1738     if (rc != 0) {
1739         /* Invalid UUID. */
1740         rc = BLE_HS_EBADDATA;
1741         goto err;
1742     }
1743 
1744     if (proc->find_inc_svcs.cur_start == 0) {
1745         /* Unexpected read response; terminate procedure. */
1746         rc = BLE_HS_EBADDATA;
1747         goto err;
1748     }
1749 
1750     if (status != 0) {
1751         rc = status;
1752         goto err;
1753     }
1754 
1755     /* Report discovered service to application. */
1756     service.start_handle = proc->find_inc_svcs.cur_start;
1757     service.end_handle = proc->find_inc_svcs.cur_end;
1758     rc = ble_gattc_find_inc_svcs_cb(proc, 0, 0, &service);
1759     if (rc != 0) {
1760         /* Application has indicated that the procedure should be aborted. */
1761         return BLE_HS_EDONE;
1762     }
1763 
1764     /* Proceed to the next service. */
1765     proc->find_inc_svcs.cur_start = 0;
1766     proc->find_inc_svcs.cur_end = 0;
1767     rc = ble_gattc_find_inc_svcs_resume(proc);
1768     if (rc != 0) {
1769         goto err;
1770     }
1771 
1772     return 0;
1773 err:
1774     ble_gattc_find_inc_svcs_cb(proc, rc, 0, NULL);
1775     return BLE_HS_EDONE;
1776 }
1777 
1778 /**
1779  * Handles an incoming "attribute data" entry from a read-by-type response for
1780  * the specified find-included-services proc.
1781  */
ble_gattc_find_inc_svcs_rx_adata(struct ble_gattc_proc * proc,struct ble_att_read_type_adata * adata)1782 static int ble_gattc_find_inc_svcs_rx_adata(struct ble_gattc_proc *proc,
1783                                             struct ble_att_read_type_adata *adata)
1784 {
1785     struct ble_gatt_svc service;
1786     int call_cb;
1787     int cbrc;
1788     int rc;
1789     ble_gattc_dbg_assert_proc_not_inserted(proc);
1790 
1791     if (proc->find_inc_svcs.cur_start != 0) {
1792         /* We only read one 128-bit UUID service at a time.  Ignore the
1793          * additional services in the response.
1794          */
1795         return 0;
1796     }
1797 
1798     call_cb = 1;
1799 
1800     if (adata->att_handle <= proc->find_inc_svcs.prev_handle) {
1801         /* Peer sent services out of order; terminate procedure. */
1802         rc = BLE_HS_EBADDATA;
1803         goto done;
1804     }
1805 
1806     proc->find_inc_svcs.prev_handle = adata->att_handle;
1807     rc = 0;
1808 
1809     switch (adata->value_len) {
1810         case BLE_GATTS_INC_SVC_LEN_NO_UUID:
1811             proc->find_inc_svcs.cur_start = get_le16(adata->value + 0);
1812             proc->find_inc_svcs.cur_end = get_le16(adata->value + 2); // 2:byte alignment
1813             call_cb = 0;
1814             break;
1815 
1816         case BLE_GATTS_INC_SVC_LEN_UUID:
1817             service.start_handle = get_le16(adata->value + 0);
1818             service.end_handle = get_le16(adata->value + 2); // 2:byte alignment
1819             rc = ble_uuid_init_from_att_buf(&service.uuid, adata->value + 4, 2); // 2:len, 4:byte alignment
1820             if (rc != 0) {
1821                 rc = BLE_HS_EBADDATA;
1822             }
1823 
1824             break;
1825 
1826         default:
1827             rc = BLE_HS_EBADDATA;
1828             break;
1829     }
1830 
1831 done:
1832 
1833     if (call_cb) {
1834         cbrc = ble_gattc_find_inc_svcs_cb(proc, 0, 0, &service);
1835 
1836         if (rc != 0) {
1837             rc = cbrc;
1838         }
1839     } else {
1840         cbrc = 0;
1841     }
1842 
1843     if (rc != 0 || cbrc != 0) {
1844         return BLE_HS_EDONE;
1845     } else {
1846         return 0;
1847     }
1848 }
1849 
1850 /**
1851  * Handles a notification that a read-by-type response has been fully
1852  * processed for the specified find-included-services proc.
1853  */
ble_gattc_find_inc_svcs_rx_complete(struct ble_gattc_proc * proc,int status)1854 static int ble_gattc_find_inc_svcs_rx_complete(struct ble_gattc_proc *proc, int status)
1855 {
1856     int rc;
1857     ble_gattc_dbg_assert_proc_not_inserted(proc);
1858 
1859     if (status != 0) {
1860         ble_gattc_find_inc_svcs_cb(proc, status, 0, NULL);
1861         return BLE_HS_EDONE;
1862     }
1863 
1864     if (proc->find_inc_svcs.prev_handle == 0xffff) {
1865         /* Procedure complete. */
1866         ble_gattc_find_inc_svcs_cb(proc, BLE_HS_EDONE, 0, NULL);
1867         return BLE_HS_EDONE;
1868     }
1869 
1870     /* Send follow-up request. */
1871     rc = ble_gattc_find_inc_svcs_resume(proc);
1872     if (rc != 0) {
1873         return BLE_HS_EDONE;
1874     }
1875 
1876     return 0;
1877 }
1878 
ble_gattc_find_inc_svcs(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,ble_gatt_disc_svc_fn * cb,void * cb_arg)1879 int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
1880                             uint16_t end_handle,
1881                             ble_gatt_disc_svc_fn *cb, void *cb_arg)
1882 {
1883 #if !MYNEWT_VAL(BLE_GATT_FIND_INC_SVCS)
1884     return BLE_HS_ENOTSUP;
1885 #endif
1886     struct ble_gattc_proc *proc;
1887     int rc;
1888     STATS_INC(ble_gattc_stats, find_inc_svcs);
1889     proc = ble_gattc_proc_alloc();
1890     if (proc == NULL) {
1891         rc = BLE_HS_ENOMEM;
1892         goto done;
1893     }
1894 
1895     proc->op = BLE_GATT_OP_FIND_INC_SVCS;
1896     proc->conn_handle = conn_handle;
1897     proc->find_inc_svcs.prev_handle = start_handle - 1;
1898     proc->find_inc_svcs.end_handle = end_handle;
1899     proc->find_inc_svcs.cb = cb;
1900     proc->find_inc_svcs.cb_arg = cb_arg;
1901     ble_gattc_log_find_inc_svcs(proc);
1902     rc = ble_gattc_find_inc_svcs_tx(proc);
1903     if (rc != 0) {
1904         goto done;
1905     }
1906 
1907 done:
1908 
1909     if (rc != 0) {
1910         STATS_INC(ble_gattc_stats, find_inc_svcs_fail);
1911     }
1912 
1913     ble_gattc_process_status(proc, rc);
1914     return rc;
1915 }
1916 
1917 /*****************************************************************************
1918  * $discover all characteristics                                             *
1919  *****************************************************************************/
1920 
1921 /**
1922  * Calls a discover-all-characteristics proc's callback with the specified
1923  * parameters.  If the proc has no callback, this function is a no-op.
1924  *
1925  * @return                      The return code of the callback (or 0 if there
1926  *                                  is no callback).
1927  */
ble_gattc_disc_all_chrs_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_chr * chr)1928 static int ble_gattc_disc_all_chrs_cb(struct ble_gattc_proc *proc, int status,
1929                                       uint16_t att_handle, struct ble_gatt_chr *chr)
1930 {
1931     int rc;
1932     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1933     BLE_HS_DBG_ASSERT(chr != NULL || status != 0);
1934     ble_gattc_dbg_assert_proc_not_inserted(proc);
1935 
1936     if (status != 0 && status != BLE_HS_EDONE) {
1937         STATS_INC(ble_gattc_stats, disc_all_chrs_fail);
1938     }
1939 
1940     if (proc->disc_all_chrs.cb == NULL) {
1941         rc = 0;
1942     } else {
1943         rc = proc->disc_all_chrs.cb(proc->conn_handle,
1944                                     ble_gattc_error(status, att_handle), chr,
1945                                     proc->disc_all_chrs.cb_arg);
1946     }
1947 
1948     return rc;
1949 }
1950 
ble_gattc_disc_all_chrs_tmo(struct ble_gattc_proc * proc)1951 static void ble_gattc_disc_all_chrs_tmo(struct ble_gattc_proc *proc)
1952 {
1953     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
1954     ble_gattc_dbg_assert_proc_not_inserted(proc);
1955     ble_gattc_disc_all_chrs_cb(proc, BLE_HS_ETIMEOUT, 0, NULL);
1956 }
1957 
1958 /**
1959  * Triggers a pending transmit for the specified discover-all-characteristics
1960  * proc.
1961  */
ble_gattc_disc_all_chrs_tx(struct ble_gattc_proc * proc)1962 static int ble_gattc_disc_all_chrs_tx(struct ble_gattc_proc *proc)
1963 {
1964     ble_uuid16_t uuid = BLE_UUID16_INIT(BLE_ATT_UUID_CHARACTERISTIC);
1965     int rc;
1966     ble_gattc_dbg_assert_proc_not_inserted(proc);
1967     rc = ble_att_clt_tx_read_type(proc->conn_handle,
1968                                   proc->disc_all_chrs.prev_handle + 1,
1969                                   proc->disc_all_chrs.end_handle, &uuid.u);
1970     if (rc != 0) {
1971         return rc;
1972     }
1973 
1974     return 0;
1975 }
1976 
ble_gattc_disc_all_chrs_resume(struct ble_gattc_proc * proc)1977 static int ble_gattc_disc_all_chrs_resume(struct ble_gattc_proc *proc)
1978 {
1979     int status;
1980     int rc;
1981     status = ble_gattc_disc_all_chrs_tx(proc);
1982     rc = ble_gattc_process_resume_status(proc, status);
1983     if (rc != 0) {
1984         ble_gattc_disc_all_chrs_cb(proc, rc, 0, NULL);
1985         return rc;
1986     }
1987 
1988     return 0;
1989 }
1990 
1991 /**
1992  * Handles an incoming ATT error response for the specified
1993  * discover-all-characteristics proc.
1994  */
ble_gattc_disc_all_chrs_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)1995 static void ble_gattc_disc_all_chrs_err(struct ble_gattc_proc *proc, int status,
1996                                         uint16_t att_handle)
1997 {
1998     ble_gattc_dbg_assert_proc_not_inserted(proc);
1999 
2000     if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) {
2001         /* Discovery is complete. */
2002         status = BLE_HS_EDONE;
2003     }
2004 
2005     ble_gattc_disc_all_chrs_cb(proc, status, att_handle, NULL);
2006 }
2007 
2008 /**
2009  * Handles an incoming "attribute data" entry from a read-by-type response for
2010  * the specified discover-all-characteristics proc.
2011  */
ble_gattc_disc_all_chrs_rx_adata(struct ble_gattc_proc * proc,struct ble_att_read_type_adata * adata)2012 static int ble_gattc_disc_all_chrs_rx_adata(struct ble_gattc_proc *proc,
2013                                             struct ble_att_read_type_adata *adata)
2014 {
2015     struct ble_gatt_chr chr;
2016     int cbrc;
2017     int rc;
2018     ble_gattc_dbg_assert_proc_not_inserted(proc);
2019     memset_s(&chr, sizeof(chr), 0, sizeof(chr));
2020     chr.def_handle = adata->att_handle;
2021 
2022     switch (adata->value_len) {
2023         case BLE_GATT_CHR_DECL_SZ_16:
2024         case BLE_GATT_CHR_DECL_SZ_128:
2025             rc = ble_uuid_init_from_att_buf(&chr.uuid, adata->value + 3, // 3:byte alignment
2026                                             adata->value_len - 3); // 3:byte alignment
2027             if (rc != 0) {
2028                 rc = BLE_HS_EBADDATA;
2029                 goto done;
2030             }
2031 
2032             break;
2033 
2034         default:
2035             rc = BLE_HS_EBADDATA;
2036             goto done;
2037     }
2038 
2039     chr.properties = adata->value[0];
2040     chr.val_handle = get_le16(adata->value + 1);
2041 
2042     if (adata->att_handle <= proc->disc_all_chrs.prev_handle) {
2043         /* Peer sent characteristics out of order; terminate procedure. */
2044         rc = BLE_HS_EBADDATA;
2045         goto done;
2046     }
2047 
2048     proc->disc_all_chrs.prev_handle = adata->att_handle;
2049     rc = 0;
2050 done:
2051     cbrc = ble_gattc_disc_all_chrs_cb(proc, rc, 0, &chr);
2052 
2053     if (rc != 0 || cbrc != 0) {
2054         return BLE_HS_EDONE;
2055     } else {
2056         return 0;
2057     }
2058 }
2059 
2060 /**
2061  * Handles a notification that a read-by-type response has been fully
2062  * processed for the specified discover-all-characteristics proc.
2063  */
ble_gattc_disc_all_chrs_rx_complete(struct ble_gattc_proc * proc,int status)2064 static int ble_gattc_disc_all_chrs_rx_complete(struct ble_gattc_proc *proc, int status)
2065 {
2066     int rc;
2067     ble_gattc_dbg_assert_proc_not_inserted(proc);
2068 
2069     if (status != 0) {
2070         ble_gattc_disc_all_chrs_cb(proc, status, 0, NULL);
2071         return BLE_HS_EDONE;
2072     }
2073 
2074     if (proc->disc_all_chrs.prev_handle == proc->disc_all_chrs.end_handle) {
2075         /* Characteristic discovery complete. */
2076         ble_gattc_disc_all_chrs_cb(proc, BLE_HS_EDONE, 0, NULL);
2077         return BLE_HS_EDONE;
2078     }
2079 
2080     /* Send follow-up request. */
2081     rc = ble_gattc_disc_all_chrs_resume(proc);
2082     if (rc != 0) {
2083         return BLE_HS_EDONE;
2084     }
2085 
2086     return 0;
2087 }
2088 
ble_gattc_disc_all_chrs(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,ble_gatt_chr_fn * cb,void * cb_arg)2089 int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
2090                             uint16_t end_handle, ble_gatt_chr_fn *cb,
2091                             void *cb_arg)
2092 {
2093 #if !MYNEWT_VAL(BLE_GATT_DISC_ALL_CHRS)
2094     return BLE_HS_ENOTSUP;
2095 #endif
2096     struct ble_gattc_proc *proc;
2097     int rc;
2098     STATS_INC(ble_gattc_stats, disc_all_chrs);
2099     proc = ble_gattc_proc_alloc();
2100     if (proc == NULL) {
2101         rc = BLE_HS_ENOMEM;
2102         goto done;
2103     }
2104 
2105     proc->op = BLE_GATT_OP_DISC_ALL_CHRS;
2106     proc->conn_handle = conn_handle;
2107     proc->disc_all_chrs.prev_handle = start_handle - 1;
2108     proc->disc_all_chrs.end_handle = end_handle;
2109     proc->disc_all_chrs.cb = cb;
2110     proc->disc_all_chrs.cb_arg = cb_arg;
2111     ble_gattc_log_disc_all_chrs(proc);
2112     rc = ble_gattc_disc_all_chrs_tx(proc);
2113     if (rc != 0) {
2114         goto done;
2115     }
2116 
2117 done:
2118 
2119     if (rc != 0) {
2120         STATS_INC(ble_gattc_stats, disc_all_chrs_fail);
2121     }
2122 
2123     ble_gattc_process_status(proc, rc);
2124     return rc;
2125 }
2126 
2127 /*****************************************************************************
2128  * $discover characteristic by uuid                                          *
2129  *****************************************************************************/
2130 
2131 /**
2132  * Calls a discover-characteristic-by-uuid proc's callback with the specified
2133  * parameters.  If the proc has no callback, this function is a no-op.
2134  *
2135  * @return                      The return code of the callback (or 0 if there
2136  *                                  is no callback).
2137  */
ble_gattc_disc_chr_uuid_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_chr * chr)2138 static int ble_gattc_disc_chr_uuid_cb(struct ble_gattc_proc *proc, int status,
2139                                       uint16_t att_handle, struct ble_gatt_chr *chr)
2140 {
2141     int rc;
2142     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2143     BLE_HS_DBG_ASSERT(chr != NULL || status != 0);
2144     ble_gattc_dbg_assert_proc_not_inserted(proc);
2145 
2146     if (status != 0 && status != BLE_HS_EDONE) {
2147         STATS_INC(ble_gattc_stats, disc_chrs_uuid_fail);
2148     }
2149 
2150     if (proc->disc_chr_uuid.cb == NULL) {
2151         rc = 0;
2152     } else {
2153         rc = proc->disc_chr_uuid.cb(proc->conn_handle,
2154                                     ble_gattc_error(status, att_handle), chr,
2155                                     proc->disc_chr_uuid.cb_arg);
2156     }
2157 
2158     return rc;
2159 }
2160 
ble_gattc_disc_chr_uuid_tmo(struct ble_gattc_proc * proc)2161 static void ble_gattc_disc_chr_uuid_tmo(struct ble_gattc_proc *proc)
2162 {
2163     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2164     ble_gattc_dbg_assert_proc_not_inserted(proc);
2165     ble_gattc_disc_chr_uuid_cb(proc, BLE_HS_ETIMEOUT, 0, NULL);
2166 }
2167 
2168 /**
2169  * Triggers a pending transmit for the specified
2170  * discover-characteristic-by-uuid proc.
2171  */
ble_gattc_disc_chr_uuid_tx(struct ble_gattc_proc * proc)2172 static int ble_gattc_disc_chr_uuid_tx(struct ble_gattc_proc *proc)
2173 {
2174     ble_uuid16_t uuid = BLE_UUID16_INIT(BLE_ATT_UUID_CHARACTERISTIC);
2175     int rc;
2176     ble_gattc_dbg_assert_proc_not_inserted(proc);
2177     rc = ble_att_clt_tx_read_type(proc->conn_handle,
2178                                   proc->disc_chr_uuid.prev_handle + 1,
2179                                   proc->disc_chr_uuid.end_handle, &uuid.u);
2180     if (rc != 0) {
2181         return rc;
2182     }
2183 
2184     return 0;
2185 }
2186 
ble_gattc_disc_chr_uuid_resume(struct ble_gattc_proc * proc)2187 static int ble_gattc_disc_chr_uuid_resume(struct ble_gattc_proc *proc)
2188 {
2189     int status;
2190     int rc;
2191     status = ble_gattc_disc_chr_uuid_tx(proc);
2192     rc = ble_gattc_process_resume_status(proc, status);
2193     if (rc != 0) {
2194         ble_gattc_disc_chr_uuid_cb(proc, rc, 0, NULL);
2195         return rc;
2196     }
2197 
2198     return 0;
2199 }
2200 
2201 /**
2202  * Handles an incoming ATT error response for the specified
2203  * discover-characteristic-by-uuid proc.
2204  */
ble_gattc_disc_chr_uuid_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)2205 static void ble_gattc_disc_chr_uuid_err(struct ble_gattc_proc *proc, int status,
2206                                         uint16_t att_handle)
2207 {
2208     ble_gattc_dbg_assert_proc_not_inserted(proc);
2209 
2210     if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) {
2211         /* Discovery is complete. */
2212         status = BLE_HS_EDONE;
2213     }
2214 
2215     ble_gattc_disc_chr_uuid_cb(proc, status, att_handle, NULL);
2216 }
2217 
2218 /**
2219  * Handles an incoming "attribute data" entry from a read-by-type response for
2220  * the specified discover-characteristics-by-uuid proc.
2221  */
ble_gattc_disc_chr_uuid_rx_adata(struct ble_gattc_proc * proc,struct ble_att_read_type_adata * adata)2222 static int ble_gattc_disc_chr_uuid_rx_adata(struct ble_gattc_proc *proc,
2223                                             struct ble_att_read_type_adata *adata)
2224 {
2225     struct ble_gatt_chr chr;
2226     int cbrc;
2227     int rc;
2228     ble_gattc_dbg_assert_proc_not_inserted(proc);
2229     memset_s(&chr, sizeof(chr), 0, sizeof(chr));
2230     chr.def_handle = adata->att_handle;
2231 
2232     switch (adata->value_len) {
2233         case BLE_GATT_CHR_DECL_SZ_16:
2234         case BLE_GATT_CHR_DECL_SZ_128:
2235             rc = ble_uuid_init_from_att_buf(&chr.uuid, adata->value + 3, // 3:byte alignment
2236                                             adata->value_len - 3); // 3:byte alignment
2237             if (rc != 0) {
2238                 rc = BLE_HS_EBADDATA;
2239                 goto done;
2240             }
2241 
2242             break;
2243 
2244         default:
2245             rc = BLE_HS_EBADDATA;
2246             goto done;
2247     }
2248 
2249     chr.properties = adata->value[0];
2250     chr.val_handle = get_le16(adata->value + 1);
2251 
2252     if (adata->att_handle <= proc->disc_chr_uuid.prev_handle) {
2253         /* Peer sent characteristics out of order; terminate procedure. */
2254         rc = BLE_HS_EBADDATA;
2255         goto done;
2256     }
2257 
2258     proc->disc_chr_uuid.prev_handle = adata->att_handle;
2259     rc = 0;
2260 done:
2261 
2262     if (rc != 0) {
2263         /* Failure. */
2264         cbrc = ble_gattc_disc_chr_uuid_cb(proc, rc, 0, NULL);
2265     } else if (ble_uuid_cmp(&chr.uuid.u, &proc->disc_chr_uuid.chr_uuid.u) == 0) {
2266         /* Requested characteristic discovered. */
2267         cbrc = ble_gattc_disc_chr_uuid_cb(proc, 0, 0, &chr);
2268     } else {
2269         /* Uninteresting characteristic; ignore. */
2270         cbrc = 0;
2271     }
2272 
2273     if (rc != 0 || cbrc != 0) {
2274         return BLE_HS_EDONE;
2275     } else {
2276         return 0;
2277     }
2278 }
2279 
2280 /**
2281  * Handles a notification that a read-by-type response has been fully
2282  * processed for the specified discover-characteristics-by-uuid proc.
2283  */
ble_gattc_disc_chr_uuid_rx_complete(struct ble_gattc_proc * proc,int status)2284 static int ble_gattc_disc_chr_uuid_rx_complete(struct ble_gattc_proc *proc, int status)
2285 {
2286     int rc;
2287     ble_gattc_dbg_assert_proc_not_inserted(proc);
2288 
2289     if (status != 0) {
2290         ble_gattc_disc_chr_uuid_cb(proc, status, 0, NULL);
2291         return BLE_HS_EDONE;
2292     }
2293 
2294     if (proc->disc_chr_uuid.prev_handle == proc->disc_chr_uuid.end_handle) {
2295         /* Characteristic discovery complete. */
2296         ble_gattc_disc_chr_uuid_cb(proc, BLE_HS_EDONE, 0, NULL);
2297         return BLE_HS_EDONE;
2298     }
2299 
2300     /* Send follow-up request. */
2301     rc = ble_gattc_disc_chr_uuid_resume(proc);
2302     if (rc != 0) {
2303         return BLE_HS_EDONE;
2304     }
2305 
2306     return 0;
2307 }
2308 
ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid,ble_gatt_chr_fn * cb,void * cb_arg)2309 int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
2310                                 uint16_t end_handle, const ble_uuid_t *uuid,
2311                                 ble_gatt_chr_fn *cb, void *cb_arg)
2312 {
2313 #if !MYNEWT_VAL(BLE_GATT_DISC_CHR_UUID)
2314     return BLE_HS_ENOTSUP;
2315 #endif
2316     struct ble_gattc_proc *proc;
2317     int rc;
2318     STATS_INC(ble_gattc_stats, disc_chrs_uuid);
2319     proc = ble_gattc_proc_alloc();
2320     if (proc == NULL) {
2321         rc = BLE_HS_ENOMEM;
2322         goto done;
2323     }
2324 
2325     proc->op = BLE_GATT_OP_DISC_CHR_UUID;
2326     proc->conn_handle = conn_handle;
2327     ble_uuid_to_any(uuid, &proc->disc_chr_uuid.chr_uuid);
2328     proc->disc_chr_uuid.prev_handle = start_handle - 1;
2329     proc->disc_chr_uuid.end_handle = end_handle;
2330     proc->disc_chr_uuid.cb = cb;
2331     proc->disc_chr_uuid.cb_arg = cb_arg;
2332     ble_gattc_log_disc_chr_uuid(proc);
2333     rc = ble_gattc_disc_chr_uuid_tx(proc);
2334     if (rc != 0) {
2335         goto done;
2336     }
2337 
2338 done:
2339 
2340     if (rc != 0) {
2341         STATS_INC(ble_gattc_stats, disc_chrs_uuid_fail);
2342     }
2343 
2344     ble_gattc_process_status(proc, rc);
2345     return rc;
2346 }
2347 
2348 /*****************************************************************************
2349  * $discover all characteristic descriptors                                  *
2350  *****************************************************************************/
2351 
2352 /**
2353  * Calls a discover-all-descriptors proc's callback with the specified
2354  * parameters.  If the proc has no callback, this function is a no-op.
2355  *
2356  * @return                      The return code of the callback (or 0 if there
2357  *                                  is no callback).
2358  */
ble_gattc_disc_all_dscs_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_dsc * dsc)2359 static int ble_gattc_disc_all_dscs_cb(struct ble_gattc_proc *proc, int status,
2360                                       uint16_t att_handle, struct ble_gatt_dsc *dsc)
2361 {
2362     int rc;
2363     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2364     BLE_HS_DBG_ASSERT(dsc != NULL || status != 0);
2365     ble_gattc_dbg_assert_proc_not_inserted(proc);
2366 
2367     if (status != 0 && status != BLE_HS_EDONE) {
2368         STATS_INC(ble_gattc_stats, disc_all_dscs_fail);
2369     }
2370 
2371     if (proc->disc_all_dscs.cb == NULL) {
2372         rc = 0;
2373     } else {
2374         rc = proc->disc_all_dscs.cb(proc->conn_handle,
2375                                     ble_gattc_error(status, att_handle),
2376                                     proc->disc_all_dscs.chr_val_handle,
2377                                     dsc, proc->disc_all_dscs.cb_arg);
2378     }
2379 
2380     return rc;
2381 }
2382 
ble_gattc_disc_all_dscs_tmo(struct ble_gattc_proc * proc)2383 static void ble_gattc_disc_all_dscs_tmo(struct ble_gattc_proc *proc)
2384 {
2385     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2386     ble_gattc_dbg_assert_proc_not_inserted(proc);
2387     ble_gattc_disc_all_dscs_cb(proc, BLE_HS_ETIMEOUT, 0, NULL);
2388 }
2389 
2390 /**
2391  * Triggers a pending transmit for the specified discover-all-descriptors proc.
2392  */
ble_gattc_disc_all_dscs_tx(struct ble_gattc_proc * proc)2393 static int ble_gattc_disc_all_dscs_tx(struct ble_gattc_proc *proc)
2394 {
2395     int rc;
2396     ble_gattc_dbg_assert_proc_not_inserted(proc);
2397     rc = ble_att_clt_tx_find_info(proc->conn_handle,
2398                                   proc->disc_all_dscs.prev_handle + 1,
2399                                   proc->disc_all_dscs.end_handle);
2400     if (rc != 0) {
2401         return rc;
2402     }
2403 
2404     return 0;
2405 }
2406 
ble_gattc_disc_all_dscs_resume(struct ble_gattc_proc * proc)2407 static int ble_gattc_disc_all_dscs_resume(struct ble_gattc_proc *proc)
2408 {
2409     int status;
2410     int rc;
2411     status = ble_gattc_disc_all_dscs_tx(proc);
2412     rc = ble_gattc_process_resume_status(proc, status);
2413     if (rc != 0) {
2414         ble_gattc_disc_all_dscs_cb(proc, rc, 0, NULL);
2415         return rc;
2416     }
2417 
2418     return 0;
2419 }
2420 
2421 /**
2422  * Handles an incoming ATT error response for the specified
2423  * discover-all-descriptors proc.
2424  */
ble_gattc_disc_all_dscs_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)2425 static void ble_gattc_disc_all_dscs_err(struct ble_gattc_proc *proc, int status,
2426                                         uint16_t att_handle)
2427 {
2428     ble_gattc_dbg_assert_proc_not_inserted(proc);
2429 
2430     if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) {
2431         /* Discovery is complete. */
2432         status = BLE_HS_EDONE;
2433     }
2434 
2435     ble_gattc_disc_all_dscs_cb(proc, status, att_handle, NULL);
2436 }
2437 
2438 /**
2439  * Handles an incoming "information data" entry from a find-information
2440  * response for the specified discover-all-descriptors proc.
2441  */
ble_gattc_disc_all_dscs_rx_idata(struct ble_gattc_proc * proc,struct ble_att_find_info_idata * idata)2442 static int ble_gattc_disc_all_dscs_rx_idata(struct ble_gattc_proc *proc,
2443                                             struct ble_att_find_info_idata *idata)
2444 {
2445     struct ble_gatt_dsc dsc;
2446     int cbrc;
2447     int rc;
2448     ble_gattc_dbg_assert_proc_not_inserted(proc);
2449 
2450     if (idata->attr_handle <= proc->disc_all_dscs.prev_handle) {
2451         /* Peer sent descriptors out of order; terminate procedure. */
2452         rc = BLE_HS_EBADDATA;
2453         goto done;
2454     }
2455 
2456     proc->disc_all_dscs.prev_handle = idata->attr_handle;
2457     rc = 0;
2458 done:
2459     dsc.handle = idata->attr_handle;
2460     dsc.uuid = idata->uuid;
2461     cbrc = ble_gattc_disc_all_dscs_cb(proc, rc, 0, &dsc);
2462     if (rc != 0 || cbrc != 0) {
2463         return BLE_HS_EDONE;
2464     } else {
2465         return 0;
2466     }
2467 }
2468 
2469 /**
2470  * Handles a notification that a find-information response has been fully
2471  * processed for the specified discover-all-descriptors proc.
2472  */
ble_gattc_disc_all_dscs_rx_complete(struct ble_gattc_proc * proc,int status)2473 static int ble_gattc_disc_all_dscs_rx_complete(struct ble_gattc_proc *proc, int status)
2474 {
2475     int rc;
2476     ble_gattc_dbg_assert_proc_not_inserted(proc);
2477 
2478     if (status != 0) {
2479         ble_gattc_disc_all_dscs_cb(proc, status, 0, NULL);
2480         return BLE_HS_EDONE;
2481     }
2482 
2483     if (proc->disc_all_dscs.prev_handle == proc->disc_all_dscs.end_handle) {
2484         /* All descriptors discovered. */
2485         ble_gattc_disc_all_dscs_cb(proc, BLE_HS_EDONE, 0, NULL);
2486         return BLE_HS_EDONE;
2487     }
2488 
2489     /* Send follow-up request. */
2490     rc = ble_gattc_disc_all_dscs_resume(proc);
2491     if (rc != 0) {
2492         return BLE_HS_EDONE;
2493     }
2494 
2495     return 0;
2496 }
2497 
ble_gattc_disc_all_dscs(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,ble_gatt_dsc_fn * cb,void * cb_arg)2498 int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
2499                             uint16_t end_handle,
2500                             ble_gatt_dsc_fn *cb, void *cb_arg)
2501 {
2502 #if !MYNEWT_VAL(BLE_GATT_DISC_ALL_DSCS)
2503     return BLE_HS_ENOTSUP;
2504 #endif
2505     struct ble_gattc_proc *proc;
2506     int rc;
2507     STATS_INC(ble_gattc_stats, disc_all_dscs);
2508     proc = ble_gattc_proc_alloc();
2509     if (proc == NULL) {
2510         rc = BLE_HS_ENOMEM;
2511         goto done;
2512     }
2513 
2514     proc->op = BLE_GATT_OP_DISC_ALL_DSCS;
2515     proc->conn_handle = conn_handle;
2516     proc->disc_all_dscs.chr_val_handle = start_handle;
2517     proc->disc_all_dscs.prev_handle = start_handle;
2518     proc->disc_all_dscs.end_handle = end_handle;
2519     proc->disc_all_dscs.cb = cb;
2520     proc->disc_all_dscs.cb_arg = cb_arg;
2521     ble_gattc_log_disc_all_dscs(proc);
2522     rc = ble_gattc_disc_all_dscs_tx(proc);
2523     if (rc != 0) {
2524         goto done;
2525     }
2526 
2527 done:
2528 
2529     if (rc != 0) {
2530         STATS_INC(ble_gattc_stats, disc_all_dscs_fail);
2531     }
2532 
2533     ble_gattc_process_status(proc, rc);
2534     return rc;
2535 }
2536 
2537 /*****************************************************************************
2538  * $read                                                                     *
2539  *****************************************************************************/
2540 
2541 /**
2542  * Calls a read-characteristic proc's callback with the specified parameters.
2543  * If the proc has no callback, this function is a no-op.
2544  *
2545  * @return                      The return code of the callback (or 0 if there
2546  *                                  is no callback).
2547  */
ble_gattc_read_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_attr * attr)2548 static int ble_gattc_read_cb(struct ble_gattc_proc *proc, int status,
2549                              uint16_t att_handle, struct ble_gatt_attr *attr)
2550 {
2551     int rc;
2552     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2553     BLE_HS_DBG_ASSERT(attr != NULL || status != 0);
2554     ble_gattc_dbg_assert_proc_not_inserted(proc);
2555 
2556     if (status != 0 && status != BLE_HS_EDONE) {
2557         STATS_INC(ble_gattc_stats, read_fail);
2558     }
2559 
2560     if (proc->read.cb == NULL) {
2561         rc = 0;
2562     } else {
2563         rc = proc->read.cb(proc->conn_handle,
2564                            ble_gattc_error(status, att_handle), attr,
2565                            proc->read.cb_arg);
2566     }
2567 
2568     return rc;
2569 }
2570 
ble_gattc_read_tmo(struct ble_gattc_proc * proc)2571 static void ble_gattc_read_tmo(struct ble_gattc_proc *proc)
2572 {
2573     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2574     ble_gattc_dbg_assert_proc_not_inserted(proc);
2575     ble_gattc_read_cb(proc, BLE_HS_ETIMEOUT, 0, NULL);
2576 }
2577 
2578 /**
2579  * Handles an incoming ATT error response for the specified
2580  * read-characteristic-value proc.
2581  */
ble_gattc_read_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)2582 static void ble_gattc_read_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
2583 {
2584     ble_gattc_dbg_assert_proc_not_inserted(proc);
2585     ble_gattc_read_cb(proc, status, att_handle, NULL);
2586 }
2587 
2588 /**
2589  * Handles an incoming read-response for the specified
2590  * read-characteristic-value proc.
2591  */
ble_gattc_read_rx_read_rsp(struct ble_gattc_proc * proc,int status,struct os_mbuf ** om)2592 static int ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status, struct os_mbuf **om)
2593 {
2594     struct ble_gatt_attr attr;
2595     ble_gattc_dbg_assert_proc_not_inserted(proc);
2596     attr.handle = proc->read.handle;
2597     attr.offset = 0;
2598     attr.om = *om;
2599     ble_gattc_read_cb(proc, status, 0, &attr);
2600     /* Indicate to the caller whether the application consumed the mbuf. */
2601     *om = attr.om;
2602     /* The read operation only has a single request / response exchange. */
2603     return BLE_HS_EDONE;
2604 }
2605 
ble_gattc_read_tx(struct ble_gattc_proc * proc)2606 static int ble_gattc_read_tx(struct ble_gattc_proc *proc)
2607 {
2608     int rc;
2609     rc = ble_att_clt_tx_read(proc->conn_handle, proc->read.handle);
2610     if (rc != 0) {
2611         return rc;
2612     }
2613 
2614     return 0;
2615 }
2616 
ble_gattc_read(uint16_t conn_handle,uint16_t attr_handle,ble_gatt_attr_fn * cb,void * cb_arg)2617 int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle, ble_gatt_attr_fn *cb, void *cb_arg)
2618 {
2619 #if !MYNEWT_VAL(BLE_GATT_READ)
2620     return BLE_HS_ENOTSUP;
2621 #endif
2622     struct ble_gattc_proc *proc;
2623     int rc;
2624     STATS_INC(ble_gattc_stats, read);
2625     proc = ble_gattc_proc_alloc();
2626     if (proc == NULL) {
2627         rc = BLE_HS_ENOMEM;
2628         goto done;
2629     }
2630 
2631     proc->op = BLE_GATT_OP_READ;
2632     proc->conn_handle = conn_handle;
2633     proc->read.handle = attr_handle;
2634     proc->read.cb = cb;
2635     proc->read.cb_arg = cb_arg;
2636     ble_gattc_log_read(attr_handle);
2637     rc = ble_gattc_read_tx(proc);
2638     if (rc != 0) {
2639         goto done;
2640     }
2641 
2642 done:
2643 
2644     if (rc != 0) {
2645         STATS_INC(ble_gattc_stats, read_fail);
2646     }
2647 
2648     ble_gattc_process_status(proc, rc);
2649     return rc;
2650 }
2651 
2652 /*****************************************************************************
2653  * $read by uuid                                                             *
2654  *****************************************************************************/
2655 
2656 /**
2657  * Calls a read-using-characteristic-uuid proc's callback with the specified
2658  * parameters.  If the proc has no callback, this function is a no-op.
2659  *
2660  * @return                      The return code of the callback (or 0 if there
2661  *                                  is no callback).
2662  */
ble_gattc_read_uuid_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_attr * attr)2663 static int ble_gattc_read_uuid_cb(struct ble_gattc_proc *proc, int status,
2664                                   uint16_t att_handle, struct ble_gatt_attr *attr)
2665 {
2666     int rc;
2667     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2668     BLE_HS_DBG_ASSERT(attr != NULL || status != 0);
2669     ble_gattc_dbg_assert_proc_not_inserted(proc);
2670 
2671     if (status != 0 && status != BLE_HS_EDONE) {
2672         STATS_INC(ble_gattc_stats, read_uuid_fail);
2673     }
2674 
2675     if (proc->read_uuid.cb == NULL) {
2676         rc = 0;
2677     } else {
2678         rc = proc->read_uuid.cb(proc->conn_handle,
2679                                 ble_gattc_error(status, att_handle), attr,
2680                                 proc->read_uuid.cb_arg);
2681     }
2682 
2683     return rc;
2684 }
2685 
ble_gattc_read_uuid_tmo(struct ble_gattc_proc * proc)2686 static void ble_gattc_read_uuid_tmo(struct ble_gattc_proc *proc)
2687 {
2688     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2689     ble_gattc_dbg_assert_proc_not_inserted(proc);
2690     ble_gattc_read_uuid_cb(proc, BLE_HS_ETIMEOUT, 0, NULL);
2691 }
2692 
2693 /**
2694  * Handles an incoming ATT error response for the specified
2695  * read-using-characteristic-uuid proc.
2696  */
ble_gattc_read_uuid_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)2697 static void ble_gattc_read_uuid_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
2698 {
2699     ble_gattc_dbg_assert_proc_not_inserted(proc);
2700     ble_gattc_read_uuid_cb(proc, status, att_handle, NULL);
2701 }
2702 
2703 /**
2704  * Handles an incoming "attribute data" entry from a read-by-type response for
2705  * the specified read-using-characteristic-uuid proc.
2706  */
ble_gattc_read_uuid_rx_adata(struct ble_gattc_proc * proc,struct ble_att_read_type_adata * adata)2707 static int ble_gattc_read_uuid_rx_adata(struct ble_gattc_proc *proc,
2708                                         struct ble_att_read_type_adata *adata)
2709 {
2710     struct ble_gatt_attr attr;
2711     int rc;
2712     ble_gattc_dbg_assert_proc_not_inserted(proc);
2713     attr.handle = adata->att_handle;
2714     attr.offset = 0;
2715     attr.om = ble_hs_mbuf_from_flat(adata->value, adata->value_len);
2716     if (attr.om == NULL) {
2717         rc = BLE_HS_ENOMEM;
2718     } else {
2719         rc = 0;
2720     }
2721 
2722     rc = ble_gattc_read_uuid_cb(proc, rc, 0, &attr);
2723     /* Free the attribute mbuf if the application has not consumed it. */
2724     os_mbuf_free_chain(attr.om);
2725 
2726     if (rc != 0) {
2727         return BLE_HS_EDONE;
2728     }
2729 
2730     return 0;
2731 }
2732 
2733 /**
2734  * Handles a notification that a read-by-type response has been fully
2735  * processed for the specified read-using-characteristic-uuid proc.
2736  */
ble_gattc_read_uuid_rx_complete(struct ble_gattc_proc * proc,int status)2737 static int ble_gattc_read_uuid_rx_complete(struct ble_gattc_proc *proc, int status)
2738 {
2739     ble_gattc_dbg_assert_proc_not_inserted(proc);
2740 
2741     if (status != 0) {
2742         ble_gattc_read_uuid_cb(proc, status, 0, NULL);
2743         return BLE_HS_EDONE;
2744     }
2745 
2746     /* XXX: We may need to send a follow-up request to address the possibility
2747      * of multiple characteristics with identical UUIDs.
2748      */
2749     ble_gattc_read_uuid_cb(proc, BLE_HS_EDONE, 0, NULL);
2750     return BLE_HS_EDONE;
2751 }
2752 
ble_gattc_read_uuid_tx(struct ble_gattc_proc * proc)2753 static int ble_gattc_read_uuid_tx(struct ble_gattc_proc *proc)
2754 {
2755     return ble_att_clt_tx_read_type(proc->conn_handle,
2756                                     proc->read_uuid.start_handle,
2757                                     proc->read_uuid.end_handle,
2758                                     &proc->read_uuid.chr_uuid.u);
2759 }
2760 
ble_gattc_read_by_uuid(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid,ble_gatt_attr_fn * cb,void * cb_arg)2761 int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
2762                            uint16_t end_handle, const ble_uuid_t *uuid,
2763                            ble_gatt_attr_fn *cb, void *cb_arg)
2764 {
2765 #if !MYNEWT_VAL(BLE_GATT_READ_UUID)
2766     return BLE_HS_ENOTSUP;
2767 #endif
2768     struct ble_gattc_proc *proc;
2769     int rc;
2770     STATS_INC(ble_gattc_stats, read_uuid);
2771     proc = ble_gattc_proc_alloc();
2772     if (proc == NULL) {
2773         rc = BLE_HS_ENOMEM;
2774         goto done;
2775     }
2776 
2777     proc->op = BLE_GATT_OP_READ_UUID;
2778     proc->conn_handle = conn_handle;
2779     ble_uuid_to_any(uuid, &proc->read_uuid.chr_uuid);
2780     proc->read_uuid.start_handle = start_handle;
2781     proc->read_uuid.end_handle = end_handle;
2782     proc->read_uuid.cb = cb;
2783     proc->read_uuid.cb_arg = cb_arg;
2784     ble_gattc_log_read_uuid(start_handle, end_handle, uuid);
2785     rc = ble_gattc_read_uuid_tx(proc);
2786     if (rc != 0) {
2787         goto done;
2788     }
2789 
2790 done:
2791 
2792     if (rc != 0) {
2793         STATS_INC(ble_gattc_stats, read_uuid_fail);
2794     }
2795 
2796     ble_gattc_process_status(proc, rc);
2797     return rc;
2798 }
2799 
2800 /*****************************************************************************
2801  * $read long                                                                *
2802  *****************************************************************************/
2803 
2804 /**
2805  * Calls a read-long-characteristic proc's callback with the specified
2806  * parameters.  If the proc has no callback, this function is a no-op.
2807  *
2808  * @return                      The return code of the callback (or 0 if there
2809  *                                  is no callback).
2810  */
ble_gattc_read_long_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct ble_gatt_attr * attr)2811 static int ble_gattc_read_long_cb(struct ble_gattc_proc *proc, int status,
2812                                   uint16_t att_handle, struct ble_gatt_attr *attr)
2813 {
2814     int rc;
2815     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2816     BLE_HS_DBG_ASSERT(attr != NULL || status != 0);
2817     ble_gattc_dbg_assert_proc_not_inserted(proc);
2818 
2819     if (status != 0 && status != BLE_HS_EDONE) {
2820         STATS_INC(ble_gattc_stats, read_long_fail);
2821     }
2822 
2823     if (proc->read_long.cb == NULL) {
2824         rc = 0;
2825     } else {
2826         rc = proc->read_long.cb(proc->conn_handle,
2827                                 ble_gattc_error(status, att_handle), attr,
2828                                 proc->read_long.cb_arg);
2829     }
2830 
2831     return rc;
2832 }
2833 
ble_gattc_read_long_tmo(struct ble_gattc_proc * proc)2834 static void ble_gattc_read_long_tmo(struct ble_gattc_proc *proc)
2835 {
2836     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2837     ble_gattc_dbg_assert_proc_not_inserted(proc);
2838     ble_gattc_read_long_cb(proc, BLE_HS_ETIMEOUT, 0, NULL);
2839 }
2840 
2841 /**
2842  * Triggers a pending transmit for the specified read-long-characteristic proc.
2843  */
ble_gattc_read_long_tx(struct ble_gattc_proc * proc)2844 static int ble_gattc_read_long_tx(struct ble_gattc_proc *proc)
2845 {
2846     int rc;
2847     ble_gattc_dbg_assert_proc_not_inserted(proc);
2848 
2849     if (proc->read_long.offset == 0) {
2850         rc = ble_att_clt_tx_read(proc->conn_handle, proc->read_long.handle);
2851         if (rc != 0) {
2852             return rc;
2853         }
2854     } else {
2855         rc = ble_att_clt_tx_read_blob(proc->conn_handle,
2856                                       proc->read_long.handle,
2857                                       proc->read_long.offset);
2858         if (rc != 0) {
2859             return rc;
2860         }
2861     }
2862 
2863     return 0;
2864 }
2865 
ble_gattc_read_long_resume(struct ble_gattc_proc * proc)2866 static int ble_gattc_read_long_resume(struct ble_gattc_proc *proc)
2867 {
2868     int status;
2869     int rc;
2870     status = ble_gattc_read_long_tx(proc);
2871     rc = ble_gattc_process_resume_status(proc, status);
2872     if (rc != 0) {
2873         ble_gattc_read_long_cb(proc, rc, 0, NULL);
2874         return rc;
2875     }
2876 
2877     return 0;
2878 }
2879 
2880 /**
2881  * Handles an incoming ATT error response for the specified
2882  * read-long-characteristic proc.
2883  */
ble_gattc_read_long_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)2884 static void ble_gattc_read_long_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
2885 {
2886     ble_gattc_dbg_assert_proc_not_inserted(proc);
2887     ble_gattc_read_long_cb(proc, status, att_handle, NULL);
2888 }
2889 
2890 /**
2891  * Handles an incoming read-response for the specified
2892  * read-long-characteristic-values proc.
2893  */
ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc * proc,int status,struct os_mbuf ** om)2894 static int ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status, struct os_mbuf **om)
2895 {
2896     struct ble_gatt_attr attr;
2897     uint16_t data_len;
2898     uint16_t mtu;
2899     int rc;
2900     ble_gattc_dbg_assert_proc_not_inserted(proc);
2901     data_len = OS_MBUF_PKTLEN(*om);
2902     attr.handle = proc->read_long.handle;
2903     attr.offset = proc->read_long.offset;
2904     attr.om = *om;
2905     /* Report partial payload to application. */
2906     rc = ble_gattc_read_long_cb(proc, status, 0, &attr);
2907     /* Indicate to the caller whether the application consumed the mbuf. */
2908     *om = attr.om;
2909 
2910     if (rc != 0 || status != 0) {
2911         return BLE_HS_EDONE;
2912     }
2913 
2914     /* Determine if this is the end of the attribute value. */
2915     mtu = ble_att_mtu(proc->conn_handle);
2916     if (mtu == 0) {
2917         /* No longer connected. */
2918         return BLE_HS_EDONE;
2919     }
2920 
2921     if (data_len < mtu - 1) {
2922         /* Response shorter than maximum allowed; read complete. */
2923         ble_gattc_read_long_cb(proc, BLE_HS_EDONE, 0, NULL);
2924         return BLE_HS_EDONE;
2925     }
2926 
2927     /* Send follow-up request. */
2928     proc->read_long.offset += data_len;
2929     rc = ble_gattc_read_long_resume(proc);
2930     if (rc != 0) {
2931         return BLE_HS_EDONE;
2932     }
2933 
2934     return 0;
2935 }
2936 
ble_gattc_read_long(uint16_t conn_handle,uint16_t handle,uint16_t offset,ble_gatt_attr_fn * cb,void * cb_arg)2937 int ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, uint16_t offset,
2938                         ble_gatt_attr_fn *cb, void *cb_arg)
2939 {
2940 #if !MYNEWT_VAL(BLE_GATT_READ_LONG)
2941     return BLE_HS_ENOTSUP;
2942 #endif
2943     struct ble_gattc_proc *proc;
2944     int rc;
2945     STATS_INC(ble_gattc_stats, read_long);
2946     proc = ble_gattc_proc_alloc();
2947     if (proc == NULL) {
2948         rc = BLE_HS_ENOMEM;
2949         goto done;
2950     }
2951 
2952     proc->op = BLE_GATT_OP_READ_LONG;
2953     proc->conn_handle = conn_handle;
2954     proc->read_long.handle = handle;
2955     proc->read_long.offset = offset;
2956     proc->read_long.cb = cb;
2957     proc->read_long.cb_arg = cb_arg;
2958     ble_gattc_log_read_long(proc);
2959     rc = ble_gattc_read_long_tx(proc);
2960     if (rc != 0) {
2961         goto done;
2962     }
2963 
2964 done:
2965 
2966     if (rc != 0) {
2967         STATS_INC(ble_gattc_stats, read_long_fail);
2968     }
2969 
2970     ble_gattc_process_status(proc, rc);
2971     return rc;
2972 }
2973 
2974 /*****************************************************************************
2975  * $read multiple                                                            *
2976  *****************************************************************************/
2977 
2978 /**
2979  * Calls a read-multiple-characteristics proc's callback with the specified
2980  * parameters.  If the proc has no callback, this function is a no-op.
2981  *
2982  * @return                      The return code of the callback (or 0 if there
2983  *                                  is no callback).
2984  */
ble_gattc_read_mult_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle,struct os_mbuf ** om)2985 static int ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int status,
2986                                   uint16_t att_handle, struct os_mbuf **om)
2987 {
2988     struct ble_gatt_attr attr;
2989     int rc;
2990     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
2991     BLE_HS_DBG_ASSERT(om != NULL || status != 0);
2992     ble_gattc_dbg_assert_proc_not_inserted(proc);
2993 
2994     if (status != 0 && status != BLE_HS_EDONE) {
2995         STATS_INC(ble_gattc_stats, read_mult_fail);
2996     }
2997 
2998     attr.handle = 0;
2999     attr.offset = 0;
3000 
3001     if (om == NULL) {
3002         attr.om = NULL;
3003     } else {
3004         attr.om = *om;
3005     }
3006 
3007     if (proc->read_mult.cb == NULL) {
3008         rc = 0;
3009     } else {
3010         rc = proc->read_mult.cb(proc->conn_handle,
3011                                 ble_gattc_error(status, att_handle), &attr,
3012                                 proc->read_mult.cb_arg);
3013     }
3014 
3015     /* Indicate to the caller whether the application consumed the mbuf. */
3016     if (om != NULL) {
3017         *om = attr.om;
3018     }
3019 
3020     return rc;
3021 }
3022 
ble_gattc_read_mult_tmo(struct ble_gattc_proc * proc)3023 static void ble_gattc_read_mult_tmo(struct ble_gattc_proc *proc)
3024 {
3025     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3026     ble_gattc_dbg_assert_proc_not_inserted(proc);
3027     ble_gattc_read_mult_cb(proc, BLE_HS_ETIMEOUT, 0, 0);
3028 }
3029 
3030 /**
3031  * Handles an incoming ATT error response for the specified
3032  * read-multiple-characteristics proc.
3033  */
ble_gattc_read_mult_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3034 static void ble_gattc_read_mult_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
3035 {
3036     ble_gattc_dbg_assert_proc_not_inserted(proc);
3037     ble_gattc_read_mult_cb(proc, status, att_handle, NULL);
3038 }
3039 
ble_gattc_read_mult_tx(struct ble_gattc_proc * proc)3040 static int ble_gattc_read_mult_tx(struct ble_gattc_proc *proc)
3041 {
3042     int rc;
3043     rc = ble_att_clt_tx_read_mult(proc->conn_handle, proc->read_mult.handles,
3044                                   proc->read_mult.num_handles);
3045     if (rc != 0) {
3046         return rc;
3047     }
3048 
3049     return 0;
3050 }
3051 
ble_gattc_read_mult(uint16_t conn_handle,const uint16_t * handles,uint8_t num_handles,ble_gatt_attr_fn * cb,void * cb_arg)3052 int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles,
3053                         uint8_t num_handles, ble_gatt_attr_fn *cb,
3054                         void *cb_arg)
3055 {
3056 #if !MYNEWT_VAL(BLE_GATT_READ_MULT)
3057     return BLE_HS_ENOTSUP;
3058 #endif
3059     struct ble_gattc_proc *proc;
3060     int rc;
3061     proc = NULL;
3062     STATS_INC(ble_gattc_stats, read_mult);
3063 
3064     if (num_handles > MYNEWT_VAL(BLE_GATT_READ_MAX_ATTRS)) {
3065         rc = BLE_HS_EINVAL;
3066         goto done;
3067     }
3068 
3069     proc = ble_gattc_proc_alloc();
3070     if (proc == NULL) {
3071         rc = BLE_HS_ENOMEM;
3072         goto done;
3073     }
3074 
3075     proc->op = BLE_GATT_OP_READ_MULT;
3076     proc->conn_handle = conn_handle;
3077     memcpy_s(proc->read_mult.handles, sizeof(proc->read_mult.handles), handles, num_handles * sizeof * handles);
3078     proc->read_mult.num_handles = num_handles;
3079     proc->read_mult.cb = cb;
3080     proc->read_mult.cb_arg = cb_arg;
3081     ble_gattc_log_read_mult(handles, num_handles);
3082     rc = ble_gattc_read_mult_tx(proc);
3083     if (rc != 0) {
3084         goto done;
3085     }
3086 
3087 done:
3088 
3089     if (rc != 0) {
3090         STATS_INC(ble_gattc_stats, read_mult_fail);
3091     }
3092 
3093     ble_gattc_process_status(proc, rc);
3094     return rc;
3095 }
3096 
3097 /*****************************************************************************
3098  * $write no response                                                        *
3099  *****************************************************************************/
3100 
ble_gattc_write_no_rsp(uint16_t conn_handle,uint16_t attr_handle,struct os_mbuf * txom)3101 int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
3102                            struct os_mbuf *txom)
3103 {
3104 #if !MYNEWT_VAL(BLE_GATT_WRITE_NO_RSP)
3105     return BLE_HS_ENOTSUP;
3106 #endif
3107     int rc;
3108     STATS_INC(ble_gattc_stats, write_no_rsp);
3109     ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(txom), 0);
3110     rc = ble_att_clt_tx_write_cmd(conn_handle, attr_handle, txom);
3111     if (rc != 0) {
3112         STATS_INC(ble_gattc_stats, write);
3113     }
3114 
3115     return rc;
3116 }
3117 
ble_gattc_write_no_rsp_flat(uint16_t conn_handle,uint16_t attr_handle,const void * data,uint16_t data_len)3118 int ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle,
3119                                 const void *data, uint16_t data_len)
3120 {
3121     struct os_mbuf *om;
3122     int rc;
3123     om = ble_hs_mbuf_from_flat(data, data_len);
3124     if (om == NULL) {
3125         return BLE_HS_ENOMEM;
3126     }
3127 
3128     rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, om);
3129     if (rc != 0) {
3130         return rc;
3131     }
3132 
3133     return 0;
3134 }
3135 
3136 /*****************************************************************************
3137  * $write                                                                    *
3138  *****************************************************************************/
3139 
3140 /**
3141  * Calls a write-characteristic-value proc's callback with the specified
3142  * parameters.  If the proc has no callback, this function is a no-op.
3143  *
3144  * @return                      The return code of the callback (or 0 if there
3145  *                                  is no callback).
3146  */
ble_gattc_write_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3147 static int ble_gattc_write_cb(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
3148 {
3149     struct ble_gatt_attr attr;
3150     int rc;
3151     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3152     ble_gattc_dbg_assert_proc_not_inserted(proc);
3153 
3154     if (status != 0 && status != BLE_HS_EDONE) {
3155         STATS_INC(ble_gattc_stats, write_fail);
3156     }
3157 
3158     if (proc->write.cb == NULL) {
3159         rc = 0;
3160     } else {
3161         memset_s(&attr, sizeof(attr), 0, sizeof(attr));
3162         attr.handle = proc->write.att_handle;
3163         rc = proc->write.cb(proc->conn_handle,
3164                             ble_gattc_error(status, att_handle),
3165                             &attr, proc->write.cb_arg);
3166     }
3167 
3168     return rc;
3169 }
3170 
ble_gattc_write_tmo(struct ble_gattc_proc * proc)3171 static void ble_gattc_write_tmo(struct ble_gattc_proc *proc)
3172 {
3173     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3174     ble_gattc_dbg_assert_proc_not_inserted(proc);
3175     ble_gattc_write_cb(proc, BLE_HS_ETIMEOUT, 0);
3176 }
3177 
3178 /**
3179  * Handles an incoming ATT error response for the specified
3180  * write-characteristic-value proc.
3181  */
ble_gattc_write_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3182 static void ble_gattc_write_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
3183 {
3184     ble_gattc_dbg_assert_proc_not_inserted(proc);
3185     ble_gattc_write_cb(proc, status, att_handle);
3186 }
3187 
ble_gattc_write(uint16_t conn_handle,uint16_t attr_handle,struct os_mbuf * txom,ble_gatt_attr_fn * cb,void * cb_arg)3188 int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle,
3189                     struct os_mbuf *txom, ble_gatt_attr_fn *cb, void *cb_arg)
3190 {
3191 #if !MYNEWT_VAL(BLE_GATT_WRITE)
3192     return BLE_HS_ENOTSUP;
3193 #endif
3194     struct os_mbuf *txom_tmp = txom;
3195     struct ble_gattc_proc *proc;
3196     int rc;
3197     STATS_INC(ble_gattc_stats, write);
3198     proc = ble_gattc_proc_alloc();
3199     if (proc == NULL) {
3200         rc = BLE_HS_ENOMEM;
3201         goto done;
3202     }
3203 
3204     proc->op = BLE_GATT_OP_WRITE;
3205     proc->conn_handle = conn_handle;
3206     proc->write.att_handle = attr_handle;
3207     proc->write.cb = cb;
3208     proc->write.cb_arg = cb_arg;
3209     ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(txom_tmp), 1);
3210     rc = ble_att_clt_tx_write_req(conn_handle, attr_handle, txom_tmp);
3211     txom_tmp = NULL;
3212 
3213     if (rc != 0) {
3214         goto done;
3215     }
3216 
3217 done:
3218 
3219     if (rc != 0) {
3220         STATS_INC(ble_gattc_stats, write_fail);
3221     }
3222 
3223     /* Free the mbuf in case the send failed. */
3224     os_mbuf_free_chain(txom_tmp);
3225     ble_gattc_process_status(proc, rc);
3226     return rc;
3227 }
3228 
ble_gattc_write_flat(uint16_t conn_handle,uint16_t attr_handle,const void * data,uint16_t data_len,ble_gatt_attr_fn * cb,void * cb_arg)3229 int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle,
3230                          const void *data, uint16_t data_len,
3231                          ble_gatt_attr_fn *cb, void *cb_arg)
3232 {
3233     struct os_mbuf *om;
3234     int rc;
3235     om = ble_hs_mbuf_from_flat(data, data_len);
3236     if (om == NULL) {
3237         return BLE_HS_ENOMEM;
3238     }
3239 
3240     rc = ble_gattc_write(conn_handle, attr_handle, om, cb, cb_arg);
3241     if (rc != 0) {
3242         return rc;
3243     }
3244 
3245     return 0;
3246 }
3247 
3248 /*****************************************************************************
3249  * $write long                                                               *
3250  *****************************************************************************/
3251 
3252 /**
3253  * Calls a write-long-characteristic-value proc's callback with the specified
3254  * parameters.  If the proc has no callback, this function is a no-op.
3255  *
3256  * @return                      The return code of the callback (or 0 if there
3257  *                                  is no callback).
3258  */
ble_gattc_write_long_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3259 static int ble_gattc_write_long_cb(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
3260 {
3261     int rc;
3262     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3263     ble_gattc_dbg_assert_proc_not_inserted(proc);
3264 
3265     if (status != 0 && status != BLE_HS_EDONE) {
3266         STATS_INC(ble_gattc_stats, write_long_fail);
3267     }
3268 
3269     if (proc->write_long.cb == NULL) {
3270         rc = 0;
3271     } else {
3272         rc = proc->write_long.cb(proc->conn_handle,
3273                                  ble_gattc_error(status, att_handle),
3274                                  &proc->write_long.attr,
3275                                  proc->write_long.cb_arg);
3276     }
3277 
3278     return rc;
3279 }
3280 
ble_gattc_write_long_tmo(struct ble_gattc_proc * proc)3281 static void ble_gattc_write_long_tmo(struct ble_gattc_proc *proc)
3282 {
3283     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3284     ble_gattc_dbg_assert_proc_not_inserted(proc);
3285     ble_gattc_write_long_cb(proc, BLE_HS_ETIMEOUT, 0);
3286 }
3287 
3288 /**
3289  * Triggers a pending transmit for the specified
3290  * write-long-characteristic-value proc.
3291  */
ble_gattc_write_long_tx(struct ble_gattc_proc * proc)3292 static int ble_gattc_write_long_tx(struct ble_gattc_proc *proc)
3293 {
3294     struct os_mbuf *om;
3295     int write_len;
3296     int max_sz;
3297     int rc;
3298     ble_gattc_dbg_assert_proc_not_inserted(proc);
3299     om = NULL;
3300     max_sz = ble_att_mtu(proc->conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
3301     if (max_sz <= 0) {
3302         /* Not connected. */
3303         rc = BLE_HS_ENOTCONN;
3304         goto done;
3305     }
3306 
3307     write_len = min(max_sz,
3308                     OS_MBUF_PKTLEN(proc->write_long.attr.om) -
3309                     proc->write_long.attr.offset);
3310     if (write_len <= 0) {
3311         rc = ble_att_clt_tx_exec_write(proc->conn_handle,
3312                                        BLE_ATT_EXEC_WRITE_F_EXECUTE);
3313         goto done;
3314     }
3315 
3316     proc->write_long.length = write_len;
3317     om = ble_hs_mbuf_att_pkt();
3318     if (om == NULL) {
3319         rc = BLE_HS_ENOMEM;
3320         goto done;
3321     }
3322 
3323     rc = os_mbuf_appendfrom(om, proc->write_long.attr.om,
3324                             proc->write_long.attr.offset,
3325                             proc->write_long.length);
3326     if (rc != 0) {
3327         rc = BLE_HS_ENOMEM;
3328         goto done;
3329     }
3330 
3331     rc = ble_att_clt_tx_prep_write(proc->conn_handle,
3332                                    proc->write_long.attr.handle,
3333                                    proc->write_long.attr.offset, om);
3334     om = NULL;
3335 
3336     if (rc != 0) {
3337         goto done;
3338     }
3339 
3340 done:
3341     os_mbuf_free_chain(om);
3342     return rc;
3343 }
3344 
ble_gattc_write_long_resume(struct ble_gattc_proc * proc)3345 static int ble_gattc_write_long_resume(struct ble_gattc_proc *proc)
3346 {
3347     int status;
3348     int rc;
3349     status = ble_gattc_write_long_tx(proc);
3350     rc = ble_gattc_process_resume_status(proc, status);
3351     if (rc != 0) {
3352         ble_gattc_write_long_cb(proc, rc, 0);
3353         return rc;
3354     }
3355 
3356     return 0;
3357 }
3358 
3359 /**
3360  * Handles an incoming ATT error response for the specified
3361  * write-long-characteristic-value proc.
3362  */
ble_gattc_write_long_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3363 static void ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status,
3364                                      uint16_t att_handle)
3365 {
3366     ble_gattc_dbg_assert_proc_not_inserted(proc);
3367 
3368     /* If we have successfully queued any data, and the failure occurred before
3369      * we could send the execute write command, then erase all queued data.
3370      */
3371     if (proc->write_long.attr.offset > 0 &&
3372             proc->write_long.attr.offset <
3373             OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
3374         ble_att_clt_tx_exec_write(proc->conn_handle,
3375                                   BLE_ATT_EXEC_WRITE_F_CANCEL);
3376     }
3377 
3378     /* Report failure. */
3379     ble_gattc_write_long_cb(proc, status, att_handle);
3380 }
3381 
3382 /**
3383  * Handles an incoming prepare-write-response for the specified
3384  * write-long-cahracteristic-values proc.
3385  */
ble_gattc_write_long_rx_prep(struct ble_gattc_proc * proc,int status,uint16_t handle,uint16_t offset,struct os_mbuf ** rxom)3386 static int ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc,
3387                                         int status,
3388                                         uint16_t handle, uint16_t offset,
3389                                         struct os_mbuf **rxom)
3390 {
3391     struct os_mbuf *om;
3392     int rc;
3393     ble_gattc_dbg_assert_proc_not_inserted(proc);
3394     /* Let the caller free the mbuf. */
3395     om = *rxom;
3396 
3397     if (status != 0) {
3398         rc = status;
3399         goto err;
3400     }
3401 
3402     /* Verify the response. */
3403     if (proc->write_long.attr.offset >=
3404             OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
3405         /* Expecting a prepare write response, not an execute write
3406          * response.
3407          */
3408         rc = BLE_HS_EBADDATA;
3409         goto err;
3410     }
3411 
3412     if (handle != proc->write_long.attr.handle) {
3413         rc = BLE_HS_EBADDATA;
3414         goto err;
3415     }
3416 
3417     if (offset != proc->write_long.attr.offset) {
3418         rc = BLE_HS_EBADDATA;
3419         goto err;
3420     }
3421 
3422     if (offset + OS_MBUF_PKTLEN(om) >
3423             OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
3424         rc = BLE_HS_EBADDATA;
3425         goto err;
3426     }
3427 
3428     if (OS_MBUF_PKTLEN(om) != proc->write_long.length) {
3429         rc = BLE_HS_EBADDATA;
3430         goto err;
3431     }
3432 
3433     if (os_mbuf_cmpm(om, 0,
3434                      proc->write_long.attr.om, offset,
3435                      proc->write_long.length) != 0) {
3436         rc = BLE_HS_EBADDATA;
3437         goto err;
3438     }
3439 
3440     /* Send follow-up request. */
3441     proc->write_long.attr.offset += OS_MBUF_PKTLEN(om);
3442     rc = ble_gattc_write_long_resume(proc);
3443     if (rc != 0) {
3444         goto err;
3445     }
3446 
3447     return 0;
3448 err:
3449     /* XXX: Might need to cancel pending writes. */
3450     ble_gattc_write_long_cb(proc, rc, 0);
3451     return BLE_HS_EDONE;
3452 }
3453 
3454 /**
3455  * Handles an incoming execute-write-response for the specified
3456  * write-long-characteristic-values proc.
3457  */
ble_gattc_write_long_rx_exec(struct ble_gattc_proc * proc,int status)3458 static int ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc, int status)
3459 {
3460     ble_gattc_dbg_assert_proc_not_inserted(proc);
3461 
3462     if (proc->write_long.attr.offset <
3463             OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
3464         /* Expecting an execute write response, not a prepare write
3465          * response.
3466          */
3467         return BLE_HS_EBADDATA;
3468     }
3469 
3470     ble_gattc_write_long_cb(proc, status, 0);
3471     return BLE_HS_EDONE;
3472 }
3473 
ble_gattc_write_long(uint16_t conn_handle,uint16_t attr_handle,uint16_t offset,struct os_mbuf * txom,ble_gatt_attr_fn * cb,void * cb_arg)3474 int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
3475                          uint16_t offset, struct os_mbuf *txom,
3476                          ble_gatt_attr_fn *cb, void *cb_arg)
3477 {
3478 #if !MYNEWT_VAL(BLE_GATT_WRITE_LONG)
3479     return BLE_HS_ENOTSUP;
3480 #endif
3481     struct os_mbuf *txom_tmp = txom;
3482     struct ble_gattc_proc *proc;
3483     int rc;
3484     STATS_INC(ble_gattc_stats, write_long);
3485     proc = ble_gattc_proc_alloc();
3486     if (proc == NULL) {
3487         rc = BLE_HS_ENOMEM;
3488         goto done;
3489     }
3490 
3491     proc->op = BLE_GATT_OP_WRITE_LONG;
3492     proc->conn_handle = conn_handle;
3493     proc->write_long.attr.handle = attr_handle;
3494     proc->write_long.attr.offset = offset;
3495     proc->write_long.attr.om = txom_tmp;
3496     proc->write_long.cb = cb;
3497     proc->write_long.cb_arg = cb_arg;
3498     /* The mbuf is consumed by the procedure. */
3499     txom_tmp = NULL;
3500     ble_gattc_log_write_long(proc);
3501     rc = ble_gattc_write_long_tx(proc);
3502     if (rc != 0) {
3503         goto done;
3504     }
3505 
3506 done:
3507 
3508     if (rc != 0) {
3509         STATS_INC(ble_gattc_stats, write_long_fail);
3510     }
3511 
3512     /* Free the mbuf in case of failure. */
3513     os_mbuf_free_chain(txom_tmp);
3514     ble_gattc_process_status(proc, rc);
3515     return rc;
3516 }
3517 
3518 /*****************************************************************************
3519  * $write reliable                                                           *
3520  *****************************************************************************/
3521 
3522 /**
3523  * Calls a write-long-characteristic-value proc's callback with the specified
3524  * parameters.  If the proc has no callback, this function is a no-op.
3525  *
3526  * @return                      The return code of the callback (or 0 if there
3527  *                                  is no callback).
3528  */
ble_gattc_write_reliable_cb(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3529 static int ble_gattc_write_reliable_cb(struct ble_gattc_proc *proc, int status,
3530                                        uint16_t att_handle)
3531 {
3532     int rc;
3533     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3534     ble_gattc_dbg_assert_proc_not_inserted(proc);
3535 
3536     if (status != 0 && status != BLE_HS_EDONE) {
3537         STATS_INC(ble_gattc_stats, write_reliable_fail);
3538     }
3539 
3540     if (proc->write_reliable.cb == NULL) {
3541         rc = 0;
3542     } else {
3543         rc = proc->write_reliable.cb(proc->conn_handle,
3544                                      ble_gattc_error(status, att_handle),
3545                                      proc->write_reliable.attrs,
3546                                      proc->write_reliable.num_attrs,
3547                                      proc->write_reliable.cb_arg);
3548     }
3549 
3550     return rc;
3551 }
3552 
ble_gattc_write_reliable_tmo(struct ble_gattc_proc * proc)3553 static void ble_gattc_write_reliable_tmo(struct ble_gattc_proc *proc)
3554 {
3555     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3556     ble_gattc_dbg_assert_proc_not_inserted(proc);
3557     ble_gattc_write_reliable_cb(proc, BLE_HS_ETIMEOUT, 0);
3558 }
3559 
3560 /**
3561  * Triggers a pending transmit for the specified
3562  * write-reliable-characteristic-value proc.
3563  */
ble_gattc_write_reliable_tx(struct ble_gattc_proc * proc)3564 static int ble_gattc_write_reliable_tx(struct ble_gattc_proc *proc)
3565 {
3566     struct ble_gatt_attr *attr;
3567     struct os_mbuf *om;
3568     uint16_t max_sz;
3569     int attr_idx;
3570     int rc;
3571     ble_gattc_dbg_assert_proc_not_inserted(proc);
3572     om = NULL;
3573     attr_idx = proc->write_reliable.cur_attr;
3574     if (attr_idx >= proc->write_reliable.num_attrs) {
3575         rc = ble_att_clt_tx_exec_write(proc->conn_handle,
3576                                        BLE_ATT_EXEC_WRITE_F_EXECUTE);
3577         goto done;
3578     }
3579 
3580     attr = proc->write_reliable.attrs + attr_idx;
3581     max_sz = ble_att_mtu(proc->conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
3582     if (max_sz == 0) {
3583         /* Not connected. */
3584         rc = BLE_HS_ENOTCONN;
3585         goto done;
3586     }
3587 
3588     proc->write_reliable.length =
3589                     min(max_sz, OS_MBUF_PKTLEN(attr->om) - attr->offset);
3590     om = ble_hs_mbuf_att_pkt();
3591     if (om == NULL) {
3592         rc = BLE_HS_ENOMEM;
3593         goto done;
3594     }
3595 
3596     rc = os_mbuf_appendfrom(om, attr->om, attr->offset,
3597                             proc->write_reliable.length);
3598     if (rc != 0) {
3599         rc = BLE_HS_ENOMEM;
3600         goto done;
3601     }
3602 
3603     rc = ble_att_clt_tx_prep_write(proc->conn_handle, attr->handle,
3604                                    attr->offset, om);
3605     om = NULL;
3606 
3607     if (rc != 0) {
3608         goto done;
3609     }
3610 
3611 done:
3612     os_mbuf_free_chain(om);
3613     return rc;
3614 }
3615 
ble_gattc_write_reliable_resume(struct ble_gattc_proc * proc)3616 static int ble_gattc_write_reliable_resume(struct ble_gattc_proc *proc)
3617 {
3618     int status;
3619     int rc;
3620     status = ble_gattc_write_reliable_tx(proc);
3621     rc = ble_gattc_process_resume_status(proc, status);
3622     if (rc != 0) {
3623         ble_gattc_write_reliable_cb(proc, rc, 0);
3624         return rc;
3625     }
3626 
3627     return 0;
3628 }
3629 
3630 /**
3631  * Handles an incoming ATT error response for the specified
3632  * write-reliable-characteristic-value proc.
3633  */
ble_gattc_write_reliable_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3634 static void ble_gattc_write_reliable_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
3635 {
3636     ble_gattc_dbg_assert_proc_not_inserted(proc);
3637     ble_gattc_write_reliable_cb(proc, status, att_handle);
3638 
3639     /* If we have successfully queued any data, and the failure occurred before
3640      * we could send the execute write command, then erase all queued data.
3641      */
3642     if (proc->write_reliable.cur_attr < proc->write_reliable.num_attrs) {
3643         ble_att_clt_tx_exec_write(proc->conn_handle,
3644                                   BLE_ATT_EXEC_WRITE_F_CANCEL);
3645     }
3646 }
3647 
3648 /**
3649  * Handles an incoming prepare-write-response for the specified
3650  * write-reliable-cahracteristic-values proc.
3651  */
ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc * proc,int status,uint16_t handle,uint16_t offset,struct os_mbuf ** rxom)3652 static int ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
3653                                             int status,
3654                                             uint16_t handle, uint16_t offset,
3655                                             struct os_mbuf **rxom)
3656 {
3657     struct ble_gatt_attr *attr;
3658     struct os_mbuf *om;
3659     int rc;
3660     ble_gattc_dbg_assert_proc_not_inserted(proc);
3661     /* Let the caller free the mbuf. */
3662     om = *rxom;
3663 
3664     if (status != 0) {
3665         rc = status;
3666         goto err;
3667     }
3668 
3669     if (proc->write_reliable.cur_attr >= proc->write_reliable.num_attrs) {
3670         /* Expecting an execute write response, not a prepare write
3671          * response.
3672          */
3673         rc = BLE_HS_EBADDATA;
3674         goto err;
3675     }
3676 
3677     attr = proc->write_reliable.attrs + proc->write_reliable.cur_attr;
3678 
3679     /* Verify the response. */
3680     if (handle != attr->handle) {
3681         rc = BLE_HS_EBADDATA;
3682         goto err;
3683     }
3684 
3685     if (offset != attr->offset) {
3686         rc = BLE_HS_EBADDATA;
3687         goto err;
3688     }
3689 
3690     if (os_mbuf_cmpm(attr->om, offset, om, 0,
3691                      proc->write_reliable.length) != 0) {
3692         rc = BLE_HS_EBADDATA;
3693         goto err;
3694     }
3695 
3696     /* Send follow-up request. */
3697     attr->offset += proc->write_reliable.length;
3698     if (attr->offset >= OS_MBUF_PKTLEN(attr->om)) {
3699         attr->offset = 0;
3700         proc->write_reliable.cur_attr++;
3701     }
3702 
3703     rc = ble_gattc_write_reliable_resume(proc);
3704     if (rc != 0) {
3705         goto err;
3706     }
3707 
3708     return 0;
3709 err:
3710     ble_gattc_write_reliable_err(proc, rc, 0);
3711     return BLE_HS_EDONE;
3712 }
3713 
3714 /**
3715  * Handles an incoming execute-write-response for the specified
3716  * write-reliable-characteristic-values proc.
3717  */
ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc * proc,int status)3718 static int ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc, int status)
3719 {
3720     ble_gattc_dbg_assert_proc_not_inserted(proc);
3721     ble_gattc_write_reliable_cb(proc, status, 0);
3722     return BLE_HS_EDONE;
3723 }
3724 
ble_gattc_write_reliable(uint16_t conn_handle,struct ble_gatt_attr * attrs,int num_attrs,ble_gatt_reliable_attr_fn * cb,void * cb_arg)3725 int ble_gattc_write_reliable(uint16_t conn_handle,
3726                              struct ble_gatt_attr *attrs,
3727                              int num_attrs,
3728                              ble_gatt_reliable_attr_fn *cb, void *cb_arg)
3729 {
3730 #if !MYNEWT_VAL(BLE_GATT_WRITE_RELIABLE)
3731     return BLE_HS_ENOTSUP;
3732 #endif
3733     struct ble_gattc_proc *proc;
3734     int rc;
3735     int i;
3736     proc = NULL;
3737     STATS_INC(ble_gattc_stats, write_reliable);
3738 
3739     if (num_attrs > MYNEWT_VAL(BLE_GATT_WRITE_MAX_ATTRS)) {
3740         rc = BLE_HS_EINVAL;
3741         goto done;
3742     }
3743 
3744     proc = ble_gattc_proc_alloc();
3745     if (proc == NULL) {
3746         rc = BLE_HS_ENOMEM;
3747         goto done;
3748     }
3749 
3750     proc->op = BLE_GATT_OP_WRITE_RELIABLE;
3751     proc->conn_handle = conn_handle;
3752     proc->write_reliable.num_attrs = num_attrs;
3753     proc->write_reliable.cur_attr = 0;
3754     proc->write_reliable.cb = cb;
3755     proc->write_reliable.cb_arg = cb_arg;
3756 
3757     for (i = 0; i < num_attrs; i++) {
3758         proc->write_reliable.attrs[i] = attrs[i];
3759         proc->write_reliable.attrs[i].offset = 0;
3760         /* Consume mbuf from caller. */
3761         attrs[i].om = NULL;
3762     }
3763 
3764     ble_gattc_log_write_reliable(proc);
3765     rc = ble_gattc_write_reliable_tx(proc);
3766     if (rc != 0) {
3767         goto done;
3768     }
3769 
3770 done:
3771 
3772     if (rc != 0) {
3773         STATS_INC(ble_gattc_stats, write_reliable_fail);
3774     }
3775 
3776     /* Free supplied mbufs in case something failed. */
3777     for (i = 0; i < num_attrs; i++) {
3778         os_mbuf_free_chain(attrs[i].om);
3779         attrs[i].om = NULL;
3780     }
3781 
3782     ble_gattc_process_status(proc, rc);
3783     return rc;
3784 }
3785 
3786 /*****************************************************************************
3787  * $notify                                                                   *
3788  *****************************************************************************/
3789 
ble_gattc_notify_custom(uint16_t conn_handle,uint16_t chr_val_handle,struct os_mbuf * txom)3790 int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle, struct os_mbuf *txom)
3791 {
3792 #if !MYNEWT_VAL(BLE_GATT_NOTIFY)
3793     return BLE_HS_ENOTSUP;
3794 #endif
3795     struct os_mbuf *txom_tmp = txom;
3796     int rc;
3797     STATS_INC(ble_gattc_stats, notify);
3798     ble_gattc_log_notify(chr_val_handle);
3799 
3800     if (txom_tmp == NULL) {
3801         /* No custom attribute data; read the value from the specified
3802          * attribute.
3803          */
3804         txom_tmp = ble_hs_mbuf_att_pkt();
3805         if (txom_tmp == NULL) {
3806             rc = BLE_HS_ENOMEM;
3807             goto done;
3808         }
3809 
3810         rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE,
3811                                      chr_val_handle, 0, txom_tmp, NULL);
3812         if (rc != 0) {
3813             /* Fatal error; application disallowed attribute read. */
3814             rc = BLE_HS_EAPP;
3815             goto done;
3816         }
3817     }
3818 
3819     rc = ble_att_clt_tx_notify(conn_handle, chr_val_handle, txom_tmp);
3820     txom_tmp = NULL;
3821 
3822     if (rc != 0) {
3823         goto done;
3824     }
3825 
3826 done:
3827 
3828     if (rc != 0) {
3829         STATS_INC(ble_gattc_stats, notify_fail);
3830     }
3831 
3832     /* Tell the application that a notification transmission was attempted. */
3833     ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 0);
3834     os_mbuf_free_chain(txom_tmp);
3835     return rc;
3836 }
3837 
ble_gattc_notify(uint16_t conn_handle,uint16_t chr_val_handle)3838 int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle)
3839 {
3840 #if !MYNEWT_VAL(BLE_GATT_NOTIFY)
3841     return BLE_HS_ENOTSUP;
3842 #endif
3843     int rc;
3844     rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL);
3845     return rc;
3846 }
3847 
3848 /*****************************************************************************
3849  * $indicate                                                                 *
3850  *****************************************************************************/
3851 
3852 /**
3853  * Handles an incoming ATT error response for the specified indication proc.
3854  * A device should never send an error in response to an indication.  If this
3855  * happens, we treat it like a confirmation (indication ack), but report the
3856  * error status to the application.
3857  */
ble_gattc_indicate_err(struct ble_gattc_proc * proc,int status,uint16_t att_handle)3858 static void ble_gattc_indicate_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle)
3859 {
3860     ble_gattc_dbg_assert_proc_not_inserted(proc);
3861 
3862     if (status != BLE_HS_ENOTCONN) {
3863         int rc = ble_gatts_rx_indicate_ack(proc->conn_handle, proc->indicate.chr_val_handle);
3864         if (rc != 0) {
3865             return;
3866         }
3867     }
3868 
3869     /* Tell the application about the received acknowledgment. */
3870     ble_gap_notify_tx_event(status, proc->conn_handle,
3871                             proc->indicate.chr_val_handle, 1);
3872     /* Send the next indication if one is pending. */
3873     ble_gatts_send_next_indicate(proc->conn_handle);
3874 }
3875 
ble_gattc_indicate_tmo(struct ble_gattc_proc * proc)3876 static void ble_gattc_indicate_tmo(struct ble_gattc_proc *proc)
3877 {
3878     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
3879     ble_gattc_dbg_assert_proc_not_inserted(proc);
3880     ble_gap_notify_tx_event(BLE_HS_ETIMEOUT, proc->conn_handle,
3881                             proc->indicate.chr_val_handle, 1);
3882 }
3883 
3884 /**
3885  * Handles an incoming handle-value-confirmation for the specified indication
3886  * proc.
3887  */
ble_gattc_indicate_rx_rsp(struct ble_gattc_proc * proc)3888 static void ble_gattc_indicate_rx_rsp(struct ble_gattc_proc *proc)
3889 {
3890     int rc;
3891     ble_gattc_dbg_assert_proc_not_inserted(proc);
3892     rc = ble_gatts_rx_indicate_ack(proc->conn_handle,
3893                                    proc->indicate.chr_val_handle);
3894     if (rc != 0) {
3895         return;
3896     }
3897 
3898     /* Tell the application about the received acknowledgment. */
3899     ble_gap_notify_tx_event(BLE_HS_EDONE, proc->conn_handle,
3900                             proc->indicate.chr_val_handle, 1);
3901     /* Send the next indication if one is pending. */
3902     ble_gatts_send_next_indicate(proc->conn_handle);
3903 }
3904 
3905 /**
3906  * Causes the indication in progress for the specified connection (if any) to
3907  * fail with a status code of BLE_HS_ENOTCONN;
3908  */
ble_gatts_indicate_fail_notconn(uint16_t conn_handle)3909 void ble_gatts_indicate_fail_notconn(uint16_t conn_handle)
3910 {
3911     ble_gattc_fail_procs(conn_handle, BLE_GATT_OP_INDICATE, BLE_HS_ENOTCONN);
3912 }
3913 
ble_gattc_indicate_custom(uint16_t conn_handle,uint16_t chr_val_handle,struct os_mbuf * txom)3914 int ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, struct os_mbuf *txom)
3915 {
3916 #if !MYNEWT_VAL(BLE_GATT_INDICATE)
3917     return BLE_HS_ENOTSUP;
3918 #endif
3919     struct os_mbuf *txom_tmp = txom;
3920     struct ble_gattc_proc *proc;
3921     struct ble_hs_conn *conn;
3922     int rc;
3923     STATS_INC(ble_gattc_stats, indicate);
3924     proc = ble_gattc_proc_alloc();
3925     if (proc == NULL) {
3926         rc = BLE_HS_ENOMEM;
3927         goto done;
3928     }
3929 
3930     proc->op = BLE_GATT_OP_INDICATE;
3931     proc->conn_handle = conn_handle;
3932     proc->indicate.chr_val_handle = chr_val_handle;
3933     ble_gattc_log_indicate(chr_val_handle);
3934 
3935     if (txom_tmp == NULL) {
3936         /* No custom attribute data; read the value from the specified
3937          * attribute.
3938          */
3939         txom_tmp = ble_hs_mbuf_att_pkt();
3940         if (txom_tmp == NULL) {
3941             rc = BLE_HS_ENOMEM;
3942             goto done;
3943         }
3944 
3945         rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle,
3946                                      0, txom_tmp, NULL);
3947         if (rc != 0) {
3948             /* Fatal error; application disallowed attribute read. */
3949             BLE_HS_DBG_ASSERT(0);
3950             rc = BLE_HS_EAPP;
3951             goto done;
3952         }
3953     }
3954 
3955     rc = ble_att_clt_tx_indicate(conn_handle, chr_val_handle, txom_tmp);
3956     txom_tmp = NULL;
3957 
3958     if (rc != 0) {
3959         goto done;
3960     }
3961 
3962     ble_hs_lock();
3963     conn = ble_hs_conn_find(conn_handle);
3964     if (conn != NULL) {
3965         BLE_HS_DBG_ASSERT(conn->bhc_gatt_svr.indicate_val_handle == 0);
3966         conn->bhc_gatt_svr.indicate_val_handle = chr_val_handle;
3967     }
3968 
3969     ble_hs_unlock();
3970 done:
3971 
3972     if (rc != 0) {
3973         STATS_INC(ble_gattc_stats, indicate_fail);
3974     }
3975 
3976     /* Tell the application that an indication transmission was attempted. */
3977     ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 1);
3978     ble_gattc_process_status(proc, rc);
3979     os_mbuf_free_chain(txom_tmp);
3980     return rc;
3981 }
3982 
ble_gattc_indicate(uint16_t conn_handle,uint16_t chr_val_handle)3983 int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle)
3984 {
3985     return ble_gattc_indicate_custom(conn_handle, chr_val_handle, NULL);
3986 }
3987 
3988 /*****************************************************************************
3989  * $rx                                                                       *
3990  *****************************************************************************/
3991 
3992 /**
3993  * Dispatches an incoming ATT error-response to the appropriate active GATT
3994  * procedure.
3995  */
ble_gattc_rx_err(uint16_t conn_handle,uint16_t handle,uint16_t status)3996 void ble_gattc_rx_err(uint16_t conn_handle, uint16_t handle, uint16_t status)
3997 {
3998     struct ble_gattc_proc *proc;
3999 
4000     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_NONE);
4001     if (proc != NULL) {
4002         ble_gattc_err_fn *err_cb = ble_gattc_err_dispatch_get(proc->op);
4003         if (err_cb != NULL) {
4004             err_cb(proc, BLE_HS_ERR_ATT_BASE + status, handle);
4005         }
4006 
4007         ble_gattc_proc_free(proc);
4008     }
4009 }
4010 
4011 /**
4012  * Dispatches an incoming ATT exchange-mtu-response to the appropriate active
4013  * GATT procedure.
4014  */
ble_gattc_rx_mtu(uint16_t conn_handle,int status,uint16_t chan_mtu)4015 void ble_gattc_rx_mtu(uint16_t conn_handle, int status, uint16_t chan_mtu)
4016 {
4017     struct ble_gattc_proc *proc;
4018     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_MTU);
4019     if (proc != NULL) {
4020         ble_gattc_mtu_cb(proc, status, 0, chan_mtu);
4021         ble_gattc_process_status(proc, BLE_HS_EDONE);
4022     }
4023 }
4024 
4025 /**
4026  * Dispatches an incoming "information data" entry from a
4027  * find-information-response to the appropriate active GATT procedure.
4028  */
ble_gattc_rx_find_info_idata(uint16_t conn_handle,struct ble_att_find_info_idata * idata)4029 void ble_gattc_rx_find_info_idata(uint16_t conn_handle, struct ble_att_find_info_idata *idata)
4030 {
4031 #if !NIMBLE_BLE_ATT_CLT_FIND_INFO
4032     return;
4033 #endif
4034     struct ble_gattc_proc *proc;
4035 
4036     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_DISC_ALL_DSCS);
4037     if (proc != NULL) {
4038         int rc = ble_gattc_disc_all_dscs_rx_idata(proc, idata);
4039         ble_gattc_process_status(proc, rc);
4040     }
4041 }
4042 
4043 /**
4044  * Dispatches an incoming notification of the end of a
4045  * find-information-response to the appropriate active GATT procedure.
4046  */
ble_gattc_rx_find_info_complete(uint16_t conn_handle,int status)4047 void ble_gattc_rx_find_info_complete(uint16_t conn_handle, int status)
4048 {
4049 #if !NIMBLE_BLE_ATT_CLT_FIND_INFO
4050     return;
4051 #endif
4052     struct ble_gattc_proc *proc;
4053 
4054     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_DISC_ALL_DSCS);
4055     if (proc != NULL) {
4056         int rc = ble_gattc_disc_all_dscs_rx_complete(proc, status);
4057         ble_gattc_process_status(proc, rc);
4058     }
4059 }
4060 
4061 /**
4062  * Dispatches an incoming "handles info" entry from a
4063  * find-by-type-value-response to the appropriate active GATT procedure.
4064  */
ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle,struct ble_att_find_type_value_hinfo * hinfo)4065 void ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle, struct ble_att_find_type_value_hinfo *hinfo)
4066 {
4067 #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE
4068     return;
4069 #endif
4070     struct ble_gattc_proc *proc;
4071 
4072     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_DISC_SVC_UUID);
4073     if (proc != NULL) {
4074         int rc = ble_gattc_disc_svc_uuid_rx_hinfo(proc, hinfo);
4075         ble_gattc_process_status(proc, rc);
4076     }
4077 }
4078 
4079 /**
4080  * Dispatches an incoming notification of the end of a
4081  * find-by-type-value-response to the appropriate active GATT procedure.
4082  */
ble_gattc_rx_find_type_value_complete(uint16_t conn_handle,int status)4083 void ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status)
4084 {
4085 #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE
4086     return;
4087 #endif
4088     struct ble_gattc_proc *proc;
4089 
4090     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_DISC_SVC_UUID);
4091     if (proc != NULL) {
4092         int rc = ble_gattc_disc_svc_uuid_rx_complete(proc, status);
4093         ble_gattc_process_status(proc, rc);
4094     }
4095 }
4096 
4097 /**
4098  * Dispatches an incoming "attribute data" entry from a read-by-type-response
4099  * to the appropriate active GATT procedure.
4100  */
ble_gattc_rx_read_type_adata(uint16_t conn_handle,struct ble_att_read_type_adata * adata)4101 void ble_gattc_rx_read_type_adata(uint16_t conn_handle, struct ble_att_read_type_adata *adata)
4102 {
4103 #if !NIMBLE_BLE_ATT_CLT_READ_TYPE
4104     return;
4105 #endif
4106     const struct ble_gattc_rx_adata_entry *rx_entry;
4107     struct ble_gattc_proc *proc;
4108 
4109     proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle,
4110                                          ble_gattc_rx_read_type_elem_entries,
4111                                          &rx_entry);
4112     if (proc != NULL) {
4113         int rc = rx_entry->cb(proc, adata);
4114         ble_gattc_process_status(proc, rc);
4115     }
4116 }
4117 
4118 /**
4119  * Dispatches an incoming notification of the end of a read-by-type-response to
4120  * the appropriate active GATT procedure.
4121  */
ble_gattc_rx_read_type_complete(uint16_t conn_handle,int status)4122 void ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status)
4123 {
4124 #if !NIMBLE_BLE_ATT_CLT_READ_TYPE
4125     return;
4126 #endif
4127     const struct ble_gattc_rx_complete_entry *rx_entry;
4128     struct ble_gattc_proc *proc;
4129 
4130     proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(
4131                            conn_handle, ble_gattc_rx_read_type_complete_entries,
4132                            &rx_entry);
4133     if (proc != NULL) {
4134         int rc = rx_entry->cb(proc, status);
4135         ble_gattc_process_status(proc, rc);
4136     }
4137 }
4138 
4139 /**
4140  * Dispatches an incoming "attribute data" entry from a
4141  * read-by-group-type-response to the appropriate active GATT procedure.
4142  */
ble_gattc_rx_read_group_type_adata(uint16_t conn_handle,struct ble_att_read_group_type_adata * adata)4143 void ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, struct ble_att_read_group_type_adata *adata)
4144 {
4145 #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE
4146     return;
4147 #endif
4148     struct ble_gattc_proc *proc;
4149 
4150     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_DISC_ALL_SVCS);
4151     if (proc != NULL) {
4152         int rc = ble_gattc_disc_all_svcs_rx_adata(proc, adata);
4153         ble_gattc_process_status(proc, rc);
4154     }
4155 }
4156 
4157 /**
4158  * Dispatches an incoming notification of the end of a
4159  * read-by-group-type-response to the appropriate active GATT procedure.
4160  */
ble_gattc_rx_read_group_type_complete(uint16_t conn_handle,int status)4161 void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int status)
4162 {
4163 #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE
4164     return;
4165 #endif
4166     struct ble_gattc_proc *proc;
4167 
4168     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_DISC_ALL_SVCS);
4169     if (proc != NULL) {
4170         int rc = ble_gattc_disc_all_svcs_rx_complete(proc, status);
4171         ble_gattc_process_status(proc, rc);
4172     }
4173 }
4174 
4175 /**
4176  * Dispatches an incoming ATT read-response to the appropriate active GATT
4177  * procedure.
4178  */
ble_gattc_rx_read_rsp(uint16_t conn_handle,int status,struct os_mbuf ** om)4179 void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, struct os_mbuf **om)
4180 {
4181 #if !NIMBLE_BLE_ATT_CLT_READ
4182     return;
4183 #endif
4184     const struct ble_gattc_rx_attr_entry *rx_entry;
4185     struct ble_gattc_proc *proc;
4186 
4187     proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle,
4188                                          ble_gattc_rx_read_rsp_entries,
4189                                          &rx_entry);
4190     if (proc != NULL) {
4191         int rc = rx_entry->cb(proc, status, om);
4192         ble_gattc_process_status(proc, rc);
4193     }
4194 }
4195 
4196 /**
4197  * Dispatches an incoming ATT read-blob-response to the appropriate active GATT
4198  * procedure.
4199  */
ble_gattc_rx_read_blob_rsp(uint16_t conn_handle,int status,struct os_mbuf ** om)4200 void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, struct os_mbuf **om)
4201 {
4202 #if !NIMBLE_BLE_ATT_CLT_READ_BLOB
4203     return;
4204 #endif
4205     struct ble_gattc_proc *proc;
4206 
4207     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_READ_LONG);
4208     if (proc != NULL) {
4209         int rc = ble_gattc_read_long_rx_read_rsp(proc, status, om);
4210         ble_gattc_process_status(proc, rc);
4211     }
4212 }
4213 
4214 /**
4215  * Dispatches an incoming ATT read-multiple-response to the appropriate active
4216  * GATT procedure.
4217  */
ble_gattc_rx_read_mult_rsp(uint16_t conn_handle,int status,struct os_mbuf ** om)4218 void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, struct os_mbuf **om)
4219 {
4220 #if !NIMBLE_BLE_ATT_CLT_READ_MULT
4221     return;
4222 #endif
4223     struct ble_gattc_proc *proc;
4224     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_READ_MULT);
4225     if (proc != NULL) {
4226         ble_gattc_read_mult_cb(proc, status, 0, om);
4227         ble_gattc_process_status(proc, BLE_HS_EDONE);
4228     }
4229 }
4230 
4231 /**
4232  * Dispatches an incoming ATT write-response to the appropriate active GATT
4233  * procedure.
4234  */
ble_gattc_rx_write_rsp(uint16_t conn_handle)4235 void ble_gattc_rx_write_rsp(uint16_t conn_handle)
4236 {
4237 #if !NIMBLE_BLE_ATT_CLT_WRITE
4238     return;
4239 #endif
4240     struct ble_gattc_proc *proc;
4241     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_WRITE);
4242     if (proc != NULL) {
4243         ble_gattc_write_cb(proc, 0, 0);
4244         ble_gattc_process_status(proc, BLE_HS_EDONE);
4245     }
4246 }
4247 
4248 /**
4249  * Dispatches an incoming ATT prepare-write-response to the appropriate active
4250  * GATT procedure.
4251  */
ble_gattc_rx_prep_write_rsp(uint16_t conn_handle,int status,uint16_t handle,uint16_t offset,struct os_mbuf ** om)4252 void ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status,
4253                                  uint16_t handle, uint16_t offset,
4254                                  struct os_mbuf **om)
4255 {
4256 #if !NIMBLE_BLE_ATT_CLT_PREP_WRITE
4257     return;
4258 #endif
4259     const struct ble_gattc_rx_prep_entry *rx_entry;
4260     struct ble_gattc_proc *proc;
4261 
4262     proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle,
4263                                          ble_gattc_rx_prep_entries,
4264                                          &rx_entry);
4265     if (proc != NULL) {
4266         int rc = rx_entry->cb(proc, status, handle, offset, om);
4267         ble_gattc_process_status(proc, rc);
4268     }
4269 }
4270 
4271 /**
4272  * Dispatches an incoming ATT execute-write-response to the appropriate active
4273  * GATT procedure.
4274  */
ble_gattc_rx_exec_write_rsp(uint16_t conn_handle,int status)4275 void ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status)
4276 {
4277 #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE
4278     return;
4279 #endif
4280     const struct ble_gattc_rx_exec_entry *rx_entry;
4281     struct ble_gattc_proc *proc;
4282 
4283     proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, ble_gattc_rx_exec_entries, &rx_entry);
4284     if (proc != NULL) {
4285         int rc = rx_entry->cb(proc, status);
4286         ble_gattc_process_status(proc, rc);
4287     }
4288 }
4289 
4290 /**
4291  * Dispatches an incoming ATT handle-value-confirmation to the appropriate
4292  * active GATT procedure.
4293  */
ble_gattc_rx_indicate_rsp(uint16_t conn_handle)4294 void ble_gattc_rx_indicate_rsp(uint16_t conn_handle)
4295 {
4296 #if !NIMBLE_BLE_ATT_CLT_INDICATE
4297     return;
4298 #endif
4299     struct ble_gattc_proc *proc;
4300     proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_INDICATE);
4301     if (proc != NULL) {
4302         ble_gattc_indicate_rx_rsp(proc);
4303         ble_gattc_process_status(proc, BLE_HS_EDONE);
4304     }
4305 }
4306 
4307 /*****************************************************************************
4308  * $misc                                                                     *
4309  *****************************************************************************/
4310 
4311 /**
4312  * Called when a BLE connection ends.  Frees all GATT resources associated with
4313  * the connection and cancels all relevant pending and in-progress GATT
4314  * procedures.
4315  *
4316  * @param conn_handle           The handle of the connection that was
4317  *                                  terminated.
4318  */
ble_gattc_connection_broken(uint16_t conn_handle)4319 void ble_gattc_connection_broken(uint16_t conn_handle)
4320 {
4321     ble_gattc_fail_procs(conn_handle, BLE_GATT_OP_NONE, BLE_HS_ENOTCONN);
4322 }
4323 
4324 /**
4325  * Indicates whether there are currently any active GATT client procedures.
4326  */
ble_gattc_any_jobs(void)4327 int ble_gattc_any_jobs(void)
4328 {
4329     return !STAILQ_EMPTY(&ble_gattc_procs);
4330 }
4331 
ble_gattc_init(void)4332 int ble_gattc_init(void)
4333 {
4334     int rc;
4335     STAILQ_INIT(&ble_gattc_procs);
4336 
4337     if (MYNEWT_VAL(BLE_GATT_MAX_PROCS) > 0) {
4338         rc = os_mempool_init(&ble_gattc_proc_pool,
4339                              MYNEWT_VAL(BLE_GATT_MAX_PROCS),
4340                              sizeof(struct ble_gattc_proc),
4341                              ble_gattc_proc_mem,
4342                              "ble_gattc_proc_pool");
4343         if (rc != 0) {
4344             return rc;
4345         }
4346     }
4347 
4348     rc = stats_init_and_reg(STATS_HDR(ble_gattc_stats), STATS_SIZE_INIT_PARMS(ble_gattc_stats, STATS_SIZE_32),
4349         STATS_NAME_INIT_PARMS(ble_gattc_stats), "ble_gattc");
4350     if (rc != 0) {
4351         return BLE_HS_EOS;
4352     }
4353 
4354     return 0;
4355 }