• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }