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 "testutil/testutil.h"
23 #include "nimble/ble.h"
24 #include "host/ble_hs_test.h"
25 #include "host/ble_uuid.h"
26 #include "ble_hs_test_util.h"
27
28 struct ble_gatt_disc_s_test_svc {
29 uint16_t start_handle;
30 uint16_t end_handle;
31 const ble_uuid_t *uuid;
32 };
33
34 #define BLE_GATT_DISC_S_TEST_MAX_SERVICES 256
35 static struct ble_gatt_svc
36 ble_gatt_disc_s_test_svcs[BLE_GATT_DISC_S_TEST_MAX_SERVICES];
37 static int ble_gatt_disc_s_test_num_svcs;
38 static int ble_gatt_disc_s_test_rx_complete;
39
40 static void
ble_gatt_disc_s_test_init(void)41 ble_gatt_disc_s_test_init(void)
42 {
43 ble_hs_test_util_init();
44 ble_gatt_disc_s_test_num_svcs = 0;
45 ble_gatt_disc_s_test_rx_complete = 0;
46 }
47
48 static int
ble_gatt_disc_s_test_misc_svc_length(struct ble_gatt_disc_s_test_svc * service)49 ble_gatt_disc_s_test_misc_svc_length(struct ble_gatt_disc_s_test_svc *service)
50 {
51 if (service->uuid->type == BLE_UUID_TYPE_16) {
52 return 6;
53 } else {
54 return 20;
55 }
56 }
57
58 static int
ble_gatt_disc_s_test_misc_rx_all_rsp_once(uint16_t conn_handle,struct ble_gatt_disc_s_test_svc * services)59 ble_gatt_disc_s_test_misc_rx_all_rsp_once(
60 uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
61 {
62 struct ble_att_read_group_type_rsp rsp;
63 uint8_t buf[1024];
64 int off;
65 int rc;
66 int i;
67
68 /* Send the pending ATT Read By Group Type Request. */
69
70 rsp.bagp_length = ble_gatt_disc_s_test_misc_svc_length(services);
71 ble_att_read_group_type_rsp_write(buf, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ,
72 &rsp);
73
74 off = BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ;
75 for (i = 0; ; i++) {
76 if (services[i].start_handle == 0) {
77 /* No more services. */
78 break;
79 }
80
81 rc = ble_gatt_disc_s_test_misc_svc_length(services + i);
82 if (rc != rsp.bagp_length) {
83 /* UUID length is changing; Need a separate response. */
84 break;
85 }
86
87 if (services[i].uuid->type == BLE_UUID_TYPE_16) {
88 if (off + BLE_ATT_READ_GROUP_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_GROUP_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, services[i].start_handle);
104 off += 2;
105
106 put_le16(buf + off, services[i].end_handle);
107 off += 2;
108
109 ble_uuid_flat(services[i].uuid, buf + off);
110 off += ble_uuid_length(services[i].uuid);
111 }
112
113 rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
114 buf, off);
115 TEST_ASSERT(rc == 0);
116
117 return i;
118 }
119
120 static void
ble_gatt_disc_s_test_misc_rx_all_rsp(uint16_t conn_handle,struct ble_gatt_disc_s_test_svc * services)121 ble_gatt_disc_s_test_misc_rx_all_rsp(
122 uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
123 {
124 int count;
125 int idx;
126
127 idx = 0;
128 while (services[idx].start_handle != 0) {
129 count = ble_gatt_disc_s_test_misc_rx_all_rsp_once(conn_handle,
130 services + idx);
131 idx += count;
132 }
133
134 if (services[idx - 1].end_handle != 0xffff) {
135 /* Send the pending ATT Request. */
136 ble_hs_test_util_rx_att_err_rsp(conn_handle,
137 BLE_ATT_OP_READ_GROUP_TYPE_REQ,
138 BLE_ATT_ERR_ATTR_NOT_FOUND,
139 services[idx - 1].start_handle);
140 }
141 }
142
143 static int
ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(uint16_t conn_handle,struct ble_gatt_disc_s_test_svc * services)144 ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(
145 uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
146 {
147 uint8_t buf[1024];
148 int off;
149 int rc;
150 int i;
151
152 /* Send the pending ATT Find By Type Value Request. */
153
154 buf[0] = BLE_ATT_OP_FIND_TYPE_VALUE_RSP;
155 off = BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ;
156 for (i = 0; ; i++) {
157 if (services[i].start_handle == 0) {
158 /* No more services. */
159 break;
160 }
161
162 if (off + BLE_ATT_FIND_TYPE_VALUE_HINFO_BASE_SZ >
163 ble_att_mtu(conn_handle)) {
164
165 /* Can't fit any more entries. */
166 break;
167 }
168
169 put_le16(buf + off, services[i].start_handle);
170 off += 2;
171
172 put_le16(buf + off, services[i].end_handle);
173 off += 2;
174 }
175
176 rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
177 buf, off);
178 TEST_ASSERT(rc == 0);
179
180 return i;
181 }
182
183 static void
ble_gatt_disc_s_test_misc_rx_uuid_rsp(uint16_t conn_handle,struct ble_gatt_disc_s_test_svc * services)184 ble_gatt_disc_s_test_misc_rx_uuid_rsp(
185 uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
186 {
187 int count;
188 int idx;
189
190 idx = 0;
191 while (services[idx].start_handle != 0) {
192 count = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(conn_handle,
193 services + idx);
194 idx += count;
195 }
196
197 if (services[idx - 1].end_handle != 0xffff) {
198 /* Send the pending ATT Request. */
199 ble_hs_test_util_rx_att_err_rsp(conn_handle,
200 BLE_ATT_OP_FIND_TYPE_VALUE_REQ,
201 BLE_ATT_ERR_ATTR_NOT_FOUND,
202 services[idx - 1].start_handle);
203 }
204 }
205
206 static void
ble_gatt_disc_s_test_misc_verify_services(struct ble_gatt_disc_s_test_svc * services)207 ble_gatt_disc_s_test_misc_verify_services(
208 struct ble_gatt_disc_s_test_svc *services)
209 {
210 int i;
211
212 for (i = 0; services[i].start_handle != 0; i++) {
213 TEST_ASSERT(services[i].start_handle ==
214 ble_gatt_disc_s_test_svcs[i].start_handle);
215 TEST_ASSERT(services[i].end_handle ==
216 ble_gatt_disc_s_test_svcs[i].end_handle);
217
218 TEST_ASSERT(ble_uuid_cmp(services[i].uuid,
219 &ble_gatt_disc_s_test_svcs[i].uuid.u) == 0);
220 }
221
222 TEST_ASSERT(i == ble_gatt_disc_s_test_num_svcs);
223 TEST_ASSERT(ble_gatt_disc_s_test_rx_complete);
224 }
225
226 static int
ble_gatt_disc_s_test_misc_disc_cb(uint16_t conn_handle,const struct ble_gatt_error * error,const struct ble_gatt_svc * service,void * arg)227 ble_gatt_disc_s_test_misc_disc_cb(uint16_t conn_handle,
228 const struct ble_gatt_error *error,
229 const struct ble_gatt_svc *service,
230 void *arg)
231 {
232 TEST_ASSERT(error != NULL);
233 TEST_ASSERT(!ble_gatt_disc_s_test_rx_complete);
234
235 switch (error->status) {
236 case 0:
237 TEST_ASSERT(service != NULL);
238 TEST_ASSERT_FATAL(ble_gatt_disc_s_test_num_svcs <
239 BLE_GATT_DISC_S_TEST_MAX_SERVICES);
240 ble_gatt_disc_s_test_svcs[ble_gatt_disc_s_test_num_svcs++] = *service;
241 break;
242
243 case BLE_HS_EDONE:
244 TEST_ASSERT(service == NULL);
245 ble_gatt_disc_s_test_rx_complete = 1;
246 break;
247
248 case BLE_HS_ETIMEOUT:
249 ble_gatt_disc_s_test_rx_complete = 1;
250 break;
251
252 default:
253 TEST_ASSERT(0);
254 }
255
256 return 0;
257 }
258
259 static void
ble_gatt_disc_s_test_misc_good_all(struct ble_gatt_disc_s_test_svc * services)260 ble_gatt_disc_s_test_misc_good_all(struct ble_gatt_disc_s_test_svc *services)
261 {
262 int rc;
263
264 ble_gatt_disc_s_test_init();
265
266 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
267 NULL, NULL);
268
269 rc = ble_gattc_disc_all_svcs(2, ble_gatt_disc_s_test_misc_disc_cb, NULL);
270 TEST_ASSERT(rc == 0);
271
272 ble_gatt_disc_s_test_misc_rx_all_rsp(2, services);
273 ble_gatt_disc_s_test_misc_verify_services(services);
274 }
275
276 static void
ble_gatt_disc_s_test_misc_good_uuid(struct ble_gatt_disc_s_test_svc * services)277 ble_gatt_disc_s_test_misc_good_uuid(
278 struct ble_gatt_disc_s_test_svc *services)
279 {
280 int rc;
281
282 ble_gatt_disc_s_test_init();
283
284 ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
285 NULL, NULL);
286
287 rc = ble_gattc_disc_svc_by_uuid(2, services[0].uuid,
288 ble_gatt_disc_s_test_misc_disc_cb, NULL);
289 TEST_ASSERT(rc == 0);
290
291 ble_hs_test_util_verify_tx_disc_svc_uuid(services[0].uuid);
292
293 ble_gatt_disc_s_test_misc_rx_uuid_rsp(2, services);
294 ble_gatt_disc_s_test_misc_verify_services(services);
295 }
296
TEST_CASE(ble_gatt_disc_s_test_disc_all)297 TEST_CASE(ble_gatt_disc_s_test_disc_all)
298 {
299 /*** One 128-bit service. */
300 ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
301 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
302 { 0 }
303 });
304
305 /*** Two 128-bit services. */
306 ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
307 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
308 { 10, 50, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), },
309 { 0 }
310 });
311
312 /*** Five 128-bit services. */
313 ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
314 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
315 { 10, 50, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), },
316 { 80, 120, BLE_UUID128_DECLARE(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ), },
317 { 123, 678, BLE_UUID128_DECLARE(4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ), },
318 { 751, 999, BLE_UUID128_DECLARE(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ), },
319 { 0 }
320 });
321
322 /*** One 128-bit service, one 16-bit-service. */
323 ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
324 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
325 { 6, 7, BLE_UUID16_DECLARE(0x1234) },
326 { 0 }
327 });
328
329 /*** End with handle 0xffff. */
330 ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
331 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
332 { 7, 0xffff,BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), },
333 { 0 }
334 });
335 }
336
TEST_CASE(ble_gatt_disc_s_test_disc_uuid)337 TEST_CASE(ble_gatt_disc_s_test_disc_uuid)
338 {
339 /*** 128-bit service; one entry. */
340 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
341 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
342 { 0 }
343 });
344
345 /*** 128-bit service; two entries. */
346 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
347 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
348 { 8, 43, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
349 { 0 }
350 });
351
352 /*** 128-bit service; five entries. */
353 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
354 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
355 { 8, 43, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
356 { 67, 100, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
357 { 102, 103, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
358 { 262, 900, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
359 { 0 }
360 });
361
362 /*** 128-bit service; end with handle 0xffff. */
363 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
364 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
365 { 7, 0xffff,BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
366 { 0 }
367 });
368
369 /*** 16-bit service; one entry. */
370 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
371 { 1, 5, BLE_UUID16_DECLARE(0x1234) },
372 { 0 }
373 });
374
375 /*** 16-bit service; two entries. */
376 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
377 { 1, 5, BLE_UUID16_DECLARE(0x1234) },
378 { 85, 243, BLE_UUID16_DECLARE(0x1234) },
379 { 0 }
380 });
381
382 /*** 16-bit service; five entries. */
383 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
384 { 1, 5, BLE_UUID16_DECLARE(0x1234) },
385 { 85, 243, BLE_UUID16_DECLARE(0x1234) },
386 { 382, 383, BLE_UUID16_DECLARE(0x1234) },
387 { 562, 898, BLE_UUID16_DECLARE(0x1234) },
388 { 902, 984, BLE_UUID16_DECLARE(0x1234) },
389 { 0 }
390 });
391
392 /*** 16-bit service; end with handle 0xffff. */
393 ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
394 { 1, 5, BLE_UUID16_DECLARE(0x1234) },
395 { 9, 0xffff,BLE_UUID16_DECLARE(0x1234) },
396 { 0 }
397 });
398 }
399
TEST_CASE(ble_gatt_disc_s_test_oom_all)400 TEST_CASE(ble_gatt_disc_s_test_oom_all)
401 {
402 struct ble_gatt_disc_s_test_svc svcs[] = {
403 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
404 { 6, 10, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), },
405 { 0 },
406 };
407
408 struct os_mbuf *oms;
409 int32_t ticks_until;
410 int num_svcs;
411 int rc;
412
413 ble_gatt_disc_s_test_init();
414
415 ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}),
416 NULL, NULL);
417
418 /* Initiate a discover all services procedure. */
419 rc = ble_gattc_disc_all_svcs(1, ble_gatt_disc_s_test_misc_disc_cb, NULL);
420 TEST_ASSERT_FATAL(rc == 0);
421
422 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
423 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
424 num_svcs = ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs);
425
426 /* Make sure there are still undiscovered services. */
427 TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1);
428
429 /* Ensure no follow-up request got sent. It should not have gotten sent
430 * due to mbuf exhaustion.
431 */
432 ble_hs_test_util_prev_tx_queue_clear();
433 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
434
435 /* Verify that we will resume the stalled GATT procedure in one second. */
436 ticks_until = ble_gattc_timer();
437 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
438
439 /* Verify the procedure proceeds after mbufs become available. */
440 rc = os_mbuf_free_chain(oms);
441 TEST_ASSERT_FATAL(rc == 0);
442 os_time_advance(ticks_until);
443 ble_gattc_timer();
444
445 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
446 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
447 ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs + num_svcs);
448
449 /* Ensure no follow-up request got sent. It should not have gotten sent
450 * due to mbuf exhaustion.
451 */
452 ble_hs_test_util_prev_tx_queue_clear();
453 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
454
455 /* Verify that we will resume the stalled GATT procedure in one second. */
456 ticks_until = ble_gattc_timer();
457 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
458
459 rc = os_mbuf_free_chain(oms);
460 TEST_ASSERT_FATAL(rc == 0);
461 os_time_advance(ticks_until);
462 ble_gattc_timer();
463
464 ble_hs_test_util_rx_att_err_rsp(1,
465 BLE_ATT_OP_READ_GROUP_TYPE_REQ,
466 BLE_ATT_ERR_ATTR_NOT_FOUND,
467 1);
468 ble_gatt_disc_s_test_misc_verify_services(svcs);
469 }
470
TEST_CASE(ble_gatt_disc_s_test_oom_uuid)471 TEST_CASE(ble_gatt_disc_s_test_oom_uuid)
472 {
473 /* Retrieve enough services to require two transactions. */
474 struct ble_gatt_disc_s_test_svc svcs[] = {
475 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
476 { 6, 10, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
477 { 11, 15, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
478 { 16, 20, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
479 { 21, 25, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
480 { 26, 30, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
481 { 0 },
482 };
483
484 struct os_mbuf *oms;
485 int32_t ticks_until;
486 int num_svcs;
487 int rc;
488
489 ble_gatt_disc_s_test_init();
490
491 ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}),
492 NULL, NULL);
493
494 /* Initiate a discover all services procedure. */
495 rc = ble_gattc_disc_svc_by_uuid(1, svcs[0].uuid,
496 ble_gatt_disc_s_test_misc_disc_cb, NULL);
497 TEST_ASSERT_FATAL(rc == 0);
498
499 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
500 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
501 num_svcs = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs);
502
503 /* Make sure there are still undiscovered services. */
504 TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1);
505
506 /* Ensure no follow-up request got sent. It should not have gotten sent
507 * due to mbuf exhaustion.
508 */
509 ble_hs_test_util_prev_tx_queue_clear();
510 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
511
512 /* Verify that we will resume the stalled GATT procedure in one second. */
513 ticks_until = ble_gattc_timer();
514 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
515
516 /* Verify the procedure proceeds after mbufs become available. */
517 rc = os_mbuf_free_chain(oms);
518 TEST_ASSERT_FATAL(rc == 0);
519 os_time_advance(ticks_until);
520 ble_gattc_timer();
521
522 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
523 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
524 ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs + num_svcs);
525
526 /* Ensure no follow-up request got sent. It should not have gotten sent
527 * due to mbuf exhaustion.
528 */
529 ble_hs_test_util_prev_tx_queue_clear();
530 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
531
532 /* Verify that we will resume the stalled GATT procedure in one second. */
533 ticks_until = ble_gattc_timer();
534 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
535
536 /* Verify that procedure completes when mbufs are available. */
537 rc = os_mbuf_free_chain(oms);
538 TEST_ASSERT_FATAL(rc == 0);
539 os_time_advance(ticks_until);
540 ble_gattc_timer();
541
542 ble_hs_test_util_rx_att_err_rsp(1,
543 BLE_ATT_OP_READ_GROUP_TYPE_REQ,
544 BLE_ATT_ERR_ATTR_NOT_FOUND,
545 1);
546 ble_gatt_disc_s_test_misc_verify_services(svcs);
547 }
548
TEST_CASE(ble_gatt_disc_s_test_oom_timeout)549 TEST_CASE(ble_gatt_disc_s_test_oom_timeout)
550 {
551 struct ble_gatt_disc_s_test_svc svcs[] = {
552 { 1, 5, BLE_UUID128_DECLARE(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), },
553 { 6, 10, BLE_UUID128_DECLARE(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ), },
554 { 0 },
555 };
556
557 struct os_mbuf *oms_temp;
558 struct os_mbuf *oms;
559 int32_t ticks_until;
560 int rc;
561 int i;
562
563 ble_gatt_disc_s_test_init();
564
565 ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}),
566 NULL, NULL);
567
568 /* Initiate a discover all services procedure. */
569 rc = ble_gattc_disc_all_svcs(1, ble_gatt_disc_s_test_misc_disc_cb, NULL);
570 TEST_ASSERT_FATAL(rc == 0);
571
572 /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
573 oms = ble_hs_test_util_mbuf_alloc_all_but(1);
574 ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs);
575
576 /* Keep trying to resume for 30 seconds, but never free any mbufs. Verify
577 * procedure eventually times out.
578 */
579 for (i = 0; i < 30; i++) {
580 /* Ensure no follow-up request got sent. It should not have gotten
581 * sent due to mbuf exhaustion.
582 */
583 ble_hs_test_util_prev_tx_queue_clear();
584 TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
585
586 oms_temp = ble_hs_test_util_mbuf_alloc_all_but(0);
587 if (oms_temp != NULL) {
588 os_mbuf_concat(oms, oms_temp);
589 }
590
591 /* Verify that we will resume the stalled GATT procedure in one
592 * second.
593 */
594 ticks_until = ble_gattc_timer();
595 TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
596
597 os_time_advance(ticks_until);
598 }
599
600 /* Verify the procedure has timed out. The connection should now be
601 * in the process of being terminated. XXX: Check this.
602 */
603 ble_hs_test_util_hci_ack_set_disconnect(0);
604 ble_gattc_timer();
605
606 ticks_until = ble_gattc_timer();
607 TEST_ASSERT(ticks_until == BLE_HS_FOREVER);
608 TEST_ASSERT(!ble_gattc_any_jobs());
609
610 rc = os_mbuf_free_chain(oms);
611 TEST_ASSERT_FATAL(rc == 0);
612 }
613
TEST_SUITE(ble_gatt_disc_s_test_suite)614 TEST_SUITE(ble_gatt_disc_s_test_suite)
615 {
616 tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
617
618 ble_gatt_disc_s_test_disc_all();
619 ble_gatt_disc_s_test_disc_uuid();
620 ble_gatt_disc_s_test_oom_all();
621 ble_gatt_disc_s_test_oom_uuid();
622 ble_gatt_disc_s_test_oom_timeout();
623 }
624
625 int
ble_gatt_disc_s_test_all(void)626 ble_gatt_disc_s_test_all(void)
627 {
628 ble_gatt_disc_s_test_suite();
629
630 return tu_any_failed;
631 }
632