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