xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_gatts.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "nimble/ble.h"
24 #include "host/ble_uuid.h"
25 #include "host/ble_store.h"
26 #include "ble_hs_priv.h"
27 
28 #define BLE_GATTS_INCLUDE_SZ    6
29 #define BLE_GATTS_CHR_MAX_SZ    19
30 
31 static const ble_uuid_t *uuid_pri =
32     BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE);
33 static const ble_uuid_t *uuid_sec =
34     BLE_UUID16_DECLARE(BLE_ATT_UUID_SECONDARY_SERVICE);
35 static const ble_uuid_t *uuid_inc =
36     BLE_UUID16_DECLARE(BLE_ATT_UUID_INCLUDE);
37 static const ble_uuid_t *uuid_chr =
38     BLE_UUID16_DECLARE(BLE_ATT_UUID_CHARACTERISTIC);
39 static const ble_uuid_t *uuid_ccc =
40     BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16);
41 
42 static const struct ble_gatt_svc_def **ble_gatts_svc_defs;
43 static int ble_gatts_num_svc_defs;
44 
45 struct ble_gatts_svc_entry {
46     const struct ble_gatt_svc_def *svc;
47     uint16_t handle;            /* 0 means unregistered. */
48     uint16_t end_group_handle;  /* 0xffff means unset. */
49 };
50 
51 static struct ble_gatts_svc_entry *ble_gatts_svc_entries;
52 static uint16_t ble_gatts_num_svc_entries;
53 
54 static os_membuf_t *ble_gatts_clt_cfg_mem;
55 static struct os_mempool ble_gatts_clt_cfg_pool;
56 
57 struct ble_gatts_clt_cfg {
58     uint16_t chr_val_handle;
59     uint8_t flags;
60     uint8_t allowed;
61 };
62 
63 /** A cached array of handles for the configurable characteristics. */
64 static struct ble_gatts_clt_cfg *ble_gatts_clt_cfgs;
65 static int ble_gatts_num_cfgable_chrs;
66 
67 STATS_SECT_DECL(ble_gatts_stats) ble_gatts_stats;
68 STATS_NAME_START(ble_gatts_stats)
STATS_NAME(ble_gatts_stats,svcs)69     STATS_NAME(ble_gatts_stats, svcs)
70     STATS_NAME(ble_gatts_stats, chrs)
71     STATS_NAME(ble_gatts_stats, dscs)
72     STATS_NAME(ble_gatts_stats, svc_def_reads)
73     STATS_NAME(ble_gatts_stats, svc_inc_reads)
74     STATS_NAME(ble_gatts_stats, chr_def_reads)
75     STATS_NAME(ble_gatts_stats, chr_val_reads)
76     STATS_NAME(ble_gatts_stats, chr_val_writes)
77     STATS_NAME(ble_gatts_stats, dsc_reads)
78     STATS_NAME(ble_gatts_stats, dsc_writes)
79 STATS_NAME_END(ble_gatts_stats)
80 
81 static int
82 ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle,
83                      uint8_t op, uint16_t offset, struct os_mbuf **om,
84                      void *arg)
85 {
86     const struct ble_gatt_svc_def *svc;
87     uint8_t *buf;
88 
89     STATS_INC(ble_gatts_stats, svc_def_reads);
90 
91     BLE_HS_DBG_ASSERT(op == BLE_ATT_ACCESS_OP_READ);
92 
93     svc = arg;
94 
95     buf = os_mbuf_extend(*om, ble_uuid_length(svc->uuid));
96     if (buf == NULL) {
97         return BLE_ATT_ERR_INSUFFICIENT_RES;
98     }
99 
100     ble_uuid_flat(svc->uuid, buf);
101 
102     return 0;
103 }
104 
105 static int
ble_gatts_inc_access(uint16_t conn_handle,uint16_t attr_handle,uint8_t op,uint16_t offset,struct os_mbuf ** om,void * arg)106 ble_gatts_inc_access(uint16_t conn_handle, uint16_t attr_handle,
107                      uint8_t op, uint16_t offset, struct os_mbuf **om,
108                      void *arg)
109 {
110     const struct ble_gatts_svc_entry *entry;
111     uint16_t uuid16;
112     uint8_t *buf;
113 
114     STATS_INC(ble_gatts_stats, svc_inc_reads);
115 
116     BLE_HS_DBG_ASSERT(op == BLE_ATT_ACCESS_OP_READ);
117 
118     entry = arg;
119 
120     buf = os_mbuf_extend(*om, 4);
121     if (buf == NULL) {
122         return BLE_ATT_ERR_INSUFFICIENT_RES;
123     }
124     put_le16(buf + 0, entry->handle);
125     put_le16(buf + 2, entry->end_group_handle);
126 
127     /* Only include the service UUID if it has a 16-bit representation. */
128     uuid16 = ble_uuid_u16(entry->svc->uuid);
129     if (uuid16 != 0) {
130         buf = os_mbuf_extend(*om, 2);
131         if (buf == NULL) {
132             return BLE_ATT_ERR_INSUFFICIENT_RES;
133         }
134         put_le16(buf, uuid16);
135     }
136 
137     return 0;
138 }
139 
140 static uint16_t
ble_gatts_chr_clt_cfg_allowed(const struct ble_gatt_chr_def * chr)141 ble_gatts_chr_clt_cfg_allowed(const struct ble_gatt_chr_def *chr)
142 {
143     uint16_t flags;
144 
145     flags = 0;
146     if (chr->flags & BLE_GATT_CHR_F_NOTIFY) {
147         flags |= BLE_GATTS_CLT_CFG_F_NOTIFY;
148     }
149     if (chr->flags & BLE_GATT_CHR_F_INDICATE) {
150         flags |= BLE_GATTS_CLT_CFG_F_INDICATE;
151     }
152 
153     return flags;
154 }
155 
156 static uint8_t
ble_gatts_att_flags_from_chr_flags(ble_gatt_chr_flags chr_flags)157 ble_gatts_att_flags_from_chr_flags(ble_gatt_chr_flags chr_flags)
158 {
159     uint8_t att_flags;
160 
161     att_flags = 0;
162     if (chr_flags & BLE_GATT_CHR_F_READ) {
163         att_flags |= BLE_ATT_F_READ;
164     }
165     if (chr_flags & (BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE)) {
166         att_flags |= BLE_ATT_F_WRITE;
167     }
168     if (chr_flags & BLE_GATT_CHR_F_READ_ENC) {
169         att_flags |= BLE_ATT_F_READ_ENC;
170     }
171     if (chr_flags & BLE_GATT_CHR_F_READ_AUTHEN) {
172         att_flags |= BLE_ATT_F_READ_AUTHEN;
173     }
174     if (chr_flags & BLE_GATT_CHR_F_READ_AUTHOR) {
175         att_flags |= BLE_ATT_F_READ_AUTHOR;
176     }
177     if (chr_flags & BLE_GATT_CHR_F_WRITE_ENC) {
178         att_flags |= BLE_ATT_F_WRITE_ENC;
179     }
180     if (chr_flags & BLE_GATT_CHR_F_WRITE_AUTHEN) {
181         att_flags |= BLE_ATT_F_WRITE_AUTHEN;
182     }
183     if (chr_flags & BLE_GATT_CHR_F_WRITE_AUTHOR) {
184         att_flags |= BLE_ATT_F_WRITE_AUTHOR;
185     }
186 
187     return att_flags;
188 }
189 
190 static uint8_t
ble_gatts_chr_properties(const struct ble_gatt_chr_def * chr)191 ble_gatts_chr_properties(const struct ble_gatt_chr_def *chr)
192 {
193     uint8_t properties;
194 
195     properties = 0;
196 
197     if (chr->flags & BLE_GATT_CHR_F_BROADCAST) {
198         properties |= BLE_GATT_CHR_PROP_BROADCAST;
199     }
200     if (chr->flags & BLE_GATT_CHR_F_READ) {
201         properties |= BLE_GATT_CHR_PROP_READ;
202     }
203     if (chr->flags & BLE_GATT_CHR_F_WRITE_NO_RSP) {
204         properties |= BLE_GATT_CHR_PROP_WRITE_NO_RSP;
205     }
206     if (chr->flags & BLE_GATT_CHR_F_WRITE) {
207         properties |= BLE_GATT_CHR_PROP_WRITE;
208     }
209     if (chr->flags & BLE_GATT_CHR_F_NOTIFY) {
210         properties |= BLE_GATT_CHR_PROP_NOTIFY;
211     }
212     if (chr->flags & BLE_GATT_CHR_F_INDICATE) {
213         properties |= BLE_GATT_CHR_PROP_INDICATE;
214     }
215     if (chr->flags & BLE_GATT_CHR_F_AUTH_SIGN_WRITE) {
216         properties |= BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE;
217     }
218     if (chr->flags &
219         (BLE_GATT_CHR_F_RELIABLE_WRITE | BLE_GATT_CHR_F_AUX_WRITE)) {
220 
221         properties |= BLE_GATT_CHR_PROP_EXTENDED;
222     }
223 
224     return properties;
225 }
226 
227 static int
ble_gatts_chr_def_access(uint16_t conn_handle,uint16_t attr_handle,uint8_t op,uint16_t offset,struct os_mbuf ** om,void * arg)228 ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle,
229                          uint8_t op, uint16_t offset, struct os_mbuf **om,
230                          void *arg)
231 {
232     const struct ble_gatt_chr_def *chr;
233     uint8_t *buf;
234 
235     STATS_INC(ble_gatts_stats, chr_def_reads);
236 
237     BLE_HS_DBG_ASSERT(op == BLE_ATT_ACCESS_OP_READ);
238 
239     chr = arg;
240 
241     buf = os_mbuf_extend(*om, 3);
242     if (buf == NULL) {
243         return BLE_ATT_ERR_INSUFFICIENT_RES;
244     }
245 
246     buf[0] = ble_gatts_chr_properties(chr);
247 
248     /* The value attribute is always immediately after the declaration. */
249     put_le16(buf + 1, attr_handle + 1);
250 
251     buf = os_mbuf_extend(*om, ble_uuid_length(chr->uuid));
252     if (buf == NULL) {
253         return BLE_ATT_ERR_INSUFFICIENT_RES;
254     }
255 
256     ble_uuid_flat(chr->uuid, buf);
257 
258     return 0;
259 }
260 
261 static int
ble_gatts_chr_is_sane(const struct ble_gatt_chr_def * chr)262 ble_gatts_chr_is_sane(const struct ble_gatt_chr_def *chr)
263 {
264     if (chr->uuid == NULL) {
265         return 0;
266     }
267 
268     if (chr->access_cb == NULL) {
269         return 0;
270     }
271 
272     /* XXX: Check properties. */
273 
274     return 1;
275 }
276 
277 static uint8_t
ble_gatts_chr_op(uint8_t att_op)278 ble_gatts_chr_op(uint8_t att_op)
279 {
280     switch (att_op) {
281     case BLE_ATT_ACCESS_OP_READ:
282         return BLE_GATT_ACCESS_OP_READ_CHR;
283 
284     case BLE_ATT_ACCESS_OP_WRITE:
285         return BLE_GATT_ACCESS_OP_WRITE_CHR;
286 
287     default:
288         BLE_HS_DBG_ASSERT(0);
289         return BLE_GATT_ACCESS_OP_READ_CHR;
290     }
291 }
292 
293 static void
ble_gatts_chr_inc_val_stat(uint8_t gatt_op)294 ble_gatts_chr_inc_val_stat(uint8_t gatt_op)
295 {
296     switch (gatt_op) {
297     case BLE_GATT_ACCESS_OP_READ_CHR:
298         STATS_INC(ble_gatts_stats, chr_val_reads);
299         break;
300 
301     case BLE_GATT_ACCESS_OP_WRITE_CHR:
302         STATS_INC(ble_gatts_stats, chr_val_writes);
303         break;
304 
305     default:
306         break;
307     }
308 }
309 
310 /**
311  * Indicates whether the set of registered services can be modified.  The
312  * service set is mutable if:
313  *     o No peers are connected, and
314  *     o No GAP operations are active (advertise, discover, or connect).
315  *
316  * @return                      true if the GATT service set can be modified;
317  *                              false otherwise.
318  */
319 static bool
ble_gatts_mutable(void)320 ble_gatts_mutable(void)
321 {
322     /* Ensure no active GAP procedures. */
323     if (ble_gap_adv_active() ||
324         ble_gap_disc_active() ||
325         ble_gap_conn_active()) {
326 
327         return false;
328     }
329 
330     /* Ensure no established connections. */
331     if (ble_hs_conn_first() != NULL) {
332         return false;
333     }
334 
335     return true;
336 }
337 
338 static int
ble_gatts_val_access(uint16_t conn_handle,uint16_t attr_handle,uint16_t offset,struct ble_gatt_access_ctxt * gatt_ctxt,struct os_mbuf ** om,ble_gatt_access_fn * access_cb,void * cb_arg)339 ble_gatts_val_access(uint16_t conn_handle, uint16_t attr_handle,
340                      uint16_t offset, struct ble_gatt_access_ctxt *gatt_ctxt,
341                      struct os_mbuf **om, ble_gatt_access_fn *access_cb,
342                      void *cb_arg)
343 {
344     uint16_t initial_len;
345     int attr_len;
346     int new_om;
347     int rc;
348 
349     switch (gatt_ctxt->op) {
350     case BLE_GATT_ACCESS_OP_READ_CHR:
351     case BLE_GATT_ACCESS_OP_READ_DSC:
352         /* A characteristic value is being read.
353          *
354          * If the read specifies an offset of 0:
355          *     just append the characteristic value directly onto the response
356          *     mbuf.
357          *
358          * Else:
359          *     allocate a new mbuf to hold the characteristic data, then append
360          *     the requested portion onto the response mbuf.
361          */
362         if (offset == 0) {
363             new_om = 0;
364             gatt_ctxt->om = *om;
365         } else {
366             new_om = 1;
367             gatt_ctxt->om = os_msys_get_pkthdr(0, 0);
368             if (gatt_ctxt->om == NULL) {
369                 return BLE_ATT_ERR_INSUFFICIENT_RES;
370             }
371         }
372 
373         initial_len = OS_MBUF_PKTLEN(gatt_ctxt->om);
374         rc = access_cb(conn_handle, attr_handle, gatt_ctxt, cb_arg);
375         if (rc == 0) {
376             attr_len = OS_MBUF_PKTLEN(gatt_ctxt->om) - initial_len - offset;
377             if (attr_len >= 0) {
378                 if (new_om) {
379                     os_mbuf_appendfrom(*om, gatt_ctxt->om, offset, attr_len);
380                 }
381             } else {
382                 rc = BLE_ATT_ERR_INVALID_OFFSET;
383             }
384         }
385 
386         if (new_om) {
387             os_mbuf_free_chain(gatt_ctxt->om);
388         }
389         return rc;
390 
391     case BLE_GATT_ACCESS_OP_WRITE_CHR:
392     case BLE_GATT_ACCESS_OP_WRITE_DSC:
393         gatt_ctxt->om = *om;
394         rc = access_cb(conn_handle, attr_handle, gatt_ctxt, cb_arg);
395         *om = gatt_ctxt->om;
396         return rc;
397 
398     default:
399         BLE_HS_DBG_ASSERT(0);
400         return BLE_ATT_ERR_UNLIKELY;
401     }
402 }
403 
404 static int
ble_gatts_chr_val_access(uint16_t conn_handle,uint16_t attr_handle,uint8_t att_op,uint16_t offset,struct os_mbuf ** om,void * arg)405 ble_gatts_chr_val_access(uint16_t conn_handle, uint16_t attr_handle,
406                          uint8_t att_op, uint16_t offset,
407                          struct os_mbuf **om, void *arg)
408 {
409     const struct ble_gatt_chr_def *chr_def;
410     struct ble_gatt_access_ctxt gatt_ctxt;
411     int rc;
412 
413     chr_def = arg;
414     BLE_HS_DBG_ASSERT(chr_def != NULL && chr_def->access_cb != NULL);
415 
416     gatt_ctxt.op = ble_gatts_chr_op(att_op);
417     gatt_ctxt.chr = chr_def;
418 
419     ble_gatts_chr_inc_val_stat(gatt_ctxt.op);
420     rc = ble_gatts_val_access(conn_handle, attr_handle, offset, &gatt_ctxt, om,
421                               chr_def->access_cb, chr_def->arg);
422 
423     return rc;
424 }
425 
426 static int
ble_gatts_find_svc_entry_idx(const struct ble_gatt_svc_def * svc)427 ble_gatts_find_svc_entry_idx(const struct ble_gatt_svc_def *svc)
428 {
429     int i;
430 
431     for (i = 0; i < ble_gatts_num_svc_entries; i++) {
432         if (ble_gatts_svc_entries[i].svc == svc) {
433             return i;
434         }
435     }
436 
437     return -1;
438 }
439 
440 static int
ble_gatts_svc_incs_satisfied(const struct ble_gatt_svc_def * svc)441 ble_gatts_svc_incs_satisfied(const struct ble_gatt_svc_def *svc)
442 {
443     int idx;
444     int i;
445 
446     if (svc->includes == NULL) {
447         /* No included services. */
448         return 1;
449     }
450 
451     for (i = 0; svc->includes[i] != NULL; i++) {
452         idx = ble_gatts_find_svc_entry_idx(svc->includes[i]);
453         if (idx == -1 || ble_gatts_svc_entries[idx].handle == 0) {
454             return 0;
455         }
456     }
457 
458     return 1;
459 }
460 
461 static int
ble_gatts_register_inc(struct ble_gatts_svc_entry * entry)462 ble_gatts_register_inc(struct ble_gatts_svc_entry *entry)
463 {
464     uint16_t handle;
465     int rc;
466 
467     BLE_HS_DBG_ASSERT(entry->handle != 0);
468     BLE_HS_DBG_ASSERT(entry->end_group_handle != 0xffff);
469 
470     rc = ble_att_svr_register(uuid_inc, BLE_ATT_F_READ, 0, &handle,
471                               ble_gatts_inc_access, entry);
472     if (rc != 0) {
473         return rc;
474     }
475 
476     return 0;
477 }
478 
479 static uint8_t
ble_gatts_dsc_op(uint8_t att_op)480 ble_gatts_dsc_op(uint8_t att_op)
481 {
482     switch (att_op) {
483     case BLE_ATT_ACCESS_OP_READ:
484         return BLE_GATT_ACCESS_OP_READ_DSC;
485 
486     case BLE_ATT_ACCESS_OP_WRITE:
487         return BLE_GATT_ACCESS_OP_WRITE_DSC;
488 
489     default:
490         BLE_HS_DBG_ASSERT(0);
491         return BLE_GATT_ACCESS_OP_READ_DSC;
492     }
493 }
494 
495 static void
ble_gatts_dsc_inc_stat(uint8_t gatt_op)496 ble_gatts_dsc_inc_stat(uint8_t gatt_op)
497 {
498     switch (gatt_op) {
499     case BLE_GATT_ACCESS_OP_READ_DSC:
500         STATS_INC(ble_gatts_stats, dsc_reads);
501         break;
502 
503     case BLE_GATT_ACCESS_OP_WRITE_DSC:
504         STATS_INC(ble_gatts_stats, dsc_writes);
505         break;
506 
507     default:
508         break;
509     }
510 }
511 
512 static int
ble_gatts_dsc_access(uint16_t conn_handle,uint16_t attr_handle,uint8_t att_op,uint16_t offset,struct os_mbuf ** om,void * arg)513 ble_gatts_dsc_access(uint16_t conn_handle, uint16_t attr_handle,
514                      uint8_t att_op, uint16_t offset, struct os_mbuf **om,
515                      void *arg)
516 {
517     const struct ble_gatt_dsc_def *dsc_def;
518     struct ble_gatt_access_ctxt gatt_ctxt;
519     int rc;
520 
521     dsc_def = arg;
522     BLE_HS_DBG_ASSERT(dsc_def != NULL && dsc_def->access_cb != NULL);
523 
524     gatt_ctxt.op = ble_gatts_dsc_op(att_op);
525     gatt_ctxt.dsc = dsc_def;
526 
527     ble_gatts_dsc_inc_stat(gatt_ctxt.op);
528     rc = ble_gatts_val_access(conn_handle, attr_handle, offset, &gatt_ctxt, om,
529                               dsc_def->access_cb, dsc_def->arg);
530 
531     return rc;
532 }
533 
534 static int
ble_gatts_dsc_is_sane(const struct ble_gatt_dsc_def * dsc)535 ble_gatts_dsc_is_sane(const struct ble_gatt_dsc_def *dsc)
536 {
537     if (dsc->uuid == NULL) {
538         return 0;
539     }
540 
541     if (dsc->access_cb == NULL) {
542         return 0;
543     }
544 
545     return 1;
546 }
547 
548 static int
ble_gatts_register_dsc(const struct ble_gatt_svc_def * svc,const struct ble_gatt_chr_def * chr,const struct ble_gatt_dsc_def * dsc,uint16_t chr_def_handle,ble_gatt_register_fn * register_cb,void * cb_arg)549 ble_gatts_register_dsc(const struct ble_gatt_svc_def *svc,
550                        const struct ble_gatt_chr_def *chr,
551                        const struct ble_gatt_dsc_def *dsc,
552                        uint16_t chr_def_handle,
553                        ble_gatt_register_fn *register_cb, void *cb_arg)
554 {
555     struct ble_gatt_register_ctxt register_ctxt;
556     uint16_t dsc_handle;
557     int rc;
558 
559     if (!ble_gatts_dsc_is_sane(dsc)) {
560         return BLE_HS_EINVAL;
561     }
562 
563     rc = ble_att_svr_register(dsc->uuid, dsc->att_flags, dsc->min_key_size,
564                               &dsc_handle, ble_gatts_dsc_access, (void *)dsc);
565     if (rc != 0) {
566         return rc;
567     }
568 
569     if (register_cb != NULL) {
570         register_ctxt.op = BLE_GATT_REGISTER_OP_DSC;
571         register_ctxt.dsc.handle = dsc_handle;
572         register_ctxt.dsc.svc_def = svc;
573         register_ctxt.dsc.chr_def = chr;
574         register_ctxt.dsc.dsc_def = dsc;
575         register_cb(&register_ctxt, cb_arg);
576     }
577 
578     STATS_INC(ble_gatts_stats, dscs);
579 
580     return 0;
581 
582 }
583 
584 static int
ble_gatts_clt_cfg_find_idx(struct ble_gatts_clt_cfg * cfgs,uint16_t chr_val_handle)585 ble_gatts_clt_cfg_find_idx(struct ble_gatts_clt_cfg *cfgs,
586                            uint16_t chr_val_handle)
587 {
588     struct ble_gatts_clt_cfg *cfg;
589     int i;
590 
591     for (i = 0; i < ble_gatts_num_cfgable_chrs; i++) {
592         cfg = cfgs + i;
593         if (cfg->chr_val_handle == chr_val_handle) {
594             return i;
595         }
596     }
597 
598     return -1;
599 }
600 
601 static struct ble_gatts_clt_cfg *
ble_gatts_clt_cfg_find(struct ble_gatts_clt_cfg * cfgs,uint16_t chr_val_handle)602 ble_gatts_clt_cfg_find(struct ble_gatts_clt_cfg *cfgs,
603                        uint16_t chr_val_handle)
604 {
605     int idx;
606 
607     idx = ble_gatts_clt_cfg_find_idx(cfgs, chr_val_handle);
608     if (idx == -1) {
609         return NULL;
610     } else {
611         return cfgs + idx;
612     }
613 }
614 
615 static void
ble_gatts_subscribe_event(uint16_t conn_handle,uint16_t attr_handle,uint8_t reason,uint8_t prev_flags,uint8_t cur_flags)616 ble_gatts_subscribe_event(uint16_t conn_handle, uint16_t attr_handle,
617                           uint8_t reason,
618                           uint8_t prev_flags, uint8_t cur_flags)
619 {
620     if ((prev_flags ^ cur_flags) & ~BLE_GATTS_CLT_CFG_F_RESERVED) {
621         ble_gap_subscribe_event(conn_handle,
622                                 attr_handle,
623                                 reason,
624                                 prev_flags  & BLE_GATTS_CLT_CFG_F_NOTIFY,
625                                 cur_flags   & BLE_GATTS_CLT_CFG_F_NOTIFY,
626                                 prev_flags  & BLE_GATTS_CLT_CFG_F_INDICATE,
627                                 cur_flags   & BLE_GATTS_CLT_CFG_F_INDICATE);
628     }
629 }
630 
631 /**
632  * Performs a read or write access on a client characteritic configuration
633  * descriptor (CCCD).
634  *
635  * @param conn                  The connection of the peer doing the accessing.
636  * @apram attr_handle           The handle of the CCCD.
637  * @param att_op                The ATT operation being performed (read or
638  *                                  write).
639  * @param ctxt                  Communication channel between this function and
640  *                                  the caller within the nimble stack.
641  *                                  Semantics depends on the operation being
642  *                                  performed.
643  * @param out_cccd              If the CCCD should be persisted as a result of
644  *                                  the access, the data-to-be-persisted gets
645  *                                  written here.  If no persistence is
646  *                                  necessary, out_cccd->chr_val_handle is set
647  *                                  to 0.
648  *
649  * @return                      0 on success; nonzero on failure.
650  */
651 static int
ble_gatts_clt_cfg_access_locked(struct ble_hs_conn * conn,uint16_t attr_handle,uint8_t att_op,uint16_t offset,struct os_mbuf * om,struct ble_store_value_cccd * out_cccd,uint8_t * out_prev_clt_cfg_flags,uint8_t * out_cur_clt_cfg_flags)652 ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
653                                 uint8_t att_op, uint16_t offset,
654                                 struct os_mbuf *om,
655                                 struct ble_store_value_cccd *out_cccd,
656                                 uint8_t *out_prev_clt_cfg_flags,
657                                 uint8_t *out_cur_clt_cfg_flags)
658 {
659     struct ble_gatts_clt_cfg *clt_cfg;
660     uint16_t chr_val_handle;
661     uint16_t flags;
662     uint8_t gatt_op;
663     uint8_t *buf;
664 
665     /* Assume nothing needs to be persisted. */
666     out_cccd->chr_val_handle = 0;
667 
668     /* We always register the client characteristics descriptor with handle
669      * (chr_val + 1).
670      */
671     chr_val_handle = attr_handle - 1;
672     if (chr_val_handle > attr_handle) {
673         /* Attribute handle wrapped somehow. */
674         return BLE_ATT_ERR_UNLIKELY;
675     }
676 
677     clt_cfg = ble_gatts_clt_cfg_find(conn->bhc_gatt_svr.clt_cfgs,
678                                      chr_val_handle);
679     if (clt_cfg == NULL) {
680         return BLE_ATT_ERR_UNLIKELY;
681     }
682 
683     /* Assume no change in flags. */
684     *out_prev_clt_cfg_flags = clt_cfg->flags;
685     *out_cur_clt_cfg_flags = clt_cfg->flags;
686 
687     gatt_op = ble_gatts_dsc_op(att_op);
688     ble_gatts_dsc_inc_stat(gatt_op);
689 
690     switch (gatt_op) {
691     case BLE_GATT_ACCESS_OP_READ_DSC:
692         STATS_INC(ble_gatts_stats, dsc_reads);
693         buf = os_mbuf_extend(om, 2);
694         if (buf == NULL) {
695             return BLE_ATT_ERR_INSUFFICIENT_RES;
696         }
697         put_le16(buf, clt_cfg->flags & ~BLE_GATTS_CLT_CFG_F_RESERVED);
698         break;
699 
700     case BLE_GATT_ACCESS_OP_WRITE_DSC:
701         STATS_INC(ble_gatts_stats, dsc_writes);
702         if (OS_MBUF_PKTLEN(om) != 2) {
703             return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
704         }
705 
706         om = os_mbuf_pullup(om, 2);
707         BLE_HS_DBG_ASSERT(om != NULL);
708 
709         flags = get_le16(om->om_data);
710         if ((flags & ~clt_cfg->allowed) != 0) {
711             return BLE_ATT_ERR_REQ_NOT_SUPPORTED;
712         }
713 
714         if (clt_cfg->flags != flags) {
715             clt_cfg->flags = flags;
716             *out_cur_clt_cfg_flags = flags;
717 
718             /* Successful writes get persisted for bonded connections. */
719             if (conn->bhc_sec_state.bonded) {
720                 out_cccd->peer_addr = conn->bhc_peer_addr;
721                 out_cccd->chr_val_handle = chr_val_handle;
722                 out_cccd->flags = clt_cfg->flags;
723                 out_cccd->value_changed = 0;
724             }
725         }
726         break;
727 
728     default:
729         BLE_HS_DBG_ASSERT(0);
730         return BLE_ATT_ERR_UNLIKELY;
731     }
732 
733     return 0;
734 }
735 
736 static int
ble_gatts_clt_cfg_access(uint16_t conn_handle,uint16_t attr_handle,uint8_t op,uint16_t offset,struct os_mbuf ** om,void * arg)737 ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
738                          uint8_t op, uint16_t offset, struct os_mbuf **om,
739                          void *arg)
740 {
741     struct ble_store_value_cccd cccd_value;
742     struct ble_store_key_cccd cccd_key;
743     struct ble_hs_conn *conn;
744     uint16_t chr_val_handle;
745     uint8_t prev_flags;
746     uint8_t cur_flags;
747     int rc;
748 
749     ble_hs_lock();
750 
751     conn = ble_hs_conn_find(conn_handle);
752     if (conn == NULL) {
753         rc = BLE_ATT_ERR_UNLIKELY;
754     } else {
755         rc = ble_gatts_clt_cfg_access_locked(conn, attr_handle, op, offset,
756                                              *om, &cccd_value, &prev_flags,
757                                              &cur_flags);
758     }
759 
760     ble_hs_unlock();
761 
762     if (rc != 0) {
763         return rc;
764     }
765 
766     /* The value attribute is always immediately after the declaration. */
767     chr_val_handle = attr_handle - 1;
768 
769     /* Tell the application if the peer changed its subscription state. */
770     ble_gatts_subscribe_event(conn_handle, chr_val_handle,
771                               BLE_GAP_SUBSCRIBE_REASON_WRITE,
772                               prev_flags, cur_flags);
773 
774     /* Persist the CCCD if required. */
775     if (cccd_value.chr_val_handle != 0) {
776         if (cccd_value.flags == 0) {
777             ble_store_key_from_value_cccd(&cccd_key, &cccd_value);
778             rc = ble_store_delete_cccd(&cccd_key);
779         } else {
780             rc = ble_store_write_cccd(&cccd_value);
781         }
782     }
783 
784     return rc;
785 }
786 
787 static int
ble_gatts_register_clt_cfg_dsc(uint16_t * att_handle)788 ble_gatts_register_clt_cfg_dsc(uint16_t *att_handle)
789 {
790     int rc;
791 
792     rc = ble_att_svr_register(uuid_ccc, BLE_ATT_F_READ | BLE_ATT_F_WRITE, 0,
793                               att_handle, ble_gatts_clt_cfg_access, NULL);
794     if (rc != 0) {
795         return rc;
796     }
797 
798     STATS_INC(ble_gatts_stats, dscs);
799 
800     return 0;
801 }
802 
803 static int
ble_gatts_register_chr(const struct ble_gatt_svc_def * svc,const struct ble_gatt_chr_def * chr,ble_gatt_register_fn * register_cb,void * cb_arg)804 ble_gatts_register_chr(const struct ble_gatt_svc_def *svc,
805                        const struct ble_gatt_chr_def *chr,
806                        ble_gatt_register_fn *register_cb, void *cb_arg)
807 {
808     struct ble_gatt_register_ctxt register_ctxt;
809     struct ble_gatt_dsc_def *dsc;
810     uint16_t def_handle;
811     uint16_t val_handle;
812     uint16_t dsc_handle;
813     uint8_t att_flags;
814     int rc;
815 
816     if (!ble_gatts_chr_is_sane(chr)) {
817         return BLE_HS_EINVAL;
818     }
819 
820     if (ble_gatts_chr_clt_cfg_allowed(chr) != 0) {
821         if (ble_gatts_num_cfgable_chrs > ble_hs_max_client_configs) {
822             return BLE_HS_ENOMEM;
823         }
824         ble_gatts_num_cfgable_chrs++;
825     }
826 
827     /* Register characteristic definition attribute (cast away const on
828      * callback arg).
829      */
830     rc = ble_att_svr_register(uuid_chr, BLE_ATT_F_READ, 0, &def_handle,
831                               ble_gatts_chr_def_access, (void *)chr);
832     if (rc != 0) {
833         return rc;
834     }
835 
836     /* Register characteristic value attribute (cast away const on callback
837      * arg).
838      */
839     att_flags = ble_gatts_att_flags_from_chr_flags(chr->flags);
840     rc = ble_att_svr_register(chr->uuid, att_flags, chr->min_key_size,
841                               &val_handle, ble_gatts_chr_val_access,
842                               (void *)chr);
843     if (rc != 0) {
844         return rc;
845     }
846     BLE_HS_DBG_ASSERT(val_handle == def_handle + 1);
847 
848     if (chr->val_handle != NULL) {
849         *chr->val_handle = val_handle;
850     }
851 
852     if (register_cb != NULL) {
853         register_ctxt.op = BLE_GATT_REGISTER_OP_CHR;
854         register_ctxt.chr.def_handle = def_handle;
855         register_ctxt.chr.val_handle = val_handle;
856         register_ctxt.chr.svc_def = svc;
857         register_ctxt.chr.chr_def = chr;
858         register_cb(&register_ctxt, cb_arg);
859     }
860 
861     if (ble_gatts_chr_clt_cfg_allowed(chr) != 0) {
862         rc = ble_gatts_register_clt_cfg_dsc(&dsc_handle);
863         if (rc != 0) {
864             return rc;
865         }
866         BLE_HS_DBG_ASSERT(dsc_handle == def_handle + 2);
867     }
868 
869     /* Register each descriptor. */
870     if (chr->descriptors != NULL) {
871         for (dsc = chr->descriptors; dsc->uuid != NULL; dsc++) {
872             rc = ble_gatts_register_dsc(svc, chr, dsc, def_handle, register_cb,
873                                         cb_arg);
874             if (rc != 0) {
875                 return rc;
876             }
877         }
878     }
879 
880     STATS_INC(ble_gatts_stats, chrs);
881 
882     return 0;
883 }
884 
885 static int
ble_gatts_svc_type_to_uuid(uint8_t svc_type,const ble_uuid_t ** uuid)886 ble_gatts_svc_type_to_uuid(uint8_t svc_type, const ble_uuid_t **uuid)
887 {
888     switch (svc_type) {
889     case BLE_GATT_SVC_TYPE_PRIMARY:
890         *uuid = uuid_pri;
891         return 0;
892 
893     case BLE_GATT_SVC_TYPE_SECONDARY:
894         *uuid = uuid_sec;
895         return 0;
896 
897     default:
898         return BLE_HS_EINVAL;
899     }
900 }
901 
902 static int
ble_gatts_svc_is_sane(const struct ble_gatt_svc_def * svc)903 ble_gatts_svc_is_sane(const struct ble_gatt_svc_def *svc)
904 {
905     if (svc->type != BLE_GATT_SVC_TYPE_PRIMARY &&
906         svc->type != BLE_GATT_SVC_TYPE_SECONDARY) {
907 
908         return 0;
909     }
910 
911     if (svc->uuid == NULL) {
912         return 0;
913     }
914 
915     return 1;
916 }
917 
918 static int
ble_gatts_register_svc(const struct ble_gatt_svc_def * svc,uint16_t * out_handle,ble_gatt_register_fn * register_cb,void * cb_arg)919 ble_gatts_register_svc(const struct ble_gatt_svc_def *svc,
920                        uint16_t *out_handle,
921                        ble_gatt_register_fn *register_cb, void *cb_arg)
922 {
923     const struct ble_gatt_chr_def *chr;
924     struct ble_gatt_register_ctxt register_ctxt;
925     const ble_uuid_t *uuid;
926     int idx;
927     int rc;
928     int i;
929 
930     if (!ble_gatts_svc_incs_satisfied(svc)) {
931         return BLE_HS_EAGAIN;
932     }
933 
934     if (!ble_gatts_svc_is_sane(svc)) {
935         return BLE_HS_EINVAL;
936     }
937 
938     /* Prevent spurious maybe-uninitialized gcc warning. */
939     uuid = NULL;
940 
941     rc = ble_gatts_svc_type_to_uuid(svc->type, &uuid);
942     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
943 
944     /* Register service definition attribute (cast away const on callback
945      * arg).
946      */
947     rc = ble_att_svr_register(uuid, BLE_ATT_F_READ, 0, out_handle,
948                               ble_gatts_svc_access, (void *)svc);
949     if (rc != 0) {
950         return rc;
951     }
952 
953     if (register_cb != NULL) {
954         register_ctxt.op = BLE_GATT_REGISTER_OP_SVC;
955         register_ctxt.svc.handle = *out_handle;
956         register_ctxt.svc.svc_def = svc;
957         register_cb(&register_ctxt, cb_arg);
958     }
959 
960     /* Register each include. */
961     if (svc->includes != NULL) {
962         for (i = 0; svc->includes[i] != NULL; i++) {
963             idx = ble_gatts_find_svc_entry_idx(svc->includes[i]);
964             BLE_HS_DBG_ASSERT_EVAL(idx != -1);
965 
966             rc = ble_gatts_register_inc(ble_gatts_svc_entries + idx);
967             if (rc != 0) {
968                 return rc;
969             }
970         }
971     }
972 
973     /* Register each characteristic. */
974     if (svc->characteristics != NULL) {
975         for (chr = svc->characteristics; chr->uuid != NULL; chr++) {
976             rc = ble_gatts_register_chr(svc, chr, register_cb, cb_arg);
977             if (rc != 0) {
978                 return rc;
979             }
980         }
981     }
982 
983     STATS_INC(ble_gatts_stats, svcs);
984 
985     return 0;
986 }
987 
988 static int
ble_gatts_register_round(int * out_num_registered,ble_gatt_register_fn * cb,void * cb_arg)989 ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb,
990                          void *cb_arg)
991 {
992     struct ble_gatts_svc_entry *entry;
993     uint16_t handle;
994     int rc;
995     int i;
996 
997     *out_num_registered = 0;
998     for (i = 0; i < ble_gatts_num_svc_entries; i++) {
999         entry = ble_gatts_svc_entries + i;
1000 
1001         if (entry->handle == 0) {
1002             rc = ble_gatts_register_svc(entry->svc, &handle, cb, cb_arg);
1003             switch (rc) {
1004             case 0:
1005                 /* Service successfully registered. */
1006                 entry->handle = handle;
1007                 entry->end_group_handle = ble_att_svr_prev_handle();
1008                 (*out_num_registered)++;
1009                 break;
1010 
1011             case BLE_HS_EAGAIN:
1012                 /* Service could not be registered due to unsatisfied includes.
1013                  * Try again on the next iteration.
1014                  */
1015                 break;
1016 
1017             default:
1018                 return rc;
1019             }
1020         }
1021     }
1022 
1023     if (*out_num_registered == 0) {
1024         /* There is a circular dependency. */
1025         return BLE_HS_EINVAL;
1026     }
1027 
1028     return 0;
1029 }
1030 
1031 /**
1032  * Registers a set of services, characteristics, and descriptors to be accessed
1033  * by GATT clients.
1034  *
1035  * @param svcs                  A table of the service definitions to be
1036  *                                  registered.
1037  * @param cb                    The function to call for each service,
1038  *                                  characteristic, and descriptor that gets
1039  *                                  registered.
1040  * @param cb_arg                The optional argument to pass to the callback
1041  *                                  function.
1042  *
1043  * @return                      0 on success;
1044  *                              BLE_HS_ENOMEM if registration failed due to
1045  *                                  resource exhaustion;
1046  *                              BLE_HS_EINVAL if the service definition table
1047  *                                  contains an invalid element.
1048  */
1049 int
ble_gatts_register_svcs(const struct ble_gatt_svc_def * svcs,ble_gatt_register_fn * cb,void * cb_arg)1050 ble_gatts_register_svcs(const struct ble_gatt_svc_def *svcs,
1051                         ble_gatt_register_fn *cb, void *cb_arg)
1052 {
1053     int total_registered;
1054     int cur_registered;
1055     int num_svcs;
1056     int idx;
1057     int rc;
1058     int i;
1059 
1060     for (i = 0; svcs[i].type != BLE_GATT_SVC_TYPE_END; i++) {
1061         idx = ble_gatts_num_svc_entries + i;
1062         if (idx >= ble_hs_max_services) {
1063             return BLE_HS_ENOMEM;
1064         }
1065 
1066         ble_gatts_svc_entries[idx].svc = svcs + i;
1067         ble_gatts_svc_entries[idx].handle = 0;
1068         ble_gatts_svc_entries[idx].end_group_handle = 0xffff;
1069     }
1070     num_svcs = i;
1071     ble_gatts_num_svc_entries += num_svcs;
1072 
1073     total_registered = 0;
1074     while (total_registered < num_svcs) {
1075         rc = ble_gatts_register_round(&cur_registered, cb, cb_arg);
1076         if (rc != 0) {
1077             return rc;
1078         }
1079         total_registered += cur_registered;
1080     }
1081 
1082     return 0;
1083 }
1084 
1085 static int
ble_gatts_clt_cfg_size(void)1086 ble_gatts_clt_cfg_size(void)
1087 {
1088     return ble_gatts_num_cfgable_chrs * sizeof (struct ble_gatts_clt_cfg);
1089 }
1090 
1091 /**
1092  * Handles GATT server clean up for a terminated connection:
1093  *     o Informs the application that the peer is no longer subscribed to any
1094  *       characteristic updates.
1095  *     o Frees GATT server resources consumed by the connection (CCCDs).
1096  */
1097 void
ble_gatts_connection_broken(uint16_t conn_handle)1098 ble_gatts_connection_broken(uint16_t conn_handle)
1099 {
1100     struct ble_gatts_clt_cfg *clt_cfgs;
1101     struct ble_hs_conn *conn;
1102     int num_clt_cfgs;
1103     int rc;
1104     int i;
1105 
1106     /* Find the specified connection and extract its CCCD entries.  Extracting
1107      * the clt_cfg pointer and setting the original to null is done for two
1108      * reasons:
1109      *     1. So that the CCCD entries can be safely processed after unlocking
1110      *        the mutex.
1111      *     2. To ensure a subsequent indicate procedure for this peer is not
1112      *        attempted, as the connection is about to be terminated.  This
1113      *        avoids a spurious notify-tx GAP event callback to the
1114      *        application.  By setting the clt_cfg pointer to null, it is
1115      *        assured that the connection has no pending indications to send.
1116      */
1117     ble_hs_lock();
1118     conn = ble_hs_conn_find(conn_handle);
1119     if (conn != NULL) {
1120         clt_cfgs = conn->bhc_gatt_svr.clt_cfgs;
1121         num_clt_cfgs = conn->bhc_gatt_svr.num_clt_cfgs;
1122 
1123         conn->bhc_gatt_svr.clt_cfgs = NULL;
1124         conn->bhc_gatt_svr.num_clt_cfgs = 0;
1125     }
1126     ble_hs_unlock();
1127 
1128     if (conn == NULL) {
1129         return;
1130     }
1131 
1132     /* If there is an indicate procedure in progress for this connection,
1133      * inform the application that it has failed.
1134      */
1135     ble_gatts_indicate_fail_notconn(conn_handle);
1136 
1137     /* Now that the mutex is unlocked, inform the application that the peer is
1138      * no longer subscribed to any characteristic updates.
1139      */
1140     if (clt_cfgs != NULL) {
1141         for (i = 0; i < num_clt_cfgs; i++) {
1142             ble_gatts_subscribe_event(conn_handle, clt_cfgs[i].chr_val_handle,
1143                                       BLE_GAP_SUBSCRIBE_REASON_TERM,
1144                                       clt_cfgs[i].flags, 0);
1145         }
1146 
1147         rc = os_memblock_put(&ble_gatts_clt_cfg_pool, clt_cfgs);
1148         BLE_HS_DBG_ASSERT_EVAL(rc == 0);
1149     }
1150 }
1151 
1152 static void
ble_gatts_free_svc_defs(void)1153 ble_gatts_free_svc_defs(void)
1154 {
1155     free(ble_gatts_svc_defs);
1156     ble_gatts_svc_defs = NULL;
1157     ble_gatts_num_svc_defs = 0;
1158 }
1159 
1160 static void
ble_gatts_free_mem(void)1161 ble_gatts_free_mem(void)
1162 {
1163     free(ble_gatts_clt_cfg_mem);
1164     ble_gatts_clt_cfg_mem = NULL;
1165 
1166     free(ble_gatts_svc_entries);
1167     ble_gatts_svc_entries = NULL;
1168 }
1169 
1170 int
ble_gatts_start(void)1171 ble_gatts_start(void)
1172 {
1173     struct ble_att_svr_entry *ha;
1174     struct ble_gatt_chr_def *chr;
1175     uint16_t allowed_flags;
1176     ble_uuid16_t uuid = BLE_UUID16_INIT(BLE_ATT_UUID_CHARACTERISTIC);
1177     int num_elems;
1178     int idx;
1179     int rc;
1180     int i;
1181 
1182     ble_hs_lock();
1183     if (!ble_gatts_mutable()) {
1184         rc = BLE_HS_EBUSY;
1185         goto done;
1186     }
1187 
1188     ble_gatts_free_mem();
1189 
1190     rc = ble_att_svr_start();
1191     if (rc != 0) {
1192         goto done;
1193     }
1194 
1195     if (ble_hs_max_client_configs > 0) {
1196         ble_gatts_clt_cfg_mem = malloc(
1197             OS_MEMPOOL_BYTES(ble_hs_max_client_configs,
1198                              sizeof (struct ble_gatts_clt_cfg)));
1199         if (ble_gatts_clt_cfg_mem == NULL) {
1200             rc = BLE_HS_ENOMEM;
1201             goto done;
1202         }
1203     }
1204 
1205     if (ble_hs_max_services > 0) {
1206         ble_gatts_svc_entries =
1207             malloc(ble_hs_max_services * sizeof *ble_gatts_svc_entries);
1208         if (ble_gatts_svc_entries == NULL) {
1209             rc = BLE_HS_ENOMEM;
1210             goto done;
1211         }
1212     }
1213 
1214 
1215     ble_gatts_num_svc_entries = 0;
1216     for (i = 0; i < ble_gatts_num_svc_defs; i++) {
1217         rc = ble_gatts_register_svcs(ble_gatts_svc_defs[i],
1218                                      ble_hs_cfg.gatts_register_cb,
1219                                      ble_hs_cfg.gatts_register_arg);
1220         if (rc != 0) {
1221             goto done;
1222         }
1223     }
1224     ble_gatts_free_svc_defs();
1225 
1226     if (ble_gatts_num_cfgable_chrs == 0) {
1227         rc = 0;
1228         goto done;
1229     }
1230 
1231     /* Initialize client-configuration memory pool. */
1232     num_elems = ble_hs_max_client_configs / ble_gatts_num_cfgable_chrs;
1233     rc = os_mempool_init(&ble_gatts_clt_cfg_pool, num_elems,
1234                          ble_gatts_clt_cfg_size(), ble_gatts_clt_cfg_mem,
1235                          "ble_gatts_clt_cfg_pool");
1236     if (rc != 0) {
1237         rc = BLE_HS_EOS;
1238         goto done;
1239     }
1240 
1241     /* Allocate the cached array of handles for the configuration
1242      * characteristics.
1243      */
1244     ble_gatts_clt_cfgs = os_memblock_get(&ble_gatts_clt_cfg_pool);
1245     if (ble_gatts_clt_cfgs == NULL) {
1246         rc = BLE_HS_ENOMEM;
1247         goto done;
1248     }
1249 
1250     /* Fill the cache. */
1251     idx = 0;
1252     ha = NULL;
1253     while ((ha = ble_att_svr_find_by_uuid(ha, &uuid.u, 0xffff)) != NULL) {
1254         chr = ha->ha_cb_arg;
1255         allowed_flags = ble_gatts_chr_clt_cfg_allowed(chr);
1256         if (allowed_flags != 0) {
1257             BLE_HS_DBG_ASSERT_EVAL(idx < ble_gatts_num_cfgable_chrs);
1258 
1259             ble_gatts_clt_cfgs[idx].chr_val_handle = ha->ha_handle_id + 1;
1260             ble_gatts_clt_cfgs[idx].allowed = allowed_flags;
1261             ble_gatts_clt_cfgs[idx].flags = 0;
1262             idx++;
1263         }
1264     }
1265 
1266 done:
1267     if (rc != 0) {
1268         ble_gatts_free_mem();
1269         ble_gatts_free_svc_defs();
1270     }
1271 
1272     ble_hs_unlock();
1273     return rc;
1274 }
1275 
1276 int
ble_gatts_conn_can_alloc(void)1277 ble_gatts_conn_can_alloc(void)
1278 {
1279     return ble_gatts_num_cfgable_chrs == 0 ||
1280            ble_gatts_clt_cfg_pool.mp_num_free > 0;
1281 }
1282 
1283 int
ble_gatts_conn_init(struct ble_gatts_conn * gatts_conn)1284 ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn)
1285 {
1286     if (ble_gatts_num_cfgable_chrs > 0) {
1287         gatts_conn->clt_cfgs = os_memblock_get(&ble_gatts_clt_cfg_pool);
1288         if (gatts_conn->clt_cfgs == NULL) {
1289             return BLE_HS_ENOMEM;
1290         }
1291 
1292         /* Initialize the client configuration with a copy of the cache. */
1293         memcpy(gatts_conn->clt_cfgs, ble_gatts_clt_cfgs,
1294                ble_gatts_clt_cfg_size());
1295         gatts_conn->num_clt_cfgs = ble_gatts_num_cfgable_chrs;
1296     } else {
1297         gatts_conn->clt_cfgs = NULL;
1298         gatts_conn->num_clt_cfgs = 0;
1299     }
1300 
1301     return 0;
1302 }
1303 
1304 
1305 /**
1306  * Schedules a notification or indication for the specified peer-CCCD pair.  If
1307  * the update should be sent immediately, it is indicated in the return code.
1308  *
1309  * @param conn                  The connection to schedule the update for.
1310  * @param clt_cfg               The client config entry corresponding to the
1311  *                                  peer and affected characteristic.
1312  *
1313  * @return                      The att_op of the update to send immediately,
1314  *                                  if any.  0 if nothing should get sent.
1315  */
1316 static uint8_t
ble_gatts_schedule_update(struct ble_hs_conn * conn,struct ble_gatts_clt_cfg * clt_cfg)1317 ble_gatts_schedule_update(struct ble_hs_conn *conn,
1318                           struct ble_gatts_clt_cfg *clt_cfg)
1319 {
1320     uint8_t att_op;
1321 
1322     if (!(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_MODIFIED)) {
1323         /* Characteristic not modified.  Nothing to send. */
1324         att_op = 0;
1325     } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_NOTIFY) {
1326         /* Notifications always get sent immediately. */
1327         att_op = BLE_ATT_OP_NOTIFY_REQ;
1328     } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE) {
1329         /* Only one outstanding indication per peer is allowed.  If we
1330          * are still awaiting an ack, mark this CCCD as updated so that
1331          * we know to send the indication upon receiving the expected ack.
1332          * If there isn't an outstanding indication, send this one now.
1333          */
1334         if (conn->bhc_gatt_svr.indicate_val_handle != 0) {
1335             att_op = 0;
1336         } else {
1337             att_op = BLE_ATT_OP_INDICATE_REQ;
1338         }
1339     } else {
1340         /* Peer isn't subscribed to notifications or indications.  Nothing to
1341          * send.
1342          */
1343         att_op = 0;
1344     }
1345 
1346     /* If we will be sending an update, clear the modified flag so that we
1347      * don't double-send.
1348      */
1349     if (att_op != 0) {
1350         clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_MODIFIED;
1351     }
1352 
1353     return att_op;
1354 }
1355 
1356 int
ble_gatts_send_next_indicate(uint16_t conn_handle)1357 ble_gatts_send_next_indicate(uint16_t conn_handle)
1358 {
1359     struct ble_gatts_clt_cfg *clt_cfg;
1360     struct ble_hs_conn *conn;
1361     uint16_t chr_val_handle;
1362     int rc;
1363     int i;
1364 
1365     /* Assume no pending indications. */
1366     chr_val_handle = 0;
1367 
1368     ble_hs_lock();
1369 
1370     conn = ble_hs_conn_find(conn_handle);
1371     if (conn != NULL) {
1372         for (i = 0; i < conn->bhc_gatt_svr.num_clt_cfgs; i++) {
1373             clt_cfg = conn->bhc_gatt_svr.clt_cfgs + i;
1374             if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_MODIFIED) {
1375                 BLE_HS_DBG_ASSERT(clt_cfg->flags &
1376                                   BLE_GATTS_CLT_CFG_F_INDICATE);
1377 
1378                 chr_val_handle = clt_cfg->chr_val_handle;
1379 
1380                 /* Clear pending flag in anticipation of indication tx. */
1381                 clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_MODIFIED;
1382                 break;
1383             }
1384         }
1385     }
1386 
1387     ble_hs_unlock();
1388 
1389     if (conn == NULL) {
1390         return BLE_HS_ENOTCONN;
1391     }
1392 
1393     if (chr_val_handle == 0) {
1394         return BLE_HS_ENOENT;
1395     }
1396 
1397     rc = ble_gattc_indicate(conn_handle, chr_val_handle);
1398     if (rc != 0) {
1399         return rc;
1400     }
1401 
1402     return 0;
1403 }
1404 
1405 int
ble_gatts_rx_indicate_ack(uint16_t conn_handle,uint16_t chr_val_handle)1406 ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle)
1407 {
1408     struct ble_store_value_cccd cccd_value;
1409     struct ble_gatts_clt_cfg *clt_cfg;
1410     struct ble_hs_conn *conn;
1411     int clt_cfg_idx;
1412     int persist;
1413     int rc;
1414 
1415     clt_cfg_idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs,
1416                                              chr_val_handle);
1417     if (clt_cfg_idx == -1) {
1418         /* This characteristic does not have a CCCD. */
1419         return BLE_HS_ENOENT;
1420     }
1421 
1422     clt_cfg = ble_gatts_clt_cfgs + clt_cfg_idx;
1423     if (!(clt_cfg->allowed & BLE_GATTS_CLT_CFG_F_INDICATE)) {
1424         /* This characteristic does not allow indications. */
1425         return BLE_HS_ENOENT;
1426     }
1427 
1428     ble_hs_lock();
1429 
1430     conn = ble_hs_conn_find(conn_handle);
1431     BLE_HS_DBG_ASSERT(conn != NULL);
1432     if (conn->bhc_gatt_svr.indicate_val_handle == chr_val_handle) {
1433         /* This acknowledgement is expected. */
1434         rc = 0;
1435 
1436         /* Mark that there is no longer an outstanding txed indicate. */
1437         conn->bhc_gatt_svr.indicate_val_handle = 0;
1438 
1439         /* Determine if we need to persist that there is no pending indication
1440          * for this peer-characteristic pair.  If the characteristic has not
1441          * been modified since we sent the indication, there is no indication
1442          * pending.
1443          */
1444         BLE_HS_DBG_ASSERT(conn->bhc_gatt_svr.num_clt_cfgs > clt_cfg_idx);
1445         clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx;
1446         BLE_HS_DBG_ASSERT(clt_cfg->chr_val_handle == chr_val_handle);
1447 
1448         persist = conn->bhc_sec_state.bonded &&
1449                   !(clt_cfg->flags & BLE_GATTS_CLT_CFG_F_MODIFIED);
1450         if (persist) {
1451             cccd_value.peer_addr = conn->bhc_peer_addr;
1452             cccd_value.chr_val_handle = chr_val_handle;
1453             cccd_value.flags = clt_cfg->flags;
1454             cccd_value.value_changed = 0;
1455         }
1456     } else {
1457         /* This acknowledgement doesn't correspond to the outstanding
1458          * indication; ignore it.
1459          */
1460         rc = BLE_HS_ENOENT;
1461     }
1462 
1463     ble_hs_unlock();
1464 
1465     if (rc != 0) {
1466         return rc;
1467     }
1468 
1469     if (persist) {
1470         rc = ble_store_write_cccd(&cccd_value);
1471         if (rc != 0) {
1472             /* XXX: How should this error get reported? */
1473         }
1474     }
1475 
1476     return 0;
1477 }
1478 
1479 void
ble_gatts_chr_updated(uint16_t chr_val_handle)1480 ble_gatts_chr_updated(uint16_t chr_val_handle)
1481 {
1482     struct ble_store_value_cccd cccd_value;
1483     struct ble_store_key_cccd cccd_key;
1484     struct ble_gatts_clt_cfg *clt_cfg;
1485     struct ble_hs_conn *conn;
1486     int new_notifications = 0;
1487     int clt_cfg_idx;
1488     int persist;
1489     int rc;
1490     int i;
1491 
1492     /* Determine if notifications or indications are allowed for this
1493      * characteristic.  If not, return immediately.
1494      */
1495     clt_cfg_idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs,
1496                                              chr_val_handle);
1497     if (clt_cfg_idx == -1) {
1498         return;
1499     }
1500 
1501     /*** Send notifications and indications to connected devices. */
1502 
1503     ble_hs_lock();
1504     for (i = 0; ; i++) {
1505         /* XXX: This is inefficient when there are a lot of connections.
1506          * Consider using a "foreach" function to walk the connection list.
1507          */
1508         conn = ble_hs_conn_find_by_idx(i);
1509         if (conn == NULL) {
1510             break;
1511         }
1512 
1513         BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs >
1514                                clt_cfg_idx);
1515         clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx;
1516         BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_val_handle == chr_val_handle);
1517 
1518         /* Mark the CCCD entry as modified. */
1519         clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_MODIFIED;
1520         new_notifications = 1;
1521     }
1522     ble_hs_unlock();
1523 
1524     if (new_notifications) {
1525         ble_hs_notifications_sched();
1526     }
1527 
1528     /*** Persist updated flag for unconnected and not-yet-bonded devices. */
1529 
1530     /* Retrieve each record corresponding to the modified characteristic. */
1531     cccd_key.peer_addr = *BLE_ADDR_ANY;
1532     cccd_key.chr_val_handle = chr_val_handle;
1533     cccd_key.idx = 0;
1534 
1535     while (1) {
1536         rc = ble_store_read_cccd(&cccd_key, &cccd_value);
1537         if (rc != 0) {
1538             /* Read error or no more CCCD records. */
1539             break;
1540         }
1541 
1542         /* Determine if this record needs to be rewritten. */
1543         ble_hs_lock();
1544         conn = ble_hs_conn_find_by_addr(&cccd_key.peer_addr);
1545 
1546         if (conn == NULL) {
1547             /* Device isn't connected; persist the changed flag so that an
1548              * update can be sent when the device reconnects and rebonds.
1549              */
1550             persist = 1;
1551         } else if (cccd_value.flags & BLE_GATTS_CLT_CFG_F_INDICATE) {
1552             /* Indication for a connected device; record that the
1553              * characteristic has changed until we receive the ack.
1554              */
1555             persist = 1;
1556         } else {
1557             /* Notification for a connected device; we already sent it so there
1558              * is no need to persist.
1559              */
1560             persist = 0;
1561         }
1562 
1563         ble_hs_unlock();
1564 
1565         /* Only persist if the value changed flag wasn't already sent (i.e.,
1566          * don't overwrite with identical data).
1567          */
1568         if (persist && !cccd_value.value_changed) {
1569             cccd_value.value_changed = 1;
1570             ble_store_write_cccd(&cccd_value);
1571         }
1572 
1573         /* Read the next matching record. */
1574         cccd_key.idx++;
1575     }
1576 }
1577 
1578 /**
1579  * Sends notifications or indications for the specified characteristic to all
1580  * connected devices.  The bluetooth spec does not allow more than one
1581  * concurrent indication for a single peer, so this function will hold off on
1582  * sending such indications.
1583  */
1584 static void
ble_gatts_tx_notifications_one_chr(uint16_t chr_val_handle)1585 ble_gatts_tx_notifications_one_chr(uint16_t chr_val_handle)
1586 {
1587     struct ble_gatts_clt_cfg *clt_cfg;
1588     struct ble_hs_conn *conn;
1589     uint16_t conn_handle;
1590     uint8_t att_op;
1591     int clt_cfg_idx;
1592     int i;
1593 
1594     /* Determine if notifications / indications are enabled for this
1595      * characteristic.
1596      */
1597     clt_cfg_idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs,
1598                                              chr_val_handle);
1599     if (clt_cfg_idx == -1) {
1600         return;
1601     }
1602 
1603     for (i = 0; ; i++) {
1604         ble_hs_lock();
1605 
1606         conn = ble_hs_conn_find_by_idx(i);
1607         if (conn != NULL) {
1608             BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs >
1609                                    clt_cfg_idx);
1610             clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx;
1611             BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_val_handle == chr_val_handle);
1612 
1613             /* Determine what type of command should get sent, if any. */
1614             att_op = ble_gatts_schedule_update(conn, clt_cfg);
1615             conn_handle = conn->bhc_handle;
1616         } else {
1617             /* Silence some spurious gcc warnings. */
1618             att_op = 0;
1619             conn_handle = BLE_HS_CONN_HANDLE_NONE;
1620         }
1621         ble_hs_unlock();
1622 
1623         if (conn == NULL) {
1624             /* No more connected devices. */
1625             break;
1626         }
1627 
1628         switch (att_op) {
1629         case 0:
1630             break;
1631 
1632         case BLE_ATT_OP_NOTIFY_REQ:
1633             ble_gattc_notify(conn_handle, chr_val_handle);
1634             break;
1635 
1636         case BLE_ATT_OP_INDICATE_REQ:
1637             ble_gattc_indicate(conn_handle, chr_val_handle);
1638             break;
1639 
1640         default:
1641             BLE_HS_DBG_ASSERT(0);
1642             break;
1643         }
1644     }
1645 }
1646 
1647 /**
1648  * Sends all pending notifications and indications.  The bluetooth spec does
1649  * not allow more than one concurrent indication for a single peer, so this
1650  * function will hold off on sending such indications.
1651  */
1652 void
ble_gatts_tx_notifications(void)1653 ble_gatts_tx_notifications(void)
1654 {
1655     uint16_t chr_val_handle;
1656     int i;
1657 
1658     for (i = 0; i < ble_gatts_num_cfgable_chrs; i++) {
1659         chr_val_handle = ble_gatts_clt_cfgs[i].chr_val_handle;
1660         ble_gatts_tx_notifications_one_chr(chr_val_handle);
1661     }
1662 }
1663 
1664 /**
1665  * Called when bonding has been restored via the encryption procedure.  This
1666  * function:
1667  *     o Restores persisted CCCD entries for the connected peer.
1668  *     o Sends all pending notifications to the connected peer.
1669  *     o Sends up to one pending indication to the connected peer; schedules
1670  *       any remaining pending indications.
1671  */
1672 void
ble_gatts_bonding_restored(uint16_t conn_handle)1673 ble_gatts_bonding_restored(uint16_t conn_handle)
1674 {
1675     struct ble_store_value_cccd cccd_value;
1676     struct ble_store_key_cccd cccd_key;
1677     struct ble_gatts_clt_cfg *clt_cfg;
1678     struct ble_hs_conn *conn;
1679     uint8_t att_op;
1680     int rc;
1681 
1682     ble_hs_lock();
1683 
1684     conn = ble_hs_conn_find(conn_handle);
1685     BLE_HS_DBG_ASSERT(conn != NULL);
1686     BLE_HS_DBG_ASSERT(conn->bhc_sec_state.bonded);
1687 
1688     cccd_key.peer_addr = conn->bhc_peer_addr;
1689     cccd_key.chr_val_handle = 0;
1690     cccd_key.idx = 0;
1691 
1692     ble_hs_unlock();
1693 
1694     while (1) {
1695         rc = ble_store_read_cccd(&cccd_key, &cccd_value);
1696         if (rc != 0) {
1697             break;
1698         }
1699 
1700         /* Assume no notification or indication will get sent. */
1701         att_op = 0;
1702 
1703         ble_hs_lock();
1704 
1705         conn = ble_hs_conn_find(conn_handle);
1706         BLE_HS_DBG_ASSERT(conn != NULL);
1707 
1708         clt_cfg = ble_gatts_clt_cfg_find(conn->bhc_gatt_svr.clt_cfgs,
1709                                          cccd_value.chr_val_handle);
1710         if (clt_cfg != NULL) {
1711             clt_cfg->flags = cccd_value.flags;
1712 
1713             if (cccd_value.value_changed) {
1714                 /* The characteristic's value changed while the device was
1715                  * disconnected or unbonded.  Schedule the notification or
1716                  * indication now.
1717                  */
1718                 clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_MODIFIED;
1719                 att_op = ble_gatts_schedule_update(conn, clt_cfg);
1720             }
1721         }
1722 
1723         ble_hs_unlock();
1724 
1725         /* Tell the application if the peer changed its subscription state
1726          * when it was restored from persistence.
1727          */
1728         ble_gatts_subscribe_event(conn_handle, cccd_value.chr_val_handle,
1729                                   BLE_GAP_SUBSCRIBE_REASON_RESTORE,
1730                                   0, cccd_value.flags);
1731 
1732         switch (att_op) {
1733         case 0:
1734             break;
1735 
1736         case BLE_ATT_OP_NOTIFY_REQ:
1737             rc = ble_gattc_notify(conn_handle, cccd_value.chr_val_handle);
1738             if (rc == 0) {
1739                 cccd_value.value_changed = 0;
1740                 ble_store_write_cccd(&cccd_value);
1741             }
1742             break;
1743 
1744         case BLE_ATT_OP_INDICATE_REQ:
1745             ble_gattc_indicate(conn_handle, cccd_value.chr_val_handle);
1746             break;
1747 
1748         default:
1749             BLE_HS_DBG_ASSERT(0);
1750             break;
1751         }
1752 
1753         cccd_key.idx++;
1754     }
1755 }
1756 
1757 static struct ble_gatts_svc_entry *
ble_gatts_find_svc_entry(const ble_uuid_t * uuid)1758 ble_gatts_find_svc_entry(const ble_uuid_t *uuid)
1759 {
1760     struct ble_gatts_svc_entry *entry;
1761     int i;
1762 
1763     for (i = 0; i < ble_gatts_num_svc_entries; i++) {
1764         entry = ble_gatts_svc_entries + i;
1765         if (ble_uuid_cmp(uuid, entry->svc->uuid) == 0) {
1766             return entry;
1767         }
1768     }
1769 
1770     return NULL;
1771 }
1772 
1773 static int
ble_gatts_find_svc_chr_attr(const ble_uuid_t * svc_uuid,const ble_uuid_t * chr_uuid,struct ble_gatts_svc_entry ** out_svc_entry,struct ble_att_svr_entry ** out_att_chr)1774 ble_gatts_find_svc_chr_attr(const ble_uuid_t *svc_uuid,
1775                             const ble_uuid_t *chr_uuid,
1776                             struct ble_gatts_svc_entry **out_svc_entry,
1777                             struct ble_att_svr_entry **out_att_chr)
1778 {
1779     struct ble_gatts_svc_entry *svc_entry;
1780     struct ble_att_svr_entry *att_svc;
1781     struct ble_att_svr_entry *next;
1782     struct ble_att_svr_entry *cur;
1783 
1784     svc_entry = ble_gatts_find_svc_entry(svc_uuid);
1785     if (svc_entry == NULL) {
1786         return BLE_HS_ENOENT;
1787     }
1788 
1789     att_svc = ble_att_svr_find_by_handle(svc_entry->handle);
1790     if (att_svc == NULL) {
1791         return BLE_HS_EUNKNOWN;
1792     }
1793 
1794     cur = STAILQ_NEXT(att_svc, ha_next);
1795     while (1) {
1796         if (cur == NULL) {
1797             /* Reached end of attribute list without a match. */
1798             return BLE_HS_ENOENT;
1799         }
1800         next = STAILQ_NEXT(cur, ha_next);
1801 
1802         if (cur->ha_handle_id == svc_entry->end_group_handle) {
1803             /* Reached end of service without a match. */
1804             return BLE_HS_ENOENT;
1805         }
1806 
1807         if (ble_uuid_u16(cur->ha_uuid) == BLE_ATT_UUID_CHARACTERISTIC &&
1808             next != NULL &&
1809             ble_uuid_cmp(next->ha_uuid, chr_uuid) == 0) {
1810 
1811             if (out_svc_entry != NULL) {
1812                 *out_svc_entry = svc_entry;
1813             }
1814             if (out_att_chr != NULL) {
1815                 *out_att_chr = next;
1816             }
1817             return 0;
1818         }
1819 
1820         cur = next;
1821     }
1822 }
1823 
1824 int
ble_gatts_find_svc(const ble_uuid_t * uuid,uint16_t * out_handle)1825 ble_gatts_find_svc(const ble_uuid_t *uuid, uint16_t *out_handle)
1826 {
1827     struct ble_gatts_svc_entry *entry;
1828 
1829     entry = ble_gatts_find_svc_entry(uuid);
1830     if (entry == NULL) {
1831         return BLE_HS_ENOENT;
1832     }
1833 
1834     if (out_handle != NULL) {
1835         *out_handle = entry->handle;
1836     }
1837     return 0;
1838 }
1839 
1840 int
ble_gatts_find_chr(const ble_uuid_t * svc_uuid,const ble_uuid_t * chr_uuid,uint16_t * out_def_handle,uint16_t * out_val_handle)1841 ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid,
1842                    uint16_t *out_def_handle, uint16_t *out_val_handle)
1843 {
1844     struct ble_att_svr_entry *att_chr;
1845     int rc;
1846 
1847     rc = ble_gatts_find_svc_chr_attr(svc_uuid, chr_uuid, NULL, &att_chr);
1848     if (rc != 0) {
1849         return rc;
1850     }
1851 
1852     if (out_def_handle) {
1853         *out_def_handle = att_chr->ha_handle_id - 1;
1854     }
1855     if (out_val_handle) {
1856         *out_val_handle = att_chr->ha_handle_id;
1857     }
1858     return 0;
1859 }
1860 
1861 int
ble_gatts_find_dsc(const ble_uuid_t * svc_uuid,const ble_uuid_t * chr_uuid,const ble_uuid_t * dsc_uuid,uint16_t * out_handle)1862 ble_gatts_find_dsc(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid,
1863                    const ble_uuid_t *dsc_uuid, uint16_t *out_handle)
1864 {
1865     struct ble_gatts_svc_entry *svc_entry;
1866     struct ble_att_svr_entry *att_chr;
1867     struct ble_att_svr_entry *cur;
1868     uint16_t uuid16;
1869     int rc;
1870 
1871     rc = ble_gatts_find_svc_chr_attr(svc_uuid, chr_uuid, &svc_entry,
1872                                      &att_chr);
1873     if (rc != 0) {
1874         return rc;
1875     }
1876 
1877     cur = STAILQ_NEXT(att_chr, ha_next);
1878     while (1) {
1879         if (cur == NULL) {
1880             /* Reached end of attribute list without a match. */
1881             return BLE_HS_ENOENT;
1882         }
1883 
1884         if (cur->ha_handle_id > svc_entry->end_group_handle) {
1885             /* Reached end of service without a match. */
1886             return BLE_HS_ENOENT;
1887         }
1888 
1889         uuid16 = ble_uuid_u16(cur->ha_uuid);
1890         if (uuid16 == BLE_ATT_UUID_CHARACTERISTIC) {
1891             /* Reached end of characteristic without a match. */
1892             return BLE_HS_ENOENT;
1893         }
1894 
1895         if (ble_uuid_cmp(cur->ha_uuid, dsc_uuid) == 0) {
1896             if (out_handle != NULL) {
1897                 *out_handle = cur->ha_handle_id;
1898                 return 0;
1899             }
1900         }
1901         cur = STAILQ_NEXT(cur, ha_next);
1902     }
1903 }
1904 
1905 int
ble_gatts_add_svcs(const struct ble_gatt_svc_def * svcs)1906 ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs)
1907 {
1908     void *p;
1909     int rc;
1910 
1911     ble_hs_lock();
1912     if (!ble_gatts_mutable()) {
1913         rc = BLE_HS_EBUSY;
1914         goto done;
1915     }
1916 
1917     p = realloc(ble_gatts_svc_defs,
1918                 (ble_gatts_num_svc_defs + 1) * sizeof *ble_gatts_svc_defs);
1919     if (p == NULL) {
1920         rc = BLE_HS_ENOMEM;
1921         goto done;
1922     }
1923 
1924     ble_gatts_svc_defs = p;
1925     ble_gatts_svc_defs[ble_gatts_num_svc_defs] = svcs;
1926     ble_gatts_num_svc_defs++;
1927 
1928     rc = 0;
1929 
1930 done:
1931     ble_hs_unlock();
1932     return rc;
1933 }
1934 
1935 int
ble_gatts_svc_set_visibility(uint16_t handle,int visible)1936 ble_gatts_svc_set_visibility(uint16_t handle, int visible)
1937 {
1938     int i;
1939 
1940     for (i = 0; i < ble_gatts_num_svc_entries; i++) {
1941         struct ble_gatts_svc_entry *entry = &ble_gatts_svc_entries[i];
1942 
1943         if (entry->handle == handle) {
1944             if (visible) {
1945                 ble_att_svr_restore_range(entry->handle, entry->end_group_handle);
1946             } else {
1947                 ble_att_svr_hide_range(entry->handle, entry->end_group_handle);
1948             }
1949             return 0;
1950         }
1951     }
1952 
1953     return BLE_HS_ENOENT;
1954 }
1955 
1956 /**
1957  * Accumulates counts of each resource type required by the specified service
1958  * definition array.  This function is generally used to calculate some host
1959  * configuration values prior to initialization.  This function adds the counts
1960  * to the appropriate fields in the supplied ble_gatt_resources object without
1961  * clearing them first, so it can be called repeatedly with different inputs to
1962  * calculate totals.  Be sure to zero the resource struct prior to the first
1963  * call to this function.
1964  *
1965  * @param svcs                  The service array containing the resource
1966  *                                  definitions to be counted.
1967  * @param res                   The resource counts are accumulated in this
1968  *                                  struct.
1969  *
1970  * @return                      0 on success;
1971  *                              BLE_HS_EINVAL if the svcs array contains an
1972  *                                  invalid resource definition.
1973  */
1974 static int
ble_gatts_count_resources(const struct ble_gatt_svc_def * svcs,struct ble_gatt_resources * res)1975 ble_gatts_count_resources(const struct ble_gatt_svc_def *svcs,
1976                           struct ble_gatt_resources *res)
1977 {
1978     const struct ble_gatt_svc_def *svc;
1979     const struct ble_gatt_chr_def *chr;
1980     int s;
1981     int i;
1982     int c;
1983     int d;
1984 
1985     for (s = 0; svcs[s].type != BLE_GATT_SVC_TYPE_END; s++) {
1986         svc = svcs + s;
1987 
1988         if (!ble_gatts_svc_is_sane(svc)) {
1989             BLE_HS_DBG_ASSERT(0);
1990             return BLE_HS_EINVAL;
1991         }
1992 
1993         /* Each service requires:
1994          *     o 1 service
1995          *     o 1 attribute
1996          */
1997         res->svcs++;
1998         res->attrs++;
1999 
2000         if (svc->includes != NULL) {
2001             for (i = 0; svc->includes[i] != NULL; i++) {
2002                 /* Each include requires:
2003                  *     o 1 include
2004                  *     o 1 attribute
2005                  */
2006                 res->incs++;
2007                 res->attrs++;
2008             }
2009         }
2010 
2011         if (svc->characteristics != NULL) {
2012             for (c = 0; svc->characteristics[c].uuid != NULL; c++) {
2013                 chr = svc->characteristics + c;
2014 
2015                 if (!ble_gatts_chr_is_sane(chr)) {
2016                     BLE_HS_DBG_ASSERT(0);
2017                     return BLE_HS_EINVAL;
2018                 }
2019 
2020                 /* Each characteristic requires:
2021                  *     o 1 characteristic
2022                  *     o 2 attributes
2023                  */
2024                 res->chrs++;
2025                 res->attrs += 2;
2026 
2027                 /* If the characteristic permits notifications or indications,
2028                  * it has a CCCD.
2029                  */
2030                 if (chr->flags & BLE_GATT_CHR_F_NOTIFY ||
2031                     chr->flags & BLE_GATT_CHR_F_INDICATE) {
2032 
2033                     /* Each CCCD requires:
2034                      *     o 1 descriptor
2035                      *     o 1 CCCD
2036                      *     o 1 attribute
2037                      */
2038                     res->dscs++;
2039                     res->cccds++;
2040                     res->attrs++;
2041                 }
2042 
2043                 if (chr->descriptors != NULL) {
2044                     for (d = 0; chr->descriptors[d].uuid != NULL; d++) {
2045                         if (!ble_gatts_dsc_is_sane(chr->descriptors + d)) {
2046                             BLE_HS_DBG_ASSERT(0);
2047                             return BLE_HS_EINVAL;
2048                         }
2049 
2050                         /* Each descriptor requires:
2051                          *     o 1 descriptor
2052                          *     o 1 attribute
2053                          */
2054                         res->dscs++;
2055                         res->attrs++;
2056                     }
2057                 }
2058             }
2059         }
2060     }
2061 
2062     return 0;
2063 }
2064 int
ble_gatts_count_cfg(const struct ble_gatt_svc_def * defs)2065 ble_gatts_count_cfg(const struct ble_gatt_svc_def *defs)
2066 {
2067     struct ble_gatt_resources res = { 0 };
2068     int rc;
2069 
2070     rc = ble_gatts_count_resources(defs, &res);
2071     if (rc != 0) {
2072         return rc;
2073     }
2074 
2075     ble_hs_max_services += res.svcs;
2076     ble_hs_max_attrs += res.attrs;
2077 
2078     /* Reserve an extra CCCD for the cache. */
2079     ble_hs_max_client_configs +=
2080         res.cccds * (MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1);
2081 
2082     return 0;
2083 }
2084 
2085 void
ble_gatts_lcl_svc_foreach(ble_gatt_svc_foreach_fn cb)2086 ble_gatts_lcl_svc_foreach(ble_gatt_svc_foreach_fn cb)
2087 {
2088     int i;
2089 
2090     for (i = 0; i < ble_gatts_num_svc_entries; i++) {
2091         cb(ble_gatts_svc_entries[i].svc,
2092            ble_gatts_svc_entries[i].handle,
2093            ble_gatts_svc_entries[i].end_group_handle);
2094     }
2095 }
2096 
2097 int
ble_gatts_reset(void)2098 ble_gatts_reset(void)
2099 {
2100     int rc;
2101 
2102     ble_hs_lock();
2103 
2104     if (!ble_gatts_mutable()) {
2105         rc = BLE_HS_EBUSY;
2106     } else {
2107         /* Unregister all ATT attributes. */
2108         ble_att_svr_reset();
2109         ble_gatts_num_cfgable_chrs = 0;
2110         rc = 0;
2111 
2112         /* Note: gatts memory gets freed on next call to ble_gatts_start(). */
2113     }
2114 
2115     ble_hs_unlock();
2116 
2117     return rc;
2118 }
2119 
2120 int
ble_gatts_init(void)2121 ble_gatts_init(void)
2122 {
2123     int rc;
2124 
2125     ble_gatts_num_cfgable_chrs = 0;
2126     ble_gatts_clt_cfgs = NULL;
2127 
2128     rc = stats_init_and_reg(
2129         STATS_HDR(ble_gatts_stats), STATS_SIZE_INIT_PARMS(ble_gatts_stats,
2130         STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_gatts_stats), "ble_gatts");
2131     if (rc != 0) {
2132         return BLE_HS_EOS;
2133     }
2134 
2135     return 0;
2136 
2137 }
2138