1*042d53a7SEvalZero /*
2*042d53a7SEvalZero * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero * or more contributor license agreements. See the NOTICE file
4*042d53a7SEvalZero * distributed with this work for additional information
5*042d53a7SEvalZero * regarding copyright ownership. The ASF licenses this file
6*042d53a7SEvalZero * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero * with the License. You may obtain a copy of the License at
9*042d53a7SEvalZero *
10*042d53a7SEvalZero * http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero *
12*042d53a7SEvalZero * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero * software distributed under the License is distributed on an
14*042d53a7SEvalZero * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero * KIND, either express or implied. See the License for the
16*042d53a7SEvalZero * specific language governing permissions and limitations
17*042d53a7SEvalZero * under the License.
18*042d53a7SEvalZero */
19*042d53a7SEvalZero
20*042d53a7SEvalZero #include <stdlib.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include <errno.h>
23*042d53a7SEvalZero #include "os/os.h"
24*042d53a7SEvalZero #include "nimble/ble.h"
25*042d53a7SEvalZero #include "host/ble_uuid.h"
26*042d53a7SEvalZero #include "ble_hs_priv.h"
27*042d53a7SEvalZero
28*042d53a7SEvalZero /**
29*042d53a7SEvalZero * ATT server - Attribute Protocol
30*042d53a7SEvalZero *
31*042d53a7SEvalZero * Notes on buffer reuse:
32*042d53a7SEvalZero * Most request handlers reuse the request buffer for the reponse. This is
33*042d53a7SEvalZero * done to prevent out-of-memory conditions. However, there are two handlers
34*042d53a7SEvalZero * which do not reuse the request buffer:
35*042d53a7SEvalZero * 1. Write request.
36*042d53a7SEvalZero * 2. Indicate request.
37*042d53a7SEvalZero *
38*042d53a7SEvalZero * Both of these handlers attempt to allocate a new buffer for the response
39*042d53a7SEvalZero * prior to processing the request. If allocation fails, the request is not
40*042d53a7SEvalZero * processed, and the request buffer is reused for the transmission of an
41*042d53a7SEvalZero * "insufficient resources" ATT error response. These handlers don't reuse the
42*042d53a7SEvalZero * request mbuf for an affirmative response because the buffer contains the
43*042d53a7SEvalZero * attribute data that gets passed to the application callback. The
44*042d53a7SEvalZero * application may choose to retain the mbuf during the callback, so the stack
45*042d53a7SEvalZero */
46*042d53a7SEvalZero
47*042d53a7SEvalZero STAILQ_HEAD(ble_att_svr_entry_list, ble_att_svr_entry);
48*042d53a7SEvalZero static struct ble_att_svr_entry_list ble_att_svr_list;
49*042d53a7SEvalZero static struct ble_att_svr_entry_list ble_att_svr_hidden_list;
50*042d53a7SEvalZero
51*042d53a7SEvalZero static uint16_t ble_att_svr_id;
52*042d53a7SEvalZero
53*042d53a7SEvalZero static void *ble_att_svr_entry_mem;
54*042d53a7SEvalZero static struct os_mempool ble_att_svr_entry_pool;
55*042d53a7SEvalZero
56*042d53a7SEvalZero static os_membuf_t ble_att_svr_prep_entry_mem[
57*042d53a7SEvalZero OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ATT_SVR_MAX_PREP_ENTRIES),
58*042d53a7SEvalZero sizeof (struct ble_att_prep_entry))
59*042d53a7SEvalZero ];
60*042d53a7SEvalZero
61*042d53a7SEvalZero static struct os_mempool ble_att_svr_prep_entry_pool;
62*042d53a7SEvalZero
63*042d53a7SEvalZero static struct ble_att_svr_entry *
ble_att_svr_entry_alloc(void)64*042d53a7SEvalZero ble_att_svr_entry_alloc(void)
65*042d53a7SEvalZero {
66*042d53a7SEvalZero struct ble_att_svr_entry *entry;
67*042d53a7SEvalZero
68*042d53a7SEvalZero entry = os_memblock_get(&ble_att_svr_entry_pool);
69*042d53a7SEvalZero if (entry != NULL) {
70*042d53a7SEvalZero memset(entry, 0, sizeof *entry);
71*042d53a7SEvalZero }
72*042d53a7SEvalZero
73*042d53a7SEvalZero return entry;
74*042d53a7SEvalZero }
75*042d53a7SEvalZero
76*042d53a7SEvalZero static void
ble_att_svr_entry_free(struct ble_att_svr_entry * entry)77*042d53a7SEvalZero ble_att_svr_entry_free(struct ble_att_svr_entry *entry)
78*042d53a7SEvalZero {
79*042d53a7SEvalZero os_memblock_put(&ble_att_svr_entry_pool, entry);
80*042d53a7SEvalZero }
81*042d53a7SEvalZero
82*042d53a7SEvalZero /**
83*042d53a7SEvalZero * Allocate the next handle id and return it.
84*042d53a7SEvalZero *
85*042d53a7SEvalZero * @return A new 16-bit handle ID.
86*042d53a7SEvalZero */
87*042d53a7SEvalZero static uint16_t
ble_att_svr_next_id(void)88*042d53a7SEvalZero ble_att_svr_next_id(void)
89*042d53a7SEvalZero {
90*042d53a7SEvalZero /* Rollover is fatal. */
91*042d53a7SEvalZero BLE_HS_DBG_ASSERT(ble_att_svr_id != UINT16_MAX);
92*042d53a7SEvalZero return ++ble_att_svr_id;
93*042d53a7SEvalZero }
94*042d53a7SEvalZero
95*042d53a7SEvalZero /**
96*042d53a7SEvalZero * Register a host attribute with the BLE stack.
97*042d53a7SEvalZero *
98*042d53a7SEvalZero * @param ha A filled out ble_att structure to register
99*042d53a7SEvalZero * @param handle_id A pointer to a 16-bit handle ID, which will be
100*042d53a7SEvalZero * the handle that is allocated.
101*042d53a7SEvalZero * @param fn The callback function that gets executed when
102*042d53a7SEvalZero * the attribute is operated on.
103*042d53a7SEvalZero *
104*042d53a7SEvalZero * @return 0 on success, non-zero error code on failure.
105*042d53a7SEvalZero */
106*042d53a7SEvalZero int
ble_att_svr_register(const ble_uuid_t * uuid,uint8_t flags,uint8_t min_key_size,uint16_t * handle_id,ble_att_svr_access_fn * cb,void * cb_arg)107*042d53a7SEvalZero ble_att_svr_register(const ble_uuid_t *uuid, uint8_t flags,
108*042d53a7SEvalZero uint8_t min_key_size, uint16_t *handle_id,
109*042d53a7SEvalZero ble_att_svr_access_fn *cb, void *cb_arg)
110*042d53a7SEvalZero {
111*042d53a7SEvalZero struct ble_att_svr_entry *entry;
112*042d53a7SEvalZero
113*042d53a7SEvalZero entry = ble_att_svr_entry_alloc();
114*042d53a7SEvalZero if (entry == NULL) {
115*042d53a7SEvalZero return BLE_HS_ENOMEM;
116*042d53a7SEvalZero }
117*042d53a7SEvalZero
118*042d53a7SEvalZero entry->ha_uuid = uuid;
119*042d53a7SEvalZero entry->ha_flags = flags;
120*042d53a7SEvalZero entry->ha_min_key_size = min_key_size;
121*042d53a7SEvalZero entry->ha_handle_id = ble_att_svr_next_id();
122*042d53a7SEvalZero entry->ha_cb = cb;
123*042d53a7SEvalZero entry->ha_cb_arg = cb_arg;
124*042d53a7SEvalZero
125*042d53a7SEvalZero STAILQ_INSERT_TAIL(&ble_att_svr_list, entry, ha_next);
126*042d53a7SEvalZero
127*042d53a7SEvalZero if (handle_id != NULL) {
128*042d53a7SEvalZero *handle_id = entry->ha_handle_id;
129*042d53a7SEvalZero }
130*042d53a7SEvalZero
131*042d53a7SEvalZero return 0;
132*042d53a7SEvalZero }
133*042d53a7SEvalZero
134*042d53a7SEvalZero uint16_t
ble_att_svr_prev_handle(void)135*042d53a7SEvalZero ble_att_svr_prev_handle(void)
136*042d53a7SEvalZero {
137*042d53a7SEvalZero return ble_att_svr_id;
138*042d53a7SEvalZero }
139*042d53a7SEvalZero
140*042d53a7SEvalZero /**
141*042d53a7SEvalZero * Find a host attribute by handle id.
142*042d53a7SEvalZero *
143*042d53a7SEvalZero * @param handle_id The handle_id to search for
144*042d53a7SEvalZero * @param ha_ptr On input: Indicates the starting point of the
145*042d53a7SEvalZero * walk; null means start at the beginning of
146*042d53a7SEvalZero * the list, non-null means start at the
147*042d53a7SEvalZero * following entry.
148*042d53a7SEvalZero * On output: Indicates the last ble_att element
149*042d53a7SEvalZero * processed, or NULL if the entire list has
150*042d53a7SEvalZero * been processed.
151*042d53a7SEvalZero *
152*042d53a7SEvalZero * @return 0 on success; BLE_HS_ENOENT on not found.
153*042d53a7SEvalZero */
154*042d53a7SEvalZero struct ble_att_svr_entry *
ble_att_svr_find_by_handle(uint16_t handle_id)155*042d53a7SEvalZero ble_att_svr_find_by_handle(uint16_t handle_id)
156*042d53a7SEvalZero {
157*042d53a7SEvalZero struct ble_att_svr_entry *entry;
158*042d53a7SEvalZero
159*042d53a7SEvalZero for (entry = STAILQ_FIRST(&ble_att_svr_list);
160*042d53a7SEvalZero entry != NULL;
161*042d53a7SEvalZero entry = STAILQ_NEXT(entry, ha_next)) {
162*042d53a7SEvalZero
163*042d53a7SEvalZero if (entry->ha_handle_id == handle_id) {
164*042d53a7SEvalZero return entry;
165*042d53a7SEvalZero }
166*042d53a7SEvalZero }
167*042d53a7SEvalZero
168*042d53a7SEvalZero return NULL;
169*042d53a7SEvalZero }
170*042d53a7SEvalZero
171*042d53a7SEvalZero /**
172*042d53a7SEvalZero * Find a host attribute by UUID.
173*042d53a7SEvalZero *
174*042d53a7SEvalZero * @param uuid The ble_uuid_t to search for
175*042d53a7SEvalZero * @param prev On input: Indicates the starting point of the
176*042d53a7SEvalZero * walk; null means start at the beginning of
177*042d53a7SEvalZero * the list, non-null means start at the
178*042d53a7SEvalZero * following entry.
179*042d53a7SEvalZero * On output: Indicates the last ble_att element
180*042d53a7SEvalZero * processed, or NULL if the entire list has
181*042d53a7SEvalZero * been processed.
182*042d53a7SEvalZero *
183*042d53a7SEvalZero * @return 0 on success; BLE_HS_ENOENT on not found.
184*042d53a7SEvalZero */
185*042d53a7SEvalZero struct ble_att_svr_entry *
ble_att_svr_find_by_uuid(struct ble_att_svr_entry * prev,const ble_uuid_t * uuid,uint16_t end_handle)186*042d53a7SEvalZero ble_att_svr_find_by_uuid(struct ble_att_svr_entry *prev, const ble_uuid_t *uuid,
187*042d53a7SEvalZero uint16_t end_handle)
188*042d53a7SEvalZero {
189*042d53a7SEvalZero struct ble_att_svr_entry *entry;
190*042d53a7SEvalZero
191*042d53a7SEvalZero if (prev == NULL) {
192*042d53a7SEvalZero entry = STAILQ_FIRST(&ble_att_svr_list);
193*042d53a7SEvalZero } else {
194*042d53a7SEvalZero entry = STAILQ_NEXT(prev, ha_next);
195*042d53a7SEvalZero }
196*042d53a7SEvalZero
197*042d53a7SEvalZero for (;
198*042d53a7SEvalZero entry != NULL && entry->ha_handle_id <= end_handle;
199*042d53a7SEvalZero entry = STAILQ_NEXT(entry, ha_next)) {
200*042d53a7SEvalZero
201*042d53a7SEvalZero if (ble_uuid_cmp(entry->ha_uuid, uuid) == 0) {
202*042d53a7SEvalZero return entry;
203*042d53a7SEvalZero }
204*042d53a7SEvalZero }
205*042d53a7SEvalZero
206*042d53a7SEvalZero return NULL;
207*042d53a7SEvalZero }
208*042d53a7SEvalZero
209*042d53a7SEvalZero static int
ble_att_svr_pullup_req_base(struct os_mbuf ** om,int base_len,uint8_t * out_att_err)210*042d53a7SEvalZero ble_att_svr_pullup_req_base(struct os_mbuf **om, int base_len,
211*042d53a7SEvalZero uint8_t *out_att_err)
212*042d53a7SEvalZero {
213*042d53a7SEvalZero uint8_t att_err;
214*042d53a7SEvalZero int rc;
215*042d53a7SEvalZero
216*042d53a7SEvalZero rc = ble_hs_mbuf_pullup_base(om, base_len);
217*042d53a7SEvalZero if (rc == BLE_HS_ENOMEM) {
218*042d53a7SEvalZero att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
219*042d53a7SEvalZero } else {
220*042d53a7SEvalZero att_err = 0;
221*042d53a7SEvalZero }
222*042d53a7SEvalZero
223*042d53a7SEvalZero if (out_att_err != NULL) {
224*042d53a7SEvalZero *out_att_err = att_err;
225*042d53a7SEvalZero }
226*042d53a7SEvalZero
227*042d53a7SEvalZero return rc;
228*042d53a7SEvalZero }
229*042d53a7SEvalZero
230*042d53a7SEvalZero static void
ble_att_svr_get_sec_state(uint16_t conn_handle,struct ble_gap_sec_state * out_sec_state)231*042d53a7SEvalZero ble_att_svr_get_sec_state(uint16_t conn_handle,
232*042d53a7SEvalZero struct ble_gap_sec_state *out_sec_state)
233*042d53a7SEvalZero {
234*042d53a7SEvalZero struct ble_hs_conn *conn;
235*042d53a7SEvalZero
236*042d53a7SEvalZero ble_hs_lock();
237*042d53a7SEvalZero
238*042d53a7SEvalZero conn = ble_hs_conn_find_assert(conn_handle);
239*042d53a7SEvalZero *out_sec_state = conn->bhc_sec_state;
240*042d53a7SEvalZero
241*042d53a7SEvalZero ble_hs_unlock();
242*042d53a7SEvalZero }
243*042d53a7SEvalZero
244*042d53a7SEvalZero static int
ble_att_svr_check_perms(uint16_t conn_handle,int is_read,struct ble_att_svr_entry * entry,uint8_t * out_att_err)245*042d53a7SEvalZero ble_att_svr_check_perms(uint16_t conn_handle, int is_read,
246*042d53a7SEvalZero struct ble_att_svr_entry *entry,
247*042d53a7SEvalZero uint8_t *out_att_err)
248*042d53a7SEvalZero {
249*042d53a7SEvalZero struct ble_gap_sec_state sec_state;
250*042d53a7SEvalZero struct ble_store_value_sec value_sec;
251*042d53a7SEvalZero struct ble_store_key_sec key_sec;
252*042d53a7SEvalZero struct ble_hs_conn_addrs addrs;
253*042d53a7SEvalZero struct ble_hs_conn *conn;
254*042d53a7SEvalZero int author;
255*042d53a7SEvalZero int authen;
256*042d53a7SEvalZero int enc;
257*042d53a7SEvalZero int rc;
258*042d53a7SEvalZero
259*042d53a7SEvalZero if (is_read) {
260*042d53a7SEvalZero if (!(entry->ha_flags & BLE_ATT_F_READ)) {
261*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_READ_NOT_PERMITTED;
262*042d53a7SEvalZero return BLE_HS_EREJECT;
263*042d53a7SEvalZero }
264*042d53a7SEvalZero
265*042d53a7SEvalZero enc = entry->ha_flags & BLE_ATT_F_READ_ENC;
266*042d53a7SEvalZero authen = entry->ha_flags & BLE_ATT_F_READ_AUTHEN;
267*042d53a7SEvalZero author = entry->ha_flags & BLE_ATT_F_READ_AUTHOR;
268*042d53a7SEvalZero } else {
269*042d53a7SEvalZero if (!(entry->ha_flags & BLE_ATT_F_WRITE)) {
270*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED;
271*042d53a7SEvalZero return BLE_HS_EREJECT;
272*042d53a7SEvalZero }
273*042d53a7SEvalZero
274*042d53a7SEvalZero enc = entry->ha_flags & BLE_ATT_F_WRITE_ENC;
275*042d53a7SEvalZero authen = entry->ha_flags & BLE_ATT_F_WRITE_AUTHEN;
276*042d53a7SEvalZero author = entry->ha_flags & BLE_ATT_F_WRITE_AUTHOR;
277*042d53a7SEvalZero }
278*042d53a7SEvalZero
279*042d53a7SEvalZero /* Bail early if this operation doesn't require security. */
280*042d53a7SEvalZero if (!enc && !authen && !author) {
281*042d53a7SEvalZero return 0;
282*042d53a7SEvalZero }
283*042d53a7SEvalZero
284*042d53a7SEvalZero ble_att_svr_get_sec_state(conn_handle, &sec_state);
285*042d53a7SEvalZero if ((enc || authen) && !sec_state.encrypted) {
286*042d53a7SEvalZero ble_hs_lock();
287*042d53a7SEvalZero conn = ble_hs_conn_find(conn_handle);
288*042d53a7SEvalZero if (conn != NULL) {
289*042d53a7SEvalZero ble_hs_conn_addrs(conn, &addrs);
290*042d53a7SEvalZero
291*042d53a7SEvalZero memset(&key_sec, 0, sizeof key_sec);
292*042d53a7SEvalZero key_sec.peer_addr = addrs.peer_id_addr;
293*042d53a7SEvalZero }
294*042d53a7SEvalZero ble_hs_unlock();
295*042d53a7SEvalZero
296*042d53a7SEvalZero rc = ble_store_read_peer_sec(&key_sec, &value_sec);
297*042d53a7SEvalZero if (rc == 0 && value_sec.ltk_present) {
298*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_ENC;
299*042d53a7SEvalZero } else {
300*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHEN;
301*042d53a7SEvalZero }
302*042d53a7SEvalZero
303*042d53a7SEvalZero return BLE_HS_ATT_ERR(*out_att_err);
304*042d53a7SEvalZero }
305*042d53a7SEvalZero
306*042d53a7SEvalZero if (authen && !sec_state.authenticated) {
307*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHEN;
308*042d53a7SEvalZero return BLE_HS_ATT_ERR(*out_att_err);
309*042d53a7SEvalZero }
310*042d53a7SEvalZero
311*042d53a7SEvalZero if (entry->ha_min_key_size > sec_state.key_size) {
312*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_KEY_SZ;
313*042d53a7SEvalZero return BLE_HS_ATT_ERR(*out_att_err);
314*042d53a7SEvalZero }
315*042d53a7SEvalZero
316*042d53a7SEvalZero if (author) {
317*042d53a7SEvalZero /* XXX: Prompt user for authorization. */
318*042d53a7SEvalZero }
319*042d53a7SEvalZero
320*042d53a7SEvalZero return 0;
321*042d53a7SEvalZero }
322*042d53a7SEvalZero
323*042d53a7SEvalZero /**
324*042d53a7SEvalZero * Calculates the number of ticks until a queued write times out on the
325*042d53a7SEvalZero * specified ATT server. If this server is not in the process of receiving a
326*042d53a7SEvalZero * queued write, then BLE_HS_FOREVER is returned. If a timeout just occurred,
327*042d53a7SEvalZero * 0 is returned.
328*042d53a7SEvalZero *
329*042d53a7SEvalZero * @param svr The ATT server to check.
330*042d53a7SEvalZero * @param now The current OS time.
331*042d53a7SEvalZero *
332*042d53a7SEvalZero * @return The number of ticks until the current queued
333*042d53a7SEvalZero * write times out.
334*042d53a7SEvalZero */
335*042d53a7SEvalZero int32_t
ble_att_svr_ticks_until_tmo(const struct ble_att_svr_conn * svr,ble_npl_time_t now)336*042d53a7SEvalZero ble_att_svr_ticks_until_tmo(const struct ble_att_svr_conn *svr, ble_npl_time_t now)
337*042d53a7SEvalZero {
338*042d53a7SEvalZero #if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO == 0
339*042d53a7SEvalZero return BLE_HS_FOREVER;
340*042d53a7SEvalZero #endif
341*042d53a7SEvalZero
342*042d53a7SEvalZero int32_t time_diff;
343*042d53a7SEvalZero
344*042d53a7SEvalZero if (SLIST_EMPTY(&svr->basc_prep_list)) {
345*042d53a7SEvalZero return BLE_HS_FOREVER;
346*042d53a7SEvalZero }
347*042d53a7SEvalZero
348*042d53a7SEvalZero time_diff = svr->basc_prep_timeout_at - now;
349*042d53a7SEvalZero if (time_diff < 0) {
350*042d53a7SEvalZero return 0;
351*042d53a7SEvalZero }
352*042d53a7SEvalZero
353*042d53a7SEvalZero return time_diff;
354*042d53a7SEvalZero }
355*042d53a7SEvalZero
356*042d53a7SEvalZero /**
357*042d53a7SEvalZero * Allocates an mbuf to be used for an ATT response. If an mbuf cannot be
358*042d53a7SEvalZero * allocated, the received request mbuf is reused for the error response.
359*042d53a7SEvalZero */
360*042d53a7SEvalZero static int
ble_att_svr_pkt(struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * out_att_err)361*042d53a7SEvalZero ble_att_svr_pkt(struct os_mbuf **rxom, struct os_mbuf **out_txom,
362*042d53a7SEvalZero uint8_t *out_att_err)
363*042d53a7SEvalZero {
364*042d53a7SEvalZero *out_txom = ble_hs_mbuf_l2cap_pkt();
365*042d53a7SEvalZero if (*out_txom != NULL) {
366*042d53a7SEvalZero return 0;
367*042d53a7SEvalZero }
368*042d53a7SEvalZero
369*042d53a7SEvalZero /* Allocation failure. Reuse receive buffer for response. */
370*042d53a7SEvalZero *out_txom = *rxom;
371*042d53a7SEvalZero *rxom = NULL;
372*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
373*042d53a7SEvalZero return BLE_HS_ENOMEM;
374*042d53a7SEvalZero }
375*042d53a7SEvalZero
376*042d53a7SEvalZero static int
ble_att_svr_read(uint16_t conn_handle,struct ble_att_svr_entry * entry,uint16_t offset,struct os_mbuf * om,uint8_t * out_att_err)377*042d53a7SEvalZero ble_att_svr_read(uint16_t conn_handle,
378*042d53a7SEvalZero struct ble_att_svr_entry *entry,
379*042d53a7SEvalZero uint16_t offset,
380*042d53a7SEvalZero struct os_mbuf *om,
381*042d53a7SEvalZero uint8_t *out_att_err)
382*042d53a7SEvalZero {
383*042d53a7SEvalZero uint8_t att_err;
384*042d53a7SEvalZero int rc;
385*042d53a7SEvalZero
386*042d53a7SEvalZero att_err = 0; /* Silence gcc warning. */
387*042d53a7SEvalZero
388*042d53a7SEvalZero if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
389*042d53a7SEvalZero rc = ble_att_svr_check_perms(conn_handle, 1, entry, &att_err);
390*042d53a7SEvalZero if (rc != 0) {
391*042d53a7SEvalZero goto err;
392*042d53a7SEvalZero }
393*042d53a7SEvalZero }
394*042d53a7SEvalZero
395*042d53a7SEvalZero BLE_HS_DBG_ASSERT(entry->ha_cb != NULL);
396*042d53a7SEvalZero rc = entry->ha_cb(conn_handle, entry->ha_handle_id,
397*042d53a7SEvalZero BLE_ATT_ACCESS_OP_READ, offset, &om, entry->ha_cb_arg);
398*042d53a7SEvalZero if (rc != 0) {
399*042d53a7SEvalZero att_err = rc;
400*042d53a7SEvalZero rc = BLE_HS_EAPP;
401*042d53a7SEvalZero goto err;
402*042d53a7SEvalZero }
403*042d53a7SEvalZero
404*042d53a7SEvalZero return 0;
405*042d53a7SEvalZero
406*042d53a7SEvalZero err:
407*042d53a7SEvalZero if (out_att_err != NULL) {
408*042d53a7SEvalZero *out_att_err = att_err;
409*042d53a7SEvalZero }
410*042d53a7SEvalZero return rc;
411*042d53a7SEvalZero }
412*042d53a7SEvalZero
413*042d53a7SEvalZero static int
ble_att_svr_read_flat(uint16_t conn_handle,struct ble_att_svr_entry * entry,uint16_t offset,uint16_t max_len,void * dst,uint16_t * out_len,uint8_t * out_att_err)414*042d53a7SEvalZero ble_att_svr_read_flat(uint16_t conn_handle,
415*042d53a7SEvalZero struct ble_att_svr_entry *entry,
416*042d53a7SEvalZero uint16_t offset,
417*042d53a7SEvalZero uint16_t max_len,
418*042d53a7SEvalZero void *dst,
419*042d53a7SEvalZero uint16_t *out_len,
420*042d53a7SEvalZero uint8_t *out_att_err)
421*042d53a7SEvalZero {
422*042d53a7SEvalZero struct os_mbuf *om;
423*042d53a7SEvalZero uint16_t len;
424*042d53a7SEvalZero int rc;
425*042d53a7SEvalZero
426*042d53a7SEvalZero om = ble_hs_mbuf_l2cap_pkt();
427*042d53a7SEvalZero if (om == NULL) {
428*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
429*042d53a7SEvalZero goto done;
430*042d53a7SEvalZero }
431*042d53a7SEvalZero
432*042d53a7SEvalZero rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err);
433*042d53a7SEvalZero if (rc != 0) {
434*042d53a7SEvalZero goto done;
435*042d53a7SEvalZero }
436*042d53a7SEvalZero
437*042d53a7SEvalZero len = OS_MBUF_PKTLEN(om);
438*042d53a7SEvalZero if (len > max_len) {
439*042d53a7SEvalZero rc = BLE_HS_EMSGSIZE;
440*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_UNLIKELY;
441*042d53a7SEvalZero goto done;
442*042d53a7SEvalZero }
443*042d53a7SEvalZero
444*042d53a7SEvalZero rc = os_mbuf_copydata(om, 0, len, dst);
445*042d53a7SEvalZero BLE_HS_DBG_ASSERT(rc == 0);
446*042d53a7SEvalZero
447*042d53a7SEvalZero *out_len = len;
448*042d53a7SEvalZero rc = 0;
449*042d53a7SEvalZero
450*042d53a7SEvalZero done:
451*042d53a7SEvalZero os_mbuf_free_chain(om);
452*042d53a7SEvalZero return rc;
453*042d53a7SEvalZero }
454*042d53a7SEvalZero
455*042d53a7SEvalZero int
ble_att_svr_read_handle(uint16_t conn_handle,uint16_t attr_handle,uint16_t offset,struct os_mbuf * om,uint8_t * out_att_err)456*042d53a7SEvalZero ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
457*042d53a7SEvalZero uint16_t offset, struct os_mbuf *om,
458*042d53a7SEvalZero uint8_t *out_att_err)
459*042d53a7SEvalZero {
460*042d53a7SEvalZero struct ble_att_svr_entry *entry;
461*042d53a7SEvalZero int rc;
462*042d53a7SEvalZero
463*042d53a7SEvalZero entry = ble_att_svr_find_by_handle(attr_handle);
464*042d53a7SEvalZero if (entry == NULL) {
465*042d53a7SEvalZero if (out_att_err != NULL) {
466*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INVALID_HANDLE;
467*042d53a7SEvalZero }
468*042d53a7SEvalZero return BLE_HS_ENOENT;
469*042d53a7SEvalZero }
470*042d53a7SEvalZero
471*042d53a7SEvalZero rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err);
472*042d53a7SEvalZero if (rc != 0) {
473*042d53a7SEvalZero return rc;
474*042d53a7SEvalZero }
475*042d53a7SEvalZero
476*042d53a7SEvalZero return 0;
477*042d53a7SEvalZero }
478*042d53a7SEvalZero
479*042d53a7SEvalZero int
ble_att_svr_read_local(uint16_t attr_handle,struct os_mbuf ** out_om)480*042d53a7SEvalZero ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om)
481*042d53a7SEvalZero {
482*042d53a7SEvalZero struct os_mbuf *om;
483*042d53a7SEvalZero int rc;
484*042d53a7SEvalZero
485*042d53a7SEvalZero om = ble_hs_mbuf_bare_pkt();
486*042d53a7SEvalZero if (om == NULL) {
487*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
488*042d53a7SEvalZero goto err;
489*042d53a7SEvalZero }
490*042d53a7SEvalZero
491*042d53a7SEvalZero rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0, om,
492*042d53a7SEvalZero NULL);
493*042d53a7SEvalZero if (rc != 0) {
494*042d53a7SEvalZero goto err;
495*042d53a7SEvalZero }
496*042d53a7SEvalZero
497*042d53a7SEvalZero *out_om = om;
498*042d53a7SEvalZero return 0;
499*042d53a7SEvalZero
500*042d53a7SEvalZero err:
501*042d53a7SEvalZero os_mbuf_free_chain(om);
502*042d53a7SEvalZero return rc;
503*042d53a7SEvalZero }
504*042d53a7SEvalZero
505*042d53a7SEvalZero static int
ble_att_svr_write(uint16_t conn_handle,struct ble_att_svr_entry * entry,uint16_t offset,struct os_mbuf ** om,uint8_t * out_att_err)506*042d53a7SEvalZero ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry,
507*042d53a7SEvalZero uint16_t offset, struct os_mbuf **om, uint8_t *out_att_err)
508*042d53a7SEvalZero {
509*042d53a7SEvalZero uint8_t att_err = 0;
510*042d53a7SEvalZero int rc;
511*042d53a7SEvalZero
512*042d53a7SEvalZero BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
513*042d53a7SEvalZero
514*042d53a7SEvalZero if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
515*042d53a7SEvalZero rc = ble_att_svr_check_perms(conn_handle, 0, entry, &att_err);
516*042d53a7SEvalZero if (rc != 0) {
517*042d53a7SEvalZero goto done;
518*042d53a7SEvalZero }
519*042d53a7SEvalZero }
520*042d53a7SEvalZero
521*042d53a7SEvalZero BLE_HS_DBG_ASSERT(entry->ha_cb != NULL);
522*042d53a7SEvalZero rc = entry->ha_cb(conn_handle, entry->ha_handle_id,
523*042d53a7SEvalZero BLE_ATT_ACCESS_OP_WRITE, offset, om, entry->ha_cb_arg);
524*042d53a7SEvalZero if (rc != 0) {
525*042d53a7SEvalZero att_err = rc;
526*042d53a7SEvalZero rc = BLE_HS_EAPP;
527*042d53a7SEvalZero goto done;
528*042d53a7SEvalZero }
529*042d53a7SEvalZero
530*042d53a7SEvalZero done:
531*042d53a7SEvalZero if (out_att_err != NULL) {
532*042d53a7SEvalZero *out_att_err = att_err;
533*042d53a7SEvalZero }
534*042d53a7SEvalZero return rc;
535*042d53a7SEvalZero }
536*042d53a7SEvalZero
537*042d53a7SEvalZero static int
ble_att_svr_write_handle(uint16_t conn_handle,uint16_t attr_handle,uint16_t offset,struct os_mbuf ** om,uint8_t * out_att_err)538*042d53a7SEvalZero ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle,
539*042d53a7SEvalZero uint16_t offset, struct os_mbuf **om,
540*042d53a7SEvalZero uint8_t *out_att_err)
541*042d53a7SEvalZero {
542*042d53a7SEvalZero struct ble_att_svr_entry *entry;
543*042d53a7SEvalZero int rc;
544*042d53a7SEvalZero
545*042d53a7SEvalZero entry = ble_att_svr_find_by_handle(attr_handle);
546*042d53a7SEvalZero if (entry == NULL) {
547*042d53a7SEvalZero if (out_att_err != NULL) {
548*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INVALID_HANDLE;
549*042d53a7SEvalZero }
550*042d53a7SEvalZero return BLE_HS_ENOENT;
551*042d53a7SEvalZero }
552*042d53a7SEvalZero
553*042d53a7SEvalZero rc = ble_att_svr_write(conn_handle, entry, offset, om, out_att_err);
554*042d53a7SEvalZero if (rc != 0) {
555*042d53a7SEvalZero return rc;
556*042d53a7SEvalZero }
557*042d53a7SEvalZero
558*042d53a7SEvalZero return 0;
559*042d53a7SEvalZero }
560*042d53a7SEvalZero
561*042d53a7SEvalZero int
ble_att_svr_tx_error_rsp(uint16_t conn_handle,struct os_mbuf * txom,uint8_t req_op,uint16_t handle,uint8_t error_code)562*042d53a7SEvalZero ble_att_svr_tx_error_rsp(uint16_t conn_handle, struct os_mbuf *txom,
563*042d53a7SEvalZero uint8_t req_op, uint16_t handle, uint8_t error_code)
564*042d53a7SEvalZero {
565*042d53a7SEvalZero struct ble_att_error_rsp *rsp;
566*042d53a7SEvalZero
567*042d53a7SEvalZero BLE_HS_DBG_ASSERT(error_code != 0);
568*042d53a7SEvalZero BLE_HS_DBG_ASSERT(OS_MBUF_PKTLEN(txom) == 0);
569*042d53a7SEvalZero
570*042d53a7SEvalZero rsp = ble_att_cmd_prepare(BLE_ATT_OP_ERROR_RSP, sizeof(*rsp), txom);
571*042d53a7SEvalZero if (rsp == NULL) {
572*042d53a7SEvalZero return BLE_HS_ENOMEM;
573*042d53a7SEvalZero }
574*042d53a7SEvalZero
575*042d53a7SEvalZero rsp->baep_req_op = req_op;
576*042d53a7SEvalZero rsp->baep_handle = htole16(handle);
577*042d53a7SEvalZero rsp->baep_error_code = error_code;
578*042d53a7SEvalZero
579*042d53a7SEvalZero BLE_ATT_LOG_CMD(1, "error rsp", conn_handle, ble_att_error_rsp_log, rsp);
580*042d53a7SEvalZero
581*042d53a7SEvalZero return ble_att_tx(conn_handle, txom);
582*042d53a7SEvalZero }
583*042d53a7SEvalZero
584*042d53a7SEvalZero /**
585*042d53a7SEvalZero * Transmits a response or error message over the specified connection.
586*042d53a7SEvalZero *
587*042d53a7SEvalZero * The specified rc and err_status values control what gets sent as follows:
588*042d53a7SEvalZero * o If rc == 0: tx an affirmative response.
589*042d53a7SEvalZero * o Else if err_status != 0: tx an error response.
590*042d53a7SEvalZero * o Else: tx nothing.
591*042d53a7SEvalZero *
592*042d53a7SEvalZero * In addition, if transmission of an affirmative response fails, an error is
593*042d53a7SEvalZero * sent instead.
594*042d53a7SEvalZero *
595*042d53a7SEvalZero * @param conn_handle The handle of the connection to send over.
596*042d53a7SEvalZero * @param hs_status The status indicating whether to transmit an
597*042d53a7SEvalZero * affirmative response or an error.
598*042d53a7SEvalZero * @param txom Contains the affirmative response payload.
599*042d53a7SEvalZero * @param att_op If an error is transmitted, this is the value
600*042d53a7SEvalZero * of the error message's op field.
601*042d53a7SEvalZero * @param err_status If an error is transmitted, this is the value
602*042d53a7SEvalZero * of the error message's status field.
603*042d53a7SEvalZero * @param err_handle If an error is transmitted, this is the value
604*042d53a7SEvalZero * of the error message's attribute handle
605*042d53a7SEvalZero * field.
606*042d53a7SEvalZero */
607*042d53a7SEvalZero static int
ble_att_svr_tx_rsp(uint16_t conn_handle,int hs_status,struct os_mbuf * om,uint8_t att_op,uint8_t err_status,uint16_t err_handle)608*042d53a7SEvalZero ble_att_svr_tx_rsp(uint16_t conn_handle, int hs_status, struct os_mbuf *om,
609*042d53a7SEvalZero uint8_t att_op, uint8_t err_status, uint16_t err_handle)
610*042d53a7SEvalZero {
611*042d53a7SEvalZero struct ble_l2cap_chan *chan;
612*042d53a7SEvalZero struct ble_hs_conn *conn;
613*042d53a7SEvalZero int do_tx;
614*042d53a7SEvalZero int rc;
615*042d53a7SEvalZero
616*042d53a7SEvalZero if (hs_status != 0 && err_status == 0) {
617*042d53a7SEvalZero /* Processing failed, but err_status of 0 means don't send error. */
618*042d53a7SEvalZero do_tx = 0;
619*042d53a7SEvalZero } else {
620*042d53a7SEvalZero do_tx = 1;
621*042d53a7SEvalZero }
622*042d53a7SEvalZero
623*042d53a7SEvalZero if (do_tx) {
624*042d53a7SEvalZero ble_hs_lock();
625*042d53a7SEvalZero
626*042d53a7SEvalZero rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
627*042d53a7SEvalZero if (rc != 0) {
628*042d53a7SEvalZero /* No longer connected. */
629*042d53a7SEvalZero hs_status = rc;
630*042d53a7SEvalZero } else {
631*042d53a7SEvalZero if (hs_status == 0) {
632*042d53a7SEvalZero BLE_HS_DBG_ASSERT(om != NULL);
633*042d53a7SEvalZero
634*042d53a7SEvalZero ble_att_inc_tx_stat(om->om_data[0]);
635*042d53a7SEvalZero ble_att_truncate_to_mtu(chan, om);
636*042d53a7SEvalZero hs_status = ble_l2cap_tx(conn, chan, om);
637*042d53a7SEvalZero om = NULL;
638*042d53a7SEvalZero if (hs_status != 0) {
639*042d53a7SEvalZero err_status = BLE_ATT_ERR_UNLIKELY;
640*042d53a7SEvalZero }
641*042d53a7SEvalZero }
642*042d53a7SEvalZero }
643*042d53a7SEvalZero
644*042d53a7SEvalZero ble_hs_unlock();
645*042d53a7SEvalZero
646*042d53a7SEvalZero if (hs_status != 0) {
647*042d53a7SEvalZero STATS_INC(ble_att_stats, error_rsp_tx);
648*042d53a7SEvalZero
649*042d53a7SEvalZero /* Reuse om for error response. */
650*042d53a7SEvalZero if (om == NULL) {
651*042d53a7SEvalZero om = ble_hs_mbuf_l2cap_pkt();
652*042d53a7SEvalZero } else {
653*042d53a7SEvalZero os_mbuf_adj(om, OS_MBUF_PKTLEN(om));
654*042d53a7SEvalZero }
655*042d53a7SEvalZero if (om != NULL) {
656*042d53a7SEvalZero ble_att_svr_tx_error_rsp(conn_handle, om, att_op,
657*042d53a7SEvalZero err_handle, err_status);
658*042d53a7SEvalZero om = NULL;
659*042d53a7SEvalZero }
660*042d53a7SEvalZero }
661*042d53a7SEvalZero }
662*042d53a7SEvalZero
663*042d53a7SEvalZero /* Free mbuf if it was not consumed (i.e., if the send failed). */
664*042d53a7SEvalZero os_mbuf_free_chain(om);
665*042d53a7SEvalZero
666*042d53a7SEvalZero return hs_status;
667*042d53a7SEvalZero }
668*042d53a7SEvalZero
669*042d53a7SEvalZero static int
ble_att_svr_build_mtu_rsp(uint16_t conn_handle,struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * att_err)670*042d53a7SEvalZero ble_att_svr_build_mtu_rsp(uint16_t conn_handle, struct os_mbuf **rxom,
671*042d53a7SEvalZero struct os_mbuf **out_txom, uint8_t *att_err)
672*042d53a7SEvalZero {
673*042d53a7SEvalZero struct ble_att_mtu_cmd *cmd;
674*042d53a7SEvalZero struct ble_l2cap_chan *chan;
675*042d53a7SEvalZero struct os_mbuf *txom;
676*042d53a7SEvalZero uint16_t mtu;
677*042d53a7SEvalZero int rc;
678*042d53a7SEvalZero
679*042d53a7SEvalZero *att_err = 0; /* Silence unnecessary warning. */
680*042d53a7SEvalZero txom = NULL;
681*042d53a7SEvalZero
682*042d53a7SEvalZero ble_hs_lock();
683*042d53a7SEvalZero rc = ble_att_conn_chan_find(conn_handle, NULL, &chan);
684*042d53a7SEvalZero if (rc == 0) {
685*042d53a7SEvalZero mtu = chan->my_mtu;
686*042d53a7SEvalZero }
687*042d53a7SEvalZero ble_hs_unlock();
688*042d53a7SEvalZero
689*042d53a7SEvalZero if (rc != 0) {
690*042d53a7SEvalZero goto done;
691*042d53a7SEvalZero }
692*042d53a7SEvalZero
693*042d53a7SEvalZero /* Just reuse the request buffer for the response. */
694*042d53a7SEvalZero txom = *rxom;
695*042d53a7SEvalZero *rxom = NULL;
696*042d53a7SEvalZero os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom));
697*042d53a7SEvalZero
698*042d53a7SEvalZero cmd = ble_att_cmd_prepare(BLE_ATT_OP_MTU_RSP, sizeof(*cmd), txom);
699*042d53a7SEvalZero if (cmd == NULL) {
700*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
701*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
702*042d53a7SEvalZero goto done;
703*042d53a7SEvalZero }
704*042d53a7SEvalZero
705*042d53a7SEvalZero cmd->bamc_mtu = htole16(mtu);
706*042d53a7SEvalZero
707*042d53a7SEvalZero BLE_ATT_LOG_CMD(1, "mtu rsp", conn_handle, ble_att_mtu_cmd_log, cmd);
708*042d53a7SEvalZero
709*042d53a7SEvalZero rc = 0;
710*042d53a7SEvalZero
711*042d53a7SEvalZero done:
712*042d53a7SEvalZero *out_txom = txom;
713*042d53a7SEvalZero return rc;
714*042d53a7SEvalZero }
715*042d53a7SEvalZero
716*042d53a7SEvalZero int
ble_att_svr_rx_mtu(uint16_t conn_handle,struct os_mbuf ** rxom)717*042d53a7SEvalZero ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom)
718*042d53a7SEvalZero {
719*042d53a7SEvalZero struct ble_att_mtu_cmd *cmd;
720*042d53a7SEvalZero struct ble_l2cap_chan *chan;
721*042d53a7SEvalZero struct ble_hs_conn *conn;
722*042d53a7SEvalZero struct os_mbuf *txom;
723*042d53a7SEvalZero uint16_t mtu;
724*042d53a7SEvalZero uint8_t att_err;
725*042d53a7SEvalZero int rc;
726*042d53a7SEvalZero
727*042d53a7SEvalZero txom = NULL;
728*042d53a7SEvalZero mtu = 0;
729*042d53a7SEvalZero
730*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*cmd), &att_err);
731*042d53a7SEvalZero if (rc != 0) {
732*042d53a7SEvalZero goto done;
733*042d53a7SEvalZero }
734*042d53a7SEvalZero
735*042d53a7SEvalZero cmd = (struct ble_att_mtu_cmd *)(*rxom)->om_data;
736*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "mtu req", conn_handle, ble_att_mtu_cmd_log, cmd);
737*042d53a7SEvalZero
738*042d53a7SEvalZero mtu = le16toh(cmd->bamc_mtu);
739*042d53a7SEvalZero
740*042d53a7SEvalZero rc = ble_att_svr_build_mtu_rsp(conn_handle, rxom, &txom, &att_err);
741*042d53a7SEvalZero if (rc != 0) {
742*042d53a7SEvalZero goto done;
743*042d53a7SEvalZero }
744*042d53a7SEvalZero
745*042d53a7SEvalZero rc = 0;
746*042d53a7SEvalZero
747*042d53a7SEvalZero done:
748*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_MTU_REQ,
749*042d53a7SEvalZero att_err, 0);
750*042d53a7SEvalZero if (rc == 0) {
751*042d53a7SEvalZero ble_hs_lock();
752*042d53a7SEvalZero
753*042d53a7SEvalZero rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
754*042d53a7SEvalZero if (rc == 0) {
755*042d53a7SEvalZero ble_att_set_peer_mtu(chan, mtu);
756*042d53a7SEvalZero chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU;
757*042d53a7SEvalZero mtu = ble_att_chan_mtu(chan);
758*042d53a7SEvalZero }
759*042d53a7SEvalZero
760*042d53a7SEvalZero ble_hs_unlock();
761*042d53a7SEvalZero
762*042d53a7SEvalZero if (rc == 0) {
763*042d53a7SEvalZero ble_gap_mtu_event(conn_handle, BLE_L2CAP_CID_ATT, mtu);
764*042d53a7SEvalZero }
765*042d53a7SEvalZero }
766*042d53a7SEvalZero return rc;
767*042d53a7SEvalZero }
768*042d53a7SEvalZero
769*042d53a7SEvalZero /**
770*042d53a7SEvalZero * Fills the supplied mbuf with the variable length Information Data field of a
771*042d53a7SEvalZero * Find Information ATT response.
772*042d53a7SEvalZero *
773*042d53a7SEvalZero * @param req The Find Information request being responded
774*042d53a7SEvalZero * to.
775*042d53a7SEvalZero * @param om The destination mbuf where the Information
776*042d53a7SEvalZero * Data field gets written.
777*042d53a7SEvalZero * @param mtu The ATT L2CAP channel MTU.
778*042d53a7SEvalZero * @param format On success, the format field of the response
779*042d53a7SEvalZero * gets stored here. One of:
780*042d53a7SEvalZero * o BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT
781*042d53a7SEvalZero * o BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT
782*042d53a7SEvalZero *
783*042d53a7SEvalZero * @return 0 on success; nonzero on failure.
784*042d53a7SEvalZero */
785*042d53a7SEvalZero static int
ble_att_svr_fill_info(uint16_t start_handle,uint16_t end_handle,struct os_mbuf * om,uint16_t mtu,uint8_t * format)786*042d53a7SEvalZero ble_att_svr_fill_info(uint16_t start_handle, uint16_t end_handle,
787*042d53a7SEvalZero struct os_mbuf *om, uint16_t mtu, uint8_t *format)
788*042d53a7SEvalZero {
789*042d53a7SEvalZero struct ble_att_svr_entry *ha;
790*042d53a7SEvalZero uint8_t *buf;
791*042d53a7SEvalZero int num_entries;
792*042d53a7SEvalZero int entry_sz;
793*042d53a7SEvalZero int rc;
794*042d53a7SEvalZero
795*042d53a7SEvalZero *format = 0;
796*042d53a7SEvalZero num_entries = 0;
797*042d53a7SEvalZero rc = 0;
798*042d53a7SEvalZero
799*042d53a7SEvalZero STAILQ_FOREACH(ha, &ble_att_svr_list, ha_next) {
800*042d53a7SEvalZero if (ha->ha_handle_id > end_handle) {
801*042d53a7SEvalZero rc = 0;
802*042d53a7SEvalZero goto done;
803*042d53a7SEvalZero }
804*042d53a7SEvalZero if (ha->ha_handle_id >= start_handle) {
805*042d53a7SEvalZero if (ha->ha_uuid->type == BLE_UUID_TYPE_16) {
806*042d53a7SEvalZero if (*format == 0) {
807*042d53a7SEvalZero *format = BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT;
808*042d53a7SEvalZero } else if (*format != BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT) {
809*042d53a7SEvalZero rc = 0;
810*042d53a7SEvalZero goto done;
811*042d53a7SEvalZero }
812*042d53a7SEvalZero
813*042d53a7SEvalZero entry_sz = 4;
814*042d53a7SEvalZero } else {
815*042d53a7SEvalZero if (*format == 0) {
816*042d53a7SEvalZero *format = BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT;
817*042d53a7SEvalZero } else if (*format != BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT) {
818*042d53a7SEvalZero rc = 0;
819*042d53a7SEvalZero goto done;
820*042d53a7SEvalZero }
821*042d53a7SEvalZero entry_sz = 18;
822*042d53a7SEvalZero }
823*042d53a7SEvalZero
824*042d53a7SEvalZero if (OS_MBUF_PKTLEN(om) + entry_sz > mtu) {
825*042d53a7SEvalZero rc = 0;
826*042d53a7SEvalZero goto done;
827*042d53a7SEvalZero }
828*042d53a7SEvalZero
829*042d53a7SEvalZero buf = os_mbuf_extend(om, entry_sz);
830*042d53a7SEvalZero if (buf == NULL) {
831*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
832*042d53a7SEvalZero goto done;
833*042d53a7SEvalZero }
834*042d53a7SEvalZero
835*042d53a7SEvalZero put_le16(buf + 0, ha->ha_handle_id);
836*042d53a7SEvalZero
837*042d53a7SEvalZero ble_uuid_flat(ha->ha_uuid, buf + 2);
838*042d53a7SEvalZero
839*042d53a7SEvalZero num_entries++;
840*042d53a7SEvalZero }
841*042d53a7SEvalZero }
842*042d53a7SEvalZero
843*042d53a7SEvalZero done:
844*042d53a7SEvalZero if (rc == 0 && num_entries == 0) {
845*042d53a7SEvalZero return BLE_HS_ENOENT;
846*042d53a7SEvalZero } else {
847*042d53a7SEvalZero return rc;
848*042d53a7SEvalZero }
849*042d53a7SEvalZero }
850*042d53a7SEvalZero
851*042d53a7SEvalZero static int
ble_att_svr_build_find_info_rsp(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * att_err)852*042d53a7SEvalZero ble_att_svr_build_find_info_rsp(uint16_t conn_handle,
853*042d53a7SEvalZero uint16_t start_handle, uint16_t end_handle,
854*042d53a7SEvalZero struct os_mbuf **rxom,
855*042d53a7SEvalZero struct os_mbuf **out_txom,
856*042d53a7SEvalZero uint8_t *att_err)
857*042d53a7SEvalZero {
858*042d53a7SEvalZero struct ble_att_find_info_rsp *rsp;
859*042d53a7SEvalZero struct os_mbuf *txom;
860*042d53a7SEvalZero uint16_t mtu;
861*042d53a7SEvalZero int rc;
862*042d53a7SEvalZero
863*042d53a7SEvalZero /* Just reuse the request buffer for the response. */
864*042d53a7SEvalZero txom = *rxom;
865*042d53a7SEvalZero *rxom = NULL;
866*042d53a7SEvalZero os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom));
867*042d53a7SEvalZero
868*042d53a7SEvalZero /* Write the response base at the start of the buffer. The format field is
869*042d53a7SEvalZero * unknown at this point; it will be filled in later.
870*042d53a7SEvalZero */
871*042d53a7SEvalZero rsp = ble_att_cmd_prepare(BLE_ATT_OP_FIND_INFO_RSP, sizeof(*rsp), txom);
872*042d53a7SEvalZero if (rsp == NULL) {
873*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
874*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
875*042d53a7SEvalZero goto done;
876*042d53a7SEvalZero }
877*042d53a7SEvalZero
878*042d53a7SEvalZero /* Write the variable length Information Data field, populating the format
879*042d53a7SEvalZero * field as appropriate.
880*042d53a7SEvalZero */
881*042d53a7SEvalZero mtu = ble_att_mtu(conn_handle);
882*042d53a7SEvalZero rc = ble_att_svr_fill_info(start_handle, end_handle, txom, mtu,
883*042d53a7SEvalZero &rsp->bafp_format);
884*042d53a7SEvalZero if (rc != 0) {
885*042d53a7SEvalZero *att_err = BLE_ATT_ERR_ATTR_NOT_FOUND;
886*042d53a7SEvalZero rc = BLE_HS_ENOENT;
887*042d53a7SEvalZero goto done;
888*042d53a7SEvalZero }
889*042d53a7SEvalZero
890*042d53a7SEvalZero BLE_ATT_LOG_CMD(1, "find info rsp", conn_handle, ble_att_find_info_rsp_log,
891*042d53a7SEvalZero rsp);
892*042d53a7SEvalZero
893*042d53a7SEvalZero rc = 0;
894*042d53a7SEvalZero
895*042d53a7SEvalZero done:
896*042d53a7SEvalZero *out_txom = txom;
897*042d53a7SEvalZero return rc;
898*042d53a7SEvalZero }
899*042d53a7SEvalZero
900*042d53a7SEvalZero int
ble_att_svr_rx_find_info(uint16_t conn_handle,struct os_mbuf ** rxom)901*042d53a7SEvalZero ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom)
902*042d53a7SEvalZero {
903*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_FIND_INFO)
904*042d53a7SEvalZero return BLE_HS_ENOTSUP;
905*042d53a7SEvalZero #endif
906*042d53a7SEvalZero
907*042d53a7SEvalZero struct ble_att_find_info_req *req;
908*042d53a7SEvalZero struct os_mbuf *txom;
909*042d53a7SEvalZero uint16_t err_handle, start_handle, end_handle;
910*042d53a7SEvalZero uint8_t att_err;
911*042d53a7SEvalZero int rc;
912*042d53a7SEvalZero
913*042d53a7SEvalZero /* Initialize some values in case of early error. */
914*042d53a7SEvalZero txom = NULL;
915*042d53a7SEvalZero att_err = 0;
916*042d53a7SEvalZero err_handle = 0;
917*042d53a7SEvalZero
918*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
919*042d53a7SEvalZero if (rc != 0) {
920*042d53a7SEvalZero err_handle = 0;
921*042d53a7SEvalZero goto done;
922*042d53a7SEvalZero }
923*042d53a7SEvalZero
924*042d53a7SEvalZero req = (struct ble_att_find_info_req *)(*rxom)->om_data;
925*042d53a7SEvalZero start_handle = le16toh(req->bafq_start_handle);
926*042d53a7SEvalZero end_handle = le16toh(req->bafq_end_handle);
927*042d53a7SEvalZero
928*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "find info req", conn_handle, ble_att_find_info_req_log,
929*042d53a7SEvalZero req);
930*042d53a7SEvalZero
931*042d53a7SEvalZero /* Tx error response if start handle is greater than end handle or is equal
932*042d53a7SEvalZero * to 0 (Vol. 3, Part F, 3.4.3.1).
933*042d53a7SEvalZero */
934*042d53a7SEvalZero if (start_handle > end_handle || start_handle == 0) {
935*042d53a7SEvalZero att_err = BLE_ATT_ERR_INVALID_HANDLE;
936*042d53a7SEvalZero err_handle = start_handle;
937*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
938*042d53a7SEvalZero goto done;
939*042d53a7SEvalZero }
940*042d53a7SEvalZero
941*042d53a7SEvalZero rc = ble_att_svr_build_find_info_rsp(conn_handle,
942*042d53a7SEvalZero start_handle, end_handle,
943*042d53a7SEvalZero rxom, &txom, &att_err);
944*042d53a7SEvalZero if (rc != 0) {
945*042d53a7SEvalZero err_handle = start_handle;
946*042d53a7SEvalZero goto done;
947*042d53a7SEvalZero }
948*042d53a7SEvalZero
949*042d53a7SEvalZero rc = 0;
950*042d53a7SEvalZero
951*042d53a7SEvalZero done:
952*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_FIND_INFO_REQ,
953*042d53a7SEvalZero att_err, err_handle);
954*042d53a7SEvalZero return rc;
955*042d53a7SEvalZero }
956*042d53a7SEvalZero
957*042d53a7SEvalZero /**
958*042d53a7SEvalZero * Fills a Find-By-Type-Value-Response with single entry.
959*042d53a7SEvalZero *
960*042d53a7SEvalZero * @param om The response mbuf.
961*042d53a7SEvalZero * @param first First handle ID in the current group of IDs.
962*042d53a7SEvalZero * @param last Last handle ID in the current group of ID.
963*042d53a7SEvalZero * @param mtu The ATT L2CAP channel MTU.
964*042d53a7SEvalZero *
965*042d53a7SEvalZero * @return 0 if the response should be sent;
966*042d53a7SEvalZero * BLE_HS_EAGAIN if the entry was successfully
967*042d53a7SEvalZero * processed and subsequent entries can be
968*042d53a7SEvalZero * inspected.
969*042d53a7SEvalZero * Other nonzero on error.
970*042d53a7SEvalZero */
971*042d53a7SEvalZero static int
ble_att_svr_fill_type_value_entry(struct os_mbuf * om,uint16_t first,uint16_t last,int mtu,uint8_t * out_att_err)972*042d53a7SEvalZero ble_att_svr_fill_type_value_entry(struct os_mbuf *om, uint16_t first,
973*042d53a7SEvalZero uint16_t last, int mtu,
974*042d53a7SEvalZero uint8_t *out_att_err)
975*042d53a7SEvalZero {
976*042d53a7SEvalZero uint16_t u16;
977*042d53a7SEvalZero int rsp_sz;
978*042d53a7SEvalZero int rc;
979*042d53a7SEvalZero
980*042d53a7SEvalZero rsp_sz = OS_MBUF_PKTHDR(om)->omp_len + 4;
981*042d53a7SEvalZero if (rsp_sz > mtu) {
982*042d53a7SEvalZero return 0;
983*042d53a7SEvalZero }
984*042d53a7SEvalZero
985*042d53a7SEvalZero put_le16(&u16, first);
986*042d53a7SEvalZero rc = os_mbuf_append(om, &u16, 2);
987*042d53a7SEvalZero if (rc != 0) {
988*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
989*042d53a7SEvalZero return BLE_HS_ENOMEM;
990*042d53a7SEvalZero }
991*042d53a7SEvalZero
992*042d53a7SEvalZero put_le16(&u16, last);
993*042d53a7SEvalZero rc = os_mbuf_append(om, &u16, 2);
994*042d53a7SEvalZero if (rc != 0) {
995*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
996*042d53a7SEvalZero return BLE_HS_ENOMEM;
997*042d53a7SEvalZero }
998*042d53a7SEvalZero
999*042d53a7SEvalZero return BLE_HS_EAGAIN;
1000*042d53a7SEvalZero }
1001*042d53a7SEvalZero
1002*042d53a7SEvalZero static int
ble_att_svr_is_valid_find_group_type(const ble_uuid_t * uuid)1003*042d53a7SEvalZero ble_att_svr_is_valid_find_group_type(const ble_uuid_t *uuid)
1004*042d53a7SEvalZero {
1005*042d53a7SEvalZero uint16_t uuid16;
1006*042d53a7SEvalZero
1007*042d53a7SEvalZero uuid16 = ble_uuid_u16(uuid);
1008*042d53a7SEvalZero
1009*042d53a7SEvalZero return uuid16 == BLE_ATT_UUID_PRIMARY_SERVICE ||
1010*042d53a7SEvalZero uuid16 == BLE_ATT_UUID_SECONDARY_SERVICE ||
1011*042d53a7SEvalZero uuid16 == BLE_ATT_UUID_CHARACTERISTIC;
1012*042d53a7SEvalZero }
1013*042d53a7SEvalZero
1014*042d53a7SEvalZero static int
ble_att_svr_is_valid_group_end(const ble_uuid_t * uuid_group,const ble_uuid_t * uuid)1015*042d53a7SEvalZero ble_att_svr_is_valid_group_end(const ble_uuid_t *uuid_group,
1016*042d53a7SEvalZero const ble_uuid_t *uuid)
1017*042d53a7SEvalZero {
1018*042d53a7SEvalZero uint16_t uuid16;
1019*042d53a7SEvalZero
1020*042d53a7SEvalZero /* Grouping is defined only for 16-bit UUIDs, so any attribute ends group
1021*042d53a7SEvalZero * for non-16-bit UUIDs.
1022*042d53a7SEvalZero */
1023*042d53a7SEvalZero if (uuid_group->type != BLE_UUID_TYPE_16) {
1024*042d53a7SEvalZero return 1;
1025*042d53a7SEvalZero }
1026*042d53a7SEvalZero
1027*042d53a7SEvalZero /* Grouping is defined only for 16-bit UUIDs, so non-16-bit UUID attribute
1028*042d53a7SEvalZero * cannot end group.
1029*042d53a7SEvalZero */
1030*042d53a7SEvalZero if (uuid->type != BLE_UUID_TYPE_16) {
1031*042d53a7SEvalZero return 0;
1032*042d53a7SEvalZero }
1033*042d53a7SEvalZero
1034*042d53a7SEvalZero switch (ble_uuid_u16(uuid_group)) {
1035*042d53a7SEvalZero case BLE_ATT_UUID_PRIMARY_SERVICE:
1036*042d53a7SEvalZero case BLE_ATT_UUID_SECONDARY_SERVICE:
1037*042d53a7SEvalZero uuid16 = ble_uuid_u16(uuid);
1038*042d53a7SEvalZero
1039*042d53a7SEvalZero /* Only Primary or Secondary Service types end service group. */
1040*042d53a7SEvalZero return uuid16 == BLE_ATT_UUID_PRIMARY_SERVICE ||
1041*042d53a7SEvalZero uuid16 == BLE_ATT_UUID_SECONDARY_SERVICE;
1042*042d53a7SEvalZero case BLE_ATT_UUID_CHARACTERISTIC:
1043*042d53a7SEvalZero /* Any valid grouping type ends characteristic group */
1044*042d53a7SEvalZero return ble_att_svr_is_valid_find_group_type(uuid);
1045*042d53a7SEvalZero default:
1046*042d53a7SEvalZero /* Any attribute type ends group of non-grouping type */
1047*042d53a7SEvalZero return 1;
1048*042d53a7SEvalZero }
1049*042d53a7SEvalZero }
1050*042d53a7SEvalZero
1051*042d53a7SEvalZero /**
1052*042d53a7SEvalZero * Fills the supplied mbuf with the variable length Handles-Information-List
1053*042d53a7SEvalZero * field of a Find-By-Type-Value ATT response.
1054*042d53a7SEvalZero *
1055*042d53a7SEvalZero * @param req The Find-By-Type-Value-Request being responded
1056*042d53a7SEvalZero * to.
1057*042d53a7SEvalZero * @param rxom The mbuf containing the received request.
1058*042d53a7SEvalZero * @param txom The destination mbuf where the
1059*042d53a7SEvalZero * Handles-Information-List field gets
1060*042d53a7SEvalZero * written.
1061*042d53a7SEvalZero * @param mtu The ATT L2CAP channel MTU.
1062*042d53a7SEvalZero *
1063*042d53a7SEvalZero * @return 0 on success;
1064*042d53a7SEvalZero * BLE_HS_ENOENT if attribute not found;
1065*042d53a7SEvalZero * BLE_HS_EAPP on other error.
1066*042d53a7SEvalZero */
1067*042d53a7SEvalZero static int
ble_att_svr_fill_type_value(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,ble_uuid16_t attr_type,struct os_mbuf * rxom,struct os_mbuf * txom,uint16_t mtu,uint8_t * out_att_err)1068*042d53a7SEvalZero ble_att_svr_fill_type_value(uint16_t conn_handle,
1069*042d53a7SEvalZero uint16_t start_handle, uint16_t end_handle,
1070*042d53a7SEvalZero ble_uuid16_t attr_type,
1071*042d53a7SEvalZero struct os_mbuf *rxom, struct os_mbuf *txom,
1072*042d53a7SEvalZero uint16_t mtu, uint8_t *out_att_err)
1073*042d53a7SEvalZero {
1074*042d53a7SEvalZero struct ble_att_svr_entry *ha;
1075*042d53a7SEvalZero uint8_t buf[16];
1076*042d53a7SEvalZero uint16_t attr_len;
1077*042d53a7SEvalZero uint16_t first;
1078*042d53a7SEvalZero uint16_t prev;
1079*042d53a7SEvalZero int any_entries;
1080*042d53a7SEvalZero int rc;
1081*042d53a7SEvalZero
1082*042d53a7SEvalZero first = 0;
1083*042d53a7SEvalZero prev = 0;
1084*042d53a7SEvalZero rc = 0;
1085*042d53a7SEvalZero
1086*042d53a7SEvalZero /* Iterate through the attribute list, keeping track of the current
1087*042d53a7SEvalZero * matching group. For each attribute entry, determine if data needs to be
1088*042d53a7SEvalZero * written to the response.
1089*042d53a7SEvalZero */
1090*042d53a7SEvalZero STAILQ_FOREACH(ha, &ble_att_svr_list, ha_next) {
1091*042d53a7SEvalZero if (ha->ha_handle_id < start_handle) {
1092*042d53a7SEvalZero continue;
1093*042d53a7SEvalZero }
1094*042d53a7SEvalZero
1095*042d53a7SEvalZero /* Continue to look for end of group in case group is in progress. */
1096*042d53a7SEvalZero if (!first && ha->ha_handle_id > end_handle) {
1097*042d53a7SEvalZero break;
1098*042d53a7SEvalZero }
1099*042d53a7SEvalZero
1100*042d53a7SEvalZero /* With group in progress, check if current attribute ends it. */
1101*042d53a7SEvalZero if (first) {
1102*042d53a7SEvalZero if (!ble_att_svr_is_valid_group_end(&attr_type.u, ha->ha_uuid)) {
1103*042d53a7SEvalZero prev = ha->ha_handle_id;
1104*042d53a7SEvalZero continue;
1105*042d53a7SEvalZero }
1106*042d53a7SEvalZero
1107*042d53a7SEvalZero rc = ble_att_svr_fill_type_value_entry(txom, first, prev, mtu,
1108*042d53a7SEvalZero out_att_err);
1109*042d53a7SEvalZero if (rc != BLE_HS_EAGAIN) {
1110*042d53a7SEvalZero goto done;
1111*042d53a7SEvalZero }
1112*042d53a7SEvalZero
1113*042d53a7SEvalZero first = 0;
1114*042d53a7SEvalZero prev = 0;
1115*042d53a7SEvalZero
1116*042d53a7SEvalZero /* Break in case we were just looking for end of group past the end
1117*042d53a7SEvalZero * handle ID. */
1118*042d53a7SEvalZero if (ha->ha_handle_id > end_handle) {
1119*042d53a7SEvalZero break;
1120*042d53a7SEvalZero }
1121*042d53a7SEvalZero }
1122*042d53a7SEvalZero
1123*042d53a7SEvalZero /* Compare the attribute type and value to the request fields to
1124*042d53a7SEvalZero * determine if this attribute matches.
1125*042d53a7SEvalZero */
1126*042d53a7SEvalZero if (ble_uuid_cmp(ha->ha_uuid, &attr_type.u) == 0) {
1127*042d53a7SEvalZero rc = ble_att_svr_read_flat(conn_handle, ha, 0, sizeof buf, buf,
1128*042d53a7SEvalZero &attr_len, out_att_err);
1129*042d53a7SEvalZero if (rc != 0) {
1130*042d53a7SEvalZero goto done;
1131*042d53a7SEvalZero }
1132*042d53a7SEvalZero /* value is at the end of req */
1133*042d53a7SEvalZero rc = os_mbuf_cmpf(rxom, sizeof(struct ble_att_find_type_value_req),
1134*042d53a7SEvalZero buf, attr_len);
1135*042d53a7SEvalZero if (rc == 0) {
1136*042d53a7SEvalZero first = ha->ha_handle_id;
1137*042d53a7SEvalZero prev = ha->ha_handle_id;
1138*042d53a7SEvalZero }
1139*042d53a7SEvalZero }
1140*042d53a7SEvalZero }
1141*042d53a7SEvalZero
1142*042d53a7SEvalZero /* Process last group in case a group was in progress when the end of the
1143*042d53a7SEvalZero * attribute list was reached.
1144*042d53a7SEvalZero */
1145*042d53a7SEvalZero if (first) {
1146*042d53a7SEvalZero rc = ble_att_svr_fill_type_value_entry(txom, first, prev, mtu,
1147*042d53a7SEvalZero out_att_err);
1148*042d53a7SEvalZero if (rc == BLE_HS_EAGAIN) {
1149*042d53a7SEvalZero rc = 0;
1150*042d53a7SEvalZero }
1151*042d53a7SEvalZero } else {
1152*042d53a7SEvalZero rc = 0;
1153*042d53a7SEvalZero }
1154*042d53a7SEvalZero
1155*042d53a7SEvalZero done:
1156*042d53a7SEvalZero any_entries = OS_MBUF_PKTHDR(txom)->omp_len >
1157*042d53a7SEvalZero BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ;
1158*042d53a7SEvalZero if (rc == 0 && !any_entries) {
1159*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_ATTR_NOT_FOUND;
1160*042d53a7SEvalZero return BLE_HS_ENOENT;
1161*042d53a7SEvalZero } else {
1162*042d53a7SEvalZero return rc;
1163*042d53a7SEvalZero }
1164*042d53a7SEvalZero }
1165*042d53a7SEvalZero
1166*042d53a7SEvalZero static int
ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,ble_uuid16_t attr_type,struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * out_att_err)1167*042d53a7SEvalZero ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle,
1168*042d53a7SEvalZero uint16_t start_handle,
1169*042d53a7SEvalZero uint16_t end_handle,
1170*042d53a7SEvalZero ble_uuid16_t attr_type,
1171*042d53a7SEvalZero struct os_mbuf **rxom,
1172*042d53a7SEvalZero struct os_mbuf **out_txom,
1173*042d53a7SEvalZero uint8_t *out_att_err)
1174*042d53a7SEvalZero {
1175*042d53a7SEvalZero struct os_mbuf *txom;
1176*042d53a7SEvalZero uint16_t mtu;
1177*042d53a7SEvalZero uint8_t *buf;
1178*042d53a7SEvalZero int rc;
1179*042d53a7SEvalZero
1180*042d53a7SEvalZero rc = ble_att_svr_pkt(rxom, &txom, out_att_err);
1181*042d53a7SEvalZero if (rc != 0) {
1182*042d53a7SEvalZero goto done;
1183*042d53a7SEvalZero }
1184*042d53a7SEvalZero
1185*042d53a7SEvalZero /* info list is filled later on */
1186*042d53a7SEvalZero buf = ble_att_cmd_prepare(BLE_ATT_OP_FIND_TYPE_VALUE_RSP, 0, txom);
1187*042d53a7SEvalZero if (buf == NULL) {
1188*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1189*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1190*042d53a7SEvalZero goto done;
1191*042d53a7SEvalZero }
1192*042d53a7SEvalZero
1193*042d53a7SEvalZero /* Write the variable length Information Data field. */
1194*042d53a7SEvalZero mtu = ble_att_mtu(conn_handle);
1195*042d53a7SEvalZero
1196*042d53a7SEvalZero rc = ble_att_svr_fill_type_value(conn_handle, start_handle, end_handle,
1197*042d53a7SEvalZero attr_type, *rxom, txom, mtu,
1198*042d53a7SEvalZero out_att_err);
1199*042d53a7SEvalZero if (rc != 0) {
1200*042d53a7SEvalZero goto done;
1201*042d53a7SEvalZero }
1202*042d53a7SEvalZero
1203*042d53a7SEvalZero BLE_ATT_LOG_EMPTY_CMD(1, "find type value rsp", conn_handle);
1204*042d53a7SEvalZero
1205*042d53a7SEvalZero rc = 0;
1206*042d53a7SEvalZero
1207*042d53a7SEvalZero done:
1208*042d53a7SEvalZero *out_txom = txom;
1209*042d53a7SEvalZero return rc;
1210*042d53a7SEvalZero }
1211*042d53a7SEvalZero
1212*042d53a7SEvalZero int
ble_att_svr_rx_find_type_value(uint16_t conn_handle,struct os_mbuf ** rxom)1213*042d53a7SEvalZero ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom)
1214*042d53a7SEvalZero {
1215*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_FIND_TYPE)
1216*042d53a7SEvalZero return BLE_HS_ENOTSUP;
1217*042d53a7SEvalZero #endif
1218*042d53a7SEvalZero
1219*042d53a7SEvalZero struct ble_att_find_type_value_req *req;
1220*042d53a7SEvalZero uint16_t start_handle, end_handle;
1221*042d53a7SEvalZero ble_uuid16_t attr_type;
1222*042d53a7SEvalZero struct os_mbuf *txom;
1223*042d53a7SEvalZero uint16_t err_handle;
1224*042d53a7SEvalZero uint8_t att_err;
1225*042d53a7SEvalZero int rc;
1226*042d53a7SEvalZero
1227*042d53a7SEvalZero /* Initialize some values in case of early error. */
1228*042d53a7SEvalZero txom = NULL;
1229*042d53a7SEvalZero att_err = 0;
1230*042d53a7SEvalZero err_handle = 0;
1231*042d53a7SEvalZero
1232*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
1233*042d53a7SEvalZero if (rc != 0) {
1234*042d53a7SEvalZero goto done;
1235*042d53a7SEvalZero }
1236*042d53a7SEvalZero
1237*042d53a7SEvalZero req = (struct ble_att_find_type_value_req *)(*rxom)->om_data;
1238*042d53a7SEvalZero start_handle = le16toh(req->bavq_start_handle);
1239*042d53a7SEvalZero end_handle = le16toh(req->bavq_end_handle);
1240*042d53a7SEvalZero attr_type = (ble_uuid16_t) BLE_UUID16_INIT(le16toh(req->bavq_attr_type));
1241*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "find type value req", conn_handle,
1242*042d53a7SEvalZero ble_att_find_type_value_req_log, req);
1243*042d53a7SEvalZero
1244*042d53a7SEvalZero /* Tx error response if start handle is greater than end handle or is equal
1245*042d53a7SEvalZero * to 0 (Vol. 3, Part F, 3.4.3.3).
1246*042d53a7SEvalZero */
1247*042d53a7SEvalZero if (start_handle > end_handle || start_handle == 0) {
1248*042d53a7SEvalZero att_err = BLE_ATT_ERR_INVALID_HANDLE;
1249*042d53a7SEvalZero err_handle = start_handle;
1250*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
1251*042d53a7SEvalZero goto done;
1252*042d53a7SEvalZero }
1253*042d53a7SEvalZero rc = ble_att_svr_build_find_type_value_rsp(conn_handle, start_handle,
1254*042d53a7SEvalZero end_handle, attr_type, rxom,
1255*042d53a7SEvalZero &txom, &att_err);
1256*042d53a7SEvalZero if (rc != 0) {
1257*042d53a7SEvalZero err_handle = start_handle;
1258*042d53a7SEvalZero goto done;
1259*042d53a7SEvalZero }
1260*042d53a7SEvalZero
1261*042d53a7SEvalZero rc = 0;
1262*042d53a7SEvalZero
1263*042d53a7SEvalZero done:
1264*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom,
1265*042d53a7SEvalZero BLE_ATT_OP_FIND_TYPE_VALUE_REQ, att_err,
1266*042d53a7SEvalZero err_handle);
1267*042d53a7SEvalZero return rc;
1268*042d53a7SEvalZero }
1269*042d53a7SEvalZero
1270*042d53a7SEvalZero static int
ble_att_svr_build_read_type_rsp(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid,struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * att_err,uint16_t * err_handle)1271*042d53a7SEvalZero ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
1272*042d53a7SEvalZero uint16_t start_handle, uint16_t end_handle,
1273*042d53a7SEvalZero const ble_uuid_t *uuid,
1274*042d53a7SEvalZero struct os_mbuf **rxom,
1275*042d53a7SEvalZero struct os_mbuf **out_txom,
1276*042d53a7SEvalZero uint8_t *att_err,
1277*042d53a7SEvalZero uint16_t *err_handle)
1278*042d53a7SEvalZero {
1279*042d53a7SEvalZero struct ble_att_attr_data_list *data;
1280*042d53a7SEvalZero struct ble_att_read_type_rsp *rsp;
1281*042d53a7SEvalZero struct ble_att_svr_entry *entry;
1282*042d53a7SEvalZero struct os_mbuf *txom;
1283*042d53a7SEvalZero uint16_t attr_len;
1284*042d53a7SEvalZero uint16_t mtu;
1285*042d53a7SEvalZero uint8_t buf[19];
1286*042d53a7SEvalZero int entry_written;
1287*042d53a7SEvalZero int txomlen;
1288*042d53a7SEvalZero int prev_attr_len;
1289*042d53a7SEvalZero int rc;
1290*042d53a7SEvalZero
1291*042d53a7SEvalZero *att_err = 0; /* Silence unnecessary warning. */
1292*042d53a7SEvalZero
1293*042d53a7SEvalZero *err_handle = start_handle;
1294*042d53a7SEvalZero entry_written = 0;
1295*042d53a7SEvalZero prev_attr_len = 0;
1296*042d53a7SEvalZero
1297*042d53a7SEvalZero /* Just reuse the request buffer for the response. */
1298*042d53a7SEvalZero txom = *rxom;
1299*042d53a7SEvalZero *rxom = NULL;
1300*042d53a7SEvalZero os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom));
1301*042d53a7SEvalZero
1302*042d53a7SEvalZero /* Allocate space for the respose base, but don't fill in the fields. They
1303*042d53a7SEvalZero * get filled in at the end, when we know the value of the length field.
1304*042d53a7SEvalZero */
1305*042d53a7SEvalZero
1306*042d53a7SEvalZero rsp = ble_att_cmd_prepare(BLE_ATT_OP_READ_TYPE_RSP, sizeof(*rsp), txom);
1307*042d53a7SEvalZero if (rsp == NULL) {
1308*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1309*042d53a7SEvalZero *err_handle = 0;
1310*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1311*042d53a7SEvalZero goto done;
1312*042d53a7SEvalZero }
1313*042d53a7SEvalZero
1314*042d53a7SEvalZero mtu = ble_att_mtu(conn_handle);
1315*042d53a7SEvalZero
1316*042d53a7SEvalZero /* Find all matching attributes, writing a record for each. */
1317*042d53a7SEvalZero entry = NULL;
1318*042d53a7SEvalZero while (1) {
1319*042d53a7SEvalZero entry = ble_att_svr_find_by_uuid(entry, uuid, end_handle);
1320*042d53a7SEvalZero if (entry == NULL) {
1321*042d53a7SEvalZero rc = BLE_HS_ENOENT;
1322*042d53a7SEvalZero break;
1323*042d53a7SEvalZero }
1324*042d53a7SEvalZero
1325*042d53a7SEvalZero if (entry->ha_handle_id >= start_handle) {
1326*042d53a7SEvalZero rc = ble_att_svr_read_flat(conn_handle, entry, 0, sizeof buf, buf,
1327*042d53a7SEvalZero &attr_len, att_err);
1328*042d53a7SEvalZero if (rc != 0) {
1329*042d53a7SEvalZero *err_handle = entry->ha_handle_id;
1330*042d53a7SEvalZero goto done;
1331*042d53a7SEvalZero }
1332*042d53a7SEvalZero
1333*042d53a7SEvalZero if (attr_len > mtu - 4) {
1334*042d53a7SEvalZero attr_len = mtu - 4;
1335*042d53a7SEvalZero }
1336*042d53a7SEvalZero
1337*042d53a7SEvalZero if (prev_attr_len == 0) {
1338*042d53a7SEvalZero prev_attr_len = attr_len;
1339*042d53a7SEvalZero } else if (prev_attr_len != attr_len) {
1340*042d53a7SEvalZero break;
1341*042d53a7SEvalZero }
1342*042d53a7SEvalZero
1343*042d53a7SEvalZero txomlen = OS_MBUF_PKTHDR(txom)->omp_len + 2 + attr_len;
1344*042d53a7SEvalZero if (txomlen > mtu) {
1345*042d53a7SEvalZero break;
1346*042d53a7SEvalZero }
1347*042d53a7SEvalZero
1348*042d53a7SEvalZero data = os_mbuf_extend(txom, 2 + attr_len);
1349*042d53a7SEvalZero if (data == NULL) {
1350*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1351*042d53a7SEvalZero *err_handle = entry->ha_handle_id;
1352*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1353*042d53a7SEvalZero goto done;
1354*042d53a7SEvalZero }
1355*042d53a7SEvalZero
1356*042d53a7SEvalZero data->handle = htole16(entry->ha_handle_id);
1357*042d53a7SEvalZero memcpy(data->value, buf, attr_len);
1358*042d53a7SEvalZero entry_written = 1;
1359*042d53a7SEvalZero }
1360*042d53a7SEvalZero }
1361*042d53a7SEvalZero
1362*042d53a7SEvalZero done:
1363*042d53a7SEvalZero if (!entry_written) {
1364*042d53a7SEvalZero /* No matching attributes. */
1365*042d53a7SEvalZero if (*att_err == 0) {
1366*042d53a7SEvalZero *att_err = BLE_ATT_ERR_ATTR_NOT_FOUND;
1367*042d53a7SEvalZero }
1368*042d53a7SEvalZero if (rc == 0) {
1369*042d53a7SEvalZero rc = BLE_HS_ENOENT;
1370*042d53a7SEvalZero }
1371*042d53a7SEvalZero } else {
1372*042d53a7SEvalZero /* Send what we can, even if an error was encountered. */
1373*042d53a7SEvalZero rc = 0;
1374*042d53a7SEvalZero *att_err = 0;
1375*042d53a7SEvalZero
1376*042d53a7SEvalZero /* Fill the response base. */
1377*042d53a7SEvalZero rsp->batp_length = htole16(sizeof(*data) + prev_attr_len);
1378*042d53a7SEvalZero BLE_ATT_LOG_CMD(1, "read type rsp", conn_handle,
1379*042d53a7SEvalZero ble_att_read_type_rsp_log, rsp);
1380*042d53a7SEvalZero }
1381*042d53a7SEvalZero
1382*042d53a7SEvalZero *out_txom = txom;
1383*042d53a7SEvalZero
1384*042d53a7SEvalZero return rc;
1385*042d53a7SEvalZero }
1386*042d53a7SEvalZero
1387*042d53a7SEvalZero int
ble_att_svr_rx_read_type(uint16_t conn_handle,struct os_mbuf ** rxom)1388*042d53a7SEvalZero ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
1389*042d53a7SEvalZero {
1390*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_READ_TYPE)
1391*042d53a7SEvalZero return BLE_HS_ENOTSUP;
1392*042d53a7SEvalZero #endif
1393*042d53a7SEvalZero
1394*042d53a7SEvalZero struct ble_att_read_type_req *req;
1395*042d53a7SEvalZero uint16_t start_handle, end_handle;
1396*042d53a7SEvalZero struct os_mbuf *txom;
1397*042d53a7SEvalZero uint16_t err_handle;
1398*042d53a7SEvalZero uint16_t pktlen;
1399*042d53a7SEvalZero ble_uuid_any_t uuid;
1400*042d53a7SEvalZero uint8_t att_err;
1401*042d53a7SEvalZero int rc;
1402*042d53a7SEvalZero
1403*042d53a7SEvalZero /* Initialize some values in case of early error. */
1404*042d53a7SEvalZero txom = NULL;
1405*042d53a7SEvalZero err_handle = 0;
1406*042d53a7SEvalZero att_err = 0;
1407*042d53a7SEvalZero
1408*042d53a7SEvalZero pktlen = OS_MBUF_PKTLEN(*rxom);
1409*042d53a7SEvalZero if (pktlen != sizeof(*req) + 2 && pktlen != sizeof(*req) + 16) {
1410*042d53a7SEvalZero /* Malformed packet */
1411*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
1412*042d53a7SEvalZero goto done;
1413*042d53a7SEvalZero }
1414*042d53a7SEvalZero
1415*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, pktlen, &att_err);
1416*042d53a7SEvalZero if (rc != 0) {
1417*042d53a7SEvalZero goto done;
1418*042d53a7SEvalZero }
1419*042d53a7SEvalZero
1420*042d53a7SEvalZero req = (struct ble_att_read_type_req *)(*rxom)->om_data;
1421*042d53a7SEvalZero
1422*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "read type req", conn_handle, ble_att_read_type_req_log,
1423*042d53a7SEvalZero req);
1424*042d53a7SEvalZero
1425*042d53a7SEvalZero start_handle = le16toh(req->batq_start_handle);
1426*042d53a7SEvalZero end_handle = le16toh(req->batq_end_handle);
1427*042d53a7SEvalZero
1428*042d53a7SEvalZero if (start_handle > end_handle || start_handle == 0) {
1429*042d53a7SEvalZero att_err = BLE_ATT_ERR_INVALID_HANDLE;
1430*042d53a7SEvalZero err_handle = start_handle;
1431*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
1432*042d53a7SEvalZero goto done;
1433*042d53a7SEvalZero }
1434*042d53a7SEvalZero
1435*042d53a7SEvalZero rc = ble_uuid_init_from_att_mbuf(&uuid, *rxom, sizeof(*req),
1436*042d53a7SEvalZero pktlen - sizeof(*req));
1437*042d53a7SEvalZero if (rc != 0) {
1438*042d53a7SEvalZero att_err = BLE_ATT_ERR_INVALID_PDU;
1439*042d53a7SEvalZero rc = BLE_HS_EMSGSIZE;
1440*042d53a7SEvalZero goto done;
1441*042d53a7SEvalZero }
1442*042d53a7SEvalZero
1443*042d53a7SEvalZero rc = ble_att_svr_build_read_type_rsp(conn_handle, start_handle, end_handle,
1444*042d53a7SEvalZero &uuid.u, rxom, &txom, &att_err,
1445*042d53a7SEvalZero &err_handle);
1446*042d53a7SEvalZero if (rc != 0) {
1447*042d53a7SEvalZero goto done;
1448*042d53a7SEvalZero }
1449*042d53a7SEvalZero
1450*042d53a7SEvalZero rc = 0;
1451*042d53a7SEvalZero
1452*042d53a7SEvalZero done:
1453*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_TYPE_REQ,
1454*042d53a7SEvalZero att_err, err_handle);
1455*042d53a7SEvalZero return rc;
1456*042d53a7SEvalZero }
1457*042d53a7SEvalZero
1458*042d53a7SEvalZero int
ble_att_svr_rx_read(uint16_t conn_handle,struct os_mbuf ** rxom)1459*042d53a7SEvalZero ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
1460*042d53a7SEvalZero {
1461*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_READ)
1462*042d53a7SEvalZero return BLE_HS_ENOTSUP;
1463*042d53a7SEvalZero #endif
1464*042d53a7SEvalZero
1465*042d53a7SEvalZero struct ble_att_read_req *req;
1466*042d53a7SEvalZero struct os_mbuf *txom;
1467*042d53a7SEvalZero uint16_t err_handle;
1468*042d53a7SEvalZero uint8_t att_err;
1469*042d53a7SEvalZero int rc;
1470*042d53a7SEvalZero
1471*042d53a7SEvalZero /* Initialize some values in case of early error. */
1472*042d53a7SEvalZero txom = NULL;
1473*042d53a7SEvalZero att_err = 0;
1474*042d53a7SEvalZero err_handle = 0;
1475*042d53a7SEvalZero
1476*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
1477*042d53a7SEvalZero if (rc != 0) {
1478*042d53a7SEvalZero goto done;
1479*042d53a7SEvalZero }
1480*042d53a7SEvalZero
1481*042d53a7SEvalZero req = (struct ble_att_read_req *)(*rxom)->om_data;
1482*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "read req", conn_handle, ble_att_read_req_log, req);
1483*042d53a7SEvalZero
1484*042d53a7SEvalZero err_handle = le16toh(req->barq_handle);
1485*042d53a7SEvalZero
1486*042d53a7SEvalZero /* Just reuse the request buffer for the response. */
1487*042d53a7SEvalZero txom = *rxom;
1488*042d53a7SEvalZero *rxom = NULL;
1489*042d53a7SEvalZero os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom));
1490*042d53a7SEvalZero
1491*042d53a7SEvalZero if (ble_att_cmd_prepare(BLE_ATT_OP_READ_RSP, 0, txom) == NULL) {
1492*042d53a7SEvalZero att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1493*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1494*042d53a7SEvalZero goto done;
1495*042d53a7SEvalZero }
1496*042d53a7SEvalZero
1497*042d53a7SEvalZero rc = ble_att_svr_read_handle(conn_handle, err_handle, 0, txom, &att_err);
1498*042d53a7SEvalZero if (rc != 0) {
1499*042d53a7SEvalZero goto done;
1500*042d53a7SEvalZero }
1501*042d53a7SEvalZero
1502*042d53a7SEvalZero done:
1503*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_REQ,
1504*042d53a7SEvalZero att_err, err_handle);
1505*042d53a7SEvalZero return rc;
1506*042d53a7SEvalZero }
1507*042d53a7SEvalZero
1508*042d53a7SEvalZero int
ble_att_svr_rx_read_blob(uint16_t conn_handle,struct os_mbuf ** rxom)1509*042d53a7SEvalZero ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
1510*042d53a7SEvalZero {
1511*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_READ_BLOB)
1512*042d53a7SEvalZero return BLE_HS_ENOTSUP;
1513*042d53a7SEvalZero #endif
1514*042d53a7SEvalZero
1515*042d53a7SEvalZero struct ble_att_read_blob_req *req;
1516*042d53a7SEvalZero struct os_mbuf *txom;
1517*042d53a7SEvalZero uint16_t err_handle, offset;
1518*042d53a7SEvalZero uint8_t att_err;
1519*042d53a7SEvalZero int rc;
1520*042d53a7SEvalZero
1521*042d53a7SEvalZero /* Initialize some values in case of early error. */
1522*042d53a7SEvalZero txom = NULL;
1523*042d53a7SEvalZero att_err = 0;
1524*042d53a7SEvalZero err_handle = 0;
1525*042d53a7SEvalZero
1526*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
1527*042d53a7SEvalZero if (rc != 0) {
1528*042d53a7SEvalZero goto done;
1529*042d53a7SEvalZero }
1530*042d53a7SEvalZero
1531*042d53a7SEvalZero req = (struct ble_att_read_blob_req *)(*rxom)->om_data;
1532*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "read blob req", conn_handle, ble_att_read_blob_req_log,
1533*042d53a7SEvalZero req);
1534*042d53a7SEvalZero
1535*042d53a7SEvalZero err_handle = le16toh(req->babq_handle);
1536*042d53a7SEvalZero offset = le16toh(req->babq_offset);
1537*042d53a7SEvalZero
1538*042d53a7SEvalZero /* Just reuse the request buffer for the response. */
1539*042d53a7SEvalZero txom = *rxom;
1540*042d53a7SEvalZero *rxom = NULL;
1541*042d53a7SEvalZero os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom));
1542*042d53a7SEvalZero
1543*042d53a7SEvalZero if (ble_att_cmd_prepare(BLE_ATT_OP_READ_BLOB_RSP, 0, txom) == NULL) {
1544*042d53a7SEvalZero att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1545*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1546*042d53a7SEvalZero goto done;
1547*042d53a7SEvalZero }
1548*042d53a7SEvalZero
1549*042d53a7SEvalZero rc = ble_att_svr_read_handle(conn_handle, err_handle, offset,
1550*042d53a7SEvalZero txom, &att_err);
1551*042d53a7SEvalZero if (rc != 0) {
1552*042d53a7SEvalZero goto done;
1553*042d53a7SEvalZero }
1554*042d53a7SEvalZero
1555*042d53a7SEvalZero BLE_ATT_LOG_EMPTY_CMD(1, "read blob rsp", conn_handle);
1556*042d53a7SEvalZero
1557*042d53a7SEvalZero rc = 0;
1558*042d53a7SEvalZero
1559*042d53a7SEvalZero done:
1560*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_BLOB_REQ,
1561*042d53a7SEvalZero att_err, err_handle);
1562*042d53a7SEvalZero return rc;
1563*042d53a7SEvalZero }
1564*042d53a7SEvalZero
1565*042d53a7SEvalZero static int
ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * att_err,uint16_t * err_handle)1566*042d53a7SEvalZero ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
1567*042d53a7SEvalZero struct os_mbuf **rxom,
1568*042d53a7SEvalZero struct os_mbuf **out_txom,
1569*042d53a7SEvalZero uint8_t *att_err,
1570*042d53a7SEvalZero uint16_t *err_handle)
1571*042d53a7SEvalZero {
1572*042d53a7SEvalZero struct os_mbuf *txom;
1573*042d53a7SEvalZero uint16_t handle;
1574*042d53a7SEvalZero uint16_t mtu;
1575*042d53a7SEvalZero int rc;
1576*042d53a7SEvalZero
1577*042d53a7SEvalZero mtu = ble_att_mtu(conn_handle);
1578*042d53a7SEvalZero
1579*042d53a7SEvalZero rc = ble_att_svr_pkt(rxom, &txom, att_err);
1580*042d53a7SEvalZero if (rc != 0) {
1581*042d53a7SEvalZero *err_handle = 0;
1582*042d53a7SEvalZero goto done;
1583*042d53a7SEvalZero }
1584*042d53a7SEvalZero
1585*042d53a7SEvalZero if (ble_att_cmd_prepare(BLE_ATT_OP_READ_MULT_RSP, 0, txom) == NULL) {
1586*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1587*042d53a7SEvalZero *err_handle = 0;
1588*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1589*042d53a7SEvalZero goto done;
1590*042d53a7SEvalZero }
1591*042d53a7SEvalZero
1592*042d53a7SEvalZero /* Iterate through requested handles, reading the corresponding attribute
1593*042d53a7SEvalZero * for each. Stop when there are no more handles to process, or the
1594*042d53a7SEvalZero * response is full.
1595*042d53a7SEvalZero */
1596*042d53a7SEvalZero while (OS_MBUF_PKTLEN(*rxom) >= 2 && OS_MBUF_PKTLEN(txom) < mtu) {
1597*042d53a7SEvalZero /* Ensure the full 16-bit handle is contiguous at the start of the
1598*042d53a7SEvalZero * mbuf.
1599*042d53a7SEvalZero */
1600*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, 2, att_err);
1601*042d53a7SEvalZero if (rc != 0) {
1602*042d53a7SEvalZero *err_handle = 0;
1603*042d53a7SEvalZero goto done;
1604*042d53a7SEvalZero }
1605*042d53a7SEvalZero
1606*042d53a7SEvalZero /* Extract the 16-bit handle and strip it from the front of the
1607*042d53a7SEvalZero * mbuf.
1608*042d53a7SEvalZero */
1609*042d53a7SEvalZero handle = get_le16((*rxom)->om_data);
1610*042d53a7SEvalZero os_mbuf_adj(*rxom, 2);
1611*042d53a7SEvalZero
1612*042d53a7SEvalZero rc = ble_att_svr_read_handle(conn_handle, handle, 0, txom, att_err);
1613*042d53a7SEvalZero if (rc != 0) {
1614*042d53a7SEvalZero *err_handle = handle;
1615*042d53a7SEvalZero goto done;
1616*042d53a7SEvalZero }
1617*042d53a7SEvalZero }
1618*042d53a7SEvalZero
1619*042d53a7SEvalZero BLE_ATT_LOG_EMPTY_CMD(1, "read mult rsp", conn_handle);
1620*042d53a7SEvalZero rc = 0;
1621*042d53a7SEvalZero
1622*042d53a7SEvalZero done:
1623*042d53a7SEvalZero *out_txom = txom;
1624*042d53a7SEvalZero return rc;
1625*042d53a7SEvalZero }
1626*042d53a7SEvalZero
1627*042d53a7SEvalZero int
ble_att_svr_rx_read_mult(uint16_t conn_handle,struct os_mbuf ** rxom)1628*042d53a7SEvalZero ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
1629*042d53a7SEvalZero {
1630*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_READ_MULT)
1631*042d53a7SEvalZero return BLE_HS_ENOTSUP;
1632*042d53a7SEvalZero #endif
1633*042d53a7SEvalZero
1634*042d53a7SEvalZero struct os_mbuf *txom;
1635*042d53a7SEvalZero uint16_t err_handle;
1636*042d53a7SEvalZero uint8_t att_err;
1637*042d53a7SEvalZero int rc;
1638*042d53a7SEvalZero
1639*042d53a7SEvalZero BLE_ATT_LOG_EMPTY_CMD(0, "read mult req", conn_handle);
1640*042d53a7SEvalZero
1641*042d53a7SEvalZero /* Initialize some values in case of early error. */
1642*042d53a7SEvalZero txom = NULL;
1643*042d53a7SEvalZero err_handle = 0;
1644*042d53a7SEvalZero att_err = 0;
1645*042d53a7SEvalZero
1646*042d53a7SEvalZero rc = ble_att_svr_build_read_mult_rsp(conn_handle, rxom, &txom, &att_err,
1647*042d53a7SEvalZero &err_handle);
1648*042d53a7SEvalZero
1649*042d53a7SEvalZero return ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_MULT_REQ,
1650*042d53a7SEvalZero att_err, err_handle);
1651*042d53a7SEvalZero }
1652*042d53a7SEvalZero
1653*042d53a7SEvalZero static int
ble_att_svr_is_valid_read_group_type(const ble_uuid_t * uuid)1654*042d53a7SEvalZero ble_att_svr_is_valid_read_group_type(const ble_uuid_t *uuid)
1655*042d53a7SEvalZero {
1656*042d53a7SEvalZero uint16_t uuid16;
1657*042d53a7SEvalZero
1658*042d53a7SEvalZero uuid16 = ble_uuid_u16(uuid);
1659*042d53a7SEvalZero
1660*042d53a7SEvalZero return uuid16 == BLE_ATT_UUID_PRIMARY_SERVICE ||
1661*042d53a7SEvalZero uuid16 == BLE_ATT_UUID_SECONDARY_SERVICE;
1662*042d53a7SEvalZero }
1663*042d53a7SEvalZero
1664*042d53a7SEvalZero static int
ble_att_svr_service_uuid(struct ble_att_svr_entry * entry,ble_uuid_any_t * uuid,uint8_t * out_att_err)1665*042d53a7SEvalZero ble_att_svr_service_uuid(struct ble_att_svr_entry *entry,
1666*042d53a7SEvalZero ble_uuid_any_t *uuid, uint8_t *out_att_err)
1667*042d53a7SEvalZero {
1668*042d53a7SEvalZero uint8_t val[16];
1669*042d53a7SEvalZero uint16_t attr_len;
1670*042d53a7SEvalZero int rc;
1671*042d53a7SEvalZero
1672*042d53a7SEvalZero rc = ble_att_svr_read_flat(BLE_HS_CONN_HANDLE_NONE, entry, 0, sizeof(val), val,
1673*042d53a7SEvalZero &attr_len, out_att_err);
1674*042d53a7SEvalZero if (rc != 0) {
1675*042d53a7SEvalZero return rc;
1676*042d53a7SEvalZero }
1677*042d53a7SEvalZero
1678*042d53a7SEvalZero rc = ble_uuid_init_from_buf(uuid, val, attr_len);
1679*042d53a7SEvalZero
1680*042d53a7SEvalZero return rc;
1681*042d53a7SEvalZero }
1682*042d53a7SEvalZero
1683*042d53a7SEvalZero static int
ble_att_svr_read_group_type_entry_write(struct os_mbuf * om,uint16_t mtu,uint16_t start_group_handle,uint16_t end_group_handle,const ble_uuid_t * service_uuid)1684*042d53a7SEvalZero ble_att_svr_read_group_type_entry_write(struct os_mbuf *om, uint16_t mtu,
1685*042d53a7SEvalZero uint16_t start_group_handle,
1686*042d53a7SEvalZero uint16_t end_group_handle,
1687*042d53a7SEvalZero const ble_uuid_t *service_uuid)
1688*042d53a7SEvalZero {
1689*042d53a7SEvalZero uint8_t *buf;
1690*042d53a7SEvalZero int len;
1691*042d53a7SEvalZero
1692*042d53a7SEvalZero if (service_uuid->type == BLE_UUID_TYPE_16) {
1693*042d53a7SEvalZero len = BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16;
1694*042d53a7SEvalZero } else {
1695*042d53a7SEvalZero len = BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128;
1696*042d53a7SEvalZero }
1697*042d53a7SEvalZero if (OS_MBUF_PKTLEN(om) + len > mtu) {
1698*042d53a7SEvalZero return BLE_HS_EMSGSIZE;
1699*042d53a7SEvalZero }
1700*042d53a7SEvalZero
1701*042d53a7SEvalZero buf = os_mbuf_extend(om, len);
1702*042d53a7SEvalZero if (buf == NULL) {
1703*042d53a7SEvalZero return BLE_HS_ENOMEM;
1704*042d53a7SEvalZero }
1705*042d53a7SEvalZero
1706*042d53a7SEvalZero put_le16(buf + 0, start_group_handle);
1707*042d53a7SEvalZero put_le16(buf + 2, end_group_handle);
1708*042d53a7SEvalZero ble_uuid_flat(service_uuid, buf + 4);
1709*042d53a7SEvalZero
1710*042d53a7SEvalZero return 0;
1711*042d53a7SEvalZero }
1712*042d53a7SEvalZero
1713*042d53a7SEvalZero /**
1714*042d53a7SEvalZero * @return 0 on success; BLE_HS error code on failure.
1715*042d53a7SEvalZero */
1716*042d53a7SEvalZero static int
ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * group_uuid,struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * att_err,uint16_t * err_handle)1717*042d53a7SEvalZero ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle,
1718*042d53a7SEvalZero uint16_t start_handle,
1719*042d53a7SEvalZero uint16_t end_handle,
1720*042d53a7SEvalZero const ble_uuid_t *group_uuid,
1721*042d53a7SEvalZero struct os_mbuf **rxom,
1722*042d53a7SEvalZero struct os_mbuf **out_txom,
1723*042d53a7SEvalZero uint8_t *att_err,
1724*042d53a7SEvalZero uint16_t *err_handle)
1725*042d53a7SEvalZero {
1726*042d53a7SEvalZero struct ble_att_read_group_type_rsp *rsp;
1727*042d53a7SEvalZero struct ble_att_svr_entry *entry;
1728*042d53a7SEvalZero struct os_mbuf *txom;
1729*042d53a7SEvalZero uint16_t start_group_handle;
1730*042d53a7SEvalZero uint16_t end_group_handle;
1731*042d53a7SEvalZero uint16_t mtu;
1732*042d53a7SEvalZero ble_uuid_any_t service_uuid;
1733*042d53a7SEvalZero int rc;
1734*042d53a7SEvalZero
1735*042d53a7SEvalZero /* Silence warnings. */
1736*042d53a7SEvalZero end_group_handle = 0;
1737*042d53a7SEvalZero
1738*042d53a7SEvalZero *att_err = 0;
1739*042d53a7SEvalZero *err_handle = start_handle;
1740*042d53a7SEvalZero
1741*042d53a7SEvalZero mtu = ble_att_mtu(conn_handle);
1742*042d53a7SEvalZero
1743*042d53a7SEvalZero /* Just reuse the request buffer for the response. */
1744*042d53a7SEvalZero txom = *rxom;
1745*042d53a7SEvalZero *rxom = NULL;
1746*042d53a7SEvalZero os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom));
1747*042d53a7SEvalZero
1748*042d53a7SEvalZero /* Reserve space for the response base. */
1749*042d53a7SEvalZero rsp = ble_att_cmd_prepare(BLE_ATT_OP_READ_GROUP_TYPE_RSP, sizeof(*rsp),
1750*042d53a7SEvalZero txom);
1751*042d53a7SEvalZero if (rsp == NULL) {
1752*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1753*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1754*042d53a7SEvalZero goto done;
1755*042d53a7SEvalZero }
1756*042d53a7SEvalZero
1757*042d53a7SEvalZero start_group_handle = 0;
1758*042d53a7SEvalZero rsp->bagp_length = 0;
1759*042d53a7SEvalZero STAILQ_FOREACH(entry, &ble_att_svr_list, ha_next) {
1760*042d53a7SEvalZero if (entry->ha_handle_id < start_handle) {
1761*042d53a7SEvalZero continue;
1762*042d53a7SEvalZero }
1763*042d53a7SEvalZero if (entry->ha_handle_id > end_handle) {
1764*042d53a7SEvalZero /* The full input range has been searched. */
1765*042d53a7SEvalZero rc = 0;
1766*042d53a7SEvalZero goto done;
1767*042d53a7SEvalZero }
1768*042d53a7SEvalZero
1769*042d53a7SEvalZero if (start_group_handle != 0) {
1770*042d53a7SEvalZero /* We have already found the start of a group. */
1771*042d53a7SEvalZero if (!ble_att_svr_is_valid_read_group_type(entry->ha_uuid)) {
1772*042d53a7SEvalZero /* This attribute is part of the current group. */
1773*042d53a7SEvalZero end_group_handle = entry->ha_handle_id;
1774*042d53a7SEvalZero } else {
1775*042d53a7SEvalZero /* This attribute marks the end of the group. Write an entry
1776*042d53a7SEvalZero * representing the group to the response.
1777*042d53a7SEvalZero */
1778*042d53a7SEvalZero rc = ble_att_svr_read_group_type_entry_write(
1779*042d53a7SEvalZero txom, mtu, start_group_handle, end_group_handle,
1780*042d53a7SEvalZero &service_uuid.u);
1781*042d53a7SEvalZero start_group_handle = 0;
1782*042d53a7SEvalZero end_group_handle = 0;
1783*042d53a7SEvalZero if (rc != 0) {
1784*042d53a7SEvalZero *err_handle = entry->ha_handle_id;
1785*042d53a7SEvalZero if (rc == BLE_HS_ENOMEM) {
1786*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1787*042d53a7SEvalZero } else {
1788*042d53a7SEvalZero BLE_HS_DBG_ASSERT(rc == BLE_HS_EMSGSIZE);
1789*042d53a7SEvalZero }
1790*042d53a7SEvalZero goto done;
1791*042d53a7SEvalZero }
1792*042d53a7SEvalZero }
1793*042d53a7SEvalZero }
1794*042d53a7SEvalZero
1795*042d53a7SEvalZero if (start_group_handle == 0) {
1796*042d53a7SEvalZero /* We are looking for the start of a group. */
1797*042d53a7SEvalZero if (ble_uuid_cmp(entry->ha_uuid, group_uuid) == 0) {
1798*042d53a7SEvalZero /* Found a group start. Read the group UUID. */
1799*042d53a7SEvalZero rc = ble_att_svr_service_uuid(entry, &service_uuid, att_err);
1800*042d53a7SEvalZero if (rc != 0) {
1801*042d53a7SEvalZero *err_handle = entry->ha_handle_id;
1802*042d53a7SEvalZero goto done;
1803*042d53a7SEvalZero }
1804*042d53a7SEvalZero
1805*042d53a7SEvalZero /* Make sure the group UUID lengths are consistent. If this
1806*042d53a7SEvalZero * group has a different length UUID, then cut the response
1807*042d53a7SEvalZero * short.
1808*042d53a7SEvalZero */
1809*042d53a7SEvalZero switch (rsp->bagp_length) {
1810*042d53a7SEvalZero case 0:
1811*042d53a7SEvalZero if (service_uuid.u.type == BLE_UUID_TYPE_16) {
1812*042d53a7SEvalZero rsp->bagp_length = BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16;
1813*042d53a7SEvalZero } else {
1814*042d53a7SEvalZero rsp->bagp_length = BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128;
1815*042d53a7SEvalZero }
1816*042d53a7SEvalZero break;
1817*042d53a7SEvalZero
1818*042d53a7SEvalZero case BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16:
1819*042d53a7SEvalZero if (service_uuid.u.type != BLE_UUID_TYPE_16) {
1820*042d53a7SEvalZero rc = 0;
1821*042d53a7SEvalZero goto done;
1822*042d53a7SEvalZero }
1823*042d53a7SEvalZero break;
1824*042d53a7SEvalZero
1825*042d53a7SEvalZero case BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128:
1826*042d53a7SEvalZero if (service_uuid.u.type == BLE_UUID_TYPE_16) {
1827*042d53a7SEvalZero rc = 0;
1828*042d53a7SEvalZero goto done;
1829*042d53a7SEvalZero }
1830*042d53a7SEvalZero break;
1831*042d53a7SEvalZero
1832*042d53a7SEvalZero default:
1833*042d53a7SEvalZero BLE_HS_DBG_ASSERT(0);
1834*042d53a7SEvalZero goto done;
1835*042d53a7SEvalZero }
1836*042d53a7SEvalZero
1837*042d53a7SEvalZero start_group_handle = entry->ha_handle_id;
1838*042d53a7SEvalZero end_group_handle = entry->ha_handle_id;
1839*042d53a7SEvalZero }
1840*042d53a7SEvalZero }
1841*042d53a7SEvalZero }
1842*042d53a7SEvalZero
1843*042d53a7SEvalZero rc = 0;
1844*042d53a7SEvalZero
1845*042d53a7SEvalZero done:
1846*042d53a7SEvalZero if (rc == 0) {
1847*042d53a7SEvalZero if (start_group_handle != 0) {
1848*042d53a7SEvalZero /* A group was being processed. Add its corresponding entry to the
1849*042d53a7SEvalZero * response.
1850*042d53a7SEvalZero */
1851*042d53a7SEvalZero
1852*042d53a7SEvalZero if (entry == NULL) {
1853*042d53a7SEvalZero /* We have reached the end of the attribute list. Indicate an
1854*042d53a7SEvalZero * end handle of 0xffff so that the client knows there are no
1855*042d53a7SEvalZero * more attributes without needing to send a follow-up request.
1856*042d53a7SEvalZero */
1857*042d53a7SEvalZero end_group_handle = 0xffff;
1858*042d53a7SEvalZero }
1859*042d53a7SEvalZero
1860*042d53a7SEvalZero rc = ble_att_svr_read_group_type_entry_write(txom, mtu,
1861*042d53a7SEvalZero start_group_handle,
1862*042d53a7SEvalZero end_group_handle,
1863*042d53a7SEvalZero &service_uuid.u);
1864*042d53a7SEvalZero if (rc == BLE_HS_ENOMEM) {
1865*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1866*042d53a7SEvalZero }
1867*042d53a7SEvalZero }
1868*042d53a7SEvalZero
1869*042d53a7SEvalZero if (OS_MBUF_PKTLEN(txom) <= BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ) {
1870*042d53a7SEvalZero *att_err = BLE_ATT_ERR_ATTR_NOT_FOUND;
1871*042d53a7SEvalZero rc = BLE_HS_ENOENT;
1872*042d53a7SEvalZero }
1873*042d53a7SEvalZero }
1874*042d53a7SEvalZero
1875*042d53a7SEvalZero if (rc == 0 || rc == BLE_HS_EMSGSIZE) {
1876*042d53a7SEvalZero BLE_ATT_LOG_CMD(1, "read group type rsp", conn_handle,
1877*042d53a7SEvalZero ble_att_read_group_type_rsp_log, rsp);
1878*042d53a7SEvalZero rc = 0;
1879*042d53a7SEvalZero }
1880*042d53a7SEvalZero
1881*042d53a7SEvalZero *out_txom = txom;
1882*042d53a7SEvalZero return rc;
1883*042d53a7SEvalZero }
1884*042d53a7SEvalZero
1885*042d53a7SEvalZero int
ble_att_svr_rx_read_group_type(uint16_t conn_handle,struct os_mbuf ** rxom)1886*042d53a7SEvalZero ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom)
1887*042d53a7SEvalZero {
1888*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_READ_GROUP_TYPE)
1889*042d53a7SEvalZero return BLE_HS_ENOTSUP;
1890*042d53a7SEvalZero #endif
1891*042d53a7SEvalZero
1892*042d53a7SEvalZero struct ble_att_read_group_type_req *req;
1893*042d53a7SEvalZero struct os_mbuf *txom;
1894*042d53a7SEvalZero ble_uuid_any_t uuid;
1895*042d53a7SEvalZero uint16_t err_handle, start_handle, end_handle;
1896*042d53a7SEvalZero uint16_t pktlen;
1897*042d53a7SEvalZero uint8_t att_err;
1898*042d53a7SEvalZero int om_uuid_len;
1899*042d53a7SEvalZero int rc;
1900*042d53a7SEvalZero
1901*042d53a7SEvalZero /* Initialize some values in case of early error. */
1902*042d53a7SEvalZero txom = NULL;
1903*042d53a7SEvalZero err_handle = 0;
1904*042d53a7SEvalZero att_err = 0;
1905*042d53a7SEvalZero
1906*042d53a7SEvalZero pktlen = OS_MBUF_PKTLEN(*rxom);
1907*042d53a7SEvalZero if (pktlen != sizeof(*req) + 2 && pktlen != sizeof(*req) + 16) {
1908*042d53a7SEvalZero /* Malformed packet */
1909*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
1910*042d53a7SEvalZero goto done;
1911*042d53a7SEvalZero }
1912*042d53a7SEvalZero
1913*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, pktlen, &att_err);
1914*042d53a7SEvalZero if (rc != 0) {
1915*042d53a7SEvalZero goto done;
1916*042d53a7SEvalZero }
1917*042d53a7SEvalZero
1918*042d53a7SEvalZero req = (struct ble_att_read_group_type_req *)(*rxom)->om_data;
1919*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "read group type req", conn_handle,
1920*042d53a7SEvalZero ble_att_read_group_type_req_log, req);
1921*042d53a7SEvalZero
1922*042d53a7SEvalZero start_handle = le16toh(req->bagq_start_handle);
1923*042d53a7SEvalZero end_handle = le16toh(req->bagq_end_handle);
1924*042d53a7SEvalZero
1925*042d53a7SEvalZero if (start_handle > end_handle || start_handle == 0) {
1926*042d53a7SEvalZero att_err = BLE_ATT_ERR_INVALID_HANDLE;
1927*042d53a7SEvalZero err_handle = start_handle;
1928*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
1929*042d53a7SEvalZero goto done;
1930*042d53a7SEvalZero }
1931*042d53a7SEvalZero
1932*042d53a7SEvalZero om_uuid_len = OS_MBUF_PKTHDR(*rxom)->omp_len - sizeof(*req);
1933*042d53a7SEvalZero rc = ble_uuid_init_from_att_mbuf(&uuid, *rxom, sizeof(*req), om_uuid_len);
1934*042d53a7SEvalZero if (rc != 0) {
1935*042d53a7SEvalZero att_err = BLE_ATT_ERR_INVALID_PDU;
1936*042d53a7SEvalZero err_handle = start_handle;
1937*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
1938*042d53a7SEvalZero goto done;
1939*042d53a7SEvalZero }
1940*042d53a7SEvalZero
1941*042d53a7SEvalZero if (!ble_att_svr_is_valid_read_group_type(&uuid.u)) {
1942*042d53a7SEvalZero att_err = BLE_ATT_ERR_UNSUPPORTED_GROUP;
1943*042d53a7SEvalZero err_handle = start_handle;
1944*042d53a7SEvalZero rc = BLE_HS_EREJECT;
1945*042d53a7SEvalZero goto done;
1946*042d53a7SEvalZero }
1947*042d53a7SEvalZero
1948*042d53a7SEvalZero rc = ble_att_svr_build_read_group_type_rsp(conn_handle, start_handle,
1949*042d53a7SEvalZero end_handle, &uuid.u,
1950*042d53a7SEvalZero rxom, &txom, &att_err,
1951*042d53a7SEvalZero &err_handle);
1952*042d53a7SEvalZero if (rc != 0) {
1953*042d53a7SEvalZero goto done;
1954*042d53a7SEvalZero }
1955*042d53a7SEvalZero
1956*042d53a7SEvalZero rc = 0;
1957*042d53a7SEvalZero
1958*042d53a7SEvalZero done:
1959*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom,
1960*042d53a7SEvalZero BLE_ATT_OP_READ_GROUP_TYPE_REQ, att_err,
1961*042d53a7SEvalZero err_handle);
1962*042d53a7SEvalZero return rc;
1963*042d53a7SEvalZero }
1964*042d53a7SEvalZero
1965*042d53a7SEvalZero static int
ble_att_svr_build_write_rsp(struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * att_err)1966*042d53a7SEvalZero ble_att_svr_build_write_rsp(struct os_mbuf **rxom, struct os_mbuf **out_txom,
1967*042d53a7SEvalZero uint8_t *att_err)
1968*042d53a7SEvalZero {
1969*042d53a7SEvalZero struct os_mbuf *txom;
1970*042d53a7SEvalZero int rc;
1971*042d53a7SEvalZero
1972*042d53a7SEvalZero /* Allocate a new buffer for the response. A write response never reuses
1973*042d53a7SEvalZero * the request buffer. See the note at the top of this file for details.
1974*042d53a7SEvalZero */
1975*042d53a7SEvalZero rc = ble_att_svr_pkt(rxom, &txom, att_err);
1976*042d53a7SEvalZero if (rc != 0) {
1977*042d53a7SEvalZero goto done;
1978*042d53a7SEvalZero }
1979*042d53a7SEvalZero
1980*042d53a7SEvalZero if (ble_att_cmd_prepare(BLE_ATT_OP_WRITE_RSP, 0, txom) == NULL) {
1981*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
1982*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
1983*042d53a7SEvalZero goto done;
1984*042d53a7SEvalZero }
1985*042d53a7SEvalZero
1986*042d53a7SEvalZero rc = 0;
1987*042d53a7SEvalZero
1988*042d53a7SEvalZero done:
1989*042d53a7SEvalZero *out_txom = txom;
1990*042d53a7SEvalZero return rc;
1991*042d53a7SEvalZero }
1992*042d53a7SEvalZero
1993*042d53a7SEvalZero int
ble_att_svr_rx_write(uint16_t conn_handle,struct os_mbuf ** rxom)1994*042d53a7SEvalZero ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
1995*042d53a7SEvalZero {
1996*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_WRITE)
1997*042d53a7SEvalZero return BLE_HS_ENOTSUP;
1998*042d53a7SEvalZero #endif
1999*042d53a7SEvalZero
2000*042d53a7SEvalZero struct ble_att_write_req *req;
2001*042d53a7SEvalZero struct os_mbuf *txom;
2002*042d53a7SEvalZero uint16_t handle;
2003*042d53a7SEvalZero uint8_t att_err;
2004*042d53a7SEvalZero int rc;
2005*042d53a7SEvalZero
2006*042d53a7SEvalZero /* Initialize some values in case of early error. */
2007*042d53a7SEvalZero txom = NULL;
2008*042d53a7SEvalZero att_err = 0;
2009*042d53a7SEvalZero handle = 0;
2010*042d53a7SEvalZero
2011*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
2012*042d53a7SEvalZero if (rc != 0) {
2013*042d53a7SEvalZero goto done;
2014*042d53a7SEvalZero }
2015*042d53a7SEvalZero
2016*042d53a7SEvalZero req = (struct ble_att_write_req *)(*rxom)->om_data;
2017*042d53a7SEvalZero
2018*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "write req", conn_handle,
2019*042d53a7SEvalZero ble_att_write_req_log, req);
2020*042d53a7SEvalZero
2021*042d53a7SEvalZero handle = le16toh(req->bawq_handle);
2022*042d53a7SEvalZero
2023*042d53a7SEvalZero /* Allocate the write response. This must be done prior to processing the
2024*042d53a7SEvalZero * request. See the note at the top of this file for details.
2025*042d53a7SEvalZero */
2026*042d53a7SEvalZero rc = ble_att_svr_build_write_rsp(rxom, &txom, &att_err);
2027*042d53a7SEvalZero if (rc != 0) {
2028*042d53a7SEvalZero goto done;
2029*042d53a7SEvalZero }
2030*042d53a7SEvalZero
2031*042d53a7SEvalZero /* Strip the request base from the front of the mbuf. */
2032*042d53a7SEvalZero os_mbuf_adj(*rxom, sizeof(*req));
2033*042d53a7SEvalZero
2034*042d53a7SEvalZero rc = ble_att_svr_write_handle(conn_handle, handle, 0, rxom, &att_err);
2035*042d53a7SEvalZero if (rc != 0) {
2036*042d53a7SEvalZero goto done;
2037*042d53a7SEvalZero }
2038*042d53a7SEvalZero
2039*042d53a7SEvalZero BLE_ATT_LOG_EMPTY_CMD(1, "write rsp", conn_handle);
2040*042d53a7SEvalZero
2041*042d53a7SEvalZero rc = 0;
2042*042d53a7SEvalZero
2043*042d53a7SEvalZero done:
2044*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_WRITE_REQ,
2045*042d53a7SEvalZero att_err, handle);
2046*042d53a7SEvalZero return rc;
2047*042d53a7SEvalZero }
2048*042d53a7SEvalZero
2049*042d53a7SEvalZero int
ble_att_svr_rx_write_no_rsp(uint16_t conn_handle,struct os_mbuf ** rxom)2050*042d53a7SEvalZero ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
2051*042d53a7SEvalZero {
2052*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_WRITE_NO_RSP)
2053*042d53a7SEvalZero return BLE_HS_ENOTSUP;
2054*042d53a7SEvalZero #endif
2055*042d53a7SEvalZero
2056*042d53a7SEvalZero struct ble_att_write_req *req;
2057*042d53a7SEvalZero uint8_t att_err;
2058*042d53a7SEvalZero uint16_t handle;
2059*042d53a7SEvalZero int rc;
2060*042d53a7SEvalZero
2061*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
2062*042d53a7SEvalZero if (rc != 0) {
2063*042d53a7SEvalZero return rc;
2064*042d53a7SEvalZero }
2065*042d53a7SEvalZero
2066*042d53a7SEvalZero req = (struct ble_att_write_req *)(*rxom)->om_data;
2067*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "write cmd", conn_handle,
2068*042d53a7SEvalZero ble_att_write_req_log, req);
2069*042d53a7SEvalZero
2070*042d53a7SEvalZero handle = le16toh(req->bawq_handle);
2071*042d53a7SEvalZero
2072*042d53a7SEvalZero /* Strip the request base from the front of the mbuf. */
2073*042d53a7SEvalZero os_mbuf_adj(*rxom, sizeof(*req));
2074*042d53a7SEvalZero
2075*042d53a7SEvalZero return ble_att_svr_write_handle(conn_handle, handle, 0, rxom, &att_err);
2076*042d53a7SEvalZero }
2077*042d53a7SEvalZero
2078*042d53a7SEvalZero int
ble_att_svr_write_local(uint16_t attr_handle,struct os_mbuf * om)2079*042d53a7SEvalZero ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf *om)
2080*042d53a7SEvalZero {
2081*042d53a7SEvalZero int rc;
2082*042d53a7SEvalZero
2083*042d53a7SEvalZero rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0,
2084*042d53a7SEvalZero &om, NULL);
2085*042d53a7SEvalZero
2086*042d53a7SEvalZero /* Free the mbuf if it wasn't relinquished to the application. */
2087*042d53a7SEvalZero os_mbuf_free_chain(om);
2088*042d53a7SEvalZero
2089*042d53a7SEvalZero return rc;
2090*042d53a7SEvalZero }
2091*042d53a7SEvalZero
2092*042d53a7SEvalZero static void
ble_att_svr_prep_free(struct ble_att_prep_entry * entry)2093*042d53a7SEvalZero ble_att_svr_prep_free(struct ble_att_prep_entry *entry)
2094*042d53a7SEvalZero {
2095*042d53a7SEvalZero if (entry != NULL) {
2096*042d53a7SEvalZero os_mbuf_free_chain(entry->bape_value);
2097*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
2098*042d53a7SEvalZero memset(entry, 0xff, sizeof *entry);
2099*042d53a7SEvalZero #endif
2100*042d53a7SEvalZero os_memblock_put(&ble_att_svr_prep_entry_pool, entry);
2101*042d53a7SEvalZero }
2102*042d53a7SEvalZero }
2103*042d53a7SEvalZero
2104*042d53a7SEvalZero static struct ble_att_prep_entry *
ble_att_svr_prep_alloc(uint8_t * att_err)2105*042d53a7SEvalZero ble_att_svr_prep_alloc(uint8_t *att_err)
2106*042d53a7SEvalZero {
2107*042d53a7SEvalZero struct ble_att_prep_entry *entry;
2108*042d53a7SEvalZero
2109*042d53a7SEvalZero entry = os_memblock_get(&ble_att_svr_prep_entry_pool);
2110*042d53a7SEvalZero if (entry == NULL) {
2111*042d53a7SEvalZero *att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL;
2112*042d53a7SEvalZero return NULL;
2113*042d53a7SEvalZero }
2114*042d53a7SEvalZero
2115*042d53a7SEvalZero memset(entry, 0, sizeof *entry);
2116*042d53a7SEvalZero entry->bape_value = ble_hs_mbuf_l2cap_pkt();
2117*042d53a7SEvalZero if (entry->bape_value == NULL) {
2118*042d53a7SEvalZero ble_att_svr_prep_free(entry);
2119*042d53a7SEvalZero *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
2120*042d53a7SEvalZero return NULL;
2121*042d53a7SEvalZero }
2122*042d53a7SEvalZero
2123*042d53a7SEvalZero return entry;
2124*042d53a7SEvalZero }
2125*042d53a7SEvalZero
2126*042d53a7SEvalZero static struct ble_att_prep_entry *
ble_att_svr_prep_find_prev(struct ble_att_svr_conn * basc,uint16_t handle,uint16_t offset)2127*042d53a7SEvalZero ble_att_svr_prep_find_prev(struct ble_att_svr_conn *basc, uint16_t handle,
2128*042d53a7SEvalZero uint16_t offset)
2129*042d53a7SEvalZero {
2130*042d53a7SEvalZero struct ble_att_prep_entry *entry;
2131*042d53a7SEvalZero struct ble_att_prep_entry *prev;
2132*042d53a7SEvalZero
2133*042d53a7SEvalZero prev = NULL;
2134*042d53a7SEvalZero SLIST_FOREACH(entry, &basc->basc_prep_list, bape_next) {
2135*042d53a7SEvalZero if (entry->bape_handle > handle) {
2136*042d53a7SEvalZero break;
2137*042d53a7SEvalZero }
2138*042d53a7SEvalZero
2139*042d53a7SEvalZero if (entry->bape_handle == handle && entry->bape_offset > offset) {
2140*042d53a7SEvalZero break;
2141*042d53a7SEvalZero }
2142*042d53a7SEvalZero
2143*042d53a7SEvalZero prev = entry;
2144*042d53a7SEvalZero }
2145*042d53a7SEvalZero
2146*042d53a7SEvalZero return prev;
2147*042d53a7SEvalZero }
2148*042d53a7SEvalZero
2149*042d53a7SEvalZero void
ble_att_svr_prep_clear(struct ble_att_prep_entry_list * prep_list)2150*042d53a7SEvalZero ble_att_svr_prep_clear(struct ble_att_prep_entry_list *prep_list)
2151*042d53a7SEvalZero {
2152*042d53a7SEvalZero struct ble_att_prep_entry *entry;
2153*042d53a7SEvalZero
2154*042d53a7SEvalZero while ((entry = SLIST_FIRST(prep_list)) != NULL) {
2155*042d53a7SEvalZero SLIST_REMOVE_HEAD(prep_list, bape_next);
2156*042d53a7SEvalZero ble_att_svr_prep_free(entry);
2157*042d53a7SEvalZero }
2158*042d53a7SEvalZero }
2159*042d53a7SEvalZero
2160*042d53a7SEvalZero /**
2161*042d53a7SEvalZero * @return 0 on success; ATT error code on failure.
2162*042d53a7SEvalZero */
2163*042d53a7SEvalZero static int
ble_att_svr_prep_validate(struct ble_att_prep_entry_list * prep_list,uint16_t * err_handle)2164*042d53a7SEvalZero ble_att_svr_prep_validate(struct ble_att_prep_entry_list *prep_list,
2165*042d53a7SEvalZero uint16_t *err_handle)
2166*042d53a7SEvalZero {
2167*042d53a7SEvalZero struct ble_att_prep_entry *entry;
2168*042d53a7SEvalZero struct ble_att_prep_entry *prev;
2169*042d53a7SEvalZero int cur_len;
2170*042d53a7SEvalZero
2171*042d53a7SEvalZero prev = NULL;
2172*042d53a7SEvalZero SLIST_FOREACH(entry, prep_list, bape_next) {
2173*042d53a7SEvalZero if (prev == NULL || prev->bape_handle != entry->bape_handle) {
2174*042d53a7SEvalZero /* Ensure attribute write starts at offset 0. */
2175*042d53a7SEvalZero if (entry->bape_offset != 0) {
2176*042d53a7SEvalZero *err_handle = entry->bape_handle;
2177*042d53a7SEvalZero return BLE_ATT_ERR_INVALID_OFFSET;
2178*042d53a7SEvalZero }
2179*042d53a7SEvalZero } else {
2180*042d53a7SEvalZero /* Ensure entry continues where previous left off. */
2181*042d53a7SEvalZero if (prev->bape_offset + OS_MBUF_PKTLEN(prev->bape_value) !=
2182*042d53a7SEvalZero entry->bape_offset) {
2183*042d53a7SEvalZero
2184*042d53a7SEvalZero *err_handle = entry->bape_handle;
2185*042d53a7SEvalZero return BLE_ATT_ERR_INVALID_OFFSET;
2186*042d53a7SEvalZero }
2187*042d53a7SEvalZero }
2188*042d53a7SEvalZero
2189*042d53a7SEvalZero cur_len = entry->bape_offset + OS_MBUF_PKTLEN(entry->bape_value);
2190*042d53a7SEvalZero if (cur_len > BLE_ATT_ATTR_MAX_LEN) {
2191*042d53a7SEvalZero *err_handle = entry->bape_handle;
2192*042d53a7SEvalZero return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
2193*042d53a7SEvalZero }
2194*042d53a7SEvalZero
2195*042d53a7SEvalZero prev = entry;
2196*042d53a7SEvalZero }
2197*042d53a7SEvalZero
2198*042d53a7SEvalZero return 0;
2199*042d53a7SEvalZero }
2200*042d53a7SEvalZero
2201*042d53a7SEvalZero static void
ble_att_svr_prep_extract(struct ble_att_prep_entry_list * prep_list,uint16_t * out_attr_handle,struct os_mbuf ** out_om)2202*042d53a7SEvalZero ble_att_svr_prep_extract(struct ble_att_prep_entry_list *prep_list,
2203*042d53a7SEvalZero uint16_t *out_attr_handle,
2204*042d53a7SEvalZero struct os_mbuf **out_om)
2205*042d53a7SEvalZero {
2206*042d53a7SEvalZero struct ble_att_prep_entry *entry;
2207*042d53a7SEvalZero struct ble_att_prep_entry *first;
2208*042d53a7SEvalZero struct os_mbuf *om;
2209*042d53a7SEvalZero uint16_t attr_handle;
2210*042d53a7SEvalZero
2211*042d53a7SEvalZero BLE_HS_DBG_ASSERT(!SLIST_EMPTY(prep_list));
2212*042d53a7SEvalZero
2213*042d53a7SEvalZero first = SLIST_FIRST(prep_list);
2214*042d53a7SEvalZero attr_handle = first->bape_handle;
2215*042d53a7SEvalZero om = NULL;
2216*042d53a7SEvalZero
2217*042d53a7SEvalZero while ((entry = SLIST_FIRST(prep_list)) != NULL) {
2218*042d53a7SEvalZero if (entry->bape_handle != attr_handle) {
2219*042d53a7SEvalZero break;
2220*042d53a7SEvalZero }
2221*042d53a7SEvalZero
2222*042d53a7SEvalZero if (om == NULL) {
2223*042d53a7SEvalZero om = entry->bape_value;
2224*042d53a7SEvalZero } else {
2225*042d53a7SEvalZero os_mbuf_concat(om, entry->bape_value);
2226*042d53a7SEvalZero }
2227*042d53a7SEvalZero entry->bape_value = NULL;
2228*042d53a7SEvalZero
2229*042d53a7SEvalZero SLIST_REMOVE_HEAD(prep_list, bape_next);
2230*042d53a7SEvalZero ble_att_svr_prep_free(entry);
2231*042d53a7SEvalZero }
2232*042d53a7SEvalZero
2233*042d53a7SEvalZero *out_attr_handle = attr_handle;
2234*042d53a7SEvalZero *out_om = om;
2235*042d53a7SEvalZero }
2236*042d53a7SEvalZero
2237*042d53a7SEvalZero /**
2238*042d53a7SEvalZero * @return 0 on success; ATT error code on failure.
2239*042d53a7SEvalZero */
2240*042d53a7SEvalZero static int
ble_att_svr_prep_write(uint16_t conn_handle,struct ble_att_prep_entry_list * prep_list,uint16_t * err_handle)2241*042d53a7SEvalZero ble_att_svr_prep_write(uint16_t conn_handle,
2242*042d53a7SEvalZero struct ble_att_prep_entry_list *prep_list,
2243*042d53a7SEvalZero uint16_t *err_handle)
2244*042d53a7SEvalZero {
2245*042d53a7SEvalZero struct ble_att_svr_entry *attr;
2246*042d53a7SEvalZero struct os_mbuf *om;
2247*042d53a7SEvalZero uint16_t attr_handle;
2248*042d53a7SEvalZero uint8_t att_err;
2249*042d53a7SEvalZero int rc;
2250*042d53a7SEvalZero
2251*042d53a7SEvalZero *err_handle = 0; /* Silence unnecessary warning. */
2252*042d53a7SEvalZero
2253*042d53a7SEvalZero /* First, validate the contents of the prepare queue. */
2254*042d53a7SEvalZero rc = ble_att_svr_prep_validate(prep_list, err_handle);
2255*042d53a7SEvalZero if (rc != 0) {
2256*042d53a7SEvalZero return rc;
2257*042d53a7SEvalZero }
2258*042d53a7SEvalZero
2259*042d53a7SEvalZero /* Contents are valid; perform the writes. */
2260*042d53a7SEvalZero while (!SLIST_EMPTY(prep_list)) {
2261*042d53a7SEvalZero ble_att_svr_prep_extract(prep_list, &attr_handle, &om);
2262*042d53a7SEvalZero
2263*042d53a7SEvalZero /* Attribute existence was verified during prepare-write request
2264*042d53a7SEvalZero * processing.
2265*042d53a7SEvalZero */
2266*042d53a7SEvalZero attr = ble_att_svr_find_by_handle(attr_handle);
2267*042d53a7SEvalZero BLE_HS_DBG_ASSERT(attr != NULL);
2268*042d53a7SEvalZero
2269*042d53a7SEvalZero rc = ble_att_svr_write(conn_handle, attr, 0, &om, &att_err);
2270*042d53a7SEvalZero os_mbuf_free_chain(om);
2271*042d53a7SEvalZero if (rc != 0) {
2272*042d53a7SEvalZero *err_handle = attr_handle;
2273*042d53a7SEvalZero return att_err;
2274*042d53a7SEvalZero }
2275*042d53a7SEvalZero }
2276*042d53a7SEvalZero
2277*042d53a7SEvalZero return 0;
2278*042d53a7SEvalZero }
2279*042d53a7SEvalZero
2280*042d53a7SEvalZero static int
ble_att_svr_insert_prep_entry(uint16_t conn_handle,uint16_t handle,uint16_t offset,const struct os_mbuf * rxom,uint8_t * out_att_err)2281*042d53a7SEvalZero ble_att_svr_insert_prep_entry(uint16_t conn_handle,
2282*042d53a7SEvalZero uint16_t handle, uint16_t offset,
2283*042d53a7SEvalZero const struct os_mbuf *rxom,
2284*042d53a7SEvalZero uint8_t *out_att_err)
2285*042d53a7SEvalZero {
2286*042d53a7SEvalZero struct ble_att_prep_entry *prep_entry;
2287*042d53a7SEvalZero struct ble_att_prep_entry *prep_prev;
2288*042d53a7SEvalZero struct ble_hs_conn *conn;
2289*042d53a7SEvalZero int rc;
2290*042d53a7SEvalZero
2291*042d53a7SEvalZero conn = ble_hs_conn_find_assert(conn_handle);
2292*042d53a7SEvalZero
2293*042d53a7SEvalZero prep_entry = ble_att_svr_prep_alloc(out_att_err);
2294*042d53a7SEvalZero if (prep_entry == NULL) {
2295*042d53a7SEvalZero return BLE_HS_ENOMEM;
2296*042d53a7SEvalZero }
2297*042d53a7SEvalZero prep_entry->bape_handle = handle;
2298*042d53a7SEvalZero prep_entry->bape_offset = offset;
2299*042d53a7SEvalZero
2300*042d53a7SEvalZero /* Append attribute value from request onto prep mbuf. */
2301*042d53a7SEvalZero rc = os_mbuf_appendfrom(
2302*042d53a7SEvalZero prep_entry->bape_value,
2303*042d53a7SEvalZero rxom,
2304*042d53a7SEvalZero sizeof(struct ble_att_prep_write_cmd),
2305*042d53a7SEvalZero OS_MBUF_PKTLEN(rxom) - sizeof(struct ble_att_prep_write_cmd));
2306*042d53a7SEvalZero if (rc != 0) {
2307*042d53a7SEvalZero /* Failed to allocate an mbuf to hold the additional data. */
2308*042d53a7SEvalZero ble_att_svr_prep_free(prep_entry);
2309*042d53a7SEvalZero
2310*042d53a7SEvalZero /* XXX: We need to differentiate between "prepare queue full" and
2311*042d53a7SEvalZero * "insufficient resources." Currently, we always indicate prepare
2312*042d53a7SEvalZero * queue full.
2313*042d53a7SEvalZero */
2314*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL;
2315*042d53a7SEvalZero return rc;
2316*042d53a7SEvalZero }
2317*042d53a7SEvalZero
2318*042d53a7SEvalZero prep_prev = ble_att_svr_prep_find_prev(&conn->bhc_att_svr,
2319*042d53a7SEvalZero handle, offset);
2320*042d53a7SEvalZero if (prep_prev == NULL) {
2321*042d53a7SEvalZero SLIST_INSERT_HEAD(&conn->bhc_att_svr.basc_prep_list, prep_entry,
2322*042d53a7SEvalZero bape_next);
2323*042d53a7SEvalZero } else {
2324*042d53a7SEvalZero SLIST_INSERT_AFTER(prep_prev, prep_entry, bape_next);
2325*042d53a7SEvalZero }
2326*042d53a7SEvalZero
2327*042d53a7SEvalZero #if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO != 0
2328*042d53a7SEvalZero conn->bhc_att_svr.basc_prep_timeout_at =
2329*042d53a7SEvalZero ble_npl_time_get() + BLE_HS_ATT_SVR_QUEUED_WRITE_TMO;
2330*042d53a7SEvalZero
2331*042d53a7SEvalZero ble_hs_timer_resched();
2332*042d53a7SEvalZero #endif
2333*042d53a7SEvalZero
2334*042d53a7SEvalZero return 0;
2335*042d53a7SEvalZero }
2336*042d53a7SEvalZero
2337*042d53a7SEvalZero int
ble_att_svr_rx_prep_write(uint16_t conn_handle,struct os_mbuf ** rxom)2338*042d53a7SEvalZero ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
2339*042d53a7SEvalZero {
2340*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_QUEUED_WRITE)
2341*042d53a7SEvalZero return BLE_HS_ENOTSUP;
2342*042d53a7SEvalZero #endif
2343*042d53a7SEvalZero
2344*042d53a7SEvalZero struct ble_att_prep_write_cmd *req;
2345*042d53a7SEvalZero struct ble_att_svr_entry *attr_entry;
2346*042d53a7SEvalZero struct os_mbuf *txom;
2347*042d53a7SEvalZero uint16_t err_handle;
2348*042d53a7SEvalZero uint8_t att_err;
2349*042d53a7SEvalZero int rc;
2350*042d53a7SEvalZero
2351*042d53a7SEvalZero /* Initialize some values in case of early error. */
2352*042d53a7SEvalZero txom = NULL;
2353*042d53a7SEvalZero att_err = 0;
2354*042d53a7SEvalZero err_handle = 0;
2355*042d53a7SEvalZero
2356*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
2357*042d53a7SEvalZero if (rc != 0) {
2358*042d53a7SEvalZero goto done;
2359*042d53a7SEvalZero }
2360*042d53a7SEvalZero
2361*042d53a7SEvalZero req = (struct ble_att_prep_write_cmd *)(*rxom)->om_data;
2362*042d53a7SEvalZero
2363*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "prep write req", conn_handle,
2364*042d53a7SEvalZero ble_att_prep_write_cmd_log, req);
2365*042d53a7SEvalZero
2366*042d53a7SEvalZero err_handle = le16toh(req->bapc_handle);
2367*042d53a7SEvalZero
2368*042d53a7SEvalZero attr_entry = ble_att_svr_find_by_handle(le16toh(req->bapc_handle));
2369*042d53a7SEvalZero
2370*042d53a7SEvalZero /* A prepare write request gets rejected for the following reasons:
2371*042d53a7SEvalZero * 1. Insufficient authorization.
2372*042d53a7SEvalZero * 2. Insufficient authentication.
2373*042d53a7SEvalZero * 3. Insufficient encryption key size (XXX: Not checked).
2374*042d53a7SEvalZero * 4. Insufficient encryption (XXX: Not checked).
2375*042d53a7SEvalZero * 5. Invalid handle.
2376*042d53a7SEvalZero * 6. Write not permitted.
2377*042d53a7SEvalZero */
2378*042d53a7SEvalZero
2379*042d53a7SEvalZero /* <5> */
2380*042d53a7SEvalZero if (attr_entry == NULL) {
2381*042d53a7SEvalZero rc = BLE_HS_ENOENT;
2382*042d53a7SEvalZero att_err = BLE_ATT_ERR_INVALID_HANDLE;
2383*042d53a7SEvalZero goto done;
2384*042d53a7SEvalZero }
2385*042d53a7SEvalZero
2386*042d53a7SEvalZero /* <1>, <2>, <4>, <6> */
2387*042d53a7SEvalZero rc = ble_att_svr_check_perms(conn_handle, 0, attr_entry, &att_err);
2388*042d53a7SEvalZero if (rc != 0) {
2389*042d53a7SEvalZero goto done;
2390*042d53a7SEvalZero }
2391*042d53a7SEvalZero
2392*042d53a7SEvalZero ble_hs_lock();
2393*042d53a7SEvalZero rc = ble_att_svr_insert_prep_entry(conn_handle, le16toh(req->bapc_handle),
2394*042d53a7SEvalZero le16toh(req->bapc_offset), *rxom,
2395*042d53a7SEvalZero &att_err);
2396*042d53a7SEvalZero ble_hs_unlock();
2397*042d53a7SEvalZero
2398*042d53a7SEvalZero /* Reuse rxom for response. On success, the response is identical to
2399*042d53a7SEvalZero * request except for op code. On error, the buffer contents will get
2400*042d53a7SEvalZero * cleared before the error gets written.
2401*042d53a7SEvalZero */
2402*042d53a7SEvalZero txom = *rxom;
2403*042d53a7SEvalZero *rxom = NULL;
2404*042d53a7SEvalZero
2405*042d53a7SEvalZero if (rc != 0) {
2406*042d53a7SEvalZero goto done;
2407*042d53a7SEvalZero }
2408*042d53a7SEvalZero
2409*042d53a7SEvalZero /* adjust for ATT header */
2410*042d53a7SEvalZero os_mbuf_prepend(txom, 1);
2411*042d53a7SEvalZero txom->om_data[0] = BLE_ATT_OP_PREP_WRITE_RSP;
2412*042d53a7SEvalZero
2413*042d53a7SEvalZero BLE_ATT_LOG_CMD(1, "prep write rsp", conn_handle,
2414*042d53a7SEvalZero ble_att_prep_write_cmd_log, req);
2415*042d53a7SEvalZero
2416*042d53a7SEvalZero rc = 0;
2417*042d53a7SEvalZero
2418*042d53a7SEvalZero done:
2419*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_PREP_WRITE_REQ,
2420*042d53a7SEvalZero att_err, err_handle);
2421*042d53a7SEvalZero return rc;
2422*042d53a7SEvalZero }
2423*042d53a7SEvalZero
2424*042d53a7SEvalZero int
ble_att_svr_rx_exec_write(uint16_t conn_handle,struct os_mbuf ** rxom)2425*042d53a7SEvalZero ble_att_svr_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom)
2426*042d53a7SEvalZero {
2427*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_QUEUED_WRITE)
2428*042d53a7SEvalZero return BLE_HS_ENOTSUP;
2429*042d53a7SEvalZero #endif
2430*042d53a7SEvalZero
2431*042d53a7SEvalZero struct ble_att_prep_entry_list prep_list;
2432*042d53a7SEvalZero struct ble_att_exec_write_req *req;
2433*042d53a7SEvalZero struct ble_hs_conn *conn;
2434*042d53a7SEvalZero struct os_mbuf *txom;
2435*042d53a7SEvalZero uint16_t err_handle;
2436*042d53a7SEvalZero uint8_t att_err;
2437*042d53a7SEvalZero uint8_t flags;
2438*042d53a7SEvalZero int rc;
2439*042d53a7SEvalZero
2440*042d53a7SEvalZero /* Initialize some values in case of early error. */
2441*042d53a7SEvalZero txom = NULL;
2442*042d53a7SEvalZero err_handle = 0;
2443*042d53a7SEvalZero
2444*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
2445*042d53a7SEvalZero if (rc != 0) {
2446*042d53a7SEvalZero flags = 0;
2447*042d53a7SEvalZero goto done;
2448*042d53a7SEvalZero }
2449*042d53a7SEvalZero
2450*042d53a7SEvalZero req = (struct ble_att_exec_write_req *)(*rxom)->om_data;
2451*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "exec write req", conn_handle,
2452*042d53a7SEvalZero ble_att_exec_write_req_log, req);
2453*042d53a7SEvalZero
2454*042d53a7SEvalZero flags = req->baeq_flags;
2455*042d53a7SEvalZero
2456*042d53a7SEvalZero /* Just reuse the request buffer for the response. */
2457*042d53a7SEvalZero txom = *rxom;
2458*042d53a7SEvalZero *rxom = NULL;
2459*042d53a7SEvalZero os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom));
2460*042d53a7SEvalZero
2461*042d53a7SEvalZero if (ble_att_cmd_prepare(BLE_ATT_OP_EXEC_WRITE_RSP, 0, txom) == NULL) {
2462*042d53a7SEvalZero att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
2463*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
2464*042d53a7SEvalZero goto done;
2465*042d53a7SEvalZero }
2466*042d53a7SEvalZero
2467*042d53a7SEvalZero rc = 0;
2468*042d53a7SEvalZero
2469*042d53a7SEvalZero done:
2470*042d53a7SEvalZero if (rc == 0) {
2471*042d53a7SEvalZero ble_hs_lock();
2472*042d53a7SEvalZero conn = ble_hs_conn_find_assert(conn_handle);
2473*042d53a7SEvalZero
2474*042d53a7SEvalZero /* Extract the list of prepared writes from the connection so
2475*042d53a7SEvalZero * that they can be processed after the mutex is unlocked. They
2476*042d53a7SEvalZero * aren't processed now because attribute writes involve executing
2477*042d53a7SEvalZero * an application callback.
2478*042d53a7SEvalZero */
2479*042d53a7SEvalZero prep_list = conn->bhc_att_svr.basc_prep_list;
2480*042d53a7SEvalZero SLIST_INIT(&conn->bhc_att_svr.basc_prep_list);
2481*042d53a7SEvalZero ble_hs_unlock();
2482*042d53a7SEvalZero
2483*042d53a7SEvalZero if (flags) {
2484*042d53a7SEvalZero /* Perform attribute writes. */
2485*042d53a7SEvalZero att_err = ble_att_svr_prep_write(conn_handle, &prep_list,
2486*042d53a7SEvalZero &err_handle);
2487*042d53a7SEvalZero if (att_err != 0) {
2488*042d53a7SEvalZero rc = BLE_HS_EAPP;
2489*042d53a7SEvalZero }
2490*042d53a7SEvalZero }
2491*042d53a7SEvalZero
2492*042d53a7SEvalZero /* Free the prep entries. */
2493*042d53a7SEvalZero ble_att_svr_prep_clear(&prep_list);
2494*042d53a7SEvalZero }
2495*042d53a7SEvalZero
2496*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_EXEC_WRITE_REQ,
2497*042d53a7SEvalZero att_err, err_handle);
2498*042d53a7SEvalZero return rc;
2499*042d53a7SEvalZero }
2500*042d53a7SEvalZero
2501*042d53a7SEvalZero int
ble_att_svr_rx_notify(uint16_t conn_handle,struct os_mbuf ** rxom)2502*042d53a7SEvalZero ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom)
2503*042d53a7SEvalZero {
2504*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_NOTIFY)
2505*042d53a7SEvalZero return BLE_HS_ENOTSUP;
2506*042d53a7SEvalZero #endif
2507*042d53a7SEvalZero
2508*042d53a7SEvalZero struct ble_att_notify_req *req;
2509*042d53a7SEvalZero uint16_t handle;
2510*042d53a7SEvalZero int rc;
2511*042d53a7SEvalZero
2512*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), NULL);
2513*042d53a7SEvalZero if (rc != 0) {
2514*042d53a7SEvalZero return BLE_HS_ENOMEM;
2515*042d53a7SEvalZero }
2516*042d53a7SEvalZero
2517*042d53a7SEvalZero req = (struct ble_att_notify_req *)(*rxom)->om_data;
2518*042d53a7SEvalZero
2519*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "notify req", conn_handle,
2520*042d53a7SEvalZero ble_att_notify_req_log, req);
2521*042d53a7SEvalZero
2522*042d53a7SEvalZero handle = le16toh(req->banq_handle);
2523*042d53a7SEvalZero
2524*042d53a7SEvalZero if (handle == 0) {
2525*042d53a7SEvalZero return BLE_HS_EBADDATA;
2526*042d53a7SEvalZero }
2527*042d53a7SEvalZero
2528*042d53a7SEvalZero /* Strip the request base from the front of the mbuf. */
2529*042d53a7SEvalZero os_mbuf_adj(*rxom, sizeof(*req));
2530*042d53a7SEvalZero
2531*042d53a7SEvalZero ble_gap_notify_rx_event(conn_handle, handle, *rxom, 0);
2532*042d53a7SEvalZero *rxom = NULL;
2533*042d53a7SEvalZero
2534*042d53a7SEvalZero return 0;
2535*042d53a7SEvalZero }
2536*042d53a7SEvalZero
2537*042d53a7SEvalZero /**
2538*042d53a7SEvalZero * @return 0 on success; nonzero on failure.
2539*042d53a7SEvalZero */
2540*042d53a7SEvalZero static int
ble_att_svr_build_indicate_rsp(struct os_mbuf ** rxom,struct os_mbuf ** out_txom,uint8_t * out_att_err)2541*042d53a7SEvalZero ble_att_svr_build_indicate_rsp(struct os_mbuf **rxom,
2542*042d53a7SEvalZero struct os_mbuf **out_txom, uint8_t *out_att_err)
2543*042d53a7SEvalZero {
2544*042d53a7SEvalZero struct os_mbuf *txom;
2545*042d53a7SEvalZero int rc;
2546*042d53a7SEvalZero
2547*042d53a7SEvalZero /* Allocate a new buffer for the response. An indicate response never
2548*042d53a7SEvalZero * reuses the request buffer. See the note at the top of this file for
2549*042d53a7SEvalZero * details.
2550*042d53a7SEvalZero */
2551*042d53a7SEvalZero rc = ble_att_svr_pkt(rxom, &txom, out_att_err);
2552*042d53a7SEvalZero if (rc != 0) {
2553*042d53a7SEvalZero goto done;
2554*042d53a7SEvalZero }
2555*042d53a7SEvalZero
2556*042d53a7SEvalZero if (ble_att_cmd_prepare(BLE_ATT_OP_INDICATE_RSP, 0, txom) == NULL) {
2557*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
2558*042d53a7SEvalZero *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
2559*042d53a7SEvalZero goto done;
2560*042d53a7SEvalZero }
2561*042d53a7SEvalZero
2562*042d53a7SEvalZero rc = 0;
2563*042d53a7SEvalZero
2564*042d53a7SEvalZero done:
2565*042d53a7SEvalZero *out_txom = txom;
2566*042d53a7SEvalZero return rc;
2567*042d53a7SEvalZero }
2568*042d53a7SEvalZero
2569*042d53a7SEvalZero int
ble_att_svr_rx_indicate(uint16_t conn_handle,struct os_mbuf ** rxom)2570*042d53a7SEvalZero ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
2571*042d53a7SEvalZero {
2572*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ATT_SVR_INDICATE)
2573*042d53a7SEvalZero return BLE_HS_ENOTSUP;
2574*042d53a7SEvalZero #endif
2575*042d53a7SEvalZero
2576*042d53a7SEvalZero struct ble_att_indicate_req *req;
2577*042d53a7SEvalZero struct os_mbuf *txom;
2578*042d53a7SEvalZero uint16_t handle;
2579*042d53a7SEvalZero uint8_t att_err;
2580*042d53a7SEvalZero int rc;
2581*042d53a7SEvalZero
2582*042d53a7SEvalZero /* Initialize some values in case of early error. */
2583*042d53a7SEvalZero txom = NULL;
2584*042d53a7SEvalZero att_err = 0;
2585*042d53a7SEvalZero handle = 0;
2586*042d53a7SEvalZero
2587*042d53a7SEvalZero rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), NULL);
2588*042d53a7SEvalZero if (rc != 0) {
2589*042d53a7SEvalZero goto done;
2590*042d53a7SEvalZero }
2591*042d53a7SEvalZero
2592*042d53a7SEvalZero req = (struct ble_att_indicate_req *)(*rxom)->om_data;
2593*042d53a7SEvalZero BLE_ATT_LOG_CMD(0, "indicate req", conn_handle,
2594*042d53a7SEvalZero ble_att_indicate_req_log, req);
2595*042d53a7SEvalZero
2596*042d53a7SEvalZero handle = le16toh(req->baiq_handle);
2597*042d53a7SEvalZero
2598*042d53a7SEvalZero if (handle == 0) {
2599*042d53a7SEvalZero rc = BLE_HS_EBADDATA;
2600*042d53a7SEvalZero goto done;
2601*042d53a7SEvalZero }
2602*042d53a7SEvalZero
2603*042d53a7SEvalZero /* Allocate the indicate response. This must be done prior to processing
2604*042d53a7SEvalZero * the request. See the note at the top of this file for details.
2605*042d53a7SEvalZero */
2606*042d53a7SEvalZero rc = ble_att_svr_build_indicate_rsp(rxom, &txom, &att_err);
2607*042d53a7SEvalZero if (rc != 0) {
2608*042d53a7SEvalZero goto done;
2609*042d53a7SEvalZero }
2610*042d53a7SEvalZero
2611*042d53a7SEvalZero /* Strip the request base from the front of the mbuf. */
2612*042d53a7SEvalZero os_mbuf_adj(*rxom, sizeof(*req));
2613*042d53a7SEvalZero
2614*042d53a7SEvalZero ble_gap_notify_rx_event(conn_handle, handle, *rxom, 1);
2615*042d53a7SEvalZero *rxom = NULL;
2616*042d53a7SEvalZero
2617*042d53a7SEvalZero BLE_ATT_LOG_EMPTY_CMD(1, "indicate rsp", conn_handle);
2618*042d53a7SEvalZero
2619*042d53a7SEvalZero rc = 0;
2620*042d53a7SEvalZero
2621*042d53a7SEvalZero done:
2622*042d53a7SEvalZero rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_INDICATE_REQ,
2623*042d53a7SEvalZero att_err, handle);
2624*042d53a7SEvalZero return rc;
2625*042d53a7SEvalZero }
2626*042d53a7SEvalZero
2627*042d53a7SEvalZero static void
ble_att_svr_move_entries(struct ble_att_svr_entry_list * src,struct ble_att_svr_entry_list * dst,uint16_t start_handle,uint16_t end_handle)2628*042d53a7SEvalZero ble_att_svr_move_entries(struct ble_att_svr_entry_list *src,
2629*042d53a7SEvalZero struct ble_att_svr_entry_list *dst,
2630*042d53a7SEvalZero uint16_t start_handle, uint16_t end_handle)
2631*042d53a7SEvalZero {
2632*042d53a7SEvalZero
2633*042d53a7SEvalZero struct ble_att_svr_entry *entry;
2634*042d53a7SEvalZero struct ble_att_svr_entry *prev;
2635*042d53a7SEvalZero struct ble_att_svr_entry *remove;
2636*042d53a7SEvalZero struct ble_att_svr_entry *insert;
2637*042d53a7SEvalZero
2638*042d53a7SEvalZero /* Find first matching element to move */
2639*042d53a7SEvalZero remove = NULL;
2640*042d53a7SEvalZero entry = STAILQ_FIRST(src);
2641*042d53a7SEvalZero while (entry && entry->ha_handle_id < start_handle) {
2642*042d53a7SEvalZero remove = entry;
2643*042d53a7SEvalZero entry = STAILQ_NEXT(entry, ha_next);
2644*042d53a7SEvalZero }
2645*042d53a7SEvalZero
2646*042d53a7SEvalZero /* Nothing to remove? */
2647*042d53a7SEvalZero if (!entry) {
2648*042d53a7SEvalZero return;
2649*042d53a7SEvalZero }
2650*042d53a7SEvalZero
2651*042d53a7SEvalZero /* Find element after which we'll put moved elements */
2652*042d53a7SEvalZero prev = NULL;
2653*042d53a7SEvalZero insert = STAILQ_FIRST(dst);
2654*042d53a7SEvalZero while (insert && insert->ha_handle_id < start_handle) {
2655*042d53a7SEvalZero prev = insert;
2656*042d53a7SEvalZero insert = STAILQ_NEXT(insert, ha_next);
2657*042d53a7SEvalZero }
2658*042d53a7SEvalZero insert = prev;
2659*042d53a7SEvalZero
2660*042d53a7SEvalZero /* Move elements */
2661*042d53a7SEvalZero while (entry && entry->ha_handle_id <= end_handle) {
2662*042d53a7SEvalZero /* Remove either from head or after prev (which is current one) */
2663*042d53a7SEvalZero if (remove == NULL) {
2664*042d53a7SEvalZero STAILQ_REMOVE_HEAD(src, ha_next);
2665*042d53a7SEvalZero } else {
2666*042d53a7SEvalZero STAILQ_REMOVE_AFTER(src, remove, ha_next);
2667*042d53a7SEvalZero }
2668*042d53a7SEvalZero
2669*042d53a7SEvalZero /* Insert current element */
2670*042d53a7SEvalZero if (insert == NULL) {
2671*042d53a7SEvalZero STAILQ_INSERT_HEAD(dst, entry, ha_next);
2672*042d53a7SEvalZero insert = STAILQ_FIRST(dst);
2673*042d53a7SEvalZero } else {
2674*042d53a7SEvalZero STAILQ_INSERT_AFTER(dst, insert, entry, ha_next);
2675*042d53a7SEvalZero insert = entry;
2676*042d53a7SEvalZero }
2677*042d53a7SEvalZero
2678*042d53a7SEvalZero /* Calculate next candidate to remove */
2679*042d53a7SEvalZero if (remove == NULL) {
2680*042d53a7SEvalZero entry = STAILQ_FIRST(src);
2681*042d53a7SEvalZero } else {
2682*042d53a7SEvalZero entry = STAILQ_NEXT(remove, ha_next);
2683*042d53a7SEvalZero }
2684*042d53a7SEvalZero }
2685*042d53a7SEvalZero }
2686*042d53a7SEvalZero
2687*042d53a7SEvalZero void
ble_att_svr_hide_range(uint16_t start_handle,uint16_t end_handle)2688*042d53a7SEvalZero ble_att_svr_hide_range(uint16_t start_handle, uint16_t end_handle)
2689*042d53a7SEvalZero {
2690*042d53a7SEvalZero ble_att_svr_move_entries(&ble_att_svr_list, &ble_att_svr_hidden_list,
2691*042d53a7SEvalZero start_handle, end_handle);
2692*042d53a7SEvalZero }
2693*042d53a7SEvalZero
2694*042d53a7SEvalZero void
ble_att_svr_restore_range(uint16_t start_handle,uint16_t end_handle)2695*042d53a7SEvalZero ble_att_svr_restore_range(uint16_t start_handle, uint16_t end_handle)
2696*042d53a7SEvalZero {
2697*042d53a7SEvalZero ble_att_svr_move_entries(&ble_att_svr_hidden_list, &ble_att_svr_list,
2698*042d53a7SEvalZero start_handle, end_handle);
2699*042d53a7SEvalZero }
2700*042d53a7SEvalZero
2701*042d53a7SEvalZero void
ble_att_svr_reset(void)2702*042d53a7SEvalZero ble_att_svr_reset(void)
2703*042d53a7SEvalZero {
2704*042d53a7SEvalZero struct ble_att_svr_entry *entry;
2705*042d53a7SEvalZero
2706*042d53a7SEvalZero while ((entry = STAILQ_FIRST(&ble_att_svr_list)) != NULL) {
2707*042d53a7SEvalZero STAILQ_REMOVE_HEAD(&ble_att_svr_list, ha_next);
2708*042d53a7SEvalZero ble_att_svr_entry_free(entry);
2709*042d53a7SEvalZero }
2710*042d53a7SEvalZero
2711*042d53a7SEvalZero while ((entry = STAILQ_FIRST(&ble_att_svr_hidden_list)) != NULL) {
2712*042d53a7SEvalZero STAILQ_REMOVE_HEAD(&ble_att_svr_hidden_list, ha_next);
2713*042d53a7SEvalZero ble_att_svr_entry_free(entry);
2714*042d53a7SEvalZero }
2715*042d53a7SEvalZero
2716*042d53a7SEvalZero /* Note: prep entries do not get freed here because it is assumed there are
2717*042d53a7SEvalZero * no established connections.
2718*042d53a7SEvalZero */
2719*042d53a7SEvalZero }
2720*042d53a7SEvalZero
2721*042d53a7SEvalZero static void
ble_att_svr_free_start_mem(void)2722*042d53a7SEvalZero ble_att_svr_free_start_mem(void)
2723*042d53a7SEvalZero {
2724*042d53a7SEvalZero free(ble_att_svr_entry_mem);
2725*042d53a7SEvalZero ble_att_svr_entry_mem = NULL;
2726*042d53a7SEvalZero }
2727*042d53a7SEvalZero
2728*042d53a7SEvalZero int
ble_att_svr_start(void)2729*042d53a7SEvalZero ble_att_svr_start(void)
2730*042d53a7SEvalZero {
2731*042d53a7SEvalZero int rc;
2732*042d53a7SEvalZero
2733*042d53a7SEvalZero ble_att_svr_free_start_mem();
2734*042d53a7SEvalZero
2735*042d53a7SEvalZero if (ble_hs_max_attrs > 0) {
2736*042d53a7SEvalZero ble_att_svr_entry_mem = malloc(
2737*042d53a7SEvalZero OS_MEMPOOL_BYTES(ble_hs_max_attrs,
2738*042d53a7SEvalZero sizeof (struct ble_att_svr_entry)));
2739*042d53a7SEvalZero if (ble_att_svr_entry_mem == NULL) {
2740*042d53a7SEvalZero rc = BLE_HS_ENOMEM;
2741*042d53a7SEvalZero goto err;
2742*042d53a7SEvalZero }
2743*042d53a7SEvalZero
2744*042d53a7SEvalZero rc = os_mempool_init(&ble_att_svr_entry_pool, ble_hs_max_attrs,
2745*042d53a7SEvalZero sizeof (struct ble_att_svr_entry),
2746*042d53a7SEvalZero ble_att_svr_entry_mem, "ble_att_svr_entry_pool");
2747*042d53a7SEvalZero if (rc != 0) {
2748*042d53a7SEvalZero rc = BLE_HS_EOS;
2749*042d53a7SEvalZero goto err;
2750*042d53a7SEvalZero }
2751*042d53a7SEvalZero }
2752*042d53a7SEvalZero
2753*042d53a7SEvalZero return 0;
2754*042d53a7SEvalZero
2755*042d53a7SEvalZero err:
2756*042d53a7SEvalZero ble_att_svr_free_start_mem();
2757*042d53a7SEvalZero return rc;
2758*042d53a7SEvalZero }
2759*042d53a7SEvalZero
2760*042d53a7SEvalZero int
ble_att_svr_init(void)2761*042d53a7SEvalZero ble_att_svr_init(void)
2762*042d53a7SEvalZero {
2763*042d53a7SEvalZero int rc;
2764*042d53a7SEvalZero
2765*042d53a7SEvalZero if (MYNEWT_VAL(BLE_ATT_SVR_MAX_PREP_ENTRIES) > 0) {
2766*042d53a7SEvalZero rc = os_mempool_init(&ble_att_svr_prep_entry_pool,
2767*042d53a7SEvalZero MYNEWT_VAL(BLE_ATT_SVR_MAX_PREP_ENTRIES),
2768*042d53a7SEvalZero sizeof (struct ble_att_prep_entry),
2769*042d53a7SEvalZero ble_att_svr_prep_entry_mem,
2770*042d53a7SEvalZero "ble_att_svr_prep_entry_pool");
2771*042d53a7SEvalZero if (rc != 0) {
2772*042d53a7SEvalZero return BLE_HS_EOS;
2773*042d53a7SEvalZero }
2774*042d53a7SEvalZero }
2775*042d53a7SEvalZero
2776*042d53a7SEvalZero STAILQ_INIT(&ble_att_svr_list);
2777*042d53a7SEvalZero STAILQ_INIT(&ble_att_svr_hidden_list);
2778*042d53a7SEvalZero
2779*042d53a7SEvalZero ble_att_svr_id = 0;
2780*042d53a7SEvalZero
2781*042d53a7SEvalZero return 0;
2782*042d53a7SEvalZero }
2783