xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/services/gap/src/ble_svc_gap.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 <assert.h>
21 #include <string.h>
22 
23 #include "sysinit/sysinit.h"
24 #include "host/ble_hs.h"
25 #include "services/gap/ble_svc_gap.h"
26 #include "os/endian.h"
27 
28 #define PPCP_ENABLED \
29     MYNEWT_VAL(BLE_ROLE_PERIPHERAL) && \
30     (MYNEWT_VAL(BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL) || \
31      MYNEWT_VAL(BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL) || \
32      MYNEWT_VAL(BLE_SVC_GAP_PPCP_SLAVE_LATENCY) || \
33      MYNEWT_VAL(BLE_SVC_GAP_PPCP_SUPERVISION_TMO))
34 
35 #define BLE_SVC_GAP_NAME_MAX_LEN \
36     MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH)
37 
38 static ble_svc_gap_chr_changed_fn *ble_svc_gap_chr_changed_cb_fn;
39 
40 static char ble_svc_gap_name[BLE_SVC_GAP_NAME_MAX_LEN + 1] =
41         MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME);
42 static uint16_t ble_svc_gap_appearance = MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE);
43 
44 static int
45 ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle,
46                    struct ble_gatt_access_ctxt *ctxt, void *arg);
47 
48 static const struct ble_gatt_svc_def ble_svc_gap_defs[] = {
49     {
50         /*** Service: GAP. */
51         .type = BLE_GATT_SVC_TYPE_PRIMARY,
52         .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_UUID16),
53         .characteristics = (struct ble_gatt_chr_def[]) { {
54             /*** Characteristic: Device Name. */
55             .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME),
56             .access_cb = ble_svc_gap_access,
57             .flags = BLE_GATT_CHR_F_READ |
58 #if MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM) >= 0
59                      BLE_GATT_CHR_F_WRITE |
60                      MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM) |
61 #endif
62                      0,
63         }, {
64             /*** Characteristic: Appearance. */
65             .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_APPEARANCE),
66             .access_cb = ble_svc_gap_access,
67             .flags = BLE_GATT_CHR_F_READ |
68 #if MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE_WRITE_PERM) >= 0
69                      BLE_GATT_CHR_F_WRITE |
70                      MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE_WRITE_PERM) |
71 #endif
72                      0,
73         }, {
74 #if PPCP_ENABLED
75             /*** Characteristic: Peripheral Preferred Connection Parameters. */
76             .uuid =
77                 BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS),
78             .access_cb = ble_svc_gap_access,
79             .flags = BLE_GATT_CHR_F_READ,
80         }, {
81 #endif
82 #if MYNEWT_VAL(BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION) >= 0
83             /*** Characteristic: Central Address Resolution. */
84             .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_CENTRAL_ADDRESS_RESOLUTION),
85             .access_cb = ble_svc_gap_access,
86             .flags = BLE_GATT_CHR_F_READ,
87         }, {
88 #endif
89             0, /* No more characteristics in this service. */
90         } },
91     },
92 
93     {
94         0, /* No more services. */
95     },
96 };
97 
98 static int
ble_svc_gap_device_name_read_access(struct ble_gatt_access_ctxt * ctxt)99 ble_svc_gap_device_name_read_access(struct ble_gatt_access_ctxt *ctxt)
100 {
101     int rc;
102 
103     rc = os_mbuf_append(ctxt->om, ble_svc_gap_name, strlen(ble_svc_gap_name));
104 
105     return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
106 }
107 
108 static int
ble_svc_gap_device_name_write_access(struct ble_gatt_access_ctxt * ctxt)109 ble_svc_gap_device_name_write_access(struct ble_gatt_access_ctxt *ctxt)
110 {
111 #if MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM) < 0
112     assert(0);
113     return 0;
114 #else
115     uint16_t om_len;
116     int rc;
117 
118     om_len = OS_MBUF_PKTLEN(ctxt->om);
119     if (om_len > BLE_SVC_GAP_NAME_MAX_LEN) {
120         return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
121     }
122 
123     rc = ble_hs_mbuf_to_flat(ctxt->om, ble_svc_gap_name, om_len, NULL);
124     if (rc != 0) {
125         return BLE_ATT_ERR_UNLIKELY;
126     }
127 
128     ble_svc_gap_name[om_len] = '\0';
129 
130     if (ble_svc_gap_chr_changed_cb_fn) {
131         ble_svc_gap_chr_changed_cb_fn(BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME);
132     }
133 
134     return rc;
135 #endif
136 }
137 
138 static int
ble_svc_gap_appearance_read_access(struct ble_gatt_access_ctxt * ctxt)139 ble_svc_gap_appearance_read_access(struct ble_gatt_access_ctxt *ctxt)
140 {
141     uint16_t appearance = htole16(ble_svc_gap_appearance);
142     int rc;
143 
144     rc = os_mbuf_append(ctxt->om, &appearance, sizeof(appearance));
145 
146     return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
147 }
148 
149 static int
ble_svc_gap_appearance_write_access(struct ble_gatt_access_ctxt * ctxt)150 ble_svc_gap_appearance_write_access(struct ble_gatt_access_ctxt *ctxt)
151 {
152 #if MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE_WRITE_PERM) < 0
153     assert(0);
154     return 0;
155 #else
156     uint16_t om_len;
157     int rc;
158 
159     om_len = OS_MBUF_PKTLEN(ctxt->om);
160     if (om_len != sizeof(ble_svc_gap_appearance)) {
161         return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
162     }
163 
164     rc = ble_hs_mbuf_to_flat(ctxt->om, ble_svc_gap_appearance, om_len, NULL);
165     if (rc != 0) {
166         return BLE_ATT_ERR_UNLIKELY;
167     }
168 
169     ble_svc_gap_appearance = le16toh(ble_svc_gap_appearance);
170 
171     if (ble_svc_gap_chr_changed_cb_fn) {
172         ble_svc_gap_chr_changed_cb_fn(BLE_SVC_GAP_CHR_UUID16_APPEARANCE);
173     }
174 
175     return rc;
176 #endif
177 }
178 
179 static int
ble_svc_gap_access(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)180 ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle,
181                    struct ble_gatt_access_ctxt *ctxt, void *arg)
182 {
183     uint16_t uuid16;
184 #if MYNEWT_VAL(BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION) >= 0
185     uint8_t central_ar = MYNEWT_VAL(BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION);
186 #endif
187 #if PPCP_ENABLED
188     uint16_t ppcp[4] = {
189         htole16(MYNEWT_VAL(BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL)),
190         htole16(MYNEWT_VAL(BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL)),
191         htole16(MYNEWT_VAL(BLE_SVC_GAP_PPCP_SLAVE_LATENCY)),
192         htole16(MYNEWT_VAL(BLE_SVC_GAP_PPCP_SUPERVISION_TMO))
193     };
194 #endif
195     int rc;
196 
197     uuid16 = ble_uuid_u16(ctxt->chr->uuid);
198     assert(uuid16 != 0);
199 
200     switch (uuid16) {
201     case BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME:
202         if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
203             rc = ble_svc_gap_device_name_read_access(ctxt);
204         } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
205             rc = ble_svc_gap_device_name_write_access(ctxt);
206         } else {
207             assert(0);
208         }
209         return rc;
210 
211     case BLE_SVC_GAP_CHR_UUID16_APPEARANCE:
212         if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
213             rc = ble_svc_gap_appearance_read_access(ctxt);
214         } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
215             rc = ble_svc_gap_appearance_write_access(ctxt);
216         } else {
217             assert(0);
218         }
219         return rc;
220 
221 #if PPCP_ENABLED
222     case BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS:
223         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
224         rc = os_mbuf_append(ctxt->om, &ppcp, sizeof(ppcp));
225         return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
226 #endif
227 
228 #if MYNEWT_VAL(BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION) >= 0
229     case BLE_SVC_GAP_CHR_UUID16_CENTRAL_ADDRESS_RESOLUTION:
230         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
231         rc = os_mbuf_append(ctxt->om, &central_ar, sizeof(central_ar));
232         return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
233 #endif
234 
235     default:
236         assert(0);
237         return BLE_ATT_ERR_UNLIKELY;
238     }
239 }
240 
241 const char *
ble_svc_gap_device_name(void)242 ble_svc_gap_device_name(void)
243 {
244     return ble_svc_gap_name;
245 }
246 
247 int
ble_svc_gap_device_name_set(const char * name)248 ble_svc_gap_device_name_set(const char *name)
249 {
250     int len;
251 
252     len = strlen(name);
253     if (len > BLE_SVC_GAP_NAME_MAX_LEN) {
254         return BLE_HS_EINVAL;
255     }
256 
257     memcpy(ble_svc_gap_name, name, len);
258     ble_svc_gap_name[len] = '\0';
259 
260     return 0;
261 }
262 
263 uint16_t
ble_svc_gap_device_appearance(void)264 ble_svc_gap_device_appearance(void)
265 {
266   return ble_svc_gap_appearance;
267 }
268 
269 int
ble_svc_gap_device_appearance_set(uint16_t appearance)270 ble_svc_gap_device_appearance_set(uint16_t appearance)
271 {
272     ble_svc_gap_appearance = appearance;
273 
274     return 0;
275 }
276 
277 void
ble_svc_gap_set_chr_changed_cb(ble_svc_gap_chr_changed_fn * cb)278 ble_svc_gap_set_chr_changed_cb(ble_svc_gap_chr_changed_fn *cb)
279 {
280     ble_svc_gap_chr_changed_cb_fn = cb;
281 }
282 
283 void
ble_svc_gap_init(void)284 ble_svc_gap_init(void)
285 {
286     int rc;
287 
288     /* Ensure this function only gets called by sysinit. */
289     SYSINIT_ASSERT_ACTIVE();
290 
291     rc = ble_gatts_count_cfg(ble_svc_gap_defs);
292     SYSINIT_PANIC_ASSERT(rc == 0);
293 
294     rc = ble_gatts_add_svcs(ble_svc_gap_defs);
295     SYSINIT_PANIC_ASSERT(rc == 0);
296 }
297