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