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