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