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