xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_att_svr.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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