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