xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_att_clt.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 <assert.h>
24*042d53a7SEvalZero #include "os/os_mempool.h"
25*042d53a7SEvalZero #include "nimble/ble.h"
26*042d53a7SEvalZero #include "host/ble_uuid.h"
27*042d53a7SEvalZero #include "ble_hs_priv.h"
28*042d53a7SEvalZero 
29*042d53a7SEvalZero /*****************************************************************************
30*042d53a7SEvalZero  * $error response                                                           *
31*042d53a7SEvalZero  *****************************************************************************/
32*042d53a7SEvalZero 
33*042d53a7SEvalZero int
ble_att_clt_rx_error(uint16_t conn_handle,struct os_mbuf ** rxom)34*042d53a7SEvalZero ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom)
35*042d53a7SEvalZero {
36*042d53a7SEvalZero     struct ble_att_error_rsp *rsp;
37*042d53a7SEvalZero     int rc;
38*042d53a7SEvalZero 
39*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
40*042d53a7SEvalZero     if (rc != 0) {
41*042d53a7SEvalZero         return rc;
42*042d53a7SEvalZero     }
43*042d53a7SEvalZero 
44*042d53a7SEvalZero     rsp = (struct ble_att_error_rsp *)(*rxom)->om_data;
45*042d53a7SEvalZero 
46*042d53a7SEvalZero     BLE_ATT_LOG_CMD(0, "error rsp", conn_handle, ble_att_error_rsp_log, rsp);
47*042d53a7SEvalZero 
48*042d53a7SEvalZero     ble_gattc_rx_err(conn_handle, le16toh(rsp->baep_handle),
49*042d53a7SEvalZero                      le16toh(rsp->baep_error_code));
50*042d53a7SEvalZero 
51*042d53a7SEvalZero     return 0;
52*042d53a7SEvalZero }
53*042d53a7SEvalZero 
54*042d53a7SEvalZero /*****************************************************************************
55*042d53a7SEvalZero  * $mtu exchange                                                             *
56*042d53a7SEvalZero  *****************************************************************************/
57*042d53a7SEvalZero 
58*042d53a7SEvalZero int
ble_att_clt_tx_mtu(uint16_t conn_handle,uint16_t mtu)59*042d53a7SEvalZero ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu)
60*042d53a7SEvalZero {
61*042d53a7SEvalZero     struct ble_att_mtu_cmd *req;
62*042d53a7SEvalZero     struct ble_l2cap_chan *chan;
63*042d53a7SEvalZero     struct ble_hs_conn *conn;
64*042d53a7SEvalZero     struct os_mbuf *txom;
65*042d53a7SEvalZero     int rc;
66*042d53a7SEvalZero 
67*042d53a7SEvalZero     if (mtu < BLE_ATT_MTU_DFLT) {
68*042d53a7SEvalZero         return BLE_HS_EINVAL;
69*042d53a7SEvalZero     }
70*042d53a7SEvalZero 
71*042d53a7SEvalZero     ble_hs_lock();
72*042d53a7SEvalZero 
73*042d53a7SEvalZero     rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
74*042d53a7SEvalZero     if (rc != 0) {
75*042d53a7SEvalZero         rc = BLE_HS_ENOTCONN;
76*042d53a7SEvalZero     } else if (chan->flags & BLE_L2CAP_CHAN_F_TXED_MTU) {
77*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
78*042d53a7SEvalZero     } else {
79*042d53a7SEvalZero         rc = 0;
80*042d53a7SEvalZero     }
81*042d53a7SEvalZero     ble_hs_unlock();
82*042d53a7SEvalZero 
83*042d53a7SEvalZero     if (rc != 0) {
84*042d53a7SEvalZero         return rc;
85*042d53a7SEvalZero     }
86*042d53a7SEvalZero 
87*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_MTU_REQ, sizeof(*req), &txom);
88*042d53a7SEvalZero     if (req == NULL) {
89*042d53a7SEvalZero         return BLE_HS_ENOMEM;
90*042d53a7SEvalZero     }
91*042d53a7SEvalZero 
92*042d53a7SEvalZero     req->bamc_mtu = htole16(mtu);
93*042d53a7SEvalZero 
94*042d53a7SEvalZero     rc = ble_att_tx(conn_handle, txom);
95*042d53a7SEvalZero     if (rc != 0) {
96*042d53a7SEvalZero         return rc;
97*042d53a7SEvalZero     }
98*042d53a7SEvalZero 
99*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "mtu req", conn_handle, ble_att_mtu_cmd_log, req);
100*042d53a7SEvalZero 
101*042d53a7SEvalZero     ble_hs_lock();
102*042d53a7SEvalZero 
103*042d53a7SEvalZero     rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
104*042d53a7SEvalZero     if (rc == 0) {
105*042d53a7SEvalZero         chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU;
106*042d53a7SEvalZero     }
107*042d53a7SEvalZero 
108*042d53a7SEvalZero     ble_hs_unlock();
109*042d53a7SEvalZero 
110*042d53a7SEvalZero     return rc;
111*042d53a7SEvalZero }
112*042d53a7SEvalZero 
113*042d53a7SEvalZero int
ble_att_clt_rx_mtu(uint16_t conn_handle,struct os_mbuf ** rxom)114*042d53a7SEvalZero ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom)
115*042d53a7SEvalZero {
116*042d53a7SEvalZero     struct ble_att_mtu_cmd *cmd;
117*042d53a7SEvalZero     struct ble_l2cap_chan *chan;
118*042d53a7SEvalZero     uint16_t mtu;
119*042d53a7SEvalZero     int rc;
120*042d53a7SEvalZero 
121*042d53a7SEvalZero     mtu = 0;
122*042d53a7SEvalZero 
123*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*cmd));
124*042d53a7SEvalZero     if (rc == 0) {
125*042d53a7SEvalZero         cmd = (struct ble_att_mtu_cmd *)(*rxom)->om_data;
126*042d53a7SEvalZero 
127*042d53a7SEvalZero         BLE_ATT_LOG_CMD(0, "mtu rsp", conn_handle, ble_att_mtu_cmd_log, cmd);
128*042d53a7SEvalZero 
129*042d53a7SEvalZero         ble_hs_lock();
130*042d53a7SEvalZero 
131*042d53a7SEvalZero         rc = ble_att_conn_chan_find(conn_handle, NULL, &chan);
132*042d53a7SEvalZero         if (rc == 0) {
133*042d53a7SEvalZero             ble_att_set_peer_mtu(chan, le16toh(cmd->bamc_mtu));
134*042d53a7SEvalZero             mtu = ble_att_chan_mtu(chan);
135*042d53a7SEvalZero         }
136*042d53a7SEvalZero 
137*042d53a7SEvalZero         ble_hs_unlock();
138*042d53a7SEvalZero 
139*042d53a7SEvalZero         if (rc == 0) {
140*042d53a7SEvalZero             ble_gap_mtu_event(conn_handle, BLE_L2CAP_CID_ATT, mtu);
141*042d53a7SEvalZero         }
142*042d53a7SEvalZero     }
143*042d53a7SEvalZero 
144*042d53a7SEvalZero     ble_gattc_rx_mtu(conn_handle, rc, mtu);
145*042d53a7SEvalZero     return rc;
146*042d53a7SEvalZero }
147*042d53a7SEvalZero 
148*042d53a7SEvalZero /*****************************************************************************
149*042d53a7SEvalZero  * $find information                                                         *
150*042d53a7SEvalZero  *****************************************************************************/
151*042d53a7SEvalZero 
152*042d53a7SEvalZero int
ble_att_clt_tx_find_info(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle)153*042d53a7SEvalZero ble_att_clt_tx_find_info(uint16_t conn_handle, uint16_t start_handle,
154*042d53a7SEvalZero                          uint16_t end_handle)
155*042d53a7SEvalZero {
156*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_FIND_INFO
157*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
158*042d53a7SEvalZero #endif
159*042d53a7SEvalZero 
160*042d53a7SEvalZero     struct ble_att_find_info_req *req;
161*042d53a7SEvalZero     struct os_mbuf *txom;
162*042d53a7SEvalZero 
163*042d53a7SEvalZero     if (start_handle == 0 || start_handle > end_handle) {
164*042d53a7SEvalZero         return BLE_HS_EINVAL;
165*042d53a7SEvalZero     }
166*042d53a7SEvalZero 
167*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_FIND_INFO_REQ, sizeof(*req), &txom);
168*042d53a7SEvalZero     if (req == NULL) {
169*042d53a7SEvalZero         return BLE_HS_ENOMEM;
170*042d53a7SEvalZero     }
171*042d53a7SEvalZero 
172*042d53a7SEvalZero     req->bafq_start_handle = htole16(start_handle);
173*042d53a7SEvalZero     req->bafq_end_handle = htole16(end_handle);
174*042d53a7SEvalZero 
175*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "find info req", conn_handle,
176*042d53a7SEvalZero                     ble_att_find_info_req_log, req);
177*042d53a7SEvalZero 
178*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom);
179*042d53a7SEvalZero }
180*042d53a7SEvalZero 
181*042d53a7SEvalZero static int
ble_att_clt_parse_find_info_entry(struct os_mbuf ** rxom,uint8_t rsp_format,struct ble_att_find_info_idata * idata)182*042d53a7SEvalZero ble_att_clt_parse_find_info_entry(struct os_mbuf **rxom, uint8_t rsp_format,
183*042d53a7SEvalZero                                   struct ble_att_find_info_idata *idata)
184*042d53a7SEvalZero {
185*042d53a7SEvalZero     int entry_len;
186*042d53a7SEvalZero     int rc;
187*042d53a7SEvalZero 
188*042d53a7SEvalZero     switch (rsp_format) {
189*042d53a7SEvalZero     case BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT:
190*042d53a7SEvalZero         entry_len = 2 + 2;
191*042d53a7SEvalZero         break;
192*042d53a7SEvalZero 
193*042d53a7SEvalZero     case BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT:
194*042d53a7SEvalZero         entry_len = 2 + 16;
195*042d53a7SEvalZero         break;
196*042d53a7SEvalZero 
197*042d53a7SEvalZero     default:
198*042d53a7SEvalZero         return BLE_HS_EBADDATA;
199*042d53a7SEvalZero     }
200*042d53a7SEvalZero 
201*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(rxom, entry_len);
202*042d53a7SEvalZero     if (rc != 0) {
203*042d53a7SEvalZero         return rc;
204*042d53a7SEvalZero     }
205*042d53a7SEvalZero 
206*042d53a7SEvalZero     idata->attr_handle = get_le16((*rxom)->om_data);
207*042d53a7SEvalZero 
208*042d53a7SEvalZero     switch (rsp_format) {
209*042d53a7SEvalZero     case BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT:
210*042d53a7SEvalZero         rc = ble_uuid_init_from_att_mbuf(&idata->uuid, *rxom, 2, 2);
211*042d53a7SEvalZero         if (rc != 0) {
212*042d53a7SEvalZero             return BLE_HS_EBADDATA;
213*042d53a7SEvalZero         }
214*042d53a7SEvalZero         break;
215*042d53a7SEvalZero 
216*042d53a7SEvalZero     case BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT:
217*042d53a7SEvalZero         rc = ble_uuid_init_from_att_mbuf(&idata->uuid, *rxom, 2, 16);
218*042d53a7SEvalZero         if (rc != 0) {
219*042d53a7SEvalZero             return BLE_HS_EBADDATA;
220*042d53a7SEvalZero         }
221*042d53a7SEvalZero         break;
222*042d53a7SEvalZero 
223*042d53a7SEvalZero     default:
224*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
225*042d53a7SEvalZero         break;
226*042d53a7SEvalZero     }
227*042d53a7SEvalZero 
228*042d53a7SEvalZero     os_mbuf_adj(*rxom, entry_len);
229*042d53a7SEvalZero     return 0;
230*042d53a7SEvalZero }
231*042d53a7SEvalZero 
232*042d53a7SEvalZero int
ble_att_clt_rx_find_info(uint16_t conn_handle,struct os_mbuf ** om)233*042d53a7SEvalZero ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om)
234*042d53a7SEvalZero {
235*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_FIND_INFO
236*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
237*042d53a7SEvalZero #endif
238*042d53a7SEvalZero 
239*042d53a7SEvalZero     struct ble_att_find_info_idata idata;
240*042d53a7SEvalZero     struct ble_att_find_info_rsp *rsp;
241*042d53a7SEvalZero     int rc;
242*042d53a7SEvalZero 
243*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(om, sizeof(*rsp));
244*042d53a7SEvalZero     if (rc != 0) {
245*042d53a7SEvalZero         goto done;
246*042d53a7SEvalZero     }
247*042d53a7SEvalZero 
248*042d53a7SEvalZero     rsp = (struct ble_att_find_info_rsp *)(*om)->om_data;
249*042d53a7SEvalZero 
250*042d53a7SEvalZero     BLE_ATT_LOG_CMD(0, "find info rsp", conn_handle, ble_att_find_info_rsp_log,
251*042d53a7SEvalZero                     rsp);
252*042d53a7SEvalZero 
253*042d53a7SEvalZero     /* Strip the response base from the front of the mbuf. */
254*042d53a7SEvalZero     os_mbuf_adj((*om), sizeof(*rsp));
255*042d53a7SEvalZero 
256*042d53a7SEvalZero     while (OS_MBUF_PKTLEN(*om) > 0) {
257*042d53a7SEvalZero         rc = ble_att_clt_parse_find_info_entry(om, rsp->bafp_format, &idata);
258*042d53a7SEvalZero         if (rc != 0) {
259*042d53a7SEvalZero             goto done;
260*042d53a7SEvalZero         }
261*042d53a7SEvalZero 
262*042d53a7SEvalZero         /* Hand find-info entry to GATT. */
263*042d53a7SEvalZero         ble_gattc_rx_find_info_idata(conn_handle, &idata);
264*042d53a7SEvalZero     }
265*042d53a7SEvalZero 
266*042d53a7SEvalZero     rc = 0;
267*042d53a7SEvalZero 
268*042d53a7SEvalZero done:
269*042d53a7SEvalZero     /* Notify GATT that response processing is done. */
270*042d53a7SEvalZero     ble_gattc_rx_find_info_complete(conn_handle, rc);
271*042d53a7SEvalZero     return rc;
272*042d53a7SEvalZero }
273*042d53a7SEvalZero 
274*042d53a7SEvalZero /*****************************************************************************
275*042d53a7SEvalZero  * $find by type value                                                       *
276*042d53a7SEvalZero  *****************************************************************************/
277*042d53a7SEvalZero 
278*042d53a7SEvalZero /*
279*042d53a7SEvalZero  * TODO consider this to accept UUID instead of value, it is used only for this
280*042d53a7SEvalZero  * anyway
281*042d53a7SEvalZero  */
282*042d53a7SEvalZero int
ble_att_clt_tx_find_type_value(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,uint16_t attribute_type,const void * attribute_value,int value_len)283*042d53a7SEvalZero ble_att_clt_tx_find_type_value(uint16_t conn_handle, uint16_t start_handle,
284*042d53a7SEvalZero                                uint16_t end_handle, uint16_t attribute_type,
285*042d53a7SEvalZero                                const void *attribute_value, int value_len)
286*042d53a7SEvalZero {
287*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE
288*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
289*042d53a7SEvalZero #endif
290*042d53a7SEvalZero 
291*042d53a7SEvalZero     struct ble_att_find_type_value_req *req;
292*042d53a7SEvalZero     struct os_mbuf *txom;
293*042d53a7SEvalZero 
294*042d53a7SEvalZero     if (start_handle == 0 || start_handle > end_handle) {
295*042d53a7SEvalZero         return BLE_HS_EINVAL;
296*042d53a7SEvalZero     }
297*042d53a7SEvalZero 
298*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_FIND_TYPE_VALUE_REQ, sizeof(*req) + value_len,
299*042d53a7SEvalZero                           &txom);
300*042d53a7SEvalZero     if (req == NULL) {
301*042d53a7SEvalZero         return BLE_HS_ENOMEM;
302*042d53a7SEvalZero     }
303*042d53a7SEvalZero 
304*042d53a7SEvalZero     req->bavq_start_handle = htole16(start_handle);
305*042d53a7SEvalZero     req->bavq_end_handle = htole16(end_handle);
306*042d53a7SEvalZero     req->bavq_attr_type = htole16(attribute_type);
307*042d53a7SEvalZero     memcpy(req->bavq_value, attribute_value, value_len);
308*042d53a7SEvalZero 
309*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "find type value req", conn_handle,
310*042d53a7SEvalZero                     ble_att_find_type_value_req_log, req);
311*042d53a7SEvalZero 
312*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom);
313*042d53a7SEvalZero }
314*042d53a7SEvalZero 
315*042d53a7SEvalZero static int
ble_att_clt_parse_find_type_value_hinfo(struct os_mbuf ** om,struct ble_att_find_type_value_hinfo * dst)316*042d53a7SEvalZero ble_att_clt_parse_find_type_value_hinfo(
317*042d53a7SEvalZero     struct os_mbuf **om, struct ble_att_find_type_value_hinfo *dst)
318*042d53a7SEvalZero {
319*042d53a7SEvalZero     struct ble_att_handle_group *group;
320*042d53a7SEvalZero     int rc;
321*042d53a7SEvalZero 
322*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(om, sizeof(*group));
323*042d53a7SEvalZero     if (rc != 0) {
324*042d53a7SEvalZero         return BLE_HS_EBADDATA;
325*042d53a7SEvalZero     }
326*042d53a7SEvalZero 
327*042d53a7SEvalZero     group = (struct ble_att_handle_group *)(*om)->om_data;
328*042d53a7SEvalZero 
329*042d53a7SEvalZero     dst->attr_handle = le16toh(group->attr_handle);
330*042d53a7SEvalZero     dst->group_end_handle = le16toh(group->group_end_handle);
331*042d53a7SEvalZero 
332*042d53a7SEvalZero     os_mbuf_adj((*om), sizeof(*group));
333*042d53a7SEvalZero 
334*042d53a7SEvalZero     return 0;
335*042d53a7SEvalZero }
336*042d53a7SEvalZero 
337*042d53a7SEvalZero int
ble_att_clt_rx_find_type_value(uint16_t conn_handle,struct os_mbuf ** rxom)338*042d53a7SEvalZero ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom)
339*042d53a7SEvalZero {
340*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE
341*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
342*042d53a7SEvalZero #endif
343*042d53a7SEvalZero 
344*042d53a7SEvalZero     struct ble_att_find_type_value_hinfo hinfo;
345*042d53a7SEvalZero     int rc;
346*042d53a7SEvalZero 
347*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(0, "find type value rsp", conn_handle);
348*042d53a7SEvalZero 
349*042d53a7SEvalZero     /* Parse the Handles-Information-List field, passing each entry to GATT. */
350*042d53a7SEvalZero     rc = 0;
351*042d53a7SEvalZero     while (OS_MBUF_PKTLEN(*rxom) > 0) {
352*042d53a7SEvalZero         rc = ble_att_clt_parse_find_type_value_hinfo(rxom, &hinfo);
353*042d53a7SEvalZero         if (rc != 0) {
354*042d53a7SEvalZero             break;
355*042d53a7SEvalZero         }
356*042d53a7SEvalZero 
357*042d53a7SEvalZero         ble_gattc_rx_find_type_value_hinfo(conn_handle, &hinfo);
358*042d53a7SEvalZero     }
359*042d53a7SEvalZero 
360*042d53a7SEvalZero     /* Notify GATT client that the full response has been parsed. */
361*042d53a7SEvalZero     ble_gattc_rx_find_type_value_complete(conn_handle, rc);
362*042d53a7SEvalZero 
363*042d53a7SEvalZero     return 0;
364*042d53a7SEvalZero }
365*042d53a7SEvalZero 
366*042d53a7SEvalZero /*****************************************************************************
367*042d53a7SEvalZero  * $read by type                                                             *
368*042d53a7SEvalZero  *****************************************************************************/
369*042d53a7SEvalZero 
370*042d53a7SEvalZero int
ble_att_clt_tx_read_type(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid)371*042d53a7SEvalZero ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t start_handle,
372*042d53a7SEvalZero                          uint16_t end_handle, const ble_uuid_t *uuid)
373*042d53a7SEvalZero {
374*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_TYPE
375*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
376*042d53a7SEvalZero #endif
377*042d53a7SEvalZero 
378*042d53a7SEvalZero     struct ble_att_read_type_req *req;
379*042d53a7SEvalZero     struct os_mbuf *txom;
380*042d53a7SEvalZero 
381*042d53a7SEvalZero     if (start_handle == 0 || start_handle > end_handle) {
382*042d53a7SEvalZero         return BLE_HS_EINVAL;
383*042d53a7SEvalZero     }
384*042d53a7SEvalZero 
385*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_READ_TYPE_REQ,
386*042d53a7SEvalZero                           sizeof(*req) + ble_uuid_length(uuid), &txom);
387*042d53a7SEvalZero     if (req == NULL) {
388*042d53a7SEvalZero         return BLE_HS_ENOMEM;
389*042d53a7SEvalZero     }
390*042d53a7SEvalZero 
391*042d53a7SEvalZero     req->batq_start_handle = htole16(start_handle);
392*042d53a7SEvalZero     req->batq_end_handle = htole16(end_handle);
393*042d53a7SEvalZero 
394*042d53a7SEvalZero     ble_uuid_flat(uuid, req->uuid);
395*042d53a7SEvalZero 
396*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "read type req", conn_handle,
397*042d53a7SEvalZero                     ble_att_read_type_req_log, req);
398*042d53a7SEvalZero 
399*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom);
400*042d53a7SEvalZero }
401*042d53a7SEvalZero 
402*042d53a7SEvalZero int
ble_att_clt_rx_read_type(uint16_t conn_handle,struct os_mbuf ** rxom)403*042d53a7SEvalZero ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
404*042d53a7SEvalZero {
405*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_TYPE
406*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
407*042d53a7SEvalZero #endif
408*042d53a7SEvalZero 
409*042d53a7SEvalZero     struct ble_att_read_type_adata adata;
410*042d53a7SEvalZero     struct ble_att_attr_data_list *data;
411*042d53a7SEvalZero     struct ble_att_read_type_rsp *rsp;
412*042d53a7SEvalZero     uint8_t data_len;
413*042d53a7SEvalZero     int rc;
414*042d53a7SEvalZero 
415*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
416*042d53a7SEvalZero     if (rc != 0) {
417*042d53a7SEvalZero         goto done;
418*042d53a7SEvalZero     }
419*042d53a7SEvalZero 
420*042d53a7SEvalZero     rsp = (struct ble_att_read_type_rsp *)(*rxom)->om_data;
421*042d53a7SEvalZero 
422*042d53a7SEvalZero     BLE_ATT_LOG_CMD(0, "read type rsp", conn_handle, ble_att_read_type_rsp_log,
423*042d53a7SEvalZero                     rsp);
424*042d53a7SEvalZero 
425*042d53a7SEvalZero     data_len = rsp->batp_length;
426*042d53a7SEvalZero 
427*042d53a7SEvalZero     /* Strip the response base from the front of the mbuf. */
428*042d53a7SEvalZero     os_mbuf_adj(*rxom, sizeof(*rsp));
429*042d53a7SEvalZero 
430*042d53a7SEvalZero     if (data_len < sizeof(*data)) {
431*042d53a7SEvalZero         rc = BLE_HS_EBADDATA;
432*042d53a7SEvalZero         goto done;
433*042d53a7SEvalZero     }
434*042d53a7SEvalZero 
435*042d53a7SEvalZero     /* Parse the Attribute Data List field, passing each entry to the GATT. */
436*042d53a7SEvalZero     while (OS_MBUF_PKTLEN(*rxom) > 0) {
437*042d53a7SEvalZero         rc = ble_hs_mbuf_pullup_base(rxom, data_len);
438*042d53a7SEvalZero         if (rc != 0) {
439*042d53a7SEvalZero             break;
440*042d53a7SEvalZero         }
441*042d53a7SEvalZero 
442*042d53a7SEvalZero         data = (struct ble_att_attr_data_list *)(*rxom)->om_data;
443*042d53a7SEvalZero 
444*042d53a7SEvalZero         adata.att_handle = le16toh(data->handle);
445*042d53a7SEvalZero         adata.value_len = data_len - sizeof(*data);
446*042d53a7SEvalZero         adata.value = data->value;
447*042d53a7SEvalZero 
448*042d53a7SEvalZero         ble_gattc_rx_read_type_adata(conn_handle, &adata);
449*042d53a7SEvalZero         os_mbuf_adj(*rxom, data_len);
450*042d53a7SEvalZero     }
451*042d53a7SEvalZero 
452*042d53a7SEvalZero done:
453*042d53a7SEvalZero     /* Notify GATT that the response is done being parsed. */
454*042d53a7SEvalZero     ble_gattc_rx_read_type_complete(conn_handle, rc);
455*042d53a7SEvalZero     return rc;
456*042d53a7SEvalZero 
457*042d53a7SEvalZero }
458*042d53a7SEvalZero 
459*042d53a7SEvalZero /*****************************************************************************
460*042d53a7SEvalZero  * $read                                                                     *
461*042d53a7SEvalZero  *****************************************************************************/
462*042d53a7SEvalZero 
463*042d53a7SEvalZero int
ble_att_clt_tx_read(uint16_t conn_handle,uint16_t handle)464*042d53a7SEvalZero ble_att_clt_tx_read(uint16_t conn_handle, uint16_t handle)
465*042d53a7SEvalZero {
466*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ
467*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
468*042d53a7SEvalZero #endif
469*042d53a7SEvalZero 
470*042d53a7SEvalZero     struct ble_att_read_req *req;
471*042d53a7SEvalZero     struct os_mbuf *txom;
472*042d53a7SEvalZero     int rc;
473*042d53a7SEvalZero 
474*042d53a7SEvalZero     if (handle == 0) {
475*042d53a7SEvalZero         return BLE_HS_EINVAL;
476*042d53a7SEvalZero     }
477*042d53a7SEvalZero 
478*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_READ_REQ, sizeof(*req), &txom);
479*042d53a7SEvalZero     if (req == NULL) {
480*042d53a7SEvalZero         return BLE_HS_ENOMEM;
481*042d53a7SEvalZero     }
482*042d53a7SEvalZero 
483*042d53a7SEvalZero     req->barq_handle = htole16(handle);
484*042d53a7SEvalZero 
485*042d53a7SEvalZero     rc = ble_att_tx(conn_handle, txom);
486*042d53a7SEvalZero     if (rc != 0) {
487*042d53a7SEvalZero         return rc;
488*042d53a7SEvalZero     }
489*042d53a7SEvalZero 
490*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "read req", conn_handle, ble_att_read_req_log, req);
491*042d53a7SEvalZero 
492*042d53a7SEvalZero     return 0;
493*042d53a7SEvalZero }
494*042d53a7SEvalZero 
495*042d53a7SEvalZero int
ble_att_clt_rx_read(uint16_t conn_handle,struct os_mbuf ** rxom)496*042d53a7SEvalZero ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
497*042d53a7SEvalZero {
498*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ
499*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
500*042d53a7SEvalZero #endif
501*042d53a7SEvalZero 
502*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(0, "read rsp", conn_handle);
503*042d53a7SEvalZero 
504*042d53a7SEvalZero     /* Pass the Attribute Value field to GATT. */
505*042d53a7SEvalZero     ble_gattc_rx_read_rsp(conn_handle, 0, rxom);
506*042d53a7SEvalZero     return 0;
507*042d53a7SEvalZero }
508*042d53a7SEvalZero 
509*042d53a7SEvalZero /*****************************************************************************
510*042d53a7SEvalZero  * $read blob                                                                *
511*042d53a7SEvalZero  *****************************************************************************/
512*042d53a7SEvalZero 
513*042d53a7SEvalZero int
ble_att_clt_tx_read_blob(uint16_t conn_handle,uint16_t handle,uint16_t offset)514*042d53a7SEvalZero ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t handle, uint16_t offset)
515*042d53a7SEvalZero {
516*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_BLOB
517*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
518*042d53a7SEvalZero #endif
519*042d53a7SEvalZero 
520*042d53a7SEvalZero     struct ble_att_read_blob_req *req;
521*042d53a7SEvalZero     struct os_mbuf *txom;
522*042d53a7SEvalZero     int rc;
523*042d53a7SEvalZero 
524*042d53a7SEvalZero     if (handle == 0) {
525*042d53a7SEvalZero         return BLE_HS_EINVAL;
526*042d53a7SEvalZero     }
527*042d53a7SEvalZero 
528*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_READ_BLOB_REQ, sizeof(*req), &txom);
529*042d53a7SEvalZero     if (req == NULL) {
530*042d53a7SEvalZero         return BLE_HS_ENOMEM;
531*042d53a7SEvalZero     }
532*042d53a7SEvalZero 
533*042d53a7SEvalZero     req->babq_handle = htole16(handle);
534*042d53a7SEvalZero     req->babq_offset = htole16(offset);
535*042d53a7SEvalZero 
536*042d53a7SEvalZero     rc = ble_att_tx(conn_handle, txom);
537*042d53a7SEvalZero     if (rc != 0) {
538*042d53a7SEvalZero         return rc;
539*042d53a7SEvalZero     }
540*042d53a7SEvalZero 
541*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "read blob req", conn_handle,
542*042d53a7SEvalZero                     ble_att_read_blob_req_log, req);
543*042d53a7SEvalZero 
544*042d53a7SEvalZero     return 0;
545*042d53a7SEvalZero }
546*042d53a7SEvalZero 
547*042d53a7SEvalZero int
ble_att_clt_rx_read_blob(uint16_t conn_handle,struct os_mbuf ** rxom)548*042d53a7SEvalZero ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
549*042d53a7SEvalZero {
550*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_BLOB
551*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
552*042d53a7SEvalZero #endif
553*042d53a7SEvalZero 
554*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(0, "read blob rsp", conn_handle);
555*042d53a7SEvalZero 
556*042d53a7SEvalZero     /* Pass the Attribute Value field to GATT. */
557*042d53a7SEvalZero     ble_gattc_rx_read_blob_rsp(conn_handle, 0, rxom);
558*042d53a7SEvalZero     return 0;
559*042d53a7SEvalZero }
560*042d53a7SEvalZero 
561*042d53a7SEvalZero /*****************************************************************************
562*042d53a7SEvalZero  * $read multiple                                                            *
563*042d53a7SEvalZero  *****************************************************************************/
564*042d53a7SEvalZero int
ble_att_clt_tx_read_mult(uint16_t conn_handle,const uint16_t * handles,int num_handles)565*042d53a7SEvalZero ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *handles,
566*042d53a7SEvalZero                          int num_handles)
567*042d53a7SEvalZero {
568*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_MULT
569*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
570*042d53a7SEvalZero #endif
571*042d53a7SEvalZero 
572*042d53a7SEvalZero     struct ble_att_read_mult_req *req;
573*042d53a7SEvalZero     struct os_mbuf *txom;
574*042d53a7SEvalZero     int i;
575*042d53a7SEvalZero 
576*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(1, "reqd mult req", conn_handle);
577*042d53a7SEvalZero 
578*042d53a7SEvalZero     if (num_handles < 1) {
579*042d53a7SEvalZero         return BLE_HS_EINVAL;
580*042d53a7SEvalZero     }
581*042d53a7SEvalZero 
582*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_READ_MULT_REQ,
583*042d53a7SEvalZero                           sizeof(req->handles[0]) * num_handles,
584*042d53a7SEvalZero                           &txom);
585*042d53a7SEvalZero     if (req == NULL) {
586*042d53a7SEvalZero         return BLE_HS_ENOMEM;
587*042d53a7SEvalZero     }
588*042d53a7SEvalZero 
589*042d53a7SEvalZero     for(i = 0; i < num_handles; i++) {
590*042d53a7SEvalZero         req->handles[i] = htole16(handles[i]);
591*042d53a7SEvalZero     }
592*042d53a7SEvalZero 
593*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom);
594*042d53a7SEvalZero }
595*042d53a7SEvalZero 
596*042d53a7SEvalZero int
ble_att_clt_rx_read_mult(uint16_t conn_handle,struct os_mbuf ** rxom)597*042d53a7SEvalZero ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
598*042d53a7SEvalZero {
599*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_MULT
600*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
601*042d53a7SEvalZero #endif
602*042d53a7SEvalZero 
603*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(0, "read mult rsp", conn_handle);
604*042d53a7SEvalZero 
605*042d53a7SEvalZero     /* Pass the Attribute Value field to GATT. */
606*042d53a7SEvalZero     ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom);
607*042d53a7SEvalZero     return 0;
608*042d53a7SEvalZero }
609*042d53a7SEvalZero 
610*042d53a7SEvalZero /*****************************************************************************
611*042d53a7SEvalZero  * $read by group type                                                       *
612*042d53a7SEvalZero  *****************************************************************************/
613*042d53a7SEvalZero 
614*042d53a7SEvalZero int
ble_att_clt_tx_read_group_type(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid)615*042d53a7SEvalZero ble_att_clt_tx_read_group_type(uint16_t conn_handle,
616*042d53a7SEvalZero                                uint16_t start_handle, uint16_t end_handle,
617*042d53a7SEvalZero                                const ble_uuid_t *uuid)
618*042d53a7SEvalZero {
619*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE
620*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
621*042d53a7SEvalZero #endif
622*042d53a7SEvalZero 
623*042d53a7SEvalZero     struct ble_att_read_group_type_req *req;
624*042d53a7SEvalZero     struct os_mbuf *txom;
625*042d53a7SEvalZero 
626*042d53a7SEvalZero     if (start_handle == 0 || start_handle > end_handle) {
627*042d53a7SEvalZero         return BLE_HS_EINVAL;
628*042d53a7SEvalZero     }
629*042d53a7SEvalZero 
630*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_READ_GROUP_TYPE_REQ,
631*042d53a7SEvalZero                           sizeof(*req) + ble_uuid_length(uuid), &txom);
632*042d53a7SEvalZero     if (req == NULL) {
633*042d53a7SEvalZero         return BLE_HS_ENOMEM;
634*042d53a7SEvalZero     }
635*042d53a7SEvalZero 
636*042d53a7SEvalZero     req->bagq_start_handle = htole16(start_handle);
637*042d53a7SEvalZero     req->bagq_end_handle = htole16(end_handle);
638*042d53a7SEvalZero     ble_uuid_flat(uuid, req->uuid);
639*042d53a7SEvalZero 
640*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "read group type req", conn_handle,
641*042d53a7SEvalZero                     ble_att_read_group_type_req_log, req);
642*042d53a7SEvalZero 
643*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom);
644*042d53a7SEvalZero }
645*042d53a7SEvalZero 
646*042d53a7SEvalZero static int
ble_att_clt_parse_read_group_type_adata(struct os_mbuf ** om,int data_len,struct ble_att_read_group_type_adata * adata)647*042d53a7SEvalZero ble_att_clt_parse_read_group_type_adata(
648*042d53a7SEvalZero     struct os_mbuf **om, int data_len,
649*042d53a7SEvalZero     struct ble_att_read_group_type_adata *adata)
650*042d53a7SEvalZero {
651*042d53a7SEvalZero     int rc;
652*042d53a7SEvalZero 
653*042d53a7SEvalZero     if (data_len < BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ + 1) {
654*042d53a7SEvalZero         return BLE_HS_EMSGSIZE;
655*042d53a7SEvalZero     }
656*042d53a7SEvalZero 
657*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(om, data_len);
658*042d53a7SEvalZero     if (rc != 0) {
659*042d53a7SEvalZero         return rc;
660*042d53a7SEvalZero     }
661*042d53a7SEvalZero 
662*042d53a7SEvalZero     adata->att_handle = get_le16((*om)->om_data + 0);
663*042d53a7SEvalZero     adata->end_group_handle = get_le16((*om)->om_data + 2);
664*042d53a7SEvalZero     adata->value_len = data_len - BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ;
665*042d53a7SEvalZero     adata->value = (*om)->om_data + BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ;
666*042d53a7SEvalZero 
667*042d53a7SEvalZero     return 0;
668*042d53a7SEvalZero }
669*042d53a7SEvalZero 
670*042d53a7SEvalZero int
ble_att_clt_rx_read_group_type(uint16_t conn_handle,struct os_mbuf ** rxom)671*042d53a7SEvalZero ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom)
672*042d53a7SEvalZero {
673*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE
674*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
675*042d53a7SEvalZero #endif
676*042d53a7SEvalZero 
677*042d53a7SEvalZero     struct ble_att_read_group_type_adata adata;
678*042d53a7SEvalZero     struct ble_att_read_group_type_rsp *rsp;
679*042d53a7SEvalZero     uint8_t len;
680*042d53a7SEvalZero     int rc;
681*042d53a7SEvalZero 
682*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
683*042d53a7SEvalZero     if (rc != 0) {
684*042d53a7SEvalZero         goto done;
685*042d53a7SEvalZero     }
686*042d53a7SEvalZero 
687*042d53a7SEvalZero     rsp = (struct ble_att_read_group_type_rsp *)(*rxom)->om_data;
688*042d53a7SEvalZero 
689*042d53a7SEvalZero     BLE_ATT_LOG_CMD(0, "read group type rsp", conn_handle,
690*042d53a7SEvalZero                     ble_att_read_group_type_rsp_log, rsp);
691*042d53a7SEvalZero 
692*042d53a7SEvalZero     len = rsp->bagp_length;
693*042d53a7SEvalZero 
694*042d53a7SEvalZero     /* Strip the base from the front of the response. */
695*042d53a7SEvalZero     os_mbuf_adj(*rxom, sizeof(*rsp));
696*042d53a7SEvalZero 
697*042d53a7SEvalZero     /* Parse the Attribute Data List field, passing each entry to GATT. */
698*042d53a7SEvalZero     while (OS_MBUF_PKTLEN(*rxom) > 0) {
699*042d53a7SEvalZero         rc = ble_att_clt_parse_read_group_type_adata(rxom, len, &adata);
700*042d53a7SEvalZero         if (rc != 0) {
701*042d53a7SEvalZero             goto done;
702*042d53a7SEvalZero         }
703*042d53a7SEvalZero 
704*042d53a7SEvalZero         ble_gattc_rx_read_group_type_adata(conn_handle, &adata);
705*042d53a7SEvalZero         os_mbuf_adj(*rxom, len);
706*042d53a7SEvalZero     }
707*042d53a7SEvalZero 
708*042d53a7SEvalZero done:
709*042d53a7SEvalZero     /* Notify GATT that the response is done being parsed. */
710*042d53a7SEvalZero     ble_gattc_rx_read_group_type_complete(conn_handle, rc);
711*042d53a7SEvalZero     return rc;
712*042d53a7SEvalZero }
713*042d53a7SEvalZero 
714*042d53a7SEvalZero /*****************************************************************************
715*042d53a7SEvalZero  * $write                                                                    *
716*042d53a7SEvalZero  *****************************************************************************/
717*042d53a7SEvalZero 
718*042d53a7SEvalZero int
ble_att_clt_tx_write_req(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)719*042d53a7SEvalZero ble_att_clt_tx_write_req(uint16_t conn_handle, uint16_t handle,
720*042d53a7SEvalZero                          struct os_mbuf *txom)
721*042d53a7SEvalZero {
722*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_WRITE
723*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
724*042d53a7SEvalZero #endif
725*042d53a7SEvalZero 
726*042d53a7SEvalZero     struct ble_att_write_req *req;
727*042d53a7SEvalZero     struct os_mbuf *txom2;
728*042d53a7SEvalZero 
729*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_WRITE_REQ, sizeof(*req), &txom2);
730*042d53a7SEvalZero     if (req == NULL) {
731*042d53a7SEvalZero         os_mbuf_free_chain(txom);
732*042d53a7SEvalZero         return BLE_HS_ENOMEM;
733*042d53a7SEvalZero     }
734*042d53a7SEvalZero 
735*042d53a7SEvalZero     req->bawq_handle = htole16(handle);
736*042d53a7SEvalZero     os_mbuf_concat(txom2, txom);
737*042d53a7SEvalZero 
738*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "write req", conn_handle, ble_att_write_req_log, req);
739*042d53a7SEvalZero 
740*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom2);
741*042d53a7SEvalZero }
742*042d53a7SEvalZero 
743*042d53a7SEvalZero int
ble_att_clt_tx_write_cmd(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)744*042d53a7SEvalZero ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t handle,
745*042d53a7SEvalZero                          struct os_mbuf *txom)
746*042d53a7SEvalZero {
747*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_WRITE_NO_RSP
748*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
749*042d53a7SEvalZero #endif
750*042d53a7SEvalZero 
751*042d53a7SEvalZero     struct ble_att_write_cmd *cmd;
752*042d53a7SEvalZero     struct os_mbuf *txom2;
753*042d53a7SEvalZero     uint8_t b;
754*042d53a7SEvalZero     int rc;
755*042d53a7SEvalZero     int i;
756*042d53a7SEvalZero 
757*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "ble_att_clt_tx_write_cmd(): ");
758*042d53a7SEvalZero     for (i = 0; i < OS_MBUF_PKTLEN(txom); i++) {
759*042d53a7SEvalZero         if (i != 0) {
760*042d53a7SEvalZero             BLE_HS_LOG(DEBUG, ":");
761*042d53a7SEvalZero         }
762*042d53a7SEvalZero         rc = os_mbuf_copydata(txom, i, 1, &b);
763*042d53a7SEvalZero         assert(rc == 0);
764*042d53a7SEvalZero         BLE_HS_LOG(DEBUG, "0x%02x", b);
765*042d53a7SEvalZero     }
766*042d53a7SEvalZero 
767*042d53a7SEvalZero 
768*042d53a7SEvalZero     cmd = ble_att_cmd_get(BLE_ATT_OP_WRITE_CMD, sizeof(*cmd), &txom2);
769*042d53a7SEvalZero     if (cmd == NULL) {
770*042d53a7SEvalZero         os_mbuf_free_chain(txom);
771*042d53a7SEvalZero         return BLE_HS_ENOMEM;
772*042d53a7SEvalZero     }
773*042d53a7SEvalZero 
774*042d53a7SEvalZero     cmd->handle = htole16(handle);
775*042d53a7SEvalZero     os_mbuf_concat(txom2, txom);
776*042d53a7SEvalZero 
777*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "write cmd", conn_handle, ble_att_write_cmd_log, cmd);
778*042d53a7SEvalZero 
779*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom2);
780*042d53a7SEvalZero }
781*042d53a7SEvalZero 
782*042d53a7SEvalZero int
ble_att_clt_rx_write(uint16_t conn_handle,struct os_mbuf ** rxom)783*042d53a7SEvalZero ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
784*042d53a7SEvalZero {
785*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_WRITE
786*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
787*042d53a7SEvalZero #endif
788*042d53a7SEvalZero 
789*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(0, "write rsp", conn_handle);
790*042d53a7SEvalZero 
791*042d53a7SEvalZero     /* No payload. */
792*042d53a7SEvalZero     ble_gattc_rx_write_rsp(conn_handle);
793*042d53a7SEvalZero     return 0;
794*042d53a7SEvalZero }
795*042d53a7SEvalZero 
796*042d53a7SEvalZero /*****************************************************************************
797*042d53a7SEvalZero  * $prepare write request                                                    *
798*042d53a7SEvalZero  *****************************************************************************/
799*042d53a7SEvalZero 
800*042d53a7SEvalZero int
ble_att_clt_tx_prep_write(uint16_t conn_handle,uint16_t handle,uint16_t offset,struct os_mbuf * txom)801*042d53a7SEvalZero ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t handle,
802*042d53a7SEvalZero                           uint16_t offset, struct os_mbuf *txom)
803*042d53a7SEvalZero {
804*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_PREP_WRITE
805*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
806*042d53a7SEvalZero #endif
807*042d53a7SEvalZero 
808*042d53a7SEvalZero     struct ble_att_prep_write_cmd *req;
809*042d53a7SEvalZero     struct os_mbuf *txom2;
810*042d53a7SEvalZero     int rc;
811*042d53a7SEvalZero 
812*042d53a7SEvalZero     if (handle == 0) {
813*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
814*042d53a7SEvalZero         goto err;
815*042d53a7SEvalZero     }
816*042d53a7SEvalZero 
817*042d53a7SEvalZero     if (offset + OS_MBUF_PKTLEN(txom) > BLE_ATT_ATTR_MAX_LEN) {
818*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
819*042d53a7SEvalZero         goto err;
820*042d53a7SEvalZero     }
821*042d53a7SEvalZero 
822*042d53a7SEvalZero     if (OS_MBUF_PKTLEN(txom) >
823*042d53a7SEvalZero         ble_att_mtu(conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ) {
824*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
825*042d53a7SEvalZero         goto err;
826*042d53a7SEvalZero     }
827*042d53a7SEvalZero 
828*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_PREP_WRITE_REQ, sizeof(*req), &txom2);
829*042d53a7SEvalZero     if (req == NULL) {
830*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
831*042d53a7SEvalZero         goto err;
832*042d53a7SEvalZero     }
833*042d53a7SEvalZero 
834*042d53a7SEvalZero     req->bapc_handle = htole16(handle);
835*042d53a7SEvalZero     req->bapc_offset = htole16(offset);
836*042d53a7SEvalZero     os_mbuf_concat(txom2, txom);
837*042d53a7SEvalZero 
838*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "prep write req", conn_handle,
839*042d53a7SEvalZero                     ble_att_prep_write_cmd_log, req);
840*042d53a7SEvalZero 
841*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom2);
842*042d53a7SEvalZero 
843*042d53a7SEvalZero err:
844*042d53a7SEvalZero     os_mbuf_free_chain(txom);
845*042d53a7SEvalZero     return rc;
846*042d53a7SEvalZero }
847*042d53a7SEvalZero 
848*042d53a7SEvalZero int
ble_att_clt_rx_prep_write(uint16_t conn_handle,struct os_mbuf ** rxom)849*042d53a7SEvalZero ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
850*042d53a7SEvalZero {
851*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_PREP_WRITE
852*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
853*042d53a7SEvalZero #endif
854*042d53a7SEvalZero 
855*042d53a7SEvalZero     struct ble_att_prep_write_cmd *rsp;
856*042d53a7SEvalZero     uint16_t handle, offset;
857*042d53a7SEvalZero     int rc;
858*042d53a7SEvalZero 
859*042d53a7SEvalZero     /* Initialize some values in case of early error. */
860*042d53a7SEvalZero     handle = 0;
861*042d53a7SEvalZero     offset = 0;
862*042d53a7SEvalZero 
863*042d53a7SEvalZero     rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
864*042d53a7SEvalZero     if (rc != 0) {
865*042d53a7SEvalZero         goto done;
866*042d53a7SEvalZero     }
867*042d53a7SEvalZero 
868*042d53a7SEvalZero     rsp = (struct ble_att_prep_write_cmd *)(*rxom)->om_data;
869*042d53a7SEvalZero     BLE_ATT_LOG_CMD(0, "prep write rsp", conn_handle,
870*042d53a7SEvalZero                     ble_att_prep_write_cmd_log, rsp);
871*042d53a7SEvalZero 
872*042d53a7SEvalZero     handle = le16toh(rsp->bapc_handle);
873*042d53a7SEvalZero     offset = le16toh(rsp->bapc_offset);
874*042d53a7SEvalZero 
875*042d53a7SEvalZero     /* Strip the base from the front of the response. */
876*042d53a7SEvalZero     os_mbuf_adj(*rxom, sizeof(*rsp));
877*042d53a7SEvalZero 
878*042d53a7SEvalZero done:
879*042d53a7SEvalZero     /* Notify GATT client that the full response has been parsed. */
880*042d53a7SEvalZero     ble_gattc_rx_prep_write_rsp(conn_handle, rc, handle, offset, rxom);
881*042d53a7SEvalZero     return rc;
882*042d53a7SEvalZero }
883*042d53a7SEvalZero 
884*042d53a7SEvalZero /*****************************************************************************
885*042d53a7SEvalZero  * $execute write request                                                    *
886*042d53a7SEvalZero  *****************************************************************************/
887*042d53a7SEvalZero 
888*042d53a7SEvalZero int
ble_att_clt_tx_exec_write(uint16_t conn_handle,uint8_t flags)889*042d53a7SEvalZero ble_att_clt_tx_exec_write(uint16_t conn_handle, uint8_t flags)
890*042d53a7SEvalZero {
891*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE
892*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
893*042d53a7SEvalZero #endif
894*042d53a7SEvalZero 
895*042d53a7SEvalZero     struct ble_att_exec_write_req *req;
896*042d53a7SEvalZero     struct os_mbuf *txom;
897*042d53a7SEvalZero     int rc;
898*042d53a7SEvalZero 
899*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_EXEC_WRITE_REQ, sizeof(*req), &txom);
900*042d53a7SEvalZero     if (req == NULL) {
901*042d53a7SEvalZero         return BLE_HS_ENOMEM;
902*042d53a7SEvalZero     }
903*042d53a7SEvalZero 
904*042d53a7SEvalZero     req->baeq_flags = flags;
905*042d53a7SEvalZero 
906*042d53a7SEvalZero     rc = ble_att_tx(conn_handle, txom);
907*042d53a7SEvalZero     if (rc != 0) {
908*042d53a7SEvalZero         return rc;
909*042d53a7SEvalZero     }
910*042d53a7SEvalZero 
911*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "exec write req", conn_handle,
912*042d53a7SEvalZero                     ble_att_exec_write_req_log, req);
913*042d53a7SEvalZero 
914*042d53a7SEvalZero     return 0;
915*042d53a7SEvalZero }
916*042d53a7SEvalZero 
917*042d53a7SEvalZero int
ble_att_clt_rx_exec_write(uint16_t conn_handle,struct os_mbuf ** rxom)918*042d53a7SEvalZero ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom)
919*042d53a7SEvalZero {
920*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE
921*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
922*042d53a7SEvalZero #endif
923*042d53a7SEvalZero 
924*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(0, "exec write rsp", conn_handle);
925*042d53a7SEvalZero 
926*042d53a7SEvalZero     ble_gattc_rx_exec_write_rsp(conn_handle, 0);
927*042d53a7SEvalZero     return 0;
928*042d53a7SEvalZero }
929*042d53a7SEvalZero 
930*042d53a7SEvalZero /*****************************************************************************
931*042d53a7SEvalZero  * $handle value notification                                                *
932*042d53a7SEvalZero  *****************************************************************************/
933*042d53a7SEvalZero 
934*042d53a7SEvalZero int
ble_att_clt_tx_notify(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)935*042d53a7SEvalZero ble_att_clt_tx_notify(uint16_t conn_handle, uint16_t handle,
936*042d53a7SEvalZero                       struct os_mbuf *txom)
937*042d53a7SEvalZero {
938*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_NOTIFY
939*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
940*042d53a7SEvalZero #endif
941*042d53a7SEvalZero 
942*042d53a7SEvalZero     struct ble_att_notify_req *req;
943*042d53a7SEvalZero     struct os_mbuf *txom2;
944*042d53a7SEvalZero     int rc;
945*042d53a7SEvalZero 
946*042d53a7SEvalZero     if (handle == 0) {
947*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
948*042d53a7SEvalZero         goto err;
949*042d53a7SEvalZero     }
950*042d53a7SEvalZero 
951*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_NOTIFY_REQ, sizeof(*req), &txom2);
952*042d53a7SEvalZero     if (req == NULL) {
953*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
954*042d53a7SEvalZero         goto err;
955*042d53a7SEvalZero     }
956*042d53a7SEvalZero 
957*042d53a7SEvalZero     req->banq_handle = htole16(handle);
958*042d53a7SEvalZero     os_mbuf_concat(txom2, txom);
959*042d53a7SEvalZero 
960*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "notify req", conn_handle, ble_att_notify_req_log, req);
961*042d53a7SEvalZero 
962*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom2);
963*042d53a7SEvalZero 
964*042d53a7SEvalZero err:
965*042d53a7SEvalZero     os_mbuf_free_chain(txom);
966*042d53a7SEvalZero     return rc;
967*042d53a7SEvalZero }
968*042d53a7SEvalZero 
969*042d53a7SEvalZero /*****************************************************************************
970*042d53a7SEvalZero  * $handle value indication                                                  *
971*042d53a7SEvalZero  *****************************************************************************/
972*042d53a7SEvalZero 
973*042d53a7SEvalZero int
ble_att_clt_tx_indicate(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)974*042d53a7SEvalZero ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t handle,
975*042d53a7SEvalZero                         struct os_mbuf *txom)
976*042d53a7SEvalZero {
977*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_INDICATE
978*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
979*042d53a7SEvalZero #endif
980*042d53a7SEvalZero 
981*042d53a7SEvalZero     struct ble_att_indicate_req *req;
982*042d53a7SEvalZero     struct os_mbuf *txom2;
983*042d53a7SEvalZero     int rc;
984*042d53a7SEvalZero 
985*042d53a7SEvalZero     if (handle == 0) {
986*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
987*042d53a7SEvalZero         goto err;
988*042d53a7SEvalZero     }
989*042d53a7SEvalZero 
990*042d53a7SEvalZero     req = ble_att_cmd_get(BLE_ATT_OP_INDICATE_REQ, sizeof(*req), &txom2);
991*042d53a7SEvalZero     if (req == NULL) {
992*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
993*042d53a7SEvalZero         goto err;
994*042d53a7SEvalZero     }
995*042d53a7SEvalZero 
996*042d53a7SEvalZero     req->baiq_handle = htole16(handle);
997*042d53a7SEvalZero     os_mbuf_concat(txom2, txom);
998*042d53a7SEvalZero 
999*042d53a7SEvalZero     BLE_ATT_LOG_CMD(1, "indicate req", conn_handle, ble_att_indicate_req_log,
1000*042d53a7SEvalZero                     req);
1001*042d53a7SEvalZero 
1002*042d53a7SEvalZero     return ble_att_tx(conn_handle, txom2);
1003*042d53a7SEvalZero 
1004*042d53a7SEvalZero err:
1005*042d53a7SEvalZero     os_mbuf_free_chain(txom);
1006*042d53a7SEvalZero     return rc;
1007*042d53a7SEvalZero }
1008*042d53a7SEvalZero 
1009*042d53a7SEvalZero int
ble_att_clt_rx_indicate(uint16_t conn_handle,struct os_mbuf ** rxom)1010*042d53a7SEvalZero ble_att_clt_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
1011*042d53a7SEvalZero {
1012*042d53a7SEvalZero #if !NIMBLE_BLE_ATT_CLT_INDICATE
1013*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
1014*042d53a7SEvalZero #endif
1015*042d53a7SEvalZero 
1016*042d53a7SEvalZero     BLE_ATT_LOG_EMPTY_CMD(0, "indicate rsp", conn_handle);
1017*042d53a7SEvalZero 
1018*042d53a7SEvalZero     /* No payload. */
1019*042d53a7SEvalZero     ble_gattc_rx_indicate_rsp(conn_handle);
1020*042d53a7SEvalZero     return 0;
1021*042d53a7SEvalZero }
1022