1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include "os/os_mempool.h"
25 #include "nimble/ble.h"
26 #include "host/ble_uuid.h"
27 #include "ble_hs_priv.h"
28
29 /*****************************************************************************
30 * $error response *
31 *****************************************************************************/
32
ble_att_clt_rx_error(uint16_t conn_handle,struct os_mbuf ** rxom)33 int ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom)
34 {
35 struct ble_att_error_rsp *rsp;
36 int rc;
37 rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
38 if (rc != 0) {
39 return rc;
40 }
41
42 rsp = (struct ble_att_error_rsp *)(*rxom)->om_data;
43 ble_gattc_rx_err(conn_handle, le16toh(rsp->baep_handle),
44 le16toh(rsp->baep_error_code));
45 return 0;
46 }
47
48 /*****************************************************************************
49 * $mtu exchange *
50 *****************************************************************************/
51
ble_att_clt_tx_mtu(uint16_t conn_handle,uint16_t mtu)52 int ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu)
53 {
54 struct ble_att_mtu_cmd *req;
55 struct ble_l2cap_chan *chan;
56 struct ble_hs_conn *conn;
57 struct os_mbuf *txom;
58 int rc;
59
60 if (mtu < BLE_ATT_MTU_DFLT) {
61 return BLE_HS_EINVAL;
62 }
63
64 ble_hs_lock();
65 rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
66 if (rc != 0) {
67 rc = BLE_HS_ENOTCONN;
68 } else if (chan->flags & BLE_L2CAP_CHAN_F_TXED_MTU) {
69 rc = BLE_HS_EALREADY;
70 } else {
71 rc = 0;
72 }
73
74 ble_hs_unlock();
75
76 if (rc != 0) {
77 return rc;
78 }
79
80 req = ble_att_cmd_get(BLE_ATT_OP_MTU_REQ, sizeof(*req), &txom);
81 if (req == NULL) {
82 return BLE_HS_ENOMEM;
83 }
84
85 req->bamc_mtu = htole16(mtu);
86 rc = ble_att_tx(conn_handle, txom);
87 if (rc != 0) {
88 return rc;
89 }
90
91 ble_hs_lock();
92 rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
93 if (rc == 0) {
94 chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU;
95 }
96
97 ble_hs_unlock();
98 return rc;
99 }
100
ble_att_clt_rx_mtu(uint16_t conn_handle,struct os_mbuf ** rxom)101 int ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom)
102 {
103 struct ble_att_mtu_cmd *cmd;
104 struct ble_l2cap_chan *chan;
105 uint16_t mtu;
106 int rc;
107 mtu = 0;
108 rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*cmd));
109 if (rc == 0) {
110 cmd = (struct ble_att_mtu_cmd *)(*rxom)->om_data;
111 ble_hs_lock();
112 rc = ble_att_conn_chan_find(conn_handle, NULL, &chan);
113 if (rc == 0) {
114 ble_att_set_peer_mtu(chan, le16toh(cmd->bamc_mtu));
115 mtu = ble_att_chan_mtu(chan);
116 }
117
118 ble_hs_unlock();
119
120 if (rc == 0) {
121 ble_gap_mtu_event(conn_handle, BLE_L2CAP_CID_ATT, mtu);
122 }
123 }
124
125 ble_gattc_rx_mtu(conn_handle, rc, mtu);
126 return rc;
127 }
128
129 /*****************************************************************************
130 * $find information *
131 *****************************************************************************/
132
ble_att_clt_tx_find_info(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle)133 int ble_att_clt_tx_find_info(uint16_t conn_handle, uint16_t start_handle,
134 uint16_t end_handle)
135 {
136 #if !NIMBLE_BLE_ATT_CLT_FIND_INFO
137 return BLE_HS_ENOTSUP;
138 #endif
139 struct ble_att_find_info_req *req;
140 struct os_mbuf *txom;
141
142 if (start_handle == 0 || start_handle > end_handle) {
143 return BLE_HS_EINVAL;
144 }
145
146 req = ble_att_cmd_get(BLE_ATT_OP_FIND_INFO_REQ, sizeof(*req), &txom);
147 if (req == NULL) {
148 return BLE_HS_ENOMEM;
149 }
150
151 req->bafq_start_handle = htole16(start_handle);
152 req->bafq_end_handle = htole16(end_handle);
153 return ble_att_tx(conn_handle, txom);
154 }
155
ble_att_clt_parse_find_info_entry(struct os_mbuf ** rxom,uint8_t rsp_format,struct ble_att_find_info_idata * idata)156 static int ble_att_clt_parse_find_info_entry(struct os_mbuf **rxom, uint8_t rsp_format,
157 struct ble_att_find_info_idata *idata)
158 {
159 int entry_len;
160 int rc;
161
162 switch (rsp_format) {
163 case BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT:
164 entry_len = 2 + 2; // 2:byte alignment
165 break;
166
167 case BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT:
168 entry_len = 2 + 16; // 2:byte alignment, 16:byte alignment
169 break;
170
171 default:
172 return BLE_HS_EBADDATA;
173 }
174
175 rc = ble_hs_mbuf_pullup_base(rxom, entry_len);
176 if (rc != 0) {
177 return rc;
178 }
179
180 idata->attr_handle = get_le16((*rxom)->om_data);
181
182 switch (rsp_format) {
183 case BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT:
184 rc = ble_uuid_init_from_att_mbuf(&idata->uuid, *rxom, 2, 2); // 2:off & len
185 if (rc != 0) {
186 return BLE_HS_EBADDATA;
187 }
188
189 break;
190
191 case BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT:
192 rc = ble_uuid_init_from_att_mbuf(&idata->uuid, *rxom, 2, 16); // 2:off, 16:len
193 if (rc != 0) {
194 return BLE_HS_EBADDATA;
195 }
196
197 break;
198
199 default:
200 BLE_HS_DBG_ASSERT(0);
201 break;
202 }
203
204 os_mbuf_adj(*rxom, entry_len);
205 return 0;
206 }
207
ble_att_clt_rx_find_info(uint16_t conn_handle,struct os_mbuf ** om)208 int ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om)
209 {
210 #if !NIMBLE_BLE_ATT_CLT_FIND_INFO
211 return BLE_HS_ENOTSUP;
212 #endif
213 struct ble_att_find_info_idata idata;
214 struct ble_att_find_info_rsp *rsp;
215 int rc;
216 rc = ble_hs_mbuf_pullup_base(om, sizeof(*rsp));
217 if (rc != 0) {
218 goto done;
219 }
220
221 rsp = (struct ble_att_find_info_rsp *)(*om)->om_data;
222 /* Strip the response base from the front of the mbuf. */
223 os_mbuf_adj((*om), sizeof(*rsp));
224
225 while (OS_MBUF_PKTLEN(*om) > 0) {
226 rc = ble_att_clt_parse_find_info_entry(om, rsp->bafp_format, &idata);
227 if (rc != 0) {
228 goto done;
229 }
230
231 /* Hand find-info entry to GATT. */
232 ble_gattc_rx_find_info_idata(conn_handle, &idata);
233 }
234
235 rc = 0;
236 done:
237 /* Notify GATT that response processing is done. */
238 ble_gattc_rx_find_info_complete(conn_handle, rc);
239 return rc;
240 }
241
242 /*****************************************************************************
243 * $find by type value *
244 *****************************************************************************/
245
246 /*
247 * consider this to accept UUID instead of value, it is used only for this
248 * anyway
249 */
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)250 int ble_att_clt_tx_find_type_value(uint16_t conn_handle, uint16_t start_handle,
251 uint16_t end_handle, uint16_t attribute_type,
252 const void *attribute_value, int value_len)
253 {
254 #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE
255 return BLE_HS_ENOTSUP;
256 #endif
257 struct ble_att_find_type_value_req *req;
258 struct os_mbuf *txom;
259
260 if (start_handle == 0 || start_handle > end_handle) {
261 return BLE_HS_EINVAL;
262 }
263
264 req = ble_att_cmd_get(BLE_ATT_OP_FIND_TYPE_VALUE_REQ, sizeof(*req) + value_len,
265 &txom);
266 if (req == NULL) {
267 return BLE_HS_ENOMEM;
268 }
269
270 req->bavq_start_handle = htole16(start_handle);
271 req->bavq_end_handle = htole16(end_handle);
272 req->bavq_attr_type = htole16(attribute_type);
273 memcpy(req->bavq_value, attribute_value, value_len);
274 return ble_att_tx(conn_handle, txom);
275 }
276
ble_att_clt_parse_find_type_value_hinfo(struct os_mbuf ** om,struct ble_att_find_type_value_hinfo * dst)277 static int ble_att_clt_parse_find_type_value_hinfo(struct os_mbuf **om, struct ble_att_find_type_value_hinfo *dst)
278 {
279 struct ble_att_handle_group *group;
280 int rc;
281 rc = ble_hs_mbuf_pullup_base(om, sizeof(*group));
282 if (rc != 0) {
283 return BLE_HS_EBADDATA;
284 }
285
286 group = (struct ble_att_handle_group *)(*om)->om_data;
287 dst->attr_handle = le16toh(group->attr_handle);
288 dst->group_end_handle = le16toh(group->group_end_handle);
289 os_mbuf_adj((*om), sizeof(*group));
290 return 0;
291 }
292
ble_att_clt_rx_find_type_value(uint16_t conn_handle,struct os_mbuf ** rxom)293 int ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom)
294 {
295 #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE
296 return BLE_HS_ENOTSUP;
297 #endif
298 struct ble_att_find_type_value_hinfo hinfo;
299 int rc;
300 /* Parse the Handles-Information-List field, passing each entry to GATT. */
301 rc = 0;
302
303 while (OS_MBUF_PKTLEN(*rxom) > 0) {
304 rc = ble_att_clt_parse_find_type_value_hinfo(rxom, &hinfo);
305 if (rc != 0) {
306 break;
307 }
308
309 ble_gattc_rx_find_type_value_hinfo(conn_handle, &hinfo);
310 }
311
312 /* Notify GATT client that the full response has been parsed. */
313 ble_gattc_rx_find_type_value_complete(conn_handle, rc);
314 return 0;
315 }
316
317 /*****************************************************************************
318 * $read by type *
319 *****************************************************************************/
320
ble_att_clt_tx_read_type(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid)321 int ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t start_handle,
322 uint16_t end_handle, const ble_uuid_t *uuid)
323 {
324 #if !NIMBLE_BLE_ATT_CLT_READ_TYPE
325 return BLE_HS_ENOTSUP;
326 #endif
327 struct ble_att_read_type_req *req;
328 struct os_mbuf *txom;
329
330 if (start_handle == 0 || start_handle > end_handle) {
331 return BLE_HS_EINVAL;
332 }
333
334 req = ble_att_cmd_get(BLE_ATT_OP_READ_TYPE_REQ,
335 sizeof(*req) + ble_uuid_length(uuid), &txom);
336 if (req == NULL) {
337 return BLE_HS_ENOMEM;
338 }
339
340 req->batq_start_handle = htole16(start_handle);
341 req->batq_end_handle = htole16(end_handle);
342 ble_uuid_flat(uuid, req->uuid);
343 return ble_att_tx(conn_handle, txom);
344 }
345
ble_att_clt_rx_read_type(uint16_t conn_handle,struct os_mbuf ** rxom)346 int ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
347 {
348 #if !NIMBLE_BLE_ATT_CLT_READ_TYPE
349 return BLE_HS_ENOTSUP;
350 #endif
351 struct ble_att_read_type_adata adata;
352 struct ble_att_attr_data_list *data;
353 struct ble_att_read_type_rsp *rsp;
354 uint8_t data_len;
355 int rc;
356 rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
357 if (rc != 0) {
358 goto done;
359 }
360
361 rsp = (struct ble_att_read_type_rsp *)(*rxom)->om_data;
362 data_len = rsp->batp_length;
363 /* Strip the response base from the front of the mbuf. */
364 os_mbuf_adj(*rxom, sizeof(*rsp));
365
366 if (data_len < sizeof(*data)) {
367 rc = BLE_HS_EBADDATA;
368 goto done;
369 }
370
371 /* Parse the Attribute Data List field, passing each entry to the GATT. */
372 while (OS_MBUF_PKTLEN(*rxom) > 0) {
373 rc = ble_hs_mbuf_pullup_base(rxom, data_len);
374 if (rc != 0) {
375 break;
376 }
377
378 data = (struct ble_att_attr_data_list *)(*rxom)->om_data;
379 adata.att_handle = le16toh(data->handle);
380 adata.value_len = data_len - sizeof(*data);
381 adata.value = data->value;
382 ble_gattc_rx_read_type_adata(conn_handle, &adata);
383 os_mbuf_adj(*rxom, data_len);
384 }
385
386 done:
387 /* Notify GATT that the response is done being parsed. */
388 ble_gattc_rx_read_type_complete(conn_handle, rc);
389 return rc;
390 }
391
392 /*****************************************************************************
393 * $read *
394 *****************************************************************************/
395
ble_att_clt_tx_read(uint16_t conn_handle,uint16_t handle)396 int ble_att_clt_tx_read(uint16_t conn_handle, uint16_t handle)
397 {
398 #if !NIMBLE_BLE_ATT_CLT_READ
399 return BLE_HS_ENOTSUP;
400 #endif
401 struct ble_att_read_req *req;
402 struct os_mbuf *txom;
403 int rc;
404
405 if (handle == 0) {
406 return BLE_HS_EINVAL;
407 }
408
409 req = ble_att_cmd_get(BLE_ATT_OP_READ_REQ, sizeof(*req), &txom);
410 if (req == NULL) {
411 return BLE_HS_ENOMEM;
412 }
413
414 req->barq_handle = htole16(handle);
415 rc = ble_att_tx(conn_handle, txom);
416 if (rc != 0) {
417 return rc;
418 }
419
420 return 0;
421 }
422
ble_att_clt_rx_read(uint16_t conn_handle,struct os_mbuf ** rxom)423 int ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
424 {
425 #if !NIMBLE_BLE_ATT_CLT_READ
426 return BLE_HS_ENOTSUP;
427 #endif
428 /* Pass the Attribute Value field to GATT. */
429 ble_gattc_rx_read_rsp(conn_handle, 0, rxom);
430 return 0;
431 }
432
433 /*****************************************************************************
434 * $read blob *
435 *****************************************************************************/
436
ble_att_clt_tx_read_blob(uint16_t conn_handle,uint16_t handle,uint16_t offset)437 int ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t handle, uint16_t offset)
438 {
439 #if !NIMBLE_BLE_ATT_CLT_READ_BLOB
440 return BLE_HS_ENOTSUP;
441 #endif
442 struct ble_att_read_blob_req *req;
443 struct os_mbuf *txom;
444 int rc;
445
446 if (handle == 0) {
447 return BLE_HS_EINVAL;
448 }
449
450 req = ble_att_cmd_get(BLE_ATT_OP_READ_BLOB_REQ, sizeof(*req), &txom);
451 if (req == NULL) {
452 return BLE_HS_ENOMEM;
453 }
454
455 req->babq_handle = htole16(handle);
456 req->babq_offset = htole16(offset);
457 rc = ble_att_tx(conn_handle, txom);
458 if (rc != 0) {
459 return rc;
460 }
461
462 return 0;
463 }
464
ble_att_clt_rx_read_blob(uint16_t conn_handle,struct os_mbuf ** rxom)465 int ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
466 {
467 #if !NIMBLE_BLE_ATT_CLT_READ_BLOB
468 return BLE_HS_ENOTSUP;
469 #endif
470 /* Pass the Attribute Value field to GATT. */
471 ble_gattc_rx_read_blob_rsp(conn_handle, 0, rxom);
472 return 0;
473 }
474
475 /*****************************************************************************
476 * $read multiple *
477 *****************************************************************************/
ble_att_clt_tx_read_mult(uint16_t conn_handle,const uint16_t * handles,int num_handles)478 int ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *handles,
479 int num_handles)
480 {
481 #if !NIMBLE_BLE_ATT_CLT_READ_MULT
482 return BLE_HS_ENOTSUP;
483 #endif
484 struct ble_att_read_mult_req *req;
485 struct os_mbuf *txom;
486 int i;
487
488 if (num_handles < 1) {
489 return BLE_HS_EINVAL;
490 }
491
492 req = ble_att_cmd_get(BLE_ATT_OP_READ_MULT_REQ,
493 sizeof(req->handles[0]) * num_handles,
494 &txom);
495 if (req == NULL) {
496 return BLE_HS_ENOMEM;
497 }
498
499 for (i = 0; i < num_handles; i++) {
500 req->handles[i] = htole16(handles[i]);
501 }
502
503 return ble_att_tx(conn_handle, txom);
504 }
505
ble_att_clt_rx_read_mult(uint16_t conn_handle,struct os_mbuf ** rxom)506 int ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
507 {
508 #if !NIMBLE_BLE_ATT_CLT_READ_MULT
509 return BLE_HS_ENOTSUP;
510 #endif
511 /* Pass the Attribute Value field to GATT. */
512 ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom);
513 return 0;
514 }
515
516 /*****************************************************************************
517 * $read by group type *
518 *****************************************************************************/
519
ble_att_clt_tx_read_group_type(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid)520 int ble_att_clt_tx_read_group_type(uint16_t conn_handle,
521 uint16_t start_handle, uint16_t end_handle,
522 const ble_uuid_t *uuid)
523 {
524 #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE
525 return BLE_HS_ENOTSUP;
526 #endif
527 struct ble_att_read_group_type_req *req;
528 struct os_mbuf *txom;
529
530 if (start_handle == 0 || start_handle > end_handle) {
531 return BLE_HS_EINVAL;
532 }
533
534 req = ble_att_cmd_get(BLE_ATT_OP_READ_GROUP_TYPE_REQ,
535 sizeof(*req) + ble_uuid_length(uuid), &txom);
536 if (req == NULL) {
537 return BLE_HS_ENOMEM;
538 }
539
540 req->bagq_start_handle = htole16(start_handle);
541 req->bagq_end_handle = htole16(end_handle);
542 ble_uuid_flat(uuid, req->uuid);
543 return ble_att_tx(conn_handle, txom);
544 }
545
ble_att_clt_parse_read_group_type_adata(struct os_mbuf ** om,int data_len,struct ble_att_read_group_type_adata * adata)546 static int ble_att_clt_parse_read_group_type_adata(
547 struct os_mbuf **om, int data_len,
548 struct ble_att_read_group_type_adata *adata)
549 {
550 int rc;
551
552 if (data_len < BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ + 1) {
553 return BLE_HS_EMSGSIZE;
554 }
555
556 rc = ble_hs_mbuf_pullup_base(om, data_len);
557 if (rc != 0) {
558 return rc;
559 }
560
561 adata->att_handle = get_le16((*om)->om_data + 0);
562 adata->end_group_handle = get_le16((*om)->om_data + 2); // 2:byte alignment
563 adata->value_len = data_len - BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ;
564 adata->value = (*om)->om_data + BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ;
565 return 0;
566 }
567
ble_att_clt_rx_read_group_type(uint16_t conn_handle,struct os_mbuf ** rxom)568 int ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom)
569 {
570 #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE
571 return BLE_HS_ENOTSUP;
572 #endif
573 struct ble_att_read_group_type_adata adata;
574 struct ble_att_read_group_type_rsp *rsp;
575 uint8_t len;
576 int rc;
577 rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
578 if (rc != 0) {
579 goto done;
580 }
581
582 rsp = (struct ble_att_read_group_type_rsp *)(*rxom)->om_data;
583 len = rsp->bagp_length;
584 /* Strip the base from the front of the response. */
585 os_mbuf_adj(*rxom, sizeof(*rsp));
586
587 /* Parse the Attribute Data List field, passing each entry to GATT. */
588 while (OS_MBUF_PKTLEN(*rxom) > 0) {
589 rc = ble_att_clt_parse_read_group_type_adata(rxom, len, &adata);
590 if (rc != 0) {
591 goto done;
592 }
593
594 ble_gattc_rx_read_group_type_adata(conn_handle, &adata);
595 os_mbuf_adj(*rxom, len);
596 }
597
598 done:
599 /* Notify GATT that the response is done being parsed. */
600 ble_gattc_rx_read_group_type_complete(conn_handle, rc);
601 return rc;
602 }
603
604 /*****************************************************************************
605 * $write *
606 *****************************************************************************/
607
ble_att_clt_tx_write_req(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)608 int ble_att_clt_tx_write_req(uint16_t conn_handle, uint16_t handle,
609 struct os_mbuf *txom)
610 {
611 #if !NIMBLE_BLE_ATT_CLT_WRITE
612 return BLE_HS_ENOTSUP;
613 #endif
614 struct ble_att_write_req *req;
615 struct os_mbuf *txom2;
616 req = ble_att_cmd_get(BLE_ATT_OP_WRITE_REQ, sizeof(*req), &txom2);
617 if (req == NULL) {
618 os_mbuf_free_chain(txom);
619 return BLE_HS_ENOMEM;
620 }
621
622 req->bawq_handle = htole16(handle);
623 os_mbuf_concat(txom2, txom);
624 return ble_att_tx(conn_handle, txom2);
625 }
626
ble_att_clt_tx_write_cmd(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)627 int ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t handle,
628 struct os_mbuf *txom)
629 {
630 #if !NIMBLE_BLE_ATT_CLT_WRITE_NO_RSP
631 return BLE_HS_ENOTSUP;
632 #endif
633 struct ble_att_write_cmd *cmd;
634 struct os_mbuf *txom2;
635 uint8_t b;
636 int i;
637 BLE_HS_LOG(DEBUG, "ble_att_clt_tx_write_cmd(): ");
638
639 for (i = 0; i < OS_MBUF_PKTLEN(txom); i++) {
640 if (i != 0) {
641 BLE_HS_LOG(DEBUG, ":");
642 }
643
644 int rc = os_mbuf_copydata(txom, i, 1, &b);
645 assert(rc == 0);
646 BLE_HS_LOG(DEBUG, "0x%02x", b);
647 }
648
649 cmd = ble_att_cmd_get(BLE_ATT_OP_WRITE_CMD, sizeof(*cmd), &txom2);
650 if (cmd == NULL) {
651 os_mbuf_free_chain(txom);
652 return BLE_HS_ENOMEM;
653 }
654
655 cmd->handle = htole16(handle);
656 os_mbuf_concat(txom2, txom);
657 return ble_att_tx(conn_handle, txom2);
658 }
659
ble_att_clt_rx_write(uint16_t conn_handle,struct os_mbuf ** rxom)660 int ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
661 {
662 #if !NIMBLE_BLE_ATT_CLT_WRITE
663 return BLE_HS_ENOTSUP;
664 #endif
665 /* No payload. */
666 ble_gattc_rx_write_rsp(conn_handle);
667 return 0;
668 }
669
670 /*****************************************************************************
671 * $prepare write request *
672 *****************************************************************************/
673
ble_att_clt_tx_prep_write(uint16_t conn_handle,uint16_t handle,uint16_t offset,struct os_mbuf * txom)674 int ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t handle,
675 uint16_t offset, struct os_mbuf *txom)
676 {
677 #if !NIMBLE_BLE_ATT_CLT_PREP_WRITE
678 return BLE_HS_ENOTSUP;
679 #endif
680 struct ble_att_prep_write_cmd *req;
681 struct os_mbuf *txom2;
682 int rc;
683
684 if (handle == 0) {
685 rc = BLE_HS_EINVAL;
686 goto err;
687 }
688
689 if (offset + OS_MBUF_PKTLEN(txom) > BLE_ATT_ATTR_MAX_LEN) {
690 rc = BLE_HS_EINVAL;
691 goto err;
692 }
693
694 if (OS_MBUF_PKTLEN(txom) >
695 ble_att_mtu(conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ) {
696 rc = BLE_HS_EINVAL;
697 goto err;
698 }
699
700 req = ble_att_cmd_get(BLE_ATT_OP_PREP_WRITE_REQ, sizeof(*req), &txom2);
701 if (req == NULL) {
702 rc = BLE_HS_ENOMEM;
703 goto err;
704 }
705
706 req->bapc_handle = htole16(handle);
707 req->bapc_offset = htole16(offset);
708 os_mbuf_concat(txom2, txom);
709 return ble_att_tx(conn_handle, txom2);
710 err:
711 os_mbuf_free_chain(txom);
712 return rc;
713 }
714
ble_att_clt_rx_prep_write(uint16_t conn_handle,struct os_mbuf ** rxom)715 int ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
716 {
717 #if !NIMBLE_BLE_ATT_CLT_PREP_WRITE
718 return BLE_HS_ENOTSUP;
719 #endif
720 struct ble_att_prep_write_cmd *rsp;
721 uint16_t handle, offset;
722 int rc;
723 /* Initialize some values in case of early error. */
724 handle = 0;
725 offset = 0;
726 rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*rsp));
727 if (rc != 0) {
728 goto done;
729 }
730
731 rsp = (struct ble_att_prep_write_cmd *)(*rxom)->om_data;
732 handle = le16toh(rsp->bapc_handle);
733 offset = le16toh(rsp->bapc_offset);
734 /* Strip the base from the front of the response. */
735 os_mbuf_adj(*rxom, sizeof(*rsp));
736 done:
737 /* Notify GATT client that the full response has been parsed. */
738 ble_gattc_rx_prep_write_rsp(conn_handle, rc, handle, offset, rxom);
739 return rc;
740 }
741
742 /*****************************************************************************
743 * $execute write request *
744 *****************************************************************************/
745
ble_att_clt_tx_exec_write(uint16_t conn_handle,uint8_t flags)746 int ble_att_clt_tx_exec_write(uint16_t conn_handle, uint8_t flags)
747 {
748 #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE
749 return BLE_HS_ENOTSUP;
750 #endif
751 struct ble_att_exec_write_req *req;
752 struct os_mbuf *txom;
753 int rc;
754 req = ble_att_cmd_get(BLE_ATT_OP_EXEC_WRITE_REQ, sizeof(*req), &txom);
755 if (req == NULL) {
756 return BLE_HS_ENOMEM;
757 }
758
759 req->baeq_flags = flags;
760 rc = ble_att_tx(conn_handle, txom);
761 if (rc != 0) {
762 return rc;
763 }
764
765 return 0;
766 }
767
ble_att_clt_rx_exec_write(uint16_t conn_handle,struct os_mbuf ** rxom)768 int ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom)
769 {
770 #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE
771 return BLE_HS_ENOTSUP;
772 #endif
773 ble_gattc_rx_exec_write_rsp(conn_handle, 0);
774 return 0;
775 }
776
777 /*****************************************************************************
778 * $handle value notification *
779 *****************************************************************************/
780
ble_att_clt_tx_notify(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)781 int ble_att_clt_tx_notify(uint16_t conn_handle, uint16_t handle,
782 struct os_mbuf *txom)
783 {
784 #if !NIMBLE_BLE_ATT_CLT_NOTIFY
785 return BLE_HS_ENOTSUP;
786 #endif
787 struct ble_att_notify_req *req;
788 struct os_mbuf *txom2;
789 int rc;
790
791 if (handle == 0) {
792 rc = BLE_HS_EINVAL;
793 goto err;
794 }
795
796 req = ble_att_cmd_get(BLE_ATT_OP_NOTIFY_REQ, sizeof(*req), &txom2);
797 if (req == NULL) {
798 rc = BLE_HS_ENOMEM;
799 goto err;
800 }
801
802 req->banq_handle = htole16(handle);
803 os_mbuf_concat(txom2, txom);
804 return ble_att_tx(conn_handle, txom2);
805 err:
806 os_mbuf_free_chain(txom);
807 return rc;
808 }
809
810 /*****************************************************************************
811 * $handle value indication *
812 *****************************************************************************/
813
ble_att_clt_tx_indicate(uint16_t conn_handle,uint16_t handle,struct os_mbuf * txom)814 int ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t handle,
815 struct os_mbuf *txom)
816 {
817 #if !NIMBLE_BLE_ATT_CLT_INDICATE
818 return BLE_HS_ENOTSUP;
819 #endif
820 struct ble_att_indicate_req *req;
821 struct os_mbuf *txom2;
822 int rc;
823
824 if (handle == 0) {
825 rc = BLE_HS_EINVAL;
826 goto err;
827 }
828
829 req = ble_att_cmd_get(BLE_ATT_OP_INDICATE_REQ, sizeof(*req), &txom2);
830 if (req == NULL) {
831 rc = BLE_HS_ENOMEM;
832 goto err;
833 }
834
835 req->baiq_handle = htole16(handle);
836 os_mbuf_concat(txom2, txom);
837 return ble_att_tx(conn_handle, txom2);
838 err:
839 os_mbuf_free_chain(txom);
840 return rc;
841 }
842
ble_att_clt_rx_indicate(uint16_t conn_handle,struct os_mbuf ** rxom)843 int ble_att_clt_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
844 {
845 #if !NIMBLE_BLE_ATT_CLT_INDICATE
846 return BLE_HS_ENOTSUP;
847 #endif
848 /* No payload. */
849 ble_gattc_rx_indicate_rsp(conn_handle);
850 return 0;
851 }