xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/test/src/ble_gatt_disc_s_test.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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