xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/test/src/ble_gatt_find_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 static struct ble_gatt_svc ble_gatt_find_s_test_svcs[256];
29 static int ble_gatt_find_s_test_num_svcs;
30 static int ble_gatt_find_s_test_proc_complete;
31 
32 struct ble_gatt_find_s_test_entry {
33     uint16_t inc_handle; /* 0 indicates no more entries. */
34     uint16_t start_handle;
35     uint16_t end_handle;
36     const ble_uuid_t *uuid;
37 };
38 
39 static void
ble_gatt_find_s_test_misc_init(void)40 ble_gatt_find_s_test_misc_init(void)
41 {
42     ble_hs_test_util_init();
43     ble_gatt_find_s_test_num_svcs = 0;
44     ble_gatt_find_s_test_proc_complete = 0;
45 }
46 
47 static int
ble_gatt_find_s_test_misc_cb(uint16_t conn_handle,const struct ble_gatt_error * error,const struct ble_gatt_svc * service,void * arg)48 ble_gatt_find_s_test_misc_cb(uint16_t conn_handle,
49                              const struct ble_gatt_error *error,
50                              const struct ble_gatt_svc *service,
51                              void *arg)
52 {
53     TEST_ASSERT(!ble_gatt_find_s_test_proc_complete);
54     TEST_ASSERT(error != NULL);
55 
56     switch (error->status) {
57     case 0:
58         ble_gatt_find_s_test_svcs[ble_gatt_find_s_test_num_svcs++] = *service;
59         break;
60 
61     case BLE_HS_EDONE:
62         ble_gatt_find_s_test_proc_complete = 1;
63         break;
64 
65     default:
66         TEST_ASSERT(0);
67         break;
68     }
69 
70     return 0;
71 }
72 
73 static void
ble_gatt_find_s_test_misc_verify_incs(struct ble_gatt_find_s_test_entry * entries)74 ble_gatt_find_s_test_misc_verify_incs(
75     struct ble_gatt_find_s_test_entry *entries)
76 {
77     int i;
78 
79     for (i = 0; entries[i].inc_handle != 0; i++) {
80         TEST_ASSERT(ble_gatt_find_s_test_svcs[i].start_handle ==
81                     entries[i].start_handle);
82         TEST_ASSERT(ble_gatt_find_s_test_svcs[i].end_handle ==
83                     entries[i].end_handle);
84         TEST_ASSERT(ble_uuid_cmp(&ble_gatt_find_s_test_svcs[i].uuid.u,
85                                  entries[i].uuid) == 0);
86     }
87 
88     TEST_ASSERT(i == ble_gatt_find_s_test_num_svcs);
89     TEST_ASSERT(ble_gatt_find_s_test_proc_complete);
90 }
91 
92 static int
ble_gatt_find_s_test_misc_rx_read_type(uint16_t conn_handle,struct ble_gatt_find_s_test_entry * entries)93 ble_gatt_find_s_test_misc_rx_read_type(
94     uint16_t conn_handle, struct ble_gatt_find_s_test_entry *entries)
95 {
96     struct ble_att_read_type_rsp rsp;
97     uint8_t buf[1024];
98     int off;
99     int rc;
100     int i;
101 
102     memset(&rsp, 0, sizeof rsp);
103 
104     off = BLE_ATT_READ_TYPE_RSP_BASE_SZ;
105     for (i = 0; entries[i].inc_handle != 0; i++) {
106         if (rsp.batp_length == BLE_GATTS_INC_SVC_LEN_NO_UUID + 2) {
107             break;
108         }
109 
110         if (entries[i].uuid->type != BLE_UUID_TYPE_16) {
111             if (rsp.batp_length != 0) {
112                 break;
113             }
114             rsp.batp_length = BLE_GATTS_INC_SVC_LEN_NO_UUID + 2;
115         } else {
116             rsp.batp_length = BLE_GATTS_INC_SVC_LEN_UUID + 2;
117         }
118 
119         TEST_ASSERT_FATAL(off + rsp.batp_length <= sizeof buf);
120 
121         put_le16(buf + off, entries[i].inc_handle);
122         off += 2;
123 
124         put_le16(buf + off, entries[i].start_handle);
125         off += 2;
126 
127         put_le16(buf + off, entries[i].end_handle);
128         off += 2;
129 
130         if (entries[i].uuid->type == BLE_UUID_TYPE_16) {
131             put_le16(buf + off, ble_uuid_u16(entries[i].uuid));
132             off += 2;
133         }
134     }
135 
136     if (i == 0) {
137         ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ,
138                                         BLE_ATT_ERR_ATTR_NOT_FOUND, 0);
139         return 0;
140     }
141 
142     ble_att_read_type_rsp_write(buf + 0, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp);
143 
144     rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
145                                                 buf, off);
146     TEST_ASSERT(rc == 0);
147 
148     return i;
149 }
150 
151 static void
ble_gatt_find_s_test_misc_rx_read(uint16_t conn_handle,const ble_uuid_t * uuid)152 ble_gatt_find_s_test_misc_rx_read(uint16_t conn_handle, const ble_uuid_t *uuid)
153 {
154     uint8_t buf[17];
155     int rc;
156 
157     TEST_ASSERT(uuid->type == BLE_UUID_TYPE_128);
158 
159     buf[0] = BLE_ATT_OP_READ_RSP;
160     ble_uuid_flat(uuid, buf + 1);
161 
162     rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
163                                                 buf, 17);
164     TEST_ASSERT(rc == 0);
165 }
166 
167 static void
ble_gatt_find_s_test_misc_verify_tx_read_type(uint16_t start_handle,uint16_t end_handle)168 ble_gatt_find_s_test_misc_verify_tx_read_type(uint16_t start_handle,
169                                               uint16_t end_handle)
170 {
171     struct ble_att_read_type_req req;
172     struct os_mbuf *om;
173     uint16_t uuid16;
174 
175     om = ble_hs_test_util_prev_tx_dequeue_pullup();
176     TEST_ASSERT_FATAL(om != NULL);
177 
178     ble_att_read_type_req_parse(om->om_data, om->om_len, &req);
179 
180     TEST_ASSERT(req.batq_start_handle == start_handle);
181     TEST_ASSERT(req.batq_end_handle == end_handle);
182     TEST_ASSERT(om->om_len == BLE_ATT_READ_TYPE_REQ_BASE_SZ + 2);
183     uuid16 = get_le16(om->om_data + BLE_ATT_READ_TYPE_REQ_BASE_SZ);
184     TEST_ASSERT(uuid16 == BLE_ATT_UUID_INCLUDE);
185 }
186 
187 static void
ble_gatt_find_s_test_misc_verify_tx_read(uint16_t handle)188 ble_gatt_find_s_test_misc_verify_tx_read(uint16_t handle)
189 {
190     struct ble_att_read_req req;
191     struct os_mbuf *om;
192 
193     om = ble_hs_test_util_prev_tx_dequeue_pullup();
194     TEST_ASSERT_FATAL(om != NULL);
195 
196     ble_att_read_req_parse(om->om_data, om->om_len, &req);
197 
198     TEST_ASSERT(req.barq_handle == handle);
199     TEST_ASSERT(om->om_len == BLE_ATT_READ_REQ_SZ);
200 }
201 
202 static void
ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,struct ble_gatt_find_s_test_entry * entries)203 ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle,
204                                    uint16_t start_handle, uint16_t end_handle,
205                                    struct ble_gatt_find_s_test_entry *entries)
206 {
207     struct ble_gatt_svc service;
208     int cur_start;
209     int num_found;
210     int idx;
211     int rc;
212     int i;
213 
214     rc = ble_gattc_find_inc_svcs(conn_handle, start_handle, end_handle,
215                                  ble_gatt_find_s_test_misc_cb, &service);
216     TEST_ASSERT(rc == 0);
217 
218     cur_start = start_handle;
219     idx = 0;
220     while (1) {
221         ble_gatt_find_s_test_misc_verify_tx_read_type(cur_start, end_handle);
222         num_found = ble_gatt_find_s_test_misc_rx_read_type(conn_handle,
223                                                            entries + idx);
224         if (num_found == 0) {
225             break;
226         }
227 
228         if (entries[idx].uuid->type == BLE_UUID_TYPE_128) {
229             TEST_ASSERT(num_found == 1);
230             ble_gatt_find_s_test_misc_verify_tx_read(
231                 entries[idx].start_handle);
232             ble_gatt_find_s_test_misc_rx_read(conn_handle,
233                                               entries[idx].uuid);
234         }
235 
236         idx += num_found;
237         cur_start = entries[idx - 1].inc_handle + 1;
238     }
239     TEST_ASSERT(idx == ble_gatt_find_s_test_num_svcs);
240     TEST_ASSERT(ble_gatt_find_s_test_proc_complete);
241 
242     for (i = 0; i < ble_gatt_find_s_test_num_svcs; i++) {
243         TEST_ASSERT(ble_gatt_find_s_test_svcs[i].start_handle ==
244                     entries[i].start_handle);
245         TEST_ASSERT(ble_gatt_find_s_test_svcs[i].end_handle ==
246                     entries[i].end_handle);
247         TEST_ASSERT(ble_uuid_cmp(&ble_gatt_find_s_test_svcs[i].uuid.u,
248                                  entries[i].uuid) == 0);
249     }
250 }
251 
TEST_CASE(ble_gatt_find_s_test_1)252 TEST_CASE(ble_gatt_find_s_test_1)
253 {
254     /* Two 16-bit UUID services; one response. */
255     ble_gatt_find_s_test_misc_init();
256     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
257                                  NULL, NULL);
258     ble_gatt_find_s_test_misc_find_inc(2, 5, 10,
259         ((struct ble_gatt_find_s_test_entry[]) { {
260             .inc_handle = 6,
261             .start_handle = 35,
262             .end_handle = 49,
263             .uuid = BLE_UUID16_DECLARE(0x5155),
264         }, {
265             .inc_handle = 9,
266             .start_handle = 543,
267             .end_handle = 870,
268             .uuid = BLE_UUID16_DECLARE(0x1122),
269         }, {
270             0,
271         } })
272     );
273 
274     /* One 128-bit UUID service; two responses. */
275     ble_gatt_find_s_test_misc_init();
276     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
277                                  NULL, NULL);
278     ble_gatt_find_s_test_misc_find_inc(2, 34, 100,
279         ((struct ble_gatt_find_s_test_entry[]) { {
280             .inc_handle = 36,
281             .start_handle = 403,
282             .end_handle = 859,
283             .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16),
284         }, {
285             0,
286         } })
287     );
288 
289     /* Two 128-bit UUID service; four responses. */
290     ble_gatt_find_s_test_misc_init();
291     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
292                                  NULL, NULL);
293     ble_gatt_find_s_test_misc_find_inc(2, 34, 100,
294         ((struct ble_gatt_find_s_test_entry[]) { {
295             .inc_handle = 36,
296             .start_handle = 403,
297             .end_handle = 859,
298             .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16),
299         }, {
300             .inc_handle = 39,
301             .start_handle = 900,
302             .end_handle = 932,
303             .uuid = BLE_UUID128_DECLARE(2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17),
304         }, {
305             0,
306         } })
307     );
308 
309     /* Two 16-bit UUID; three 128-bit UUID; seven responses. */
310     ble_gatt_find_s_test_misc_init();
311     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
312                                  NULL, NULL);
313     ble_gatt_find_s_test_misc_find_inc(2, 1, 100,
314         ((struct ble_gatt_find_s_test_entry[]) { {
315             .inc_handle = 36,
316             .start_handle = 403,
317             .end_handle = 859,
318             .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16),
319         }, {
320             .inc_handle = 37,
321             .start_handle = 35,
322             .end_handle = 49,
323             .uuid = BLE_UUID16_DECLARE(0x5155),
324         }, {
325             .inc_handle = 38,
326             .start_handle = 543,
327             .end_handle = 870,
328             .uuid = BLE_UUID16_DECLARE(0x1122),
329         }, {
330             .inc_handle = 39,
331             .start_handle = 900,
332             .end_handle = 932,
333             .uuid = BLE_UUID128_DECLARE(2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17),
334         }, {
335             .inc_handle = 40,
336             .start_handle = 940,
337             .end_handle = 950,
338             .uuid = BLE_UUID128_DECLARE(3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18),
339         }, {
340             0,
341         } })
342     );
343 }
344 
TEST_CASE(ble_gatt_find_s_test_oom)345 TEST_CASE(ble_gatt_find_s_test_oom)
346 {
347 
348     struct ble_gatt_find_s_test_entry incs[] = {
349         {
350             .inc_handle = 21,
351             .start_handle = 800,
352             .end_handle = 899,
353             .uuid = BLE_UUID128_DECLARE(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15),
354         },
355         {
356             .inc_handle = 22,
357             .start_handle = 900,
358             .end_handle = 999,
359             .uuid = BLE_UUID128_DECLARE(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16),
360         },
361         { 0 }
362     };
363 
364     struct os_mbuf *oms;
365     int32_t ticks_until;
366     int rc;
367 
368     ble_gatt_find_s_test_misc_init();
369 
370     ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}),
371                                  NULL, NULL);
372 
373     /* Initiate a discover all characteristics procedure. */
374     rc = ble_gattc_find_inc_svcs(1, 20, 30,
375                                  ble_gatt_find_s_test_misc_cb, NULL);
376     TEST_ASSERT_FATAL(rc == 0);
377 
378     /* Exhaust the msys pool.  Leave one mbuf for the forthcoming response. */
379     oms = ble_hs_test_util_mbuf_alloc_all_but(1);
380     ble_gatt_find_s_test_misc_rx_read_type(1, incs);
381 
382     /* Ensure no follow-up request got sent.  It should not have gotten sent
383      * due to mbuf exhaustion.
384      */
385     ble_hs_test_util_prev_tx_queue_clear();
386     TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
387 
388     /* Verify that we will resume the stalled GATT procedure in one second. */
389     ticks_until = ble_gattc_timer();
390     TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
391 
392     /* Verify the procedure succeeds after mbufs become available. */
393     rc = os_mbuf_free_chain(oms);
394     TEST_ASSERT_FATAL(rc == 0);
395     os_time_advance(ticks_until);
396     ble_gattc_timer();
397 
398     /* We can't cause a memory exhaustion error on the follow up request.  The
399      * GATT client frees the read response immediately before sending the
400      * follow-up request, so there is always an mbuf available.
401      */
402     /* XXX: Find a way to test this. */
403     ble_gatt_find_s_test_misc_rx_read(1, incs[0].uuid);
404 
405     /* Exhaust the msys pool.  Leave one mbuf for the forthcoming response. */
406     oms = ble_hs_test_util_mbuf_alloc_all_but(1);
407     ble_gatt_find_s_test_misc_rx_read_type(1, incs + 1);
408 
409     /* Verify the procedure succeeds after mbufs become available. */
410     rc = os_mbuf_free_chain(oms);
411     TEST_ASSERT_FATAL(rc == 0);
412     os_time_advance(ticks_until);
413     ble_gattc_timer();
414 
415     ble_gatt_find_s_test_misc_rx_read(1, incs[1].uuid);
416 
417     ble_hs_test_util_rx_att_err_rsp(1,
418                                     BLE_ATT_OP_READ_TYPE_REQ,
419                                     BLE_ATT_ERR_ATTR_NOT_FOUND,
420                                     1);
421 
422     ble_gatt_find_s_test_misc_verify_incs(incs);
423 }
424 
TEST_SUITE(ble_gatt_find_s_test_suite)425 TEST_SUITE(ble_gatt_find_s_test_suite)
426 {
427     tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
428 
429     ble_gatt_find_s_test_1();
430     ble_gatt_find_s_test_oom();
431 }
432 
433 int
ble_gatt_find_s_test_all(void)434 ble_gatt_find_s_test_all(void)
435 {
436     ble_gatt_find_s_test_suite();
437 
438     return tu_any_failed;
439 }
440