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 <string.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include "testutil/testutil.h"
24 #include "nimble/ble.h"
25 #include "host/ble_hs_test.h"
26 #include "host/ble_uuid.h"
27 #include "ble_hs_test_util.h"
28
29 struct ble_gatt_read_test_attr {
30 uint16_t conn_handle;
31 uint16_t handle;
32 uint8_t value_len;
33 uint8_t value[BLE_ATT_ATTR_MAX_LEN];
34 };
35
36 #define BLE_GATT_READ_TEST_MAX_ATTRS 256
37
38 struct ble_gatt_read_test_attr
39 ble_gatt_read_test_attrs[BLE_GATT_READ_TEST_MAX_ATTRS];
40 int ble_gatt_read_test_num_attrs;
41 int ble_gatt_read_test_complete;
42
43 uint16_t ble_gatt_read_test_bad_conn_handle;
44 int ble_gatt_read_test_bad_status;
45
46 static void
ble_gatt_read_test_misc_init(void)47 ble_gatt_read_test_misc_init(void)
48 {
49 ble_hs_test_util_init();
50 ble_gatt_read_test_num_attrs = 0;
51 ble_gatt_read_test_complete = 0;
52 ble_gatt_read_test_bad_conn_handle = 0;
53 ble_gatt_read_test_bad_status = 0;
54
55 memset(&ble_gatt_read_test_attrs[0], 0,
56 sizeof ble_gatt_read_test_attrs[0]);
57 }
58
59 static int
ble_gatt_read_test_cb(uint16_t conn_handle,const struct ble_gatt_error * error,struct ble_gatt_attr * attr,void * arg)60 ble_gatt_read_test_cb(uint16_t conn_handle, const struct ble_gatt_error *error,
61 struct ble_gatt_attr *attr, void *arg)
62 {
63 struct ble_gatt_read_test_attr *dst;
64 int *stop_after;
65 int rc;
66
67 stop_after = arg;
68
69 TEST_ASSERT_FATAL(error != NULL);
70
71 if (error->status != 0) {
72 ble_gatt_read_test_bad_conn_handle = conn_handle;
73 ble_gatt_read_test_bad_status = error->status;
74 ble_gatt_read_test_complete = 1;
75 return 0;
76 }
77
78 if (attr == NULL) {
79 ble_gatt_read_test_complete = 1;
80 return 0;
81 }
82
83 TEST_ASSERT_FATAL(ble_gatt_read_test_num_attrs <
84 BLE_GATT_READ_TEST_MAX_ATTRS);
85 dst = ble_gatt_read_test_attrs + ble_gatt_read_test_num_attrs++;
86
87 TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <= sizeof dst->value);
88
89 dst->conn_handle = conn_handle;
90 dst->handle = attr->handle;
91 dst->value_len = OS_MBUF_PKTLEN(attr->om);
92 rc = os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om), dst->value);
93 TEST_ASSERT_FATAL(rc == 0);
94
95 if (stop_after != NULL && *stop_after > 0) {
96 (*stop_after)--;
97 if (*stop_after == 0) {
98 ble_gatt_read_test_complete = 1;
99 return 1;
100 }
101 } else {
102 ble_gatt_read_test_complete = 1;
103 }
104
105 return 0;
106 }
107
108 static int
ble_gatt_read_test_long_cb(uint16_t conn_handle,const struct ble_gatt_error * error,struct ble_gatt_attr * attr,void * arg)109 ble_gatt_read_test_long_cb(uint16_t conn_handle,
110 const struct ble_gatt_error *error,
111 struct ble_gatt_attr *attr, void *arg)
112 {
113 struct ble_gatt_read_test_attr *dst;
114 int *reads_left;
115 int rc;
116
117 reads_left = arg;
118
119 TEST_ASSERT_FATAL(error != NULL);
120
121 if (error->status != 0) {
122 ble_gatt_read_test_bad_conn_handle = conn_handle;
123 ble_gatt_read_test_bad_status = error->status;
124 ble_gatt_read_test_complete = 1;
125 return 0;
126 }
127
128 if (attr == NULL) {
129 ble_gatt_read_test_complete = 1;
130 return 0;
131 }
132
133 dst = ble_gatt_read_test_attrs + 0;
134
135 TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <=
136 dst->value_len + sizeof dst->value);
137 TEST_ASSERT(attr->offset == dst->value_len);
138
139 if (attr->offset == 0) {
140 dst->conn_handle = conn_handle;
141 dst->handle = attr->handle;
142 } else {
143 TEST_ASSERT(conn_handle == dst->conn_handle);
144 TEST_ASSERT(attr->handle == dst->handle);
145 }
146 rc = os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om),
147 dst->value + dst->value_len);
148 TEST_ASSERT_FATAL(rc == 0);
149 dst->value_len += OS_MBUF_PKTLEN(attr->om);
150
151 if (reads_left != NULL && *reads_left > 0) {
152 (*reads_left)--;
153 if (*reads_left == 0) {
154 ble_gatt_read_test_complete = 1;
155 return 1;
156 }
157 }
158
159 return 0;
160 }
161
162 static void
ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle,uint8_t att_op,const void * data,int data_len)163 ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle,
164 uint8_t att_op,
165 const void *data, int data_len)
166 {
167 uint8_t buf[1024];
168 int rc;
169
170 TEST_ASSERT_FATAL(data_len <= sizeof buf);
171
172 /* Send the pending ATT Read Request. */
173
174 buf[0] = att_op;
175 memcpy(buf + 1, data, data_len);
176
177 rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
178 buf, 1 + data_len);
179 TEST_ASSERT(rc == 0);
180 }
181
182 static void
ble_gatt_read_test_misc_rx_rsp_good(uint16_t conn_handle,struct ble_hs_test_util_flat_attr * attr)183 ble_gatt_read_test_misc_rx_rsp_good(uint16_t conn_handle,
184 struct ble_hs_test_util_flat_attr *attr)
185 {
186 ble_gatt_read_test_misc_rx_rsp_good_raw(conn_handle, BLE_ATT_OP_READ_RSP,
187 attr->value,
188 attr->value_len);
189 }
190
191 static void
ble_gatt_read_test_misc_rx_rsp_bad(uint16_t conn_handle,uint8_t att_error,uint16_t err_handle)192 ble_gatt_read_test_misc_rx_rsp_bad(uint16_t conn_handle,
193 uint8_t att_error, uint16_t err_handle)
194 {
195 /* Send the pending ATT Read Request. */
196
197 ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_REQ,
198 att_error, err_handle);
199 }
200
201 static int
ble_gatt_read_test_misc_uuid_rx_rsp_good(uint16_t conn_handle,struct ble_hs_test_util_flat_attr * attrs)202 ble_gatt_read_test_misc_uuid_rx_rsp_good(
203 uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs)
204 {
205 struct ble_att_read_type_rsp rsp;
206 uint8_t buf[1024];
207 int prev_len;
208 int off;
209 int rc;
210 int i;
211
212 if (ble_gatt_read_test_complete || attrs[0].handle == 0) {
213 return 0;
214 }
215
216 /* Send the pending ATT Read By Type Request. */
217
218 rsp.batp_length = 2 + attrs[0].value_len;
219 ble_att_read_type_rsp_write(buf, sizeof buf, &rsp);
220
221 prev_len = 0;
222 off = BLE_ATT_READ_TYPE_RSP_BASE_SZ;
223 for (i = 0; attrs[i].handle != 0; i++) {
224 if (prev_len != 0 && prev_len != attrs[i].value_len) {
225 break;
226 }
227 prev_len = attrs[i].value_len;
228
229 put_le16(buf + off, attrs[i].handle);
230 off += 2;
231
232 memcpy(buf + off, attrs[i].value, attrs[i].value_len);
233 off += attrs[i].value_len;
234 }
235
236 rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
237 buf, off);
238 TEST_ASSERT(rc == 0);
239
240 return i;
241 }
242
243 static void
ble_gatt_read_test_misc_verify_good(struct ble_hs_test_util_flat_attr * attr)244 ble_gatt_read_test_misc_verify_good(struct ble_hs_test_util_flat_attr *attr)
245 {
246 int rc;
247
248 ble_gatt_read_test_misc_init();
249 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
250 NULL, NULL);
251
252 /* Exchange MTU: We need plus 1 for the read response opcode */
253 ble_hs_test_util_set_att_mtu(2, attr->value_len + 1);
254
255 rc = ble_gattc_read(2, attr->handle, ble_gatt_read_test_cb, NULL);
256 TEST_ASSERT_FATAL(rc == 0);
257
258 ble_gatt_read_test_misc_rx_rsp_good(2, attr);
259
260 TEST_ASSERT(ble_gatt_read_test_num_attrs == 1);
261 TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2);
262 TEST_ASSERT(ble_gatt_read_test_attrs[0].handle == attr->handle);
263 TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == attr->value_len);
264 TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, attr->value,
265 attr->value_len) == 0);
266 }
267
268 static void
ble_gatt_read_test_misc_verify_bad(uint8_t att_status,struct ble_hs_test_util_flat_attr * attr)269 ble_gatt_read_test_misc_verify_bad(uint8_t att_status,
270 struct ble_hs_test_util_flat_attr *attr)
271 {
272 int rc;
273
274 ble_gatt_read_test_misc_init();
275 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
276 NULL, NULL);
277
278 rc = ble_gattc_read(2, attr->handle, ble_gatt_read_test_cb, NULL);
279 TEST_ASSERT_FATAL(rc == 0);
280
281 ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, attr->handle);
282
283 TEST_ASSERT(ble_gatt_read_test_num_attrs == 0);
284 TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2);
285 TEST_ASSERT(ble_gatt_read_test_bad_status ==
286 BLE_HS_ERR_ATT_BASE + att_status);
287 TEST_ASSERT(!ble_gattc_any_jobs());
288 }
289
290 static void
ble_gatt_read_test_misc_uuid_verify_good(uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid,int stop_after,struct ble_hs_test_util_flat_attr * attrs)291 ble_gatt_read_test_misc_uuid_verify_good(
292 uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid,
293 int stop_after, struct ble_hs_test_util_flat_attr *attrs)
294 {
295 int num_read;
296 int idx;
297 int rc;
298 int i;
299
300 ble_gatt_read_test_misc_init();
301 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
302 NULL, NULL);
303
304 rc = ble_gattc_read_by_uuid(2, start_handle, end_handle, uuid,
305 ble_gatt_read_test_cb, &stop_after);
306 TEST_ASSERT_FATAL(rc == 0);
307
308 idx = 0;
309 while (1) {
310 num_read = ble_gatt_read_test_misc_uuid_rx_rsp_good(2, attrs + idx);
311 if (num_read == 0) {
312 ble_hs_test_util_rx_att_err_rsp(2, BLE_ATT_OP_READ_TYPE_REQ,
313 BLE_ATT_ERR_ATTR_NOT_FOUND,
314 start_handle);
315 break;
316 }
317
318 idx += num_read;
319 }
320
321 TEST_ASSERT(ble_gatt_read_test_complete);
322 TEST_ASSERT(idx == ble_gatt_read_test_num_attrs);
323
324 for (i = 0; i < idx; i++) {
325 TEST_ASSERT(ble_gatt_read_test_attrs[i].conn_handle == 2);
326 TEST_ASSERT(ble_gatt_read_test_attrs[i].handle == attrs[i].handle);
327 TEST_ASSERT(ble_gatt_read_test_attrs[i].value_len ==
328 attrs[i].value_len);
329 TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[i].value, attrs[i].value,
330 attrs[i].value_len) == 0);
331 }
332 TEST_ASSERT(!ble_gattc_any_jobs());
333 }
334
335 static void
ble_gatt_read_test_misc_long_verify_good(int max_reads,struct ble_hs_test_util_flat_attr * attr)336 ble_gatt_read_test_misc_long_verify_good(
337 int max_reads, struct ble_hs_test_util_flat_attr *attr)
338 {
339 int reads_left;
340 int chunk_sz;
341 int rem_len;
342 int att_op;
343 uint16_t offset = 0;
344 int off;
345 int rc;
346
347 ble_gatt_read_test_misc_init();
348 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
349 NULL, NULL);
350
351 if (max_reads == 0) {
352 max_reads = INT_MAX;
353 }
354 reads_left = max_reads;
355 rc = ble_gattc_read_long(2, attr->handle, offset,
356 ble_gatt_read_test_long_cb, &reads_left);
357 TEST_ASSERT_FATAL(rc == 0);
358
359 off = 0;
360 rem_len = attr->value_len;
361 do {
362 if (rem_len > BLE_ATT_MTU_DFLT - 1) {
363 chunk_sz = BLE_ATT_MTU_DFLT - 1;
364 } else {
365 chunk_sz = rem_len;
366 }
367 if (off == 0) {
368 att_op = BLE_ATT_OP_READ_RSP;
369 } else {
370 att_op = BLE_ATT_OP_READ_BLOB_RSP;
371 }
372 ble_gatt_read_test_misc_rx_rsp_good_raw(2, att_op,
373 attr->value + off, chunk_sz);
374 rem_len -= chunk_sz;
375 off += chunk_sz;
376 } while (rem_len > 0 && reads_left > 0);
377
378 TEST_ASSERT(ble_gatt_read_test_complete);
379 TEST_ASSERT(!ble_gattc_any_jobs());
380 TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2);
381 TEST_ASSERT(ble_gatt_read_test_attrs[0].handle == attr->handle);
382 if (reads_left > 0) {
383 TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == attr->value_len);
384 }
385 TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, attr->value,
386 ble_gatt_read_test_attrs[0].value_len) == 0);
387 }
388
389 static void
ble_gatt_read_test_misc_long_verify_bad(uint8_t att_status,struct ble_hs_test_util_flat_attr * attr)390 ble_gatt_read_test_misc_long_verify_bad(
391 uint8_t att_status, struct ble_hs_test_util_flat_attr *attr)
392 {
393 uint16_t offset = 0;
394 int rc;
395
396 ble_gatt_read_test_misc_init();
397 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
398 NULL, NULL);
399
400 rc = ble_gattc_read_long(2, attr->handle, offset,
401 ble_gatt_read_test_long_cb, NULL);
402 TEST_ASSERT_FATAL(rc == 0);
403
404 ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, attr->handle);
405
406 TEST_ASSERT(ble_gatt_read_test_num_attrs == 0);
407 TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2);
408 TEST_ASSERT(ble_gatt_read_test_bad_status ==
409 BLE_HS_ERR_ATT_BASE + att_status);
410 TEST_ASSERT(!ble_gattc_any_jobs());
411 }
412
413 static int
ble_gatt_read_test_misc_extract_handles(struct ble_hs_test_util_flat_attr * attrs,uint16_t * handles)414 ble_gatt_read_test_misc_extract_handles(
415 struct ble_hs_test_util_flat_attr *attrs, uint16_t *handles)
416 {
417 int i;
418
419 for (i = 0; attrs[i].handle != 0; i++) {
420 handles[i] = attrs[i].handle;
421 }
422 return i;
423 }
424
425 static void
ble_gatt_read_test_misc_mult_verify_good(struct ble_hs_test_util_flat_attr * attrs)426 ble_gatt_read_test_misc_mult_verify_good(
427 struct ble_hs_test_util_flat_attr *attrs)
428 {
429 uint8_t expected_value[512];
430 uint16_t handles[256];
431 int num_attrs;
432 int chunk_sz;
433 int off;
434 int rc;
435 int i;
436
437 ble_gatt_read_test_misc_init();
438 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
439 NULL, NULL);
440
441 num_attrs = ble_gatt_read_test_misc_extract_handles(attrs, handles);
442
443 off = 0;
444 for (i = 0; i < num_attrs; i++) {
445 if (attrs[i].value_len > BLE_ATT_MTU_DFLT - 1 - off) {
446 chunk_sz = BLE_ATT_MTU_DFLT - 1 - off;
447 } else {
448 chunk_sz = attrs[i].value_len;
449 }
450
451 if (chunk_sz > 0) {
452 memcpy(expected_value + off, attrs[i].value, chunk_sz);
453 off += chunk_sz;
454 }
455 }
456
457 rc = ble_gattc_read_mult(2, handles, num_attrs,
458 ble_gatt_read_test_cb, NULL);
459 TEST_ASSERT_FATAL(rc == 0);
460
461 ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_MULT_RSP,
462 expected_value, off);
463
464 TEST_ASSERT(ble_gatt_read_test_complete);
465 TEST_ASSERT(!ble_gattc_any_jobs());
466 TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2);
467 TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == off);
468 TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, expected_value,
469 off) == 0);
470 }
471
472 static void
ble_gatt_read_test_misc_mult_verify_bad(uint8_t att_status,uint16_t err_handle,struct ble_hs_test_util_flat_attr * attrs)473 ble_gatt_read_test_misc_mult_verify_bad(
474 uint8_t att_status, uint16_t err_handle,
475 struct ble_hs_test_util_flat_attr *attrs)
476 {
477 uint16_t handles[256];
478 int num_attrs;
479 int rc;
480
481 ble_gatt_read_test_misc_init();
482 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
483 NULL, NULL);
484
485 num_attrs = ble_gatt_read_test_misc_extract_handles(attrs, handles);
486
487 rc = ble_gattc_read_mult(2, handles, num_attrs,
488 ble_gatt_read_test_cb, NULL);
489 TEST_ASSERT_FATAL(rc == 0);
490
491 ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, err_handle);
492
493 TEST_ASSERT(ble_gatt_read_test_num_attrs == 0);
494 TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2);
495 TEST_ASSERT(ble_gatt_read_test_bad_status ==
496 BLE_HS_ERR_ATT_BASE + att_status);
497 TEST_ASSERT(!ble_gattc_any_jobs());
498 }
499
TEST_CASE(ble_gatt_read_test_by_handle)500 TEST_CASE(ble_gatt_read_test_by_handle)
501 {
502 /* Read a seven-byte attribute. */
503 ble_gatt_read_test_misc_verify_good(
504 (struct ble_hs_test_util_flat_attr[]) { {
505 .handle = 43,
506 .value = { 1,2,3,4,5,6,7 },
507 .value_len = 7
508 } });
509
510 /* Read a one-byte attribute. */
511 ble_gatt_read_test_misc_verify_good(
512 (struct ble_hs_test_util_flat_attr[]) { {
513 .handle = 0x5432,
514 .value = { 0xff },
515 .value_len = 1
516 } });
517
518 /* Read a 200-byte attribute. */
519 ble_gatt_read_test_misc_verify_good(
520 (struct ble_hs_test_util_flat_attr[]) { {
521 .handle = 815,
522 .value = { 0 },
523 .value_len = 200,
524 } });
525
526 /* Fail due to attribute not found. */
527 ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND,
528 (struct ble_hs_test_util_flat_attr[]) { {
529 .handle = 719,
530 .value = { 1,2,3,4,5,6,7 },
531 .value_len = 7
532 } });
533
534 /* Fail due to invalid PDU. */
535 ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_INVALID_PDU,
536 (struct ble_hs_test_util_flat_attr[]) { {
537 .handle = 65,
538 .value = { 0xfa, 0x4c },
539 .value_len = 2
540 } });
541 }
542
TEST_CASE(ble_gatt_read_test_by_uuid)543 TEST_CASE(ble_gatt_read_test_by_uuid)
544 {
545 /* Read a single seven-byte attribute. */
546 ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 0,
547 (struct ble_hs_test_util_flat_attr[]) { {
548 .handle = 43,
549 .value = { 1,2,3,4,5,6,7 },
550 .value_len = 7
551 }, {
552 0,
553 } });
554
555 /* Read two seven-byte attributes; one response. */
556 ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 0,
557 (struct ble_hs_test_util_flat_attr[]) { {
558 .handle = 43,
559 .value = { 1,2,3,4,5,6,7 },
560 .value_len = 7
561 }, {
562 .handle = 44,
563 .value = { 2,3,4,5,6,7,8 },
564 .value_len = 7
565 }, {
566 0,
567 } });
568
569 /* Read two attributes; two responses. */
570 ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 0,
571 (struct ble_hs_test_util_flat_attr[]) { {
572 .handle = 43,
573 .value = { 1,2,3,4,5,6,7 },
574 .value_len = 7
575 }, {
576 .handle = 44,
577 .value = { 2,3,4 },
578 .value_len = 3
579 }, {
580 0,
581 } });
582
583 /* Stop after three reads. */
584 ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16_DECLARE(0x1234), 3,
585 (struct ble_hs_test_util_flat_attr[]) { {
586 .handle = 43,
587 .value = { 1,2,3,4,5,6,7 },
588 .value_len = 7
589 }, {
590 .handle = 44,
591 .value = { 2,3,4 },
592 .value_len = 3
593 }, {
594 .handle = 45,
595 .value = { 2,3,4 },
596 .value_len = 3
597 }, {
598 .handle = 46,
599 .value = { 3,4,5,6 },
600 .value_len = 4
601 }, {
602 .handle = 47,
603 .value = { 2,3,4 },
604 .value_len = 3
605 }, {
606 0,
607 } });
608 }
609
TEST_CASE(ble_gatt_read_test_long)610 TEST_CASE(ble_gatt_read_test_long)
611 {
612 uint8_t data512[512];
613 int i;
614
615 for (i = 0; i < sizeof data512; i++) {
616 data512[i] = i;
617 }
618
619 /* Read a seven-byte attribute. */
620 ble_gatt_read_test_misc_long_verify_good(0,
621 (struct ble_hs_test_util_flat_attr[]) { {
622 .handle = 43,
623 .value = { 1,2,3,4,5,6,7 },
624 .value_len = 7
625 } });
626
627 /* Read a zero-byte attribute. */
628 ble_gatt_read_test_misc_long_verify_good(0,
629 (struct ble_hs_test_util_flat_attr[]) { {
630 .handle = 43,
631 .value = { 0 },
632 .value_len = 0
633 } });
634
635 /* Read a 60-byte attribute; three requests. */
636 ble_gatt_read_test_misc_long_verify_good(0,
637 (struct ble_hs_test_util_flat_attr[]) { {
638 .handle = 34,
639 .value = {
640 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
641 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
642 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
643 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
644 },
645 .value_len = 60
646 } });
647
648 /* Stop after two reads. */
649 ble_gatt_read_test_misc_long_verify_good(2,
650 (struct ble_hs_test_util_flat_attr[]) { {
651 .handle = 34,
652 .value = {
653 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
654 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
655 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
656 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
657 },
658 .value_len = 60
659 } });
660
661 /* Fail due to attribute not found. */
662 ble_gatt_read_test_misc_long_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND,
663 (struct ble_hs_test_util_flat_attr[]) { {
664 .handle = 719,
665 .value = { 1, 2, 3, 4, 5, 6, 7 },
666 .value_len = 7
667 } });
668 }
669
TEST_CASE(ble_gatt_read_test_mult)670 TEST_CASE(ble_gatt_read_test_mult)
671 {
672 uint8_t data512[512];
673 int i;
674
675 for (i = 0; i < sizeof data512; i++) {
676 data512[i] = i;
677 }
678
679 /* Read one attribute. */
680 ble_gatt_read_test_misc_mult_verify_good(
681 (struct ble_hs_test_util_flat_attr[]) { {
682 .handle = 43,
683 .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
684 .value_len = 7
685 }, {
686 0
687 } });
688
689 /* Read two attributes. */
690 ble_gatt_read_test_misc_mult_verify_good(
691 (struct ble_hs_test_util_flat_attr[]) { {
692 .handle = 43,
693 .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
694 .value_len = 7,
695 }, {
696 .handle = 44,
697 .value = { 8, 9, 10, 11 },
698 .value_len = 4,
699 }, {
700 0
701 } });
702
703 /* Read two attributes (swap order). */
704 ble_gatt_read_test_misc_mult_verify_good(
705 (struct ble_hs_test_util_flat_attr[]) { {
706 .handle = 44,
707 .value = { 8, 9, 10, 11 },
708 .value_len = 4,
709 }, {
710 .handle = 43,
711 .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
712 .value_len = 7,
713 }, {
714 0
715 } });
716
717 /* Read five attributes. */
718 ble_gatt_read_test_misc_mult_verify_good(
719 (struct ble_hs_test_util_flat_attr[]) { {
720 .handle = 43,
721 .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
722 .value_len = 7,
723 }, {
724 .handle = 44,
725 .value = { 8, 9, 10, 11 },
726 .value_len = 4,
727 }, {
728 .handle = 145,
729 .value = { 12, 13 },
730 .value_len = 2,
731 }, {
732 .handle = 191,
733 .value = { 14, 15, 16 },
734 .value_len = 3,
735 }, {
736 .handle = 352,
737 .value = { 17, 18, 19, 20 },
738 .value_len = 4,
739 }, {
740 0
741 } });
742
743 /* Fail due to attribute not found. */
744 ble_gatt_read_test_misc_mult_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, 719,
745 (struct ble_hs_test_util_flat_attr[]) { {
746 .handle = 719,
747 .value = { 1,2,3,4,5,6,7 },
748 .value_len = 7
749 }, {
750 0
751 } });
752 }
753
TEST_CASE(ble_gatt_read_test_concurrent)754 TEST_CASE(ble_gatt_read_test_concurrent)
755 {
756 int rc;
757 int i;
758
759 ble_gatt_read_test_misc_init();
760 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
761 NULL, NULL);
762
763 /***
764 * Perform three concurrent reads. Assert that each response is correctly
765 * matched up with its corresponding GATT procedure.
766 */
767
768 struct ble_hs_test_util_flat_attr attrs[3] = {
769 {
770 .handle = 1,
771 .offset = 0,
772 .value_len = 3,
773 .value = { 1, 2, 3 },
774 },
775 {
776 .handle = 2,
777 .offset = 0,
778 .value_len = 4,
779 .value = { 2, 3, 4, 5 },
780 },
781 {
782 .handle = 3,
783 .offset = 0,
784 .value_len = 5,
785 .value = { 3, 4, 5, 6, 7 },
786 },
787 };
788
789 rc = ble_gattc_read(2, attrs[0].handle, ble_gatt_read_test_cb, NULL);
790 TEST_ASSERT_FATAL(rc == 0);
791 rc = ble_gattc_read(2, attrs[1].handle, ble_gatt_read_test_cb, NULL);
792 TEST_ASSERT_FATAL(rc == 0);
793 rc = ble_gattc_read(2, attrs[2].handle, ble_gatt_read_test_cb, NULL);
794 TEST_ASSERT_FATAL(rc == 0);
795
796 ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 0);
797 ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 1);
798 ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 2);
799
800 TEST_ASSERT(ble_gatt_read_test_num_attrs == 3);
801
802 for (i = 0; i < 3; i++) {
803 TEST_ASSERT(ble_gatt_read_test_attrs[i].handle == attrs[i].handle);
804 TEST_ASSERT(ble_gatt_read_test_attrs[i].value_len ==
805 attrs[i].value_len);
806 TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[i].value, attrs[i].value,
807 attrs[i].value_len) == 0);
808 }
809 }
810
TEST_CASE(ble_gatt_read_test_long_oom)811 TEST_CASE(ble_gatt_read_test_long_oom)
812 {
813 static const struct ble_hs_test_util_flat_attr attr = {
814 .handle = 34,
815 .value = {
816 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
817 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
818 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
819 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
820 },
821 .value_len = 60,
822 };
823
824 struct os_mbuf *oms;
825 int32_t ticks_until;
826 int reads_left;
827 int chunk_sz;
828 uint16_t offset = 0;
829 int off;
830 int rc;
831
832 ble_gatt_read_test_misc_init();
833 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
834 NULL, NULL);
835
836 /* Initiate a read long procedure. */
837 off = 0;
838 reads_left = 0;
839 rc = ble_gattc_read_long(2, attr.handle, offset, ble_gatt_read_test_long_cb,
840 &reads_left);
841 TEST_ASSERT_FATAL(rc == 0);
842
843 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
844 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
845 chunk_sz = ble_att_mtu(2) - BLE_ATT_READ_RSP_BASE_SZ;
846 ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP,
847 attr.value + off, chunk_sz);
848 off += chunk_sz;
849
850 /* Ensure no follow-up request got sent. It should not have gotten sent
851 * due to mbuf exhaustion.
852 */
853 ble_hs_test_util_prev_tx_queue_clear();
854 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
855
856 /* Verify that we will resume the stalled GATT procedure in one second. */
857 ticks_until = ble_gattc_timer();
858 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
859
860 /* Verify the procedure proceeds after mbufs become available. */
861 rc = os_mbuf_free_chain(oms);
862 TEST_ASSERT_FATAL(rc == 0);
863 os_time_advance(ticks_until);
864 ble_gattc_timer();
865
866 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
867 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
868 chunk_sz = ble_att_mtu(2) - BLE_ATT_READ_RSP_BASE_SZ;
869 ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP,
870 attr.value + off, chunk_sz);
871 off += chunk_sz;
872
873 /* Ensure no follow-up request got sent. It should not have gotten sent
874 * due to mbuf exhaustion.
875 */
876 ble_hs_test_util_prev_tx_queue_clear();
877 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
878
879 /* Verify that we will resume the stalled GATT procedure in one second. */
880 ticks_until = ble_gattc_timer();
881 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
882
883 /* Verify that procedure completes when mbufs are available. */
884 rc = os_mbuf_free_chain(oms);
885 TEST_ASSERT_FATAL(rc == 0);
886 os_time_advance(ticks_until);
887 ble_gattc_timer();
888
889 chunk_sz = attr.value_len - off;
890 ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP,
891 attr.value + off, chunk_sz);
892 off += chunk_sz;
893
894 TEST_ASSERT(ble_gatt_read_test_complete);
895 TEST_ASSERT(!ble_gattc_any_jobs());
896 TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2);
897 TEST_ASSERT(ble_gatt_read_test_attrs[0].handle == attr.handle);
898 TEST_ASSERT(ble_gatt_read_test_attrs[0].value_len == attr.value_len);
899 TEST_ASSERT(memcmp(ble_gatt_read_test_attrs[0].value, attr.value,
900 ble_gatt_read_test_attrs[0].value_len) == 0);
901 }
902
TEST_SUITE(ble_gatt_read_test_suite)903 TEST_SUITE(ble_gatt_read_test_suite)
904 {
905 tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
906
907 ble_gatt_read_test_by_handle();
908 ble_gatt_read_test_by_uuid();
909 ble_gatt_read_test_long();
910 ble_gatt_read_test_mult();
911 ble_gatt_read_test_concurrent();
912 ble_gatt_read_test_long_oom();
913 }
914
915 int
ble_gatt_read_test_all(void)916 ble_gatt_read_test_all(void)
917 {
918 ble_gatt_read_test_suite();
919
920 return tu_any_failed;
921 }
922