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 }