xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/test/src/ble_gatt_disc_d_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 <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_d_test_dsc {
31     uint16_t chr_val_handle; /* 0 if last entry. */
32     uint16_t dsc_handle;
33     ble_uuid_any_t dsc_uuid;
34 };
35 
36 #define BLE_GATT_DISC_D_TEST_MAX_DSCS  256
37 static struct ble_gatt_disc_d_test_dsc
38     ble_gatt_disc_d_test_dscs[BLE_GATT_DISC_D_TEST_MAX_DSCS];
39 static int ble_gatt_disc_d_test_num_dscs;
40 static int ble_gatt_disc_d_test_rx_complete;
41 
42 static void
ble_gatt_disc_d_test_init(void)43 ble_gatt_disc_d_test_init(void)
44 {
45     ble_hs_test_util_init();
46 
47     ble_gatt_disc_d_test_num_dscs = 0;
48     ble_gatt_disc_d_test_rx_complete = 0;
49 }
50 
51 static int
ble_gatt_disc_d_test_misc_rx_rsp_once(uint16_t conn_handle,struct ble_gatt_disc_d_test_dsc * dscs)52 ble_gatt_disc_d_test_misc_rx_rsp_once(
53     uint16_t conn_handle, struct ble_gatt_disc_d_test_dsc *dscs)
54 {
55     struct ble_att_find_info_rsp rsp;
56     uint8_t buf[1024];
57     int off;
58     int rc;
59     int i;
60 
61     /* Send the pending ATT Read By Type Request. */
62 
63     if (dscs[0].dsc_uuid.u.type == BLE_UUID_TYPE_16) {
64         rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT;
65     } else {
66         rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT;
67     }
68 
69     ble_att_find_info_rsp_write(buf, BLE_ATT_FIND_INFO_RSP_BASE_SZ, &rsp);
70 
71     off = BLE_ATT_FIND_INFO_RSP_BASE_SZ;
72     for (i = 0; ; i++) {
73         if (dscs[i].chr_val_handle == 0) {
74             /* No more descriptors. */
75             break;
76         }
77 
78         if (dscs[i].dsc_uuid.u.type == BLE_UUID_TYPE_16) {
79             if (off + BLE_ATT_FIND_INFO_IDATA_16_SZ >
80                 ble_att_mtu(conn_handle)) {
81 
82                 /* Can't fit any more entries. */
83                 break;
84             }
85         } else {
86             if (off + BLE_ATT_FIND_INFO_IDATA_128_SZ >
87                 ble_att_mtu(conn_handle)) {
88 
89                 /* Can't fit any more entries. */
90                 break;
91             }
92         }
93 
94         /* If the value length is changing, we need a separate response. */
95         if (((dscs[0].dsc_uuid.u.type == BLE_UUID_TYPE_16) ^
96             (dscs[i].dsc_uuid.u.type == BLE_UUID_TYPE_16)) != 0) {
97             break;
98         }
99 
100         put_le16(buf + off, dscs[i].dsc_handle);
101         off += 2;
102 
103         ble_uuid_flat(&dscs[i].dsc_uuid.u, buf + off);
104         off += ble_uuid_length(&dscs[i].dsc_uuid.u);
105     }
106 
107     rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
108                                                 buf, off);
109     TEST_ASSERT(rc == 0);
110 
111     return i;
112 }
113 
114 static void
ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle,uint16_t end_handle,struct ble_gatt_disc_d_test_dsc * dscs)115 ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle,
116                                  uint16_t end_handle,
117                                  struct ble_gatt_disc_d_test_dsc *dscs)
118 {
119     int count;
120     int idx;
121 
122     idx = 0;
123     while (dscs[idx].chr_val_handle != 0) {
124         count = ble_gatt_disc_d_test_misc_rx_rsp_once(conn_handle, dscs + idx);
125         if (count == 0) {
126             break;
127         }
128         idx += count;
129     }
130 
131     if (dscs[idx - 1].dsc_handle != end_handle) {
132         /* Send the pending ATT Request. */
133         ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_FIND_INFO_REQ,
134                                         BLE_ATT_ERR_ATTR_NOT_FOUND,
135                                         end_handle);
136     }
137 }
138 
139 static void
ble_gatt_disc_d_test_misc_verify_dscs(struct ble_gatt_disc_d_test_dsc * dscs,int stop_after)140 ble_gatt_disc_d_test_misc_verify_dscs(struct ble_gatt_disc_d_test_dsc *dscs,
141                                       int stop_after)
142 {
143     int i;
144 
145     if (stop_after == 0) {
146         stop_after = BLE_GATT_DISC_D_TEST_MAX_DSCS;
147     }
148 
149     for (i = 0; i < stop_after && dscs[i].chr_val_handle != 0; i++) {
150         TEST_ASSERT(dscs[i].chr_val_handle ==
151                     ble_gatt_disc_d_test_dscs[i].chr_val_handle);
152         TEST_ASSERT(dscs[i].dsc_handle ==
153                     ble_gatt_disc_d_test_dscs[i].dsc_handle);
154         TEST_ASSERT(ble_uuid_cmp(&dscs[i].dsc_uuid.u,
155                                  &ble_gatt_disc_d_test_dscs[i].dsc_uuid.u) == 0);
156     }
157 
158     TEST_ASSERT(i == ble_gatt_disc_d_test_num_dscs);
159     TEST_ASSERT(ble_gatt_disc_d_test_rx_complete);
160 }
161 
162 static int
ble_gatt_disc_d_test_misc_cb(uint16_t conn_handle,const struct ble_gatt_error * error,uint16_t chr_val_handle,const struct ble_gatt_dsc * dsc,void * arg)163 ble_gatt_disc_d_test_misc_cb(uint16_t conn_handle,
164                              const struct ble_gatt_error *error,
165                              uint16_t chr_val_handle,
166                              const struct ble_gatt_dsc *dsc,
167                              void *arg)
168 {
169     struct ble_gatt_disc_d_test_dsc *dst;
170     int *stop_after;
171 
172     TEST_ASSERT(error != NULL);
173     TEST_ASSERT(!ble_gatt_disc_d_test_rx_complete);
174 
175     stop_after = arg;
176 
177     switch (error->status) {
178     case 0:
179         TEST_ASSERT_FATAL(ble_gatt_disc_d_test_num_dscs <
180                           BLE_GATT_DISC_D_TEST_MAX_DSCS);
181 
182         dst = ble_gatt_disc_d_test_dscs + ble_gatt_disc_d_test_num_dscs++;
183         dst->chr_val_handle = chr_val_handle;
184         dst->dsc_handle = dsc->handle;
185         dst->dsc_uuid = dsc->uuid;
186         break;
187 
188     case BLE_HS_EDONE:
189         ble_gatt_disc_d_test_rx_complete = 1;
190         break;
191 
192     default:
193         TEST_ASSERT(0);
194         break;
195     }
196 
197     if (*stop_after > 0) {
198         (*stop_after)--;
199         if (*stop_after == 0) {
200             ble_gatt_disc_d_test_rx_complete = 1;
201             return 1;
202         }
203     }
204 
205     return 0;
206 }
207 
208 static void
ble_gatt_disc_d_test_misc_all(uint16_t chr_val_handle,uint16_t end_handle,int stop_after,struct ble_gatt_disc_d_test_dsc * dscs)209 ble_gatt_disc_d_test_misc_all(uint16_t chr_val_handle, uint16_t end_handle,
210                               int stop_after,
211                               struct ble_gatt_disc_d_test_dsc *dscs)
212 {
213     int num_left;
214     int rc;
215 
216     ble_gatt_disc_d_test_init();
217 
218     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
219                                  NULL, NULL);
220 
221     num_left = stop_after;
222     rc = ble_gattc_disc_all_dscs(2, chr_val_handle, end_handle,
223                                  ble_gatt_disc_d_test_misc_cb, &num_left);
224     TEST_ASSERT(rc == 0);
225 
226     ble_gatt_disc_d_test_misc_rx_rsp(2, end_handle, dscs);
227     ble_gatt_disc_d_test_misc_verify_dscs(dscs, stop_after);
228 }
229 
TEST_CASE(ble_gatt_disc_d_test_1)230 TEST_CASE(ble_gatt_disc_d_test_1)
231 {
232     /*** One 16-bit descriptor. */
233     ble_gatt_disc_d_test_misc_all(5, 10, 0,
234         ((struct ble_gatt_disc_d_test_dsc[]) { {
235             .chr_val_handle = 5,
236             .dsc_handle = 6,
237             .dsc_uuid.u16 = BLE_UUID16_INIT(0x1234),
238         }, {
239             0
240         } })
241     );
242 
243     /*** Two 16-bit descriptors. */
244     ble_gatt_disc_d_test_misc_all(50, 100, 0,
245         ((struct ble_gatt_disc_d_test_dsc[]) { {
246             .chr_val_handle = 50,
247             .dsc_handle = 51,
248             .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111),
249         }, {
250             .chr_val_handle = 50,
251             .dsc_handle = 52,
252             .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222),
253         }, {
254             0
255         } })
256     );
257 
258     /*** Five 16-bit descriptors. */
259     ble_gatt_disc_d_test_misc_all(50, 100, 0,
260         ((struct ble_gatt_disc_d_test_dsc[]) { {
261             .chr_val_handle = 50,
262             .dsc_handle = 51,
263             .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111),
264         }, {
265             .chr_val_handle = 50,
266             .dsc_handle = 52,
267             .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222),
268         }, {
269             .chr_val_handle = 50,
270             .dsc_handle = 53,
271             .dsc_uuid.u16 = BLE_UUID16_INIT(0x3333),
272         }, {
273             .chr_val_handle = 50,
274             .dsc_handle = 54,
275             .dsc_uuid.u16 = BLE_UUID16_INIT(0x4444),
276         }, {
277             .chr_val_handle = 50,
278             .dsc_handle = 55,
279             .dsc_uuid.u16 = BLE_UUID16_INIT(0x5555),
280         }, {
281             0
282         } })
283     );
284 
285     /*** Interleaved 16-bit and 128-bit descriptors. */
286     ble_gatt_disc_d_test_misc_all(50, 100, 0,
287         ((struct ble_gatt_disc_d_test_dsc[]) { {
288             .chr_val_handle = 50,
289             .dsc_handle = 51,
290             .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111),
291         }, {
292             .chr_val_handle = 50,
293             .dsc_handle = 52,
294             .dsc_uuid.u128 = BLE_UUID128_INIT( 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
295         }, {
296             .chr_val_handle = 50,
297             .dsc_handle = 53,
298             .dsc_uuid.u16 = BLE_UUID16_INIT(0x3333),
299         }, {
300             .chr_val_handle = 50,
301             .dsc_handle = 54,
302             .dsc_uuid.u128 = BLE_UUID128_INIT(1,0,4,0,6,9,17,7,8,43,7,4,12,43,19,35),
303         }, {
304             .chr_val_handle = 50,
305             .dsc_handle = 55,
306             .dsc_uuid.u16 = BLE_UUID16_INIT(0x5555),
307         }, {
308             0
309         } })
310     );
311 
312     /*** Ends with final handle ID. */
313     ble_gatt_disc_d_test_misc_all(50, 52, 0,
314         ((struct ble_gatt_disc_d_test_dsc[]) { {
315             .chr_val_handle = 50,
316             .dsc_handle = 51,
317             .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111),
318         }, {
319             .chr_val_handle = 50,
320             .dsc_handle = 52,
321             .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222),
322         }, {
323             0
324         } })
325     );
326 
327     /*** Stop after two descriptors. */
328     ble_gatt_disc_d_test_misc_all(50, 100, 2,
329         ((struct ble_gatt_disc_d_test_dsc[]) { {
330             .chr_val_handle = 50,
331             .dsc_handle = 51,
332             .dsc_uuid.u16 = BLE_UUID16_INIT(0x1111),
333         }, {
334             .chr_val_handle = 50,
335             .dsc_handle = 52,
336             .dsc_uuid.u16 = BLE_UUID16_INIT(0x2222),
337         }, {
338             .chr_val_handle = 50,
339             .dsc_handle = 53,
340             .dsc_uuid.u16 = BLE_UUID16_INIT(0x3333),
341         }, {
342             .chr_val_handle = 50,
343             .dsc_handle = 54,
344             .dsc_uuid.u16 = BLE_UUID16_INIT(0x4444),
345         }, {
346             .chr_val_handle = 50,
347             .dsc_handle = 55,
348             .dsc_uuid.u16 = BLE_UUID16_INIT(0x5555),
349         }, {
350             0
351         } })
352     );
353 }
354 
TEST_CASE(ble_gatt_disc_d_test_oom_all)355 TEST_CASE(ble_gatt_disc_d_test_oom_all)
356 {
357     struct ble_gatt_disc_d_test_dsc dscs[] = {
358         {
359             .chr_val_handle = 543,
360             .dsc_handle = 548,
361             .dsc_uuid.u128 = BLE_UUID128_INIT(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
362         },
363         {
364             .chr_val_handle = 543,
365             .dsc_handle = 549,
366             .dsc_uuid.u128 = BLE_UUID128_INIT(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16),
367         },
368         { 0 }
369     };
370 
371     struct os_mbuf *oms;
372     int32_t ticks_until;
373     int stop_after;
374     int num_dscs;
375     int rc;
376 
377     ble_gatt_disc_d_test_init();
378 
379     ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}),
380                                  NULL, NULL);
381 
382     /* Initiate a discover all characteristics procedure. */
383     stop_after = 0;
384     rc = ble_gattc_disc_all_dscs(1, 543, 560,
385                                  ble_gatt_disc_d_test_misc_cb, &stop_after);
386     TEST_ASSERT_FATAL(rc == 0);
387 
388     /* Exhaust the msys pool.  Leave one mbuf for the forthcoming response. */
389     oms = ble_hs_test_util_mbuf_alloc_all_but(1);
390     num_dscs = ble_gatt_disc_d_test_misc_rx_rsp_once(1, dscs);
391 
392     /* Make sure there are still undiscovered services. */
393     TEST_ASSERT_FATAL(num_dscs < sizeof dscs / sizeof dscs[0] - 1);
394 
395     /* Ensure no follow-up request got sent.  It should not have gotten sent
396      * due to mbuf exhaustion.
397      */
398     ble_hs_test_util_prev_tx_queue_clear();
399     TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
400 
401     /* Verify that we will resume the stalled GATT procedure in one second. */
402     ticks_until = ble_gattc_timer();
403     TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
404 
405     /* Verify the procedure proceeds after mbufs become available. */
406     rc = os_mbuf_free_chain(oms);
407     TEST_ASSERT_FATAL(rc == 0);
408     os_time_advance(ticks_until);
409     ble_gattc_timer();
410 
411     /* Exhaust the msys pool.  Leave one mbuf for the forthcoming response. */
412     oms = ble_hs_test_util_mbuf_alloc_all_but(1);
413     ble_gatt_disc_d_test_misc_rx_rsp_once(1, dscs + num_dscs);
414 
415     /* Ensure no follow-up request got sent.  It should not have gotten sent
416      * due to mbuf exhaustion.
417      */
418     ble_hs_test_util_prev_tx_queue_clear();
419     TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
420 
421     /* Verify that we will resume the stalled GATT procedure in one second. */
422     ticks_until = ble_gattc_timer();
423     TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
424 
425     /* Verify the procedure succeeds after mbufs become available. */
426     rc = os_mbuf_free_chain(oms);
427     TEST_ASSERT_FATAL(rc == 0);
428     os_time_advance(ticks_until);
429     ble_gattc_timer();
430 
431     ble_hs_test_util_rx_att_err_rsp(1,
432                                     BLE_ATT_OP_READ_TYPE_REQ,
433                                     BLE_ATT_ERR_ATTR_NOT_FOUND,
434                                     1);
435     ble_gatt_disc_d_test_misc_verify_dscs(dscs, 0);
436 }
437 
TEST_SUITE(ble_gatt_disc_d_test_suite)438 TEST_SUITE(ble_gatt_disc_d_test_suite)
439 {
440     tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
441 
442     ble_gatt_disc_d_test_1();
443     ble_gatt_disc_d_test_oom_all();
444 }
445 
446 int
ble_gatt_disc_d_test_all(void)447 ble_gatt_disc_d_test_all(void)
448 {
449     ble_gatt_disc_d_test_suite();
450 
451     return tu_any_failed;
452 }
453