/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include "testutil/testutil.h" #include "host/ble_hs.h" #include "ble_hs_test.h" #include "ble_hs_test_util.h" #define BHST_MAX_EVENTS 32 static struct ble_gap_event bhst_events[BHST_MAX_EVENTS]; static int bhst_num_events; static struct ble_hs_stop_listener bhst_listener; static struct os_sem bhst_sem; static int bhst_gap_event(struct ble_gap_event *event, void *arg) { TEST_ASSERT_FATAL(bhst_num_events < BHST_MAX_EVENTS); bhst_events[bhst_num_events++] = *event; return 0; } static void bhst_stop_cb(int status, void *arg) { int rc; rc = os_sem_release(&bhst_sem); TEST_ASSERT_FATAL(rc == 0); } TEST_CASE_TASK(ble_hs_stop_test_new_procs) { static const struct ble_gap_disc_params disc_params; static const struct ble_gap_adv_params adv_params; static const ble_addr_t peer_addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 } }; int rc; rc = os_sem_init(&bhst_sem, 0); TEST_ASSERT_FATAL(rc == 0); /* Stop the host and wait for the stop procedure to complete. */ ble_hs_test_util_hci_ack_set( BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE), 0); rc = ble_hs_stop(&bhst_listener, bhst_stop_cb, NULL); TEST_ASSERT_FATAL(rc == 0); rc = os_sem_pend(&bhst_sem, OS_TIMEOUT_NEVER); TEST_ASSERT_FATAL(rc == 0); /*** Ensure all GAP procedures fail. */ /* Advertise. */ rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, BLE_HS_FOREVER, bhst_gap_event, NULL, 0, 0); TEST_ASSERT(rc == BLE_HS_EDISABLED); /* Discover. */ rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, &disc_params, bhst_gap_event, NULL, 0, 0); TEST_ASSERT(rc == BLE_HS_EDISABLED); /* Connect. */ rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, BLE_HS_FOREVER, NULL, bhst_gap_event, NULL, 0); TEST_ASSERT(rc == BLE_HS_EDISABLED); /*** Restart stack; ensure GAP procedures succeed. */ ble_hs_test_util_hci_ack_set_startup(); ble_hs_sched_start(); /* Advertise. */ rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, BLE_HS_FOREVER, bhst_gap_event, NULL, 0, 0); TEST_ASSERT(rc == 0); rc = ble_hs_test_util_adv_stop(0); TEST_ASSERT(rc == 0); /* Discover. */ rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, &disc_params, bhst_gap_event, NULL, 0, 0); TEST_ASSERT(rc == 0); rc = ble_hs_test_util_disc_cancel(0); TEST_ASSERT(rc == 0); /* Connect. */ rc = ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &peer_addr, BLE_HS_FOREVER, NULL, bhst_gap_event, NULL, 0); TEST_ASSERT(rc == 0); rc = ble_hs_test_util_conn_cancel(0); TEST_ASSERT(rc == 0); ble_hs_test_util_assert_mbufs_freed(NULL); } TEST_CASE_TASK(ble_hs_stop_test_cur_procs) { static const struct ble_gap_disc_params disc_params; static const struct ble_gap_adv_params adv_params; int rc; rc = os_sem_init(&bhst_sem, 0); TEST_ASSERT_FATAL(rc == 0); /* Advertise. */ rc = ble_hs_test_util_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, &adv_params, BLE_HS_FOREVER, bhst_gap_event, NULL, 0, 0); TEST_ASSERT(rc == 0); /* Discover. */ rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER, &disc_params, bhst_gap_event, NULL, 0, 0); TEST_ASSERT(rc == 0); /* Preload the host with HCI acks for the cancel commands that will be sent * automatically when the host stops. */ ble_hs_test_util_hci_ack_set( BLE_HS_TEST_UTIL_LE_OPCODE(BLE_HCI_OCF_LE_SET_ADV_ENABLE), 0); ble_hs_test_util_hci_ack_append( ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_ENABLE), 0); /* Stop the host and wait for the stop procedure to complete. */ bhst_num_events = 0; rc = ble_hs_stop(&bhst_listener, bhst_stop_cb, NULL); TEST_ASSERT_FATAL(rc == 0); rc = os_sem_pend(&bhst_sem, OS_TIMEOUT_NEVER); TEST_ASSERT_FATAL(rc == 0); /* Ensure the GAP procedure cancellations were reported. */ TEST_ASSERT_FATAL(bhst_num_events == 2); TEST_ASSERT(bhst_events[0].type == BLE_GAP_EVENT_ADV_COMPLETE); TEST_ASSERT(bhst_events[0].adv_complete.reason == BLE_HS_EPREEMPTED); TEST_ASSERT(bhst_events[1].type == BLE_GAP_EVENT_DISC_COMPLETE); TEST_ASSERT(bhst_events[1].disc_complete.reason == BLE_HS_EPREEMPTED); ble_hs_test_util_assert_mbufs_freed(NULL); } static void bhst_pre_test(void *arg) { ble_hs_test_util_init_no_sysinit_no_start(); /* Preload the host with HCI acks for the startup sequence. */ ble_hs_test_util_hci_ack_set_startup(); } TEST_SUITE(ble_hs_stop_test_suite) { tu_suite_set_pre_test_cb(bhst_pre_test, NULL); ble_hs_stop_test_new_procs(); ble_hs_stop_test_cur_procs(); } int ble_stop_test_all(void) { ble_hs_stop_test_suite(); return tu_any_failed; }