• 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 <stddef.h>
21 #include "ble_hs_priv.h"
22 
23 static uint16_t ble_att_preferred_mtu_val;
24 
25 /** Dispatch table for incoming ATT requests.  Sorted by op code. */
26 typedef int ble_att_rx_fn(uint16_t conn_handle, struct os_mbuf **om);
27 struct ble_att_rx_dispatch_entry {
28     uint8_t bde_op;
29     ble_att_rx_fn *bde_fn;
30 };
31 
32 /** Dispatch table for incoming ATT commands.  Must be ordered by op code. */
33 static const struct ble_att_rx_dispatch_entry ble_att_rx_dispatch[] = {
34     { BLE_ATT_OP_ERROR_RSP,            ble_att_clt_rx_error },
35     { BLE_ATT_OP_MTU_REQ,              ble_att_svr_rx_mtu },
36     { BLE_ATT_OP_MTU_RSP,              ble_att_clt_rx_mtu },
37     { BLE_ATT_OP_FIND_INFO_REQ,        ble_att_svr_rx_find_info },
38     { BLE_ATT_OP_FIND_INFO_RSP,        ble_att_clt_rx_find_info },
39     { BLE_ATT_OP_FIND_TYPE_VALUE_REQ,  ble_att_svr_rx_find_type_value },
40     { BLE_ATT_OP_FIND_TYPE_VALUE_RSP,  ble_att_clt_rx_find_type_value },
41     { BLE_ATT_OP_READ_TYPE_REQ,        ble_att_svr_rx_read_type },
42     { BLE_ATT_OP_READ_TYPE_RSP,        ble_att_clt_rx_read_type },
43     { BLE_ATT_OP_READ_REQ,             ble_att_svr_rx_read },
44     { BLE_ATT_OP_READ_RSP,             ble_att_clt_rx_read },
45     { BLE_ATT_OP_READ_BLOB_REQ,        ble_att_svr_rx_read_blob },
46     { BLE_ATT_OP_READ_BLOB_RSP,        ble_att_clt_rx_read_blob },
47     { BLE_ATT_OP_READ_MULT_REQ,        ble_att_svr_rx_read_mult },
48     { BLE_ATT_OP_READ_MULT_RSP,        ble_att_clt_rx_read_mult },
49     { BLE_ATT_OP_READ_GROUP_TYPE_REQ,  ble_att_svr_rx_read_group_type },
50     { BLE_ATT_OP_READ_GROUP_TYPE_RSP,  ble_att_clt_rx_read_group_type },
51     { BLE_ATT_OP_WRITE_REQ,            ble_att_svr_rx_write },
52     { BLE_ATT_OP_WRITE_RSP,            ble_att_clt_rx_write },
53     { BLE_ATT_OP_PREP_WRITE_REQ,       ble_att_svr_rx_prep_write },
54     { BLE_ATT_OP_PREP_WRITE_RSP,       ble_att_clt_rx_prep_write },
55     { BLE_ATT_OP_EXEC_WRITE_REQ,       ble_att_svr_rx_exec_write },
56     { BLE_ATT_OP_EXEC_WRITE_RSP,       ble_att_clt_rx_exec_write },
57     { BLE_ATT_OP_NOTIFY_REQ,           ble_att_svr_rx_notify },
58     { BLE_ATT_OP_INDICATE_REQ,         ble_att_svr_rx_indicate },
59     { BLE_ATT_OP_INDICATE_RSP,         ble_att_clt_rx_indicate },
60     { BLE_ATT_OP_WRITE_CMD,            ble_att_svr_rx_write_no_rsp },
61 };
62 
63 #define BLE_ATT_RX_DISPATCH_SZ \
64     (sizeof ble_att_rx_dispatch / sizeof ble_att_rx_dispatch[0])
65 
66 STATS_SECT_DECL(ble_att_stats) ble_att_stats;
67 STATS_NAME_START(ble_att_stats)
STATS_NAME(ble_att_stats,error_rsp_rx)68 STATS_NAME(ble_att_stats, error_rsp_rx)
69 STATS_NAME(ble_att_stats, error_rsp_tx)
70 STATS_NAME(ble_att_stats, mtu_req_rx)
71 STATS_NAME(ble_att_stats, mtu_req_tx)
72 STATS_NAME(ble_att_stats, mtu_rsp_rx)
73 STATS_NAME(ble_att_stats, mtu_rsp_tx)
74 STATS_NAME(ble_att_stats, find_info_req_rx)
75 STATS_NAME(ble_att_stats, find_info_req_tx)
76 STATS_NAME(ble_att_stats, find_info_rsp_rx)
77 STATS_NAME(ble_att_stats, find_info_rsp_tx)
78 STATS_NAME(ble_att_stats, find_type_value_req_rx)
79 STATS_NAME(ble_att_stats, find_type_value_req_tx)
80 STATS_NAME(ble_att_stats, find_type_value_rsp_rx)
81 STATS_NAME(ble_att_stats, find_type_value_rsp_tx)
82 STATS_NAME(ble_att_stats, read_type_req_rx)
83 STATS_NAME(ble_att_stats, read_type_req_tx)
84 STATS_NAME(ble_att_stats, read_type_rsp_rx)
85 STATS_NAME(ble_att_stats, read_type_rsp_tx)
86 STATS_NAME(ble_att_stats, read_req_rx)
87 STATS_NAME(ble_att_stats, read_req_tx)
88 STATS_NAME(ble_att_stats, read_rsp_rx)
89 STATS_NAME(ble_att_stats, read_rsp_tx)
90 STATS_NAME(ble_att_stats, read_blob_req_rx)
91 STATS_NAME(ble_att_stats, read_blob_req_tx)
92 STATS_NAME(ble_att_stats, read_blob_rsp_rx)
93 STATS_NAME(ble_att_stats, read_blob_rsp_tx)
94 STATS_NAME(ble_att_stats, read_mult_req_rx)
95 STATS_NAME(ble_att_stats, read_mult_req_tx)
96 STATS_NAME(ble_att_stats, read_mult_rsp_rx)
97 STATS_NAME(ble_att_stats, read_mult_rsp_tx)
98 STATS_NAME(ble_att_stats, read_group_type_req_rx)
99 STATS_NAME(ble_att_stats, read_group_type_req_tx)
100 STATS_NAME(ble_att_stats, read_group_type_rsp_rx)
101 STATS_NAME(ble_att_stats, read_group_type_rsp_tx)
102 STATS_NAME(ble_att_stats, write_req_rx)
103 STATS_NAME(ble_att_stats, write_req_tx)
104 STATS_NAME(ble_att_stats, write_rsp_rx)
105 STATS_NAME(ble_att_stats, write_rsp_tx)
106 STATS_NAME(ble_att_stats, prep_write_req_rx)
107 STATS_NAME(ble_att_stats, prep_write_req_tx)
108 STATS_NAME(ble_att_stats, prep_write_rsp_rx)
109 STATS_NAME(ble_att_stats, prep_write_rsp_tx)
110 STATS_NAME(ble_att_stats, exec_write_req_rx)
111 STATS_NAME(ble_att_stats, exec_write_req_tx)
112 STATS_NAME(ble_att_stats, exec_write_rsp_rx)
113 STATS_NAME(ble_att_stats, exec_write_rsp_tx)
114 STATS_NAME(ble_att_stats, notify_req_rx)
115 STATS_NAME(ble_att_stats, notify_req_tx)
116 STATS_NAME(ble_att_stats, indicate_req_rx)
117 STATS_NAME(ble_att_stats, indicate_req_tx)
118 STATS_NAME(ble_att_stats, indicate_rsp_rx)
119 STATS_NAME(ble_att_stats, indicate_rsp_tx)
120 STATS_NAME(ble_att_stats, write_cmd_rx)
121 STATS_NAME(ble_att_stats, write_cmd_tx)
122 STATS_NAME_END(ble_att_stats)
123 
124 static const struct ble_att_rx_dispatch_entry *ble_att_rx_dispatch_entry_find(uint8_t op)
125 {
126     const struct ble_att_rx_dispatch_entry *entry;
127     int i;
128 
129     for (i = 0; i < BLE_ATT_RX_DISPATCH_SZ; i++) {
130         entry = ble_att_rx_dispatch + i;
131         if (entry->bde_op == op) {
132             return entry;
133         }
134 
135         if (entry->bde_op > op) {
136             break;
137         }
138     }
139 
140     return NULL;
141 }
142 
ble_att_conn_chan_find(uint16_t conn_handle,struct ble_hs_conn ** out_conn,struct ble_l2cap_chan ** out_chan)143 int ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan)
144 {
145     return ble_hs_misc_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT,
146                                       out_conn, out_chan);
147 }
148 
ble_att_inc_tx_stat(uint8_t att_op)149 void ble_att_inc_tx_stat(uint8_t att_op)
150 {
151     switch (att_op) {
152         case BLE_ATT_OP_ERROR_RSP:
153             STATS_INC(ble_att_stats, error_rsp_tx);
154             break;
155 
156         case BLE_ATT_OP_MTU_REQ:
157             STATS_INC(ble_att_stats, mtu_req_tx);
158             break;
159 
160         case BLE_ATT_OP_MTU_RSP:
161             STATS_INC(ble_att_stats, mtu_rsp_tx);
162             break;
163 
164         case BLE_ATT_OP_FIND_INFO_REQ:
165             STATS_INC(ble_att_stats, find_info_req_tx);
166             break;
167 
168         case BLE_ATT_OP_FIND_INFO_RSP:
169             STATS_INC(ble_att_stats, find_info_rsp_tx);
170             break;
171 
172         case BLE_ATT_OP_FIND_TYPE_VALUE_REQ:
173             STATS_INC(ble_att_stats, find_type_value_req_tx);
174             break;
175 
176         case BLE_ATT_OP_FIND_TYPE_VALUE_RSP:
177             STATS_INC(ble_att_stats, find_type_value_rsp_tx);
178             break;
179 
180         case BLE_ATT_OP_READ_TYPE_REQ:
181             STATS_INC(ble_att_stats, read_type_req_tx);
182             break;
183 
184         case BLE_ATT_OP_READ_TYPE_RSP:
185             STATS_INC(ble_att_stats, read_type_rsp_tx);
186             break;
187 
188         case BLE_ATT_OP_READ_REQ:
189             STATS_INC(ble_att_stats, read_req_tx);
190             break;
191 
192         case BLE_ATT_OP_READ_RSP:
193             STATS_INC(ble_att_stats, read_rsp_tx);
194             break;
195 
196         case BLE_ATT_OP_READ_BLOB_REQ:
197             STATS_INC(ble_att_stats, read_blob_req_tx);
198             break;
199 
200         case BLE_ATT_OP_READ_BLOB_RSP:
201             STATS_INC(ble_att_stats, read_blob_rsp_tx);
202             break;
203 
204         case BLE_ATT_OP_READ_MULT_REQ:
205             STATS_INC(ble_att_stats, read_mult_req_tx);
206             break;
207 
208         case BLE_ATT_OP_READ_MULT_RSP:
209             STATS_INC(ble_att_stats, read_mult_rsp_tx);
210             break;
211 
212         case BLE_ATT_OP_READ_GROUP_TYPE_REQ:
213             STATS_INC(ble_att_stats, read_group_type_req_tx);
214             break;
215 
216         case BLE_ATT_OP_READ_GROUP_TYPE_RSP:
217             STATS_INC(ble_att_stats, read_group_type_rsp_tx);
218             break;
219 
220         case BLE_ATT_OP_WRITE_REQ:
221             STATS_INC(ble_att_stats, write_req_tx);
222             break;
223 
224         case BLE_ATT_OP_WRITE_RSP:
225             STATS_INC(ble_att_stats, write_rsp_tx);
226             break;
227 
228         case BLE_ATT_OP_PREP_WRITE_REQ:
229             STATS_INC(ble_att_stats, prep_write_req_tx);
230             break;
231 
232         case BLE_ATT_OP_PREP_WRITE_RSP:
233             STATS_INC(ble_att_stats, prep_write_rsp_tx);
234             break;
235 
236         case BLE_ATT_OP_EXEC_WRITE_REQ:
237             STATS_INC(ble_att_stats, exec_write_req_tx);
238             break;
239 
240         case BLE_ATT_OP_EXEC_WRITE_RSP:
241             STATS_INC(ble_att_stats, exec_write_rsp_tx);
242             break;
243 
244         case BLE_ATT_OP_NOTIFY_REQ:
245             STATS_INC(ble_att_stats, notify_req_tx);
246             break;
247 
248         case BLE_ATT_OP_INDICATE_REQ:
249             STATS_INC(ble_att_stats, indicate_req_tx);
250             break;
251 
252         case BLE_ATT_OP_INDICATE_RSP:
253             STATS_INC(ble_att_stats, indicate_rsp_tx);
254             break;
255 
256         case BLE_ATT_OP_WRITE_CMD:
257             STATS_INC(ble_att_stats, write_cmd_tx);
258             break;
259 
260         default:
261             break;
262     }
263 }
264 
ble_att_inc_rx_stat(uint8_t att_op)265 static void ble_att_inc_rx_stat(uint8_t att_op)
266 {
267     switch (att_op) {
268         case BLE_ATT_OP_ERROR_RSP:
269             STATS_INC(ble_att_stats, error_rsp_rx);
270             break;
271 
272         case BLE_ATT_OP_MTU_REQ:
273             STATS_INC(ble_att_stats, mtu_req_rx);
274             break;
275 
276         case BLE_ATT_OP_MTU_RSP:
277             STATS_INC(ble_att_stats, mtu_rsp_rx);
278             break;
279 
280         case BLE_ATT_OP_FIND_INFO_REQ:
281             STATS_INC(ble_att_stats, find_info_req_rx);
282             break;
283 
284         case BLE_ATT_OP_FIND_INFO_RSP:
285             STATS_INC(ble_att_stats, find_info_rsp_rx);
286             break;
287 
288         case BLE_ATT_OP_FIND_TYPE_VALUE_REQ:
289             STATS_INC(ble_att_stats, find_type_value_req_rx);
290             break;
291 
292         case BLE_ATT_OP_FIND_TYPE_VALUE_RSP:
293             STATS_INC(ble_att_stats, find_type_value_rsp_rx);
294             break;
295 
296         case BLE_ATT_OP_READ_TYPE_REQ:
297             STATS_INC(ble_att_stats, read_type_req_rx);
298             break;
299 
300         case BLE_ATT_OP_READ_TYPE_RSP:
301             STATS_INC(ble_att_stats, read_type_rsp_rx);
302             break;
303 
304         case BLE_ATT_OP_READ_REQ:
305             STATS_INC(ble_att_stats, read_req_rx);
306             break;
307 
308         case BLE_ATT_OP_READ_RSP:
309             STATS_INC(ble_att_stats, read_rsp_rx);
310             break;
311 
312         case BLE_ATT_OP_READ_BLOB_REQ:
313             STATS_INC(ble_att_stats, read_blob_req_rx);
314             break;
315 
316         case BLE_ATT_OP_READ_BLOB_RSP:
317             STATS_INC(ble_att_stats, read_blob_rsp_rx);
318             break;
319 
320         case BLE_ATT_OP_READ_MULT_REQ:
321             STATS_INC(ble_att_stats, read_mult_req_rx);
322             break;
323 
324         case BLE_ATT_OP_READ_MULT_RSP:
325             STATS_INC(ble_att_stats, read_mult_rsp_rx);
326             break;
327 
328         case BLE_ATT_OP_READ_GROUP_TYPE_REQ:
329             STATS_INC(ble_att_stats, read_group_type_req_rx);
330             break;
331 
332         case BLE_ATT_OP_READ_GROUP_TYPE_RSP:
333             STATS_INC(ble_att_stats, read_group_type_rsp_rx);
334             break;
335 
336         case BLE_ATT_OP_WRITE_REQ:
337             STATS_INC(ble_att_stats, write_req_rx);
338             break;
339 
340         case BLE_ATT_OP_WRITE_RSP:
341             STATS_INC(ble_att_stats, write_rsp_rx);
342             break;
343 
344         case BLE_ATT_OP_PREP_WRITE_REQ:
345             STATS_INC(ble_att_stats, prep_write_req_rx);
346             break;
347 
348         case BLE_ATT_OP_PREP_WRITE_RSP:
349             STATS_INC(ble_att_stats, prep_write_rsp_rx);
350             break;
351 
352         case BLE_ATT_OP_EXEC_WRITE_REQ:
353             STATS_INC(ble_att_stats, exec_write_req_rx);
354             break;
355 
356         case BLE_ATT_OP_EXEC_WRITE_RSP:
357             STATS_INC(ble_att_stats, exec_write_rsp_rx);
358             break;
359 
360         case BLE_ATT_OP_NOTIFY_REQ:
361             STATS_INC(ble_att_stats, notify_req_rx);
362             break;
363 
364         case BLE_ATT_OP_INDICATE_REQ:
365             STATS_INC(ble_att_stats, indicate_req_rx);
366             break;
367 
368         case BLE_ATT_OP_INDICATE_RSP:
369             STATS_INC(ble_att_stats, indicate_rsp_rx);
370             break;
371 
372         case BLE_ATT_OP_WRITE_CMD:
373             STATS_INC(ble_att_stats, write_cmd_rx);
374             break;
375 
376         default:
377             break;
378     }
379 }
380 
ble_att_truncate_to_mtu(const struct ble_l2cap_chan * att_chan,struct os_mbuf * txom)381 void ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan,
382                              struct os_mbuf *txom)
383 {
384     int32_t extra_len;
385     uint16_t mtu;
386     mtu = ble_att_chan_mtu(att_chan);
387     extra_len = OS_MBUF_PKTLEN(txom) - mtu;
388     if (extra_len > 0) {
389         os_mbuf_adj(txom, -extra_len);
390     }
391 }
392 
ble_att_mtu(uint16_t conn_handle)393 uint16_t ble_att_mtu(uint16_t conn_handle)
394 {
395     struct ble_l2cap_chan *chan;
396     struct ble_hs_conn *conn;
397     uint16_t mtu;
398     int rc;
399     ble_hs_lock();
400     rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
401     if (rc == 0) {
402         mtu = ble_att_chan_mtu(chan);
403     } else {
404         mtu = 0;
405     }
406 
407     ble_hs_unlock();
408     return mtu;
409 }
410 
ble_att_set_peer_mtu(struct ble_l2cap_chan * chan,uint16_t peer_mtu)411 void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu)
412 {
413     if (peer_mtu < BLE_ATT_MTU_DFLT) {
414         peer_mtu = BLE_ATT_MTU_DFLT;
415     }
416 
417     chan->peer_mtu = peer_mtu;
418 }
419 
ble_att_chan_mtu(const struct ble_l2cap_chan * chan)420 uint16_t ble_att_chan_mtu(const struct ble_l2cap_chan *chan)
421 {
422     uint16_t mtu;
423 
424     /* If either side has not exchanged MTU size, use the default.  Otherwise,
425      * use the lesser of the two exchanged values.
426      */
427     if (!(ble_l2cap_is_mtu_req_sent(chan)) ||
428             chan->peer_mtu == 0) {
429         mtu = BLE_ATT_MTU_DFLT;
430     } else {
431         mtu = min(chan->my_mtu, chan->peer_mtu);
432     }
433 
434     BLE_HS_DBG_ASSERT(mtu >= BLE_ATT_MTU_DFLT);
435     return mtu;
436 }
437 
ble_att_rx_handle_unknown_request(uint8_t op,uint16_t conn_handle,struct os_mbuf ** om)438 static void ble_att_rx_handle_unknown_request(uint8_t op, uint16_t conn_handle,
439                                               struct os_mbuf **om)
440 {
441     /* If this is command (bit6 is set to 1), do nothing */
442     if (op & 0x40) {
443         return;
444     }
445 
446     os_mbuf_adj(*om, OS_MBUF_PKTLEN(*om));
447     ble_att_svr_tx_error_rsp(conn_handle, *om, op, 0,
448                              BLE_ATT_ERR_REQ_NOT_SUPPORTED);
449     *om = NULL;
450 }
451 
ble_att_rx(struct ble_l2cap_chan * chan)452 static int ble_att_rx(struct ble_l2cap_chan *chan)
453 {
454     const struct ble_att_rx_dispatch_entry *entry;
455     uint8_t op;
456     uint16_t conn_handle;
457     struct os_mbuf **om;
458     int rc;
459     conn_handle = ble_l2cap_get_conn_handle(chan);
460     if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
461         return BLE_HS_ENOTCONN;
462     }
463 
464     om = &chan->rx_buf;
465     BLE_HS_DBG_ASSERT(*om != NULL);
466     rc = os_mbuf_copydata(*om, 0, 1, &op);
467     if (rc != 0) {
468         return BLE_HS_EMSGSIZE;
469     }
470 
471     entry = ble_att_rx_dispatch_entry_find(op);
472     if (entry == NULL) {
473         ble_att_rx_handle_unknown_request(op, conn_handle, om);
474         return BLE_HS_ENOTSUP;
475     }
476 
477     ble_att_inc_rx_stat(op);
478     /* Strip L2CAP ATT header from the front of the mbuf. */
479     os_mbuf_adj(*om, 1);
480     rc = entry->bde_fn(conn_handle, om);
481     if (rc != 0) {
482         if (rc == BLE_HS_ENOTSUP) {
483             ble_att_rx_handle_unknown_request(op, conn_handle, om);
484         }
485 
486         return rc;
487     }
488 
489     return 0;
490 }
491 
ble_att_preferred_mtu(void)492 uint16_t ble_att_preferred_mtu(void)
493 {
494     return ble_att_preferred_mtu_val;
495 }
496 
ble_att_set_preferred_mtu(uint16_t mtu)497 int ble_att_set_preferred_mtu(uint16_t mtu)
498 {
499     struct ble_hs_conn *conn;
500     int i;
501 
502     if (mtu < BLE_ATT_MTU_DFLT) {
503         return BLE_HS_EINVAL;
504     }
505 
506     if (mtu > BLE_ATT_MTU_MAX) {
507         return BLE_HS_EINVAL;
508     }
509 
510     ble_att_preferred_mtu_val = mtu;
511     /* Set my_mtu for established connections that haven't exchanged. */
512     ble_hs_lock();
513     i = 0;
514 
515     while ((conn = ble_hs_conn_find_by_idx(i)) != NULL) {
516         struct ble_l2cap_chan *chan = ble_hs_conn_chan_find_by_scid(conn, BLE_L2CAP_CID_ATT);
517         BLE_HS_DBG_ASSERT(chan != NULL);
518 
519         if (!(chan->flags & BLE_L2CAP_CHAN_F_TXED_MTU)) {
520             chan->my_mtu = mtu;
521         }
522 
523         i++;
524     }
525 
526     ble_hs_unlock();
527     return 0;
528 }
529 
ble_att_create_chan(uint16_t conn_handle)530 struct ble_l2cap_chan *ble_att_create_chan(uint16_t conn_handle)
531 {
532     struct ble_l2cap_chan *chan;
533     chan = ble_l2cap_chan_alloc(conn_handle);
534     if (chan == NULL) {
535         return NULL;
536     }
537 
538     chan->scid = BLE_L2CAP_CID_ATT;
539     chan->dcid = BLE_L2CAP_CID_ATT;
540     chan->my_mtu = ble_att_preferred_mtu_val;
541     chan->rx_fn = ble_att_rx;
542     return chan;
543 }
544 
ble_att_init(void)545 int ble_att_init(void)
546 {
547     int rc;
548     ble_att_preferred_mtu_val = MYNEWT_VAL(BLE_ATT_PREFERRED_MTU);
549     rc = stats_init_and_reg(STATS_HDR(ble_att_stats), STATS_SIZE_INIT_PARMS(ble_att_stats, STATS_SIZE_32),
550         STATS_NAME_INIT_PARMS(ble_att_stats), "ble_att");
551     if (rc != 0) {
552         return BLE_HS_EOS;
553     }
554 
555     return 0;
556 }