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_gatt.h"
27 #include "host/ble_uuid.h"
28 #include "ble_hs_test_util.h"
29
30 struct ble_gatt_disc_c_test_char {
31 uint16_t def_handle;
32 uint16_t val_handle;
33 uint8_t properties;
34 const ble_uuid_t *uuid;
35 };
36
37 #define BLE_GATT_DISC_C_TEST_MAX_CHARS 256
38 static struct ble_gatt_chr
39 ble_gatt_disc_c_test_chars[BLE_GATT_DISC_C_TEST_MAX_CHARS];
40 static int ble_gatt_disc_c_test_num_chars;
41 static int ble_gatt_disc_c_test_rx_complete;
42
43 static void
ble_gatt_disc_c_test_init(void)44 ble_gatt_disc_c_test_init(void)
45 {
46 ble_hs_test_util_init();
47
48 ble_gatt_disc_c_test_num_chars = 0;
49 ble_gatt_disc_c_test_rx_complete = 0;
50 }
51
52 static int
ble_gatt_disc_c_test_misc_rx_rsp_once(uint16_t conn_handle,struct ble_gatt_disc_c_test_char * chars)53 ble_gatt_disc_c_test_misc_rx_rsp_once(
54 uint16_t conn_handle, struct ble_gatt_disc_c_test_char *chars)
55 {
56 struct ble_att_read_type_rsp rsp;
57 uint8_t buf[1024];
58 int off;
59 int rc;
60 int i;
61
62 /* Send the pending ATT Read By Type Request. */
63
64 if (chars[0].uuid->type == BLE_UUID_TYPE_16) {
65 rsp.batp_length = BLE_ATT_READ_TYPE_ADATA_BASE_SZ +
66 BLE_GATT_CHR_DECL_SZ_16;
67 } else {
68 rsp.batp_length = BLE_ATT_READ_TYPE_ADATA_BASE_SZ +
69 BLE_GATT_CHR_DECL_SZ_128;
70 }
71
72 ble_att_read_type_rsp_write(buf, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp);
73
74 off = BLE_ATT_READ_TYPE_RSP_BASE_SZ;
75 for (i = 0; ; i++) {
76 if (chars[i].def_handle == 0) {
77 /* No more services. */
78 break;
79 }
80
81 /* If the value length is changing, we need a separate response. */
82 if (((chars[i].uuid->type == BLE_UUID_TYPE_16) ^
83 (chars[0].uuid->type == BLE_UUID_TYPE_16)) != 0) {
84 break;
85 }
86
87 if (chars[i].uuid->type == BLE_UUID_TYPE_16) {
88 if (off + BLE_ATT_READ_TYPE_ADATA_SZ_16 >
89 ble_att_mtu(conn_handle)) {
90
91 /* Can't fit any more entries. */
92 break;
93 }
94 } else {
95 if (off + BLE_ATT_READ_TYPE_ADATA_SZ_128 >
96 ble_att_mtu(conn_handle)) {
97
98 /* Can't fit any more entries. */
99 break;
100 }
101 }
102
103 put_le16(buf + off, chars[i].def_handle);
104 off += 2;
105
106 buf[off] = chars[i].properties;
107 off++;
108
109 put_le16(buf + off, chars[i].val_handle);
110 off += 2;
111
112 ble_uuid_flat(chars[i].uuid, buf + off);
113 off += ble_uuid_length(chars[i].uuid);
114 }
115
116 rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
117 buf, off);
118 TEST_ASSERT(rc == 0);
119
120 return i;
121 }
122
123 static void
ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle,uint16_t end_handle,struct ble_gatt_disc_c_test_char * chars)124 ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle,
125 uint16_t end_handle,
126 struct ble_gatt_disc_c_test_char *chars)
127 {
128 int count;
129 int idx;
130
131 idx = 0;
132 while (chars[idx].def_handle != 0) {
133 count = ble_gatt_disc_c_test_misc_rx_rsp_once(conn_handle,
134 chars + idx);
135 if (count == 0) {
136 break;
137 }
138 idx += count;
139 }
140
141 if (chars[idx - 1].def_handle != end_handle) {
142 /* Send the pending ATT Request. */
143 ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ,
144 BLE_ATT_ERR_ATTR_NOT_FOUND,
145 chars[idx - 1].def_handle);
146 }
147 }
148
149 static void
ble_gatt_disc_c_test_misc_verify_chars(struct ble_gatt_disc_c_test_char * chars,int stop_after)150 ble_gatt_disc_c_test_misc_verify_chars(struct ble_gatt_disc_c_test_char *chars,
151 int stop_after)
152 {
153 int i;
154
155 if (stop_after == 0) {
156 stop_after = BLE_GATT_DISC_C_TEST_MAX_CHARS;
157 }
158
159 for (i = 0; i < stop_after && chars[i].def_handle != 0; i++) {
160 TEST_ASSERT(chars[i].def_handle ==
161 ble_gatt_disc_c_test_chars[i].def_handle);
162 TEST_ASSERT(chars[i].val_handle ==
163 ble_gatt_disc_c_test_chars[i].val_handle);
164 TEST_ASSERT(ble_uuid_cmp(chars[i].uuid,
165 &ble_gatt_disc_c_test_chars[i].uuid.u) == 0);
166 }
167
168 TEST_ASSERT(i == ble_gatt_disc_c_test_num_chars);
169 TEST_ASSERT(ble_gatt_disc_c_test_rx_complete);
170 }
171
172 static int
ble_gatt_disc_c_test_misc_cb(uint16_t conn_handle,const struct ble_gatt_error * error,const struct ble_gatt_chr * chr,void * arg)173 ble_gatt_disc_c_test_misc_cb(uint16_t conn_handle,
174 const struct ble_gatt_error *error,
175 const struct ble_gatt_chr *chr, void *arg)
176 {
177 struct ble_gatt_chr *dst;
178 int *stop_after;
179
180 TEST_ASSERT(error != NULL);
181 TEST_ASSERT(!ble_gatt_disc_c_test_rx_complete);
182
183 stop_after = arg;
184
185 switch (error->status) {
186 case 0:
187 TEST_ASSERT_FATAL(ble_gatt_disc_c_test_num_chars <
188 BLE_GATT_DISC_C_TEST_MAX_CHARS);
189
190 dst = ble_gatt_disc_c_test_chars + ble_gatt_disc_c_test_num_chars++;
191 *dst = *chr;
192 break;
193
194 case BLE_HS_EDONE:
195 ble_gatt_disc_c_test_rx_complete = 1;
196 break;
197
198 default:
199 TEST_ASSERT(0);
200 break;
201 }
202
203 if (*stop_after > 0) {
204 (*stop_after)--;
205 if (*stop_after == 0) {
206 ble_gatt_disc_c_test_rx_complete = 1;
207 return 1;
208 }
209 }
210
211 return 0;
212 }
213
214 static void
ble_gatt_disc_c_test_misc_all(uint16_t start_handle,uint16_t end_handle,int stop_after,struct ble_gatt_disc_c_test_char * chars)215 ble_gatt_disc_c_test_misc_all(uint16_t start_handle, uint16_t end_handle,
216 int stop_after,
217 struct ble_gatt_disc_c_test_char *chars)
218 {
219 int num_left;
220 int rc;
221
222 ble_gatt_disc_c_test_init();
223
224 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
225 NULL, NULL);
226
227 num_left = stop_after;
228 rc = ble_gattc_disc_all_chrs(2, start_handle, end_handle,
229 ble_gatt_disc_c_test_misc_cb, &num_left);
230 TEST_ASSERT(rc == 0);
231
232 ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, chars);
233 ble_gatt_disc_c_test_misc_verify_chars(chars, stop_after);
234 }
235
236 static void
ble_gatt_disc_c_test_misc_uuid(uint16_t start_handle,uint16_t end_handle,int stop_after,const ble_uuid_t * uuid,struct ble_gatt_disc_c_test_char * rsp_chars,struct ble_gatt_disc_c_test_char * ret_chars)237 ble_gatt_disc_c_test_misc_uuid(uint16_t start_handle, uint16_t end_handle,
238 int stop_after, const ble_uuid_t *uuid,
239 struct ble_gatt_disc_c_test_char *rsp_chars,
240 struct ble_gatt_disc_c_test_char *ret_chars)
241 {
242 int rc;
243
244 ble_gatt_disc_c_test_init();
245
246 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
247 NULL, NULL);
248
249 rc = ble_gattc_disc_chrs_by_uuid(2, start_handle, end_handle,
250 uuid,
251 ble_gatt_disc_c_test_misc_cb,
252 &stop_after);
253 TEST_ASSERT(rc == 0);
254
255 ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, rsp_chars);
256 ble_gatt_disc_c_test_misc_verify_chars(ret_chars, 0);
257 }
258
TEST_CASE(ble_gatt_disc_c_test_disc_all)259 TEST_CASE(ble_gatt_disc_c_test_disc_all)
260 {
261 /*** One 16-bit characteristic. */
262 ble_gatt_disc_c_test_misc_all(50, 100, 0,
263 (struct ble_gatt_disc_c_test_char[]) {
264 {
265 .def_handle = 55,
266 .val_handle = 56,
267 .uuid = BLE_UUID16_DECLARE(0x2010),
268 }, { 0 }
269 });
270
271 /*** Two 16-bit characteristics. */
272 ble_gatt_disc_c_test_misc_all(50, 100, 0,
273 (struct ble_gatt_disc_c_test_char[]) {
274 {
275 .def_handle = 55,
276 .val_handle = 56,
277 .uuid = BLE_UUID16_DECLARE(0x2010),
278 }, {
279 .def_handle = 57,
280 .val_handle = 58,
281 .uuid = BLE_UUID16_DECLARE(0x64ba),
282 }, { 0 }
283 });
284
285 /*** Five 16-bit characteristics. */
286 ble_gatt_disc_c_test_misc_all(50, 100, 0,
287 (struct ble_gatt_disc_c_test_char[]) {
288 {
289 .def_handle = 55,
290 .val_handle = 56,
291 .uuid = BLE_UUID16_DECLARE(0x2010),
292 }, {
293 .def_handle = 57,
294 .val_handle = 58,
295 .uuid = BLE_UUID16_DECLARE(0x64ba),
296 }, {
297 .def_handle = 59,
298 .val_handle = 60,
299 .uuid = BLE_UUID16_DECLARE(0x5372),
300 }, {
301 .def_handle = 61,
302 .val_handle = 62,
303 .uuid = BLE_UUID16_DECLARE(0xab93),
304 }, {
305 .def_handle = 63,
306 .val_handle = 64,
307 .uuid = BLE_UUID16_DECLARE(0x0023),
308 }, { 0 }
309 });
310
311 /*** Interleaved 16-bit and 128-bit characteristics. */
312 ble_gatt_disc_c_test_misc_all(50, 100, 0,
313 (struct ble_gatt_disc_c_test_char[]) {
314 {
315 .def_handle = 83,
316 .val_handle = 84,
317 .uuid = BLE_UUID16_DECLARE(0x2010),
318 }, {
319 .def_handle = 87,
320 .val_handle = 88,
321 .uuid = BLE_UUID128_DECLARE(0, 1, 2, 3, 4, 5, 6, 7,
322 8, 9, 10, 11, 12, 13, 14, 15),
323 }, {
324 .def_handle = 91,
325 .val_handle = 92,
326 .uuid = BLE_UUID16_DECLARE(0x0003),
327 }, {
328 .def_handle = 93,
329 .val_handle = 94,
330 .uuid = BLE_UUID128_DECLARE(1, 0, 4, 0, 6, 9, 17, 7,
331 8, 43, 7, 4, 12, 43, 19, 35),
332 }, {
333 .def_handle = 98,
334 .val_handle = 99,
335 .uuid = BLE_UUID16_DECLARE(0xabfa),
336 }, { 0 }
337 });
338
339 /*** Ends with final handle ID. */
340 ble_gatt_disc_c_test_misc_all(50, 100, 0,
341 (struct ble_gatt_disc_c_test_char[]) {
342 {
343 .def_handle = 55,
344 .val_handle = 56,
345 .uuid = BLE_UUID16_DECLARE(0x2010),
346 }, {
347 .def_handle = 99,
348 .val_handle = 100,
349 .uuid = BLE_UUID16_DECLARE(0x64ba),
350 }, { 0 }
351 });
352
353 /*** Stop after two characteristics. */
354 ble_gatt_disc_c_test_misc_all(50, 100, 2,
355 (struct ble_gatt_disc_c_test_char[]) {
356 {
357 .def_handle = 55,
358 .val_handle = 56,
359 .uuid = BLE_UUID16_DECLARE(0x2010),
360 }, {
361 .def_handle = 57,
362 .val_handle = 58,
363 .uuid = BLE_UUID16_DECLARE(0x64ba),
364 }, {
365 .def_handle = 59,
366 .val_handle = 60,
367 .uuid = BLE_UUID16_DECLARE(0x5372),
368 }, {
369 .def_handle = 61,
370 .val_handle = 62,
371 .uuid = BLE_UUID16_DECLARE(0xab93),
372 }, {
373 .def_handle = 63,
374 .val_handle = 64,
375 .uuid = BLE_UUID16_DECLARE(0x0023),
376 }, { 0 }
377 });
378 }
379
TEST_CASE(ble_gatt_disc_c_test_disc_uuid)380 TEST_CASE(ble_gatt_disc_c_test_disc_uuid)
381 {
382 /*** One 16-bit characteristic. */
383 ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x2010),
384 (struct ble_gatt_disc_c_test_char[]) {
385 {
386 .def_handle = 55,
387 .val_handle = 56,
388 .uuid = BLE_UUID16_DECLARE(0x2010),
389 }, { 0 } },
390 (struct ble_gatt_disc_c_test_char[]) {
391 {
392 .def_handle = 55,
393 .val_handle = 56,
394 .uuid = BLE_UUID16_DECLARE(0x2010),
395 }, { 0 } }
396 );
397
398 /*** No matching characteristics. */
399 ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x2010),
400 (struct ble_gatt_disc_c_test_char[]) {
401 {
402 .def_handle = 55,
403 .val_handle = 56,
404 .uuid = BLE_UUID16_DECLARE(0x1234),
405 }, { 0 } },
406 (struct ble_gatt_disc_c_test_char[]) {
407 { 0 } }
408 );
409
410 /*** 2/5 16-bit characteristics. */
411 ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x2010),
412 (struct ble_gatt_disc_c_test_char[]) {
413 {
414 .def_handle = 55,
415 .val_handle = 56,
416 .uuid = BLE_UUID16_DECLARE(0x2010),
417 }, {
418 .def_handle = 57,
419 .val_handle = 58,
420 .uuid = BLE_UUID16_DECLARE(0x64ba),
421 }, {
422 .def_handle = 59,
423 .val_handle = 60,
424 .uuid = BLE_UUID16_DECLARE(0x5372),
425 }, {
426 .def_handle = 61,
427 .val_handle = 62,
428 .uuid = BLE_UUID16_DECLARE(0x2010),
429 }, {
430 .def_handle = 63,
431 .val_handle = 64,
432 .uuid = BLE_UUID16_DECLARE(0x0023),
433 }, { 0 } },
434 (struct ble_gatt_disc_c_test_char[]) {
435 {
436 .def_handle = 55,
437 .val_handle = 56,
438 .uuid = BLE_UUID16_DECLARE(0x2010),
439 }, {
440 .def_handle = 61,
441 .val_handle = 62,
442 .uuid = BLE_UUID16_DECLARE(0x2010),
443 }, { 0 } }
444 );
445
446 /*** Interleaved 16-bit and 128-bit characteristics. */
447 ble_gatt_disc_c_test_misc_uuid(
448 50, 100, 0,
449 BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
450 (struct ble_gatt_disc_c_test_char[]) {
451 {
452 .def_handle = 83,
453 .val_handle = 84,
454 .uuid = BLE_UUID16_DECLARE(0x2010),
455 }, {
456 .def_handle = 87,
457 .val_handle = 88,
458 .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
459 }, {
460 .def_handle = 91,
461 .val_handle = 92,
462 .uuid = BLE_UUID16_DECLARE(0x0003),
463 }, {
464 .def_handle = 93,
465 .val_handle = 94,
466 .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
467 }, {
468 .def_handle = 98,
469 .val_handle = 99,
470 .uuid = BLE_UUID16_DECLARE(0xabfa),
471 }, { 0 } },
472 (struct ble_gatt_disc_c_test_char[]) {
473 {
474 .def_handle = 87,
475 .val_handle = 88,
476 .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
477 }, {
478 .def_handle = 93,
479 .val_handle = 94,
480 .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
481 }, { 0 } }
482 );
483
484 /*** Ends with final handle ID. */
485 ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16_DECLARE(0x64ba),
486 (struct ble_gatt_disc_c_test_char[]) {
487 {
488 .def_handle = 55,
489 .val_handle = 56,
490 .uuid = BLE_UUID16_DECLARE(0x2010),
491 }, {
492 .def_handle = 99,
493 .val_handle = 100,
494 .uuid = BLE_UUID16_DECLARE(0x64ba),
495 }, { 0 } },
496 (struct ble_gatt_disc_c_test_char[]) {
497 {
498 .def_handle = 99,
499 .val_handle = 100,
500 .uuid = BLE_UUID16_DECLARE(0x64ba),
501 }, { 0 } }
502 );
503
504 /*** Stop after first characteristic. */
505 ble_gatt_disc_c_test_misc_uuid(50, 100, 1, BLE_UUID16_DECLARE(0x2010),
506 (struct ble_gatt_disc_c_test_char[]) {
507 {
508 .def_handle = 55,
509 .val_handle = 56,
510 .uuid = BLE_UUID16_DECLARE(0x2010),
511 }, {
512 .def_handle = 57,
513 .val_handle = 58,
514 .uuid = BLE_UUID16_DECLARE(0x64ba),
515 }, {
516 .def_handle = 59,
517 .val_handle = 60,
518 .uuid = BLE_UUID16_DECLARE(0x5372),
519 }, {
520 .def_handle = 61,
521 .val_handle = 62,
522 .uuid = BLE_UUID16_DECLARE(0x2010),
523 }, {
524 .def_handle = 63,
525 .val_handle = 64,
526 .uuid = BLE_UUID16_DECLARE(0x0023),
527 }, { 0 } },
528 (struct ble_gatt_disc_c_test_char[]) {
529 {
530 .def_handle = 55,
531 .val_handle = 56,
532 .uuid = BLE_UUID16_DECLARE(0x2010),
533 }, { 0 } }
534 );
535 }
536
TEST_CASE(ble_gatt_disc_c_test_oom_all)537 TEST_CASE(ble_gatt_disc_c_test_oom_all)
538 {
539 /* Retrieve enough characteristics to require two transactions. */
540 struct ble_gatt_disc_c_test_char chrs[] = {
541 {
542 .def_handle = 93,
543 .val_handle = 94,
544 .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
545 },
546 {
547 .def_handle = 95,
548 .val_handle = 96,
549 .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16),
550 },
551 { 0 }
552 };
553
554 struct os_mbuf *oms;
555 int32_t ticks_until;
556 int stop_after;
557 int num_chrs;
558 int rc;
559
560 ble_gatt_disc_c_test_init();
561
562 ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}),
563 NULL, NULL);
564
565 /* Initiate a discover all characteristics procedure. */
566 stop_after = 0;
567 rc = ble_gattc_disc_all_chrs(1, 1, 0xffff,
568 ble_gatt_disc_c_test_misc_cb, &stop_after);
569 TEST_ASSERT_FATAL(rc == 0);
570
571 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
572 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
573 num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs);
574
575 /* Make sure there are still undiscovered characteristics. */
576 TEST_ASSERT_FATAL(num_chrs < sizeof chrs / sizeof chrs[0] - 1);
577
578 /* Ensure no follow-up request got sent. It should not have gotten sent
579 * due to mbuf exhaustion.
580 */
581 ble_hs_test_util_prev_tx_queue_clear();
582 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
583
584 /* Verify that we will resume the stalled GATT procedure in one second. */
585 ticks_until = ble_gattc_timer();
586 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
587
588 /* Verify the procedure proceeds after mbufs become available. */
589 rc = os_mbuf_free_chain(oms);
590 TEST_ASSERT_FATAL(rc == 0);
591
592 os_time_advance(ticks_until);
593 ble_gattc_timer();
594
595 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
596 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
597 ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs + num_chrs);
598
599 /* Ensure no follow-up request got sent. It should not have gotten sent
600 * due to mbuf exhaustion.
601 */
602 ble_hs_test_util_prev_tx_queue_clear();
603 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
604
605 /* Verify that we will resume the stalled GATT procedure in one second. */
606 ticks_until = ble_gattc_timer();
607 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
608
609 /* Verify that procedure completes when mbufs are available. */
610 rc = os_mbuf_free_chain(oms);
611 TEST_ASSERT_FATAL(rc == 0);
612
613 os_time_advance(ticks_until);
614 ble_gattc_timer();
615
616 ble_hs_test_util_rx_att_err_rsp(1,
617 BLE_ATT_OP_READ_TYPE_REQ,
618 BLE_ATT_ERR_ATTR_NOT_FOUND,
619 1);
620 ble_gatt_disc_c_test_misc_verify_chars(chrs, 0);
621 }
622
TEST_CASE(ble_gatt_disc_c_test_oom_uuid)623 TEST_CASE(ble_gatt_disc_c_test_oom_uuid)
624 {
625 /* Retrieve enough characteristics to require two transactions. */
626 struct ble_gatt_disc_c_test_char chrs[] = {
627 {
628 .def_handle = 93,
629 .val_handle = 94,
630 .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
631 },
632 {
633 .def_handle = 95,
634 .val_handle = 96,
635 .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
636 },
637 { 0 }
638 };
639
640 struct os_mbuf *oms;
641 int32_t ticks_until;
642 int stop_after;
643 int num_chrs;
644 int rc;
645
646 ble_gatt_disc_c_test_init();
647
648 ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}),
649 NULL, NULL);
650
651 /* Initiate a discover characteristics by UUID procedure. */
652 stop_after = 0;
653 rc = ble_gattc_disc_chrs_by_uuid(1, 1, 0xffff, chrs[0].uuid,
654 ble_gatt_disc_c_test_misc_cb,
655 &stop_after);
656 TEST_ASSERT_FATAL(rc == 0);
657
658 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
659 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
660 num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs);
661
662 /* Make sure there are still undiscovered characteristics. */
663 TEST_ASSERT_FATAL(num_chrs < sizeof chrs / sizeof chrs[0] - 1);
664
665 /* Ensure no follow-up request got sent. It should not have gotten sent
666 * due to mbuf exhaustion.
667 */
668 ble_hs_test_util_prev_tx_queue_clear();
669 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
670
671 /* Verify that we will resume the stalled GATT procedure in one second. */
672 ticks_until = ble_gattc_timer();
673 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
674
675 /* Verify the procedure proceeds after mbufs become available. */
676 rc = os_mbuf_free_chain(oms);
677 TEST_ASSERT_FATAL(rc == 0);
678 os_time_advance(ticks_until);
679 ble_gattc_timer();
680
681 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
682 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
683 ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs + num_chrs);
684
685 /* Ensure no follow-up request got sent. It should not have gotten sent
686 * due to mbuf exhaustion.
687 */
688 ble_hs_test_util_prev_tx_queue_clear();
689 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
690
691 /* Verify that we will resume the stalled GATT procedure in one second. */
692 ticks_until = ble_gattc_timer();
693 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
694
695 /* Verify that procedure completes when mbufs are available. */
696 rc = os_mbuf_free_chain(oms);
697 TEST_ASSERT_FATAL(rc == 0);
698 os_time_advance(ticks_until);
699 ble_gattc_timer();
700
701 ble_hs_test_util_rx_att_err_rsp(1,
702 BLE_ATT_OP_READ_TYPE_REQ,
703 BLE_ATT_ERR_ATTR_NOT_FOUND,
704 1);
705 ble_gatt_disc_c_test_misc_verify_chars(chrs, 0);
706 }
707
TEST_SUITE(ble_gatt_disc_c_test_suite)708 TEST_SUITE(ble_gatt_disc_c_test_suite)
709 {
710 tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
711
712 ble_gatt_disc_c_test_disc_all();
713 ble_gatt_disc_c_test_disc_uuid();
714 ble_gatt_disc_c_test_oom_all();
715 ble_gatt_disc_c_test_oom_uuid();
716 }
717
718 int
ble_gatt_disc_c_test_all(void)719 ble_gatt_disc_c_test_all(void)
720 {
721 ble_gatt_disc_c_test_suite();
722 ble_gatt_disc_c_test_oom_all();
723
724 return tu_any_failed;
725 }
726