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