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