xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/test/src/ble_hs_pvcy_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 <stddef.h>
21 #include <errno.h>
22 #include <string.h>
23 #include "testutil/testutil.h"
24 #include "host/ble_hs_test.h"
25 #include "ble_hs_test_util.h"
26 
27 #define BLE_HS_PVCY_TEST_MAX_GAP_EVENTS 256
28 static struct ble_gap_event
29 ble_hs_pvcy_test_gap_events[BLE_HS_PVCY_TEST_MAX_GAP_EVENTS];
30 static int ble_hs_pvcy_test_num_gap_events;
31 
32 static void
ble_hs_pvcy_test_util_init(void)33 ble_hs_pvcy_test_util_init(void)
34 {
35     ble_hs_test_util_init();
36     ble_hs_pvcy_test_num_gap_events = 0;
37 }
38 
39 static int
ble_hs_pvcy_test_util_gap_event(struct ble_gap_event * event,void * arg)40 ble_hs_pvcy_test_util_gap_event(struct ble_gap_event *event, void *arg)
41 {
42     TEST_ASSERT_FATAL(ble_hs_pvcy_test_num_gap_events <
43                       BLE_HS_PVCY_TEST_MAX_GAP_EVENTS);
44     ble_hs_pvcy_test_gap_events[ble_hs_pvcy_test_num_gap_events++] = *event;
45 
46     return 0;
47 }
48 
49 static void
ble_hs_pvcy_test_util_all_gap_procs(int adv_status,int conn_status,int disc_status)50 ble_hs_pvcy_test_util_all_gap_procs(int adv_status,
51                                     int conn_status,
52                                     int disc_status)
53 {
54     struct ble_gap_disc_params disc_params;
55     ble_addr_t peer_addr;
56     int rc;
57 
58     /* Advertise. */
59     rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC,
60                                     NULL, &ble_hs_test_util_adv_params,
61                                     BLE_HS_FOREVER,
62                                     ble_hs_pvcy_test_util_gap_event,
63                                     NULL, 0, 0);
64     TEST_ASSERT_FATAL(rc == adv_status);
65 
66     if (rc == 0) {
67         rc = ble_hs_test_util_adv_stop(0);
68         TEST_ASSERT_FATAL(rc == 0);
69     }
70 
71     /* Connect. */
72     peer_addr = (ble_addr_t){ BLE_ADDR_PUBLIC, {1,2,3,4,5,6} };
73     rc = ble_hs_test_util_connect(BLE_ADDR_PUBLIC, &peer_addr,
74                                   BLE_HS_FOREVER, NULL,
75                                   ble_hs_pvcy_test_util_gap_event, NULL, 0);
76     TEST_ASSERT_FATAL(rc == conn_status);
77 
78     if (rc == 0) {
79         ble_hs_test_util_conn_cancel_full();
80     }
81 
82     /* Discover. */
83     disc_params = (struct ble_gap_disc_params){ 0 };
84     rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER,
85                                &disc_params, ble_hs_pvcy_test_util_gap_event,
86                                NULL, -1, 0);
87     TEST_ASSERT_FATAL(rc == disc_status);
88 
89     if (rc == 0) {
90         rc = ble_hs_test_util_disc_cancel(0);
91         TEST_ASSERT_FATAL(rc == 0);
92     }
93 }
94 
95 static void
ble_hs_pvcy_test_util_add_irk_set_acks(bool scanning,bool connecting)96 ble_hs_pvcy_test_util_add_irk_set_acks(bool scanning, bool connecting)
97 {
98     ble_hs_test_util_hci_ack_append(
99         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE), 0);
100 
101     if (connecting) {
102         ble_hs_test_util_hci_ack_append(
103             BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_CREATE_CONN_CANCEL),
104             0);
105     }
106 
107     if (scanning) {
108         ble_hs_test_util_hci_ack_append(
109             BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_SCAN_ENABLE),
110             0);
111     }
112 
113     ble_hs_test_util_hci_ack_append(
114         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST), 0);
115     ble_hs_test_util_hci_ack_append(
116         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PRIVACY_MODE), 0);
117 }
118 
119 static void
ble_hs_pvcy_test_util_start_host(int num_expected_irks)120 ble_hs_pvcy_test_util_start_host(int num_expected_irks)
121 {
122     int rc;
123     int i;
124 
125     /* Clear our IRK.  This ensures the full startup sequence, including
126      * setting the default IRK, takes place.  We need this so that we can plan
127      * which HCI acks to fake.
128      */
129     rc = ble_hs_test_util_set_our_irk((uint8_t[16]){0}, -1, 0);
130     TEST_ASSERT_FATAL(rc == 0);
131     ble_hs_test_util_hci_out_clear();
132 
133     ble_hs_test_util_hci_ack_set_startup();
134 
135     for (i = 0; i < num_expected_irks; i++) {
136         ble_hs_pvcy_test_util_add_irk_set_acks(false, false);
137     }
138 
139     ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF;
140     rc = ble_hs_start();
141     TEST_ASSERT_FATAL(rc == 0);
142 
143     /* Discard startup HCI commands. */
144     ble_hs_test_util_hci_out_adj(ble_hs_test_util_hci_startup_seq_cnt());
145 }
146 
147 static void
ble_hs_pvcy_test_util_add_irk_verify_tx(const ble_addr_t * peer_addr,const uint8_t * peer_irk,const uint8_t * local_irk,bool scanning,bool connecting)148 ble_hs_pvcy_test_util_add_irk_verify_tx(const ble_addr_t *peer_addr,
149                                         const uint8_t *peer_irk,
150                                         const uint8_t *local_irk,
151                                         bool scanning,
152                                         bool connecting)
153 {
154     ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
155                                    BLE_HCI_OCF_LE_SET_ADV_ENABLE,
156                                    NULL);
157 
158     if (connecting) {
159         ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
160                                        BLE_HCI_OCF_LE_CREATE_CONN_CANCEL,
161                                        NULL);
162     }
163 
164     if (scanning) {
165         ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
166                                        BLE_HCI_OCF_LE_SET_SCAN_ENABLE,
167                                        NULL);
168     }
169 
170     ble_hs_test_util_hci_verify_tx_add_irk(peer_addr->type,
171                                            peer_addr->val,
172                                            peer_irk,
173                                            local_irk);
174 
175     ble_hs_test_util_hci_verify_tx_set_priv_mode(peer_addr->type,
176                                                  peer_addr->val,
177                                                  BLE_GAP_PRIVATE_MODE_DEVICE);
178 }
179 
180 static void
ble_hs_pvcy_test_util_add_irk(const ble_addr_t * peer_addr,const uint8_t * peer_irk,const uint8_t * local_irk,bool scanning,bool connecting)181 ble_hs_pvcy_test_util_add_irk(const ble_addr_t *peer_addr,
182                               const uint8_t *peer_irk,
183                               const uint8_t *local_irk,
184                               bool scanning,
185                               bool connecting)
186 {
187     int num_acks;
188     int rc;
189 
190     ble_hs_pvcy_test_util_add_irk_set_acks(scanning, connecting);
191 
192     rc = ble_hs_pvcy_add_entry(peer_addr->val, peer_addr->type, peer_irk);
193     TEST_ASSERT_FATAL(rc == 0);
194 
195     num_acks = 3;
196     if (scanning) {
197         num_acks++;
198     }
199     if (connecting) {
200         num_acks++;
201     }
202     ble_hs_test_util_hci_out_adj(-num_acks);
203     ble_hs_pvcy_test_util_add_irk_verify_tx(peer_addr, peer_irk, local_irk,
204                                             scanning, connecting);
205 }
206 
207 static void
ble_hs_pvcy_test_util_add_arbitrary_irk(bool scanning,bool connecting)208 ble_hs_pvcy_test_util_add_arbitrary_irk(bool scanning, bool connecting)
209 {
210     ble_addr_t peer_addr;
211 
212     peer_addr = (ble_addr_t) {
213         .type = BLE_ADDR_PUBLIC,
214         .val = {1,2,3,4,5,6},
215     };
216     ble_hs_pvcy_test_util_add_irk(
217         &peer_addr,
218         (uint8_t[16]){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
219         ble_hs_pvcy_default_irk,
220         scanning,
221         connecting);
222 }
223 
224 static void
ble_hs_pvcy_test_util_restore_irk(const struct ble_store_value_sec * value_sec,bool scanning,bool connecting)225 ble_hs_pvcy_test_util_restore_irk(const struct ble_store_value_sec *value_sec,
226                                   bool scanning,
227                                   bool connecting)
228 {
229     int rc;
230 
231     ble_hs_pvcy_test_util_add_irk_set_acks(scanning, connecting);
232 
233     rc = ble_store_write_peer_sec(value_sec);
234     TEST_ASSERT_FATAL(rc == 0);
235 
236     ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec->peer_addr,
237                                             value_sec->irk,
238                                             ble_hs_pvcy_default_irk,
239                                             scanning,
240                                             connecting);
241 }
242 
TEST_CASE(ble_hs_pvcy_test_case_restore_irks)243 TEST_CASE(ble_hs_pvcy_test_case_restore_irks)
244 {
245     struct ble_store_value_sec value_sec1;
246     struct ble_store_value_sec value_sec2;
247 
248     ble_hs_pvcy_test_util_init();
249 
250     /*** No persisted IRKs. */
251     ble_hs_pvcy_test_util_start_host(0);
252 
253     /*** One persisted IRK. */
254 
255     /* Persist IRK; ensure it automatically gets added to the list. */
256     value_sec1 = (struct ble_store_value_sec) {
257         .peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } },
258         .key_size = 16,
259         .ediv = 1,
260         .rand_num = 2,
261         .irk = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 },
262         .irk_present = 1,
263     };
264     ble_hs_pvcy_test_util_restore_irk(&value_sec1, false, false);
265 
266     /* Ensure it gets added to list on startup. */
267     ble_hs_pvcy_test_util_start_host(1);
268     ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec1.peer_addr,
269                                             value_sec1.irk,
270                                             ble_hs_pvcy_default_irk,
271                                             false, false);
272 
273     /* Two persisted IRKs. */
274     value_sec2 = (struct ble_store_value_sec) {
275         .peer_addr = { BLE_ADDR_PUBLIC, { 2, 3, 4, 5, 6, 7 } },
276         .key_size = 16,
277         .ediv = 12,
278         .rand_num = 20,
279         .irk = { 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 9, 9, 9, 9, 9, 10 },
280         .irk_present = 1,
281     };
282     ble_hs_pvcy_test_util_restore_irk(&value_sec2, false, false);
283 
284     /* Ensure both get added to list on startup. */
285     ble_hs_pvcy_test_util_start_host(2);
286     ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec1.peer_addr,
287                                             value_sec1.irk,
288                                             ble_hs_pvcy_default_irk,
289                                             false, false);
290     ble_hs_pvcy_test_util_add_irk_verify_tx(&value_sec2.peer_addr,
291                                             value_sec2.irk,
292                                             ble_hs_pvcy_default_irk,
293                                             false, false);
294 }
295 
296 /** No active GAP procedures. */
TEST_CASE(ble_hs_pvcy_test_case_add_irk_idle)297 TEST_CASE(ble_hs_pvcy_test_case_add_irk_idle)
298 {
299     ble_hs_pvcy_test_util_init();
300 
301     ble_hs_pvcy_test_util_add_arbitrary_irk(false, false);
302     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 0);
303 }
304 
305 /*** Advertising active. */
TEST_CASE(ble_hs_pvcy_test_case_add_irk_adv)306 TEST_CASE(ble_hs_pvcy_test_case_add_irk_adv)
307 {
308     int rc;
309 
310     ble_hs_pvcy_test_util_init();
311 
312     /* Start an advertising procedure. */
313     rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC,
314                                     NULL, &ble_hs_test_util_adv_params,
315                                     BLE_HS_FOREVER,
316                                     ble_hs_pvcy_test_util_gap_event,
317                                     NULL, 0, 0);
318     TEST_ASSERT_FATAL(rc == 0);
319 
320     ble_hs_pvcy_test_util_add_arbitrary_irk(false, false);
321 
322     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1);
323     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type ==
324                 BLE_GAP_EVENT_ADV_COMPLETE);
325     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].adv_complete.reason ==
326                 BLE_HS_EPREEMPTED);
327 
328     /* Ensure GAP procedures are no longer preempted. */
329     ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0);
330 }
331 
332 /*** Discovery active. */
TEST_CASE(ble_hs_pvcy_test_case_add_irk_disc)333 TEST_CASE(ble_hs_pvcy_test_case_add_irk_disc)
334 {
335     struct ble_gap_disc_params disc_params;
336     int rc;
337 
338     ble_hs_pvcy_test_util_init();
339 
340     /* Start an advertising procedure. */
341     disc_params = (struct ble_gap_disc_params){ 0 };
342     rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER,
343                                &disc_params, ble_hs_pvcy_test_util_gap_event,
344                                NULL, -1, 0);
345     TEST_ASSERT_FATAL(rc == 0);
346 
347     ble_hs_pvcy_test_util_add_arbitrary_irk(true, false);
348 
349     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1);
350     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type ==
351                 BLE_GAP_EVENT_DISC_COMPLETE);
352     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].disc_complete.reason ==
353                 BLE_HS_EPREEMPTED);
354 
355     /* Ensure GAP procedures are no longer preempted. */
356     ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0);
357 }
358 
359 /*** Connect active. */
TEST_CASE(ble_hs_pvcy_test_case_add_irk_conn)360 TEST_CASE(ble_hs_pvcy_test_case_add_irk_conn)
361 {
362     ble_addr_t peer_addr;
363     int rc;
364 
365     ble_hs_pvcy_test_util_init();
366 
367     /* Start a connect procedure. */
368     peer_addr = (ble_addr_t){ BLE_ADDR_PUBLIC, {1,2,3,4,5,6} };
369     rc = ble_hs_test_util_connect(BLE_ADDR_PUBLIC, &peer_addr,
370                                   BLE_HS_FOREVER, NULL,
371                                   ble_hs_pvcy_test_util_gap_event, NULL, 0);
372     TEST_ASSERT_FATAL(rc == 0);
373 
374     ble_hs_pvcy_test_util_add_arbitrary_irk(false, true);
375 
376     /* Cancel is now in progress. */
377     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 0);
378 
379     /* Ensure no GAP procedures are allowed. */
380     ble_hs_pvcy_test_util_all_gap_procs(BLE_HS_EPREEMPTED,
381                                         BLE_HS_EALREADY,
382                                         BLE_HS_EBUSY);
383 
384     /* Receive cancel event. */
385     ble_hs_test_util_rx_conn_cancel_evt();
386 
387     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1);
388     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type ==
389                 BLE_GAP_EVENT_CONNECT);
390     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].connect.status ==
391                 BLE_HS_EPREEMPTED);
392 
393     /* Ensure GAP procedures are no longer preempted. */
394     ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0);
395 }
396 
397 /*** Advertising and discovery active. */
TEST_CASE(ble_hs_pvcy_test_case_add_irk_adv_disc)398 TEST_CASE(ble_hs_pvcy_test_case_add_irk_adv_disc)
399 {
400     struct ble_gap_disc_params disc_params;
401     int rc;
402 
403     ble_hs_pvcy_test_util_init();
404 
405     /* Start an advertising procedure. */
406     rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC,
407                                     NULL, &ble_hs_test_util_adv_params,
408                                     BLE_HS_FOREVER,
409                                     ble_hs_pvcy_test_util_gap_event,
410                                     NULL, 0, 0);
411     TEST_ASSERT_FATAL(rc == 0);
412 
413     /* Start a discovery procedure. */
414     disc_params = (struct ble_gap_disc_params){ 0 };
415     rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER,
416                                &disc_params, ble_hs_pvcy_test_util_gap_event,
417                                NULL, -1, 0);
418     TEST_ASSERT_FATAL(rc == 0);
419 
420     ble_hs_pvcy_test_util_add_arbitrary_irk(true, false);
421 
422     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 2);
423     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type ==
424                 BLE_GAP_EVENT_ADV_COMPLETE);
425     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].adv_complete.reason ==
426                 BLE_HS_EPREEMPTED);
427     TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].type ==
428                 BLE_GAP_EVENT_DISC_COMPLETE);
429     TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].disc_complete.reason ==
430                 BLE_HS_EPREEMPTED);
431 
432     /* Ensure GAP procedures are no longer preempted. */
433     ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0);
434 }
435 
436 /*** Advertising and connecting active. */
TEST_CASE(ble_hs_pvcy_test_case_add_irk_adv_conn)437 TEST_CASE(ble_hs_pvcy_test_case_add_irk_adv_conn)
438 {
439     ble_addr_t peer_addr;
440     int rc;
441 
442     ble_hs_pvcy_test_util_init();
443 
444     /* Start an advertising procedure. */
445     rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC,
446                                     NULL, &ble_hs_test_util_adv_params,
447                                     BLE_HS_FOREVER,
448                                     ble_hs_pvcy_test_util_gap_event,
449                                     NULL, 0, 0);
450     TEST_ASSERT_FATAL(rc == 0);
451 
452     /* Start a connect procedure. */
453     peer_addr = (ble_addr_t){ BLE_ADDR_PUBLIC, {1,2,3,4,5,6} };
454     rc = ble_hs_test_util_connect(BLE_ADDR_PUBLIC, &peer_addr,
455                                   BLE_HS_FOREVER, NULL,
456                                   ble_hs_pvcy_test_util_gap_event, NULL, 0);
457     TEST_ASSERT_FATAL(rc == 0);
458 
459     ble_hs_pvcy_test_util_add_arbitrary_irk(false, true);
460 
461     /* Cancel is now in progress. */
462     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 1);
463     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].type ==
464                 BLE_GAP_EVENT_ADV_COMPLETE);
465     TEST_ASSERT(ble_hs_pvcy_test_gap_events[0].adv_complete.reason ==
466                 BLE_HS_EPREEMPTED);
467 
468     /* Ensure no GAP procedures are allowed. */
469     ble_hs_pvcy_test_util_all_gap_procs(BLE_HS_EPREEMPTED,
470                                         BLE_HS_EALREADY,
471                                         BLE_HS_EBUSY);
472 
473     /* Receive cancel event. */
474     ble_hs_test_util_rx_conn_cancel_evt();
475 
476     TEST_ASSERT(ble_hs_pvcy_test_num_gap_events == 2);
477     TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].type ==
478                 BLE_GAP_EVENT_CONNECT);
479     TEST_ASSERT(ble_hs_pvcy_test_gap_events[1].connect.status ==
480                 BLE_HS_EPREEMPTED);
481 
482     /* Ensure GAP procedures are no longer preempted. */
483     ble_hs_pvcy_test_util_all_gap_procs(0, 0, 0);
484 }
485 
TEST_SUITE(ble_hs_pvcy_test_suite_irk)486 TEST_SUITE(ble_hs_pvcy_test_suite_irk)
487 {
488     tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
489 
490     ble_hs_pvcy_test_case_restore_irks();
491     ble_hs_pvcy_test_case_add_irk_idle();
492     ble_hs_pvcy_test_case_add_irk_adv();
493     ble_hs_pvcy_test_case_add_irk_disc();
494     ble_hs_pvcy_test_case_add_irk_conn();
495     ble_hs_pvcy_test_case_add_irk_adv_disc();
496     ble_hs_pvcy_test_case_add_irk_adv_conn();
497 }
498 
499 int
ble_hs_pvcy_test_all(void)500 ble_hs_pvcy_test_all(void)
501 {
502     ble_hs_pvcy_test_suite_irk();
503 
504     return tu_any_failed;
505 }
506