http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/c5901fcc/net/nimble/host/test/src/ble_gap_test.c ---------------------------------------------------------------------- diff --cc net/nimble/host/test/src/ble_gap_test.c index 16a7309,0000000..3fe398f mode 100644,000000..100644 --- a/net/nimble/host/test/src/ble_gap_test.c +++ b/net/nimble/host/test/src/ble_gap_test.c @@@ -1,2580 -1,0 +1,2920 @@@ +/** + * 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 <string.h> +#include <errno.h> +#include "testutil/testutil.h" +#include "nimble/ble.h" +#include "nimble/hci_common.h" +#include "host/ble_hs_adv.h" +#include "host/ble_hs_test.h" +#include "ble_hs_test_util.h" + - static int ble_gap_test_conn_event_type; ++static struct ble_gap_event ble_gap_test_event; +static int ble_gap_test_conn_status; +static struct ble_gap_conn_desc ble_gap_test_conn_desc; +static void *ble_gap_test_conn_arg; +static struct ble_gap_upd_params ble_gap_test_conn_peer_params; +static struct ble_gap_upd_params ble_gap_test_conn_self_params; + +static int ble_gap_test_disc_event_type; +static struct ble_gap_disc_desc ble_gap_test_disc_desc; +static void *ble_gap_test_disc_arg; + +/***************************************************************************** + * $misc * + *****************************************************************************/ + - static int - ble_gap_test_util_update_in_progress(uint16_t conn_handle) - { - ble_hs_conn_flags_t conn_flags; - int rc; - - rc = ble_hs_atomic_conn_flags(conn_handle, &conn_flags); - return rc == 0 && conn_flags & BLE_HS_CONN_F_UPDATE; - } - +static void +ble_gap_test_util_reset_cb_info(void) +{ - ble_gap_test_conn_event_type = -1; ++ memset(&ble_gap_test_event, 0xff, sizeof ble_gap_test_event); + ble_gap_test_conn_status = -1; + memset(&ble_gap_test_conn_desc, 0xff, sizeof ble_gap_test_conn_desc); + ble_gap_test_conn_arg = (void *)-1; + + ble_gap_test_disc_event_type = -1; + memset(&ble_gap_test_disc_desc, 0xff, sizeof ble_gap_test_disc_desc); + ble_gap_test_disc_arg = (void *)-1; +} + +static void +ble_gap_test_util_init(void) +{ + ble_hs_test_util_init(); + ble_hs_test_util_set_static_rnd_addr(); + ble_gap_test_util_reset_cb_info(); +} + +static int +ble_gap_test_util_disc_cb(struct ble_gap_event *event, void *arg) +{ + ble_gap_test_disc_event_type = event->type; + ble_gap_test_disc_arg = arg; + + if (event->type == BLE_GAP_EVENT_DISC) { + ble_gap_test_disc_desc = event->disc; + } + + return 0; +} + +static int +ble_gap_test_util_connect_cb(struct ble_gap_event *event, void *arg) +{ + int *fail_reason; + - ble_gap_test_conn_event_type = event->type; ++ ble_gap_test_event = *event; + ble_gap_test_conn_arg = arg; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ble_gap_test_conn_status = event->connect.status; + ble_gap_conn_find(event->connect.conn_handle, &ble_gap_test_conn_desc); + break; + + case BLE_GAP_EVENT_DISCONNECT: + ble_gap_test_conn_status = event->disconnect.reason; + ble_gap_test_conn_desc = event->disconnect.conn; + break; + + case BLE_GAP_EVENT_CONN_UPDATE: + ble_gap_test_conn_status = event->conn_update.status; + ble_gap_conn_find(event->conn_update.conn_handle, + &ble_gap_test_conn_desc); + break; + + case BLE_GAP_EVENT_CONN_CANCEL: + break; + + case BLE_GAP_EVENT_TERM_FAILURE: + ble_gap_test_conn_status = event->term_failure.status; + ble_gap_conn_find(event->term_failure.conn_handle, + &ble_gap_test_conn_desc); + break; + + case BLE_GAP_EVENT_ADV_COMPLETE: + ble_gap_test_conn_arg = arg; + break; + + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + ble_gap_test_conn_peer_params = *event->conn_update_req.peer_params; + *event->conn_update_req.self_params = ble_gap_test_conn_self_params; + ble_gap_conn_find(event->conn_update_req.conn_handle, + &ble_gap_test_conn_desc); + + fail_reason = arg; + if (fail_reason == NULL) { + return 0; + } else { + return *fail_reason; + } + break; + ++ case BLE_GAP_EVENT_MTU: ++ break; ++ + default: + TEST_ASSERT_FATAL(0); + break; + } + + return 0; +} + +static void +ble_gap_test_util_verify_tx_clear_wl(void) +{ + uint8_t param_len; + + ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CLEAR_WHITE_LIST, + ¶m_len); + TEST_ASSERT(param_len == 0); +} + +static void +ble_gap_test_util_verify_tx_add_wl(struct ble_gap_white_entry *entry) +{ + uint8_t param_len; + uint8_t *param; + int i; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_ADD_WHITE_LIST, + ¶m_len); + TEST_ASSERT(param_len == 7); + TEST_ASSERT(param[0] == entry->addr_type); + for (i = 0; i < 6; i++) { + TEST_ASSERT(param[1 + i] == entry->addr[i]); + } +} + +static void +ble_gap_test_util_verify_tx_set_scan_params(uint8_t own_addr_type, + uint8_t scan_type, + uint16_t itvl, + uint16_t scan_window, + uint8_t filter_policy) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_PARAMS, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_SCAN_PARAM_LEN); + TEST_ASSERT(param[0] == scan_type); + TEST_ASSERT(le16toh(param + 1) == itvl); + TEST_ASSERT(le16toh(param + 3) == scan_window); + TEST_ASSERT(param[5] == own_addr_type); + TEST_ASSERT(param[6] == filter_policy); +} + +static void +ble_gap_test_util_verify_tx_scan_enable(uint8_t enable, + uint8_t filter_duplicates) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_ENABLE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_SCAN_ENABLE_LEN); + TEST_ASSERT(param[0] == enable); + TEST_ASSERT(param[1] == filter_duplicates); +} + +static void +ble_hs_test_util_verify_tx_create_conn_cancel(void) +{ + uint8_t param_len; + + ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_CONN_CANCEL, + ¶m_len); + TEST_ASSERT(param_len == 0); +} + +static void +ble_gap_test_util_verify_tx_disconnect(void) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LINK_CTRL, + BLE_HCI_OCF_DISCONNECT_CMD, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_DISCONNECT_CMD_LEN); + TEST_ASSERT(le16toh(param + 0) == 2); + TEST_ASSERT(param[2] == BLE_ERR_REM_USER_CONN_TERM); +} + +static void +ble_gap_test_util_verify_tx_adv_params(void) +{ + uint8_t param_len; + + ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_PARAMS, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_ADV_PARAM_LEN); + + /* Note: Content of message verified in ble_hs_adv_test.c. */ +} + +static void +ble_gap_test_util_verify_tx_adv_data(void) +{ + uint8_t param_len; + + ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_DATA, + ¶m_len); + /* Note: Content of message verified in ble_hs_adv_test.c. */ +} + +static void +ble_gap_test_util_verify_tx_rsp_data(void) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA, + ¶m_len); + (void)param; /* XXX: Verify other fields. */ +} + +static void +ble_gap_test_util_verify_tx_adv_enable(int enabled) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_ENABLE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_SET_ADV_ENABLE_LEN); + TEST_ASSERT(param[0] == !!enabled); +} + +static void +ble_gap_test_util_verify_tx_update_conn(struct ble_gap_upd_params *params) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CONN_UPDATE, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CONN_UPDATE_LEN); + TEST_ASSERT(le16toh(param + 0) == 2); + TEST_ASSERT(le16toh(param + 2) == params->itvl_min); + TEST_ASSERT(le16toh(param + 4) == params->itvl_max); + TEST_ASSERT(le16toh(param + 6) == params->latency); + TEST_ASSERT(le16toh(param + 8) == params->supervision_timeout); + TEST_ASSERT(le16toh(param + 10) == params->min_ce_len); + TEST_ASSERT(le16toh(param + 12) == params->max_ce_len); +} + +static void +ble_gap_test_util_verify_tx_params_reply_pos(void) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_REM_CONN_PARAM_RR, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CONN_PARAM_REPLY_LEN); + TEST_ASSERT(le16toh(param + 0) == 2); + TEST_ASSERT(le16toh(param + 2) == ble_gap_test_conn_self_params.itvl_min); + TEST_ASSERT(le16toh(param + 4) == ble_gap_test_conn_self_params.itvl_max); + TEST_ASSERT(le16toh(param + 6) == ble_gap_test_conn_self_params.latency); + TEST_ASSERT(le16toh(param + 8) == + ble_gap_test_conn_self_params.supervision_timeout); + TEST_ASSERT(le16toh(param + 10) == + ble_gap_test_conn_self_params.min_ce_len); + TEST_ASSERT(le16toh(param + 12) == + ble_gap_test_conn_self_params.max_ce_len); +} + +static void +ble_gap_test_util_verify_tx_params_reply_neg(uint8_t reason) +{ + uint8_t param_len; + uint8_t *param; + + param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR, + ¶m_len); + TEST_ASSERT(param_len == BLE_HCI_CONN_PARAM_NEG_REPLY_LEN); + TEST_ASSERT(le16toh(param + 0) == 2); + TEST_ASSERT(param[2] == reason); +} + +static void +ble_gap_test_util_rx_update_complete( + uint8_t status, - struct ble_gap_upd_params *params) ++ const struct ble_gap_upd_params *params) +{ + struct hci_le_conn_upd_complete evt; + + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE; + evt.status = status; + evt.connection_handle = 2; + evt.conn_itvl = params->itvl_max; + evt.conn_latency = params->latency; + evt.supervision_timeout = params->supervision_timeout; + + ble_gap_rx_update_complete(&evt); +} + +static int +ble_gap_test_util_rx_param_req(struct ble_gap_upd_params *params, int pos, + int *cmd_idx, int cmd_fail_idx, + uint8_t fail_status) +{ + struct hci_le_conn_param_req evt; + uint16_t opcode; + uint8_t hci_status; + + evt.subevent_code = BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ; + evt.connection_handle = 2; + evt.itvl_min = params->itvl_min; + evt.itvl_max = params->itvl_max; + evt.latency = params->latency; + evt.timeout = params->supervision_timeout; + + if (pos) { + opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_RR); + } else { + opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR); + } + if (*cmd_idx == cmd_fail_idx) { + hci_status = fail_status; + } else { + hci_status = 0; + } + (*cmd_idx)++; + + ble_hs_test_util_set_ack(opcode, hci_status); + ble_gap_rx_param_req(&evt); + + return hci_status; +} + +/***************************************************************************** + * $white list * + *****************************************************************************/ + +static void +ble_gap_test_util_wl_set(struct ble_gap_white_entry *white_list, + int white_list_count, int cmd_fail_idx, + uint8_t fail_status) +{ + int cmd_idx; + int rc; + int i; + + ble_gap_test_util_init(); + cmd_idx = 0; + + rc = ble_hs_test_util_wl_set(white_list, white_list_count, cmd_fail_idx, + fail_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + + /* Verify tx of clear white list command. */ + ble_gap_test_util_verify_tx_clear_wl(); + if (cmd_idx >= cmd_fail_idx) { + return; + } + cmd_idx++; + + /* Verify tx of add white list commands. */ + for (i = 0; i < white_list_count; i++) { + ble_gap_test_util_verify_tx_add_wl(white_list + i); + if (cmd_idx >= cmd_fail_idx) { + return; + } + cmd_idx++; + } +} + +TEST_CASE(ble_gap_test_case_wl_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + /*** 0 white list entries. */ + rc = ble_hs_test_util_wl_set(NULL, 0, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** Invalid address type. */ + rc = ble_hs_test_util_wl_set( + ((struct ble_gap_white_entry[]) { { + 5, { 1, 2, 3, 4, 5, 6 } + }, }), + 1, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + /*** White-list-using connection in progress. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_GAP_ADDR_TYPE_WL, NULL, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + + rc = ble_hs_test_util_wl_set( + ((struct ble_gap_white_entry[]) { { + BLE_ADDR_TYPE_PUBLIC, { 1, 2, 3, 4, 5, 6 } + }, }), + 1, 0, 0); + TEST_ASSERT(rc == BLE_HS_EBUSY); +} + +TEST_CASE(ble_gap_test_case_wl_ctlr_fail) +{ + int i; + + struct ble_gap_white_entry white_list[] = { + { BLE_ADDR_TYPE_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + { BLE_ADDR_TYPE_PUBLIC, { 2, 3, 4, 5, 6, 7 } }, + { BLE_ADDR_TYPE_PUBLIC, { 3, 4, 5, 6, 7, 8 } }, + { BLE_ADDR_TYPE_PUBLIC, { 4, 5, 6, 7, 8, 9 } }, + }; + int white_list_count = sizeof white_list / sizeof white_list[0]; + + for (i = 0; i < 5; i++) { + ble_gap_test_util_wl_set(white_list, white_list_count, i, + BLE_ERR_UNSPECIFIED); + } +} + +TEST_CASE(ble_gap_test_case_wl_good) +{ + struct ble_gap_white_entry white_list[] = { + { BLE_ADDR_TYPE_PUBLIC, { 1, 2, 3, 4, 5, 6 } }, + { BLE_ADDR_TYPE_PUBLIC, { 2, 3, 4, 5, 6, 7 } }, + { BLE_ADDR_TYPE_PUBLIC, { 3, 4, 5, 6, 7, 8 } }, + { BLE_ADDR_TYPE_PUBLIC, { 4, 5, 6, 7, 8, 9 } }, + }; + int white_list_count = sizeof white_list / sizeof white_list[0]; + + ble_gap_test_util_wl_set(white_list, white_list_count, 0, 0); +} + +TEST_SUITE(ble_gap_test_suite_wl) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_wl_good(); + ble_gap_test_case_wl_bad_args(); + ble_gap_test_case_wl_ctlr_fail(); +} + +/***************************************************************************** + * $discovery * + *****************************************************************************/ + +static int +ble_gap_test_util_disc(uint8_t own_addr_type, + const struct ble_gap_disc_params *disc_params, + struct ble_gap_disc_desc *desc, int cmd_fail_idx, + uint8_t fail_status) +{ + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_disc_active()); + + /* Begin the discovery procedure. */ + rc = ble_hs_test_util_disc(own_addr_type, BLE_HS_FOREVER, disc_params, + ble_gap_test_util_disc_cb, NULL, cmd_fail_idx, + fail_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + if (rc == 0) { + TEST_ASSERT(ble_gap_master_in_progress()); + ble_gap_rx_adv_report(desc); + } else { + TEST_ASSERT(ble_gap_test_disc_event_type == -1); + } + + if (cmd_fail_idx > 0) { + /* Verify tx of set scan parameters command. */ + ble_gap_test_util_verify_tx_set_scan_params( + own_addr_type, + disc_params->passive ? + BLE_HCI_SCAN_TYPE_PASSIVE : + BLE_HCI_SCAN_TYPE_ACTIVE, + disc_params->itvl, + disc_params->window, + disc_params->filter_policy); + } + + if (cmd_fail_idx > 1) { + /* Verify tx of scan enable command. */ + ble_gap_test_util_verify_tx_scan_enable( + 1, disc_params->filter_duplicates); + } + + if (rc == 0) { + TEST_ASSERT(ble_gap_disc_active()); + } + + return rc; +} + +TEST_CASE(ble_gap_test_case_disc_bad_args) +{ + struct ble_gap_disc_params params; + int rc; + + params.itvl = 0; + params.window = 0; + params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL; + params.limited = 0; + params.passive = 0; + params.filter_duplicates = 0; + + ble_gap_test_util_init(); + + /*** Invalid filter policy. */ + params.filter_policy = 6; + rc = ble_gap_disc(BLE_ADDR_TYPE_PUBLIC, 0, ¶ms, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); +} + +TEST_CASE(ble_gap_test_case_disc_good) +{ + uint8_t adv_data[32]; + uint8_t flags; + uint8_t own_addr_type; + int passive; + int limited; + int rc; + + struct ble_gap_disc_desc desc = { + .event_type = BLE_HCI_ADV_TYPE_ADV_IND, + .addr_type = BLE_ADDR_TYPE_PUBLIC, + .length_data = 0, + .rssi = 0, + .addr = { 1, 2, 3, 4, 5, 6 }, + .data = adv_data, + }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 0, + .passive = 0, + .filter_duplicates = 0, + }; + + flags = BLE_HS_ADV_F_DISC_LTD; + rc = ble_hs_adv_set_flat(BLE_HS_ADV_TYPE_FLAGS, 1, &flags, + desc.data, &desc.length_data, + sizeof adv_data); + TEST_ASSERT_FATAL(rc == 0); + + for (own_addr_type = 0; + own_addr_type <= BLE_ADDR_TYPE_RPA_RND_DEFAULT; + own_addr_type++) + for (passive = 0; passive <= 1; passive++) + for (limited = 0; limited <= 1; limited++) { + disc_params.passive = passive; + disc_params.limited = limited; + ble_gap_test_util_disc(own_addr_type, &disc_params, &desc, -1, 0); + + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC); + TEST_ASSERT(ble_gap_test_disc_desc.event_type == + BLE_HCI_ADV_TYPE_ADV_IND); + TEST_ASSERT(ble_gap_test_disc_desc.addr_type == + BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(ble_gap_test_disc_desc.length_data == 3); + TEST_ASSERT(ble_gap_test_disc_desc.rssi == 0); + TEST_ASSERT(memcmp(ble_gap_test_disc_desc.addr, desc.addr, 6) == 0); + TEST_ASSERT(ble_gap_test_disc_arg == NULL); + + } +} + +TEST_CASE(ble_gap_test_case_disc_ltd_mismatch) +{ + int rc; + struct ble_gap_disc_desc desc = { + .event_type = BLE_HCI_ADV_TYPE_ADV_IND, + .addr_type = BLE_ADDR_TYPE_PUBLIC, + .length_data = 0, + .rssi = 0, + .addr = { 1, 2, 3, 4, 5, 6 }, + .data = (uint8_t[BLE_HCI_MAX_ADV_DATA_LEN]){ + 2, + BLE_HS_ADV_TYPE_FLAGS, + BLE_HS_ADV_F_DISC_GEN, + }, + }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 1, + .passive = 0, + .filter_duplicates = 0, + }; + + rc = ble_gap_test_util_disc(BLE_ADDR_TYPE_PUBLIC, &disc_params, &desc, + -1, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* Verify that the report was ignored because of a mismatched LTD flag. */ + TEST_ASSERT(ble_gap_test_disc_event_type == -1); + + /* Stop the scan and swap the flags. */ + rc = ble_hs_test_util_disc_cancel(0); + TEST_ASSERT(rc == 0); + + desc.data[2] = BLE_HS_ADV_F_DISC_LTD; + disc_params.limited = 0; + rc = ble_gap_test_util_disc(BLE_ADDR_TYPE_PUBLIC, &disc_params, &desc, + -1, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* This time we should have reported the advertisement; general discovery + * hears everything. + */ + TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC); + +} + +TEST_CASE(ble_gap_test_case_disc_hci_fail) +{ + int fail_idx; + int limited; + int rc; + + struct ble_gap_disc_desc desc = { + .event_type = BLE_HCI_ADV_TYPE_ADV_IND, + .addr_type = BLE_ADDR_TYPE_PUBLIC, + .length_data = 0, + .rssi = 0, + .addr = { 1, 2, 3, 4, 5, 6 }, + .data = NULL, + }; + struct ble_gap_disc_params disc_params = { + .itvl = BLE_GAP_SCAN_SLOW_INTERVAL1, + .window = BLE_GAP_SCAN_SLOW_WINDOW1, + .filter_policy = BLE_HCI_CONN_FILT_NO_WL, + .limited = 0, + .passive = 0, + .filter_duplicates = 0, + }; + + for (limited = 0; limited <= 1; limited++) { + disc_params.limited = limited; + + for (fail_idx = 0; fail_idx < 2; fail_idx++) { + rc = ble_gap_test_util_disc(BLE_ADDR_TYPE_PUBLIC, &disc_params, + &desc, fail_idx, BLE_ERR_UNSUPPORTED); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(BLE_ERR_UNSUPPORTED)); + TEST_ASSERT(!ble_gap_master_in_progress()); + } + } +} + +static void +ble_gap_test_util_disc_dflts_once(int limited) +{ + struct ble_gap_disc_params params; + uint16_t exp_window; + uint16_t exp_itvl; + int rc; + + ble_gap_test_util_init(); + + memset(¶ms, 0, sizeof params); + params.limited = limited; + + rc = ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, 0, ¶ms, + ble_gap_test_util_disc_cb, NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + if (limited) { + exp_itvl = BLE_GAP_LIM_DISC_SCAN_INT; + exp_window = BLE_GAP_LIM_DISC_SCAN_WINDOW; + } else { + exp_itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN; + exp_window = BLE_GAP_SCAN_FAST_WINDOW; + } + ble_gap_test_util_verify_tx_set_scan_params( + BLE_ADDR_TYPE_PUBLIC, + BLE_HCI_SCAN_TYPE_ACTIVE, + exp_itvl, + exp_window, + BLE_HCI_SCAN_FILT_NO_WL); + + ble_gap_test_util_verify_tx_scan_enable(1, 0); +} + +TEST_CASE(ble_gap_test_case_disc_dflts) +{ + ble_gap_test_util_disc_dflts_once(0); + ble_gap_test_util_disc_dflts_once(1); +} + +TEST_CASE(ble_gap_test_case_disc_already) +{ + static const struct ble_gap_disc_params disc_params = { 0 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a discovery procedure. */ + rc = ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_gap_test_util_disc_cb, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EALREADY if we try to discover. */ + rc = ble_gap_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, &disc_params, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); +} + +TEST_CASE(ble_gap_test_case_disc_busy) +{ + static const struct ble_gap_disc_params disc_params = { 0 }; + static const uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a connect procedure. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EBUSY if we try to discover. */ + rc = ble_gap_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, &disc_params, + ble_gap_test_util_disc_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EBUSY); +} + +TEST_SUITE(ble_gap_test_suite_disc) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_disc_bad_args(); + ble_gap_test_case_disc_good(); + ble_gap_test_case_disc_ltd_mismatch(); + ble_gap_test_case_disc_hci_fail(); + ble_gap_test_case_disc_dflts(); + ble_gap_test_case_disc_already(); + ble_gap_test_case_disc_busy(); +} + +/***************************************************************************** + * $direct connect * + *****************************************************************************/ + +TEST_CASE(ble_gap_test_case_conn_gen_good) +{ + struct hci_le_conn_complete evt; + struct ble_gap_conn_params params; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_master_in_progress()); + TEST_ASSERT(!ble_gap_conn_active()); + + params.scan_itvl = 0x12; + params.scan_window = 0x11; + params.itvl_min = 25; + params.itvl_max = 26; + params.latency = 1; + params.supervision_timeout = 20; + params.min_ce_len = 3; + params.max_ce_len = 4; + + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, 0, ¶ms, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(ble_gap_conn_active()); + + TEST_ASSERT(ble_gap_master_in_progress()); + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); + + /* Receive connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + memcpy(evt.peer_addr, peer_addr, 6); + rc = ble_gap_rx_conn_complete(&evt); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(!ble_gap_master_in_progress()); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONNECT); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); +} + +TEST_CASE(ble_gap_test_case_conn_gen_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + /*** Invalid address type. */ + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, 5, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), 0, NULL, + ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /*** Connection already in progress. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), 0, + NULL, ble_gap_test_util_connect_cb, + NULL, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[]){ 1, 2, 3, 4, 5, 6 }), 0, NULL, + ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); +} + +TEST_CASE(ble_gap_test_case_conn_gen_dflt_params) +{ + static const uint8_t peer_addr[6] = { 2, 3, 8, 6, 6, 1 }; + int rc; + + ble_gap_test_util_init(); + + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); +} + +TEST_CASE(ble_gap_test_case_conn_gen_already) +{ + static const struct ble_gap_conn_params conn_params = { 0 }; + static const uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a connect procedure. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EALREADY if we try to connect. */ + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, BLE_HS_FOREVER, &conn_params, + ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EALREADY); +} + +TEST_CASE(ble_gap_test_case_conn_gen_busy) +{ + static const struct ble_gap_disc_params disc_params = { 0 }; + static const struct ble_gap_conn_params conn_params = { 0 }; + static const uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int rc; + + ble_gap_test_util_init(); + + /* Start a discovery procedure. */ + rc = ble_hs_test_util_disc(BLE_ADDR_TYPE_PUBLIC, BLE_HS_FOREVER, + &disc_params, ble_gap_test_util_disc_cb, + NULL, -1, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure host indicates BLE_HS_EBUSY if we try to connect. */ + rc = ble_gap_connect(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, BLE_HS_FOREVER, &conn_params, + ble_gap_test_util_connect_cb, NULL); + TEST_ASSERT(rc == BLE_HS_EBUSY); +} + +TEST_SUITE(ble_gap_test_suite_conn_gen) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_conn_gen_good(); + ble_gap_test_case_conn_gen_bad_args(); + ble_gap_test_case_conn_gen_dflt_params(); + ble_gap_test_case_conn_gen_already(); + ble_gap_test_case_conn_gen_busy(); +} + +/***************************************************************************** + * $cancel * + *****************************************************************************/ + +static void +ble_gap_test_util_conn_cancel(uint8_t hci_status) +{ + struct hci_le_conn_complete evt; + int rc; + + /* Initiate cancel procedure. */ + rc = ble_hs_test_util_conn_cancel(hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + + /* Verify tx of cancel create connection command. */ + ble_hs_test_util_verify_tx_create_conn_cancel(); + if (rc != 0) { + return; + } + TEST_ASSERT(ble_gap_master_in_progress()); + + /* Receive connection complete event. */ + memset(&evt, 0, sizeof evt); + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; + evt.status = BLE_ERR_UNK_CONN_ID; + rc = ble_gap_rx_conn_complete(&evt); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_CANCEL); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_CANCEL); +} + +static void +ble_gap_test_util_conn_and_cancel(uint8_t *peer_addr, uint8_t hci_status) +{ + int rc; + + ble_gap_test_util_init(); + + /* Begin creating a connection. */ + rc = ble_hs_test_util_connect(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, 0, NULL, + ble_gap_test_util_connect_cb, NULL, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_master_in_progress()); + + /* Initiate cancel procedure. */ + ble_gap_test_util_conn_cancel(hci_status); + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); +} + +TEST_CASE(ble_gap_test_case_conn_cancel_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + /* Initiate cancel procedure with no connection in progress. */ + TEST_ASSERT(!ble_gap_master_in_progress()); + rc = ble_hs_test_util_conn_cancel(0); + TEST_ASSERT(rc == BLE_HS_EALREADY); +} + +TEST_CASE(ble_gap_test_case_conn_cancel_good) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_conn_and_cancel(peer_addr, 0); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_CANCEL); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_CANCEL); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == BLE_HS_CONN_HANDLE_NONE); +} + +TEST_CASE(ble_gap_test_case_conn_cancel_ctlr_fail) +{ + struct hci_le_conn_complete evt; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_conn_and_cancel(peer_addr, BLE_ERR_REPEATED_ATTEMPTS); + + /* Make sure the host didn't invoke the application callback. The cancel + * failure was indicated via the return code from the gap call. + */ - TEST_ASSERT(ble_gap_test_conn_event_type == -1); ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); + + /* Allow connection complete to succeed. */ + memset(&evt, 0, sizeof evt); + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; + evt.status = BLE_ERR_SUCCESS; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER; + memcpy(evt.peer_addr, peer_addr, 6); + rc = ble_gap_rx_conn_complete(&evt); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(!ble_gap_master_in_progress()); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONNECT); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); +} + +TEST_SUITE(ble_gap_test_suite_conn_cancel) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_conn_cancel_good(); + ble_gap_test_case_conn_cancel_bad_args(); + ble_gap_test_case_conn_cancel_ctlr_fail(); +} + +/***************************************************************************** + * $terminate * + *****************************************************************************/ + +static void +ble_gap_test_util_terminate(uint8_t *peer_addr, uint8_t hci_status) +{ + struct hci_disconn_complete evt; + int rc; + + ble_gap_test_util_init(); + + /* Create a connection. */ + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + /* Reset the callback event code; we don't care about the successful + * connection in this test. + */ - ble_gap_test_conn_event_type = -1; ++ ble_gap_test_event.type = -1; + + /* Terminate the connection. */ + rc = ble_hs_test_util_conn_terminate(2, hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of disconnect command. */ + ble_gap_test_util_verify_tx_disconnect(); + + if (hci_status == 0) { + /* Receive disconnection complete event. */ + evt.connection_handle = 2; + evt.status = 0; + evt.reason = BLE_ERR_CONN_TERM_LOCAL; + ble_gap_rx_disconn_complete(&evt); + } +} + +TEST_CASE(ble_gap_test_case_conn_terminate_bad_args) +{ + int rc; + + ble_gap_test_util_init(); + + /*** Nonexistent connection. */ + rc = ble_hs_test_util_conn_terminate(2, 0); + TEST_ASSERT(rc == BLE_HS_ENOTCONN); +} + +TEST_CASE(ble_gap_test_case_conn_terminate_good) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_terminate(peer_addr, 0); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_DISCONNECT); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_DISCONNECT); + TEST_ASSERT(ble_gap_test_conn_status == + BLE_HS_HCI_ERR(BLE_ERR_CONN_TERM_LOCAL)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr_type == + BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == BLE_HS_ENOTCONN); + TEST_ASSERT(!ble_gap_master_in_progress()); +} + +TEST_CASE(ble_gap_test_case_conn_terminate_ctlr_fail) +{ + struct hci_disconn_complete evt; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + /* Create a connection. */ + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + /* Terminate the connection. */ + rc = ble_hs_test_util_conn_terminate(2, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of disconnect command. */ + ble_gap_test_util_verify_tx_disconnect(); + + /* Receive failed disconnection complete event. */ + evt.connection_handle = 2; + evt.status = BLE_ERR_UNSUPPORTED; + evt.reason = 0; + ble_gap_rx_disconn_complete(&evt); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_TERM_FAILURE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_TERM_FAILURE); + TEST_ASSERT(ble_gap_test_conn_status == + BLE_HS_HCI_ERR(BLE_ERR_UNSUPPORTED)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(ble_gap_test_conn_desc.peer_id_addr_type == + BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); +} + +TEST_CASE(ble_gap_test_case_conn_terminate_hci_fail) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_terminate(peer_addr, BLE_ERR_REPEATED_ATTEMPTS); + - TEST_ASSERT(ble_gap_test_conn_event_type == -1); ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_hs_atomic_conn_flags(2, NULL) == 0); + TEST_ASSERT(!ble_gap_master_in_progress()); +} + +TEST_SUITE(ble_gap_test_suite_conn_terminate) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_conn_terminate_bad_args(); + ble_gap_test_case_conn_terminate_good(); + ble_gap_test_case_conn_terminate_ctlr_fail(); + ble_gap_test_case_conn_terminate_hci_fail(); +} + +/***************************************************************************** + * $conn find * + *****************************************************************************/ + +TEST_CASE(ble_gap_test_case_conn_find) +{ + + struct ble_gap_conn_desc desc; + struct ble_hs_conn *conn; + uint8_t pub_addr[6]; + int rc; + + /*** We are master; public addresses. */ + ble_gap_test_util_init(); + + ble_hs_test_util_create_rpa_conn(8, + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[6]){0,0,0,0,0,0}), + BLE_ADDR_TYPE_PUBLIC, + ((uint8_t[6]){2,3,4,5,6,7}), + ((uint8_t[6]){0,0,0,0,0,0}), + ble_gap_test_util_connect_cb, + NULL); + + + rc = ble_hs_id_copy_addr(BLE_ADDR_TYPE_PUBLIC, pub_addr, NULL); + TEST_ASSERT_FATAL(rc == 0); + + rc = ble_gap_conn_find(8, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.conn_handle == 8); + TEST_ASSERT(desc.our_id_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.our_ota_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.peer_ota_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_MASTER); + TEST_ASSERT(memcmp(desc.our_ota_addr, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.our_id_addr, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.peer_ota_addr, + ((uint8_t[6]){2,3,4,5,6,7}), 6) == 0); + TEST_ASSERT(memcmp(desc.peer_id_addr, + ((uint8_t[6]){2,3,4,5,6,7}), 6) == 0); + TEST_ASSERT(desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(desc.conn_latency == BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); + TEST_ASSERT(desc.master_clock_accuracy == 0); + TEST_ASSERT(!desc.sec_state.encrypted); + TEST_ASSERT(!desc.sec_state.authenticated); + TEST_ASSERT(!desc.sec_state.bonded); + + /*** Swap roles. */ + ble_hs_lock(); + conn = ble_hs_conn_find(8); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + rc = ble_gap_conn_find(8, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_SLAVE); + + /*** We are master; RPAs. */ + ble_gap_test_util_init(); + + ble_hs_test_util_create_rpa_conn(54, + BLE_ADDR_TYPE_RPA_PUB_DEFAULT, + ((uint8_t[6]){0x40,1,2,3,4,5}), + BLE_ADDR_TYPE_RPA_RND_DEFAULT, + ((uint8_t[6]){3,4,5,6,7,8}), + ((uint8_t[6]){0x50,1,2,3,4,5}), + ble_gap_test_util_connect_cb, + NULL); + + rc = ble_gap_conn_find(54, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.conn_handle == 54); + TEST_ASSERT(desc.our_id_addr_type == BLE_ADDR_TYPE_PUBLIC); + TEST_ASSERT(desc.our_ota_addr_type == BLE_ADDR_TYPE_RPA_PUB_DEFAULT); + TEST_ASSERT(desc.peer_ota_addr_type == BLE_ADDR_TYPE_RPA_RND_DEFAULT); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_MASTER); + TEST_ASSERT(memcmp(desc.our_ota_addr, + ((uint8_t[6]){0x40,1,2,3,4,5}), 6) == 0); + TEST_ASSERT(memcmp(desc.our_id_addr, pub_addr, 6) == 0); + TEST_ASSERT(memcmp(desc.peer_ota_addr, + ((uint8_t[6]){0x50,1,2,3,4,5}), 6) == 0); + TEST_ASSERT(memcmp(desc.peer_id_addr, + ((uint8_t[6]){3,4,5,6,7,8}), 6) == 0); + TEST_ASSERT(desc.conn_itvl == BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(desc.conn_latency == BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); + TEST_ASSERT(desc.master_clock_accuracy == 0); + TEST_ASSERT(!desc.sec_state.encrypted); + TEST_ASSERT(!desc.sec_state.authenticated); + TEST_ASSERT(!desc.sec_state.bonded); + + /*** Swap roles. */ + ble_hs_lock(); + conn = ble_hs_conn_find(54); + conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; + ble_hs_unlock(); + + rc = ble_gap_conn_find(54, &desc); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(desc.role == BLE_GAP_ROLE_SLAVE); +} + +TEST_SUITE(ble_gap_test_suite_conn_find) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_conn_find(); +} + +/***************************************************************************** + * $advertise * + *****************************************************************************/ + +static void +ble_gap_test_util_adv(uint8_t own_addr_type, uint8_t peer_addr_type, + const uint8_t *peer_addr, uint8_t conn_mode, + uint8_t disc_mode, int connect_status, + int cmd_fail_idx, uint8_t fail_status) +{ + struct hci_le_conn_complete evt; + struct ble_gap_adv_params adv_params; + struct ble_hs_adv_fields adv_fields; + uint8_t hci_status; + int cmd_idx; + int rc; + + ble_gap_test_util_init(); + + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = conn_mode; + adv_params.disc_mode = disc_mode; + + TEST_ASSERT(!ble_gap_adv_active()); + + cmd_idx = 0; + + if (conn_mode != BLE_GAP_CONN_MODE_DIR) { + memset(&adv_fields, 0, sizeof adv_fields); + adv_fields.tx_pwr_lvl_is_present = 1; + adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; + + hci_status = ble_hs_test_util_exp_hci_status(cmd_idx, cmd_fail_idx, + fail_status); + rc = ble_hs_test_util_adv_set_fields(&adv_fields, hci_status); + + if (adv_fields.tx_pwr_lvl_is_present && + adv_fields.tx_pwr_lvl == BLE_HS_ADV_TX_PWR_LVL_AUTO) { + + TEST_ASSERT_FATAL(rc == BLE_HS_HCI_ERR(hci_status)); + cmd_idx++; + } + } + + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + rc = ble_hs_test_util_adv_start(own_addr_type, peer_addr_type, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, + cmd_fail_idx - cmd_idx, fail_status); + + TEST_ASSERT(rc == BLE_HS_HCI_ERR(fail_status)); + } + + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + /* Verify tx of set advertising params command. */ + ble_gap_test_util_verify_tx_adv_params(); + } + cmd_idx++; + + if (conn_mode != BLE_GAP_CONN_MODE_DIR) { + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + /* Verify tx of set advertise data command. */ + ble_gap_test_util_verify_tx_adv_data(); + } + cmd_idx++; + + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + /* Verify tx of set scan response data command. */ + ble_gap_test_util_verify_tx_rsp_data(); + } + cmd_idx++; + } + + if (fail_status == 0 || cmd_fail_idx >= cmd_idx) { + /* Verify tx of set advertise enable command. */ + ble_gap_test_util_verify_tx_adv_enable(1); + } + cmd_idx++; + + if (connect_status != -1 && + (fail_status == 0 || cmd_fail_idx >= cmd_idx)) { + + TEST_ASSERT(ble_gap_adv_active()); + + /* Receive a connection complete event. */ + if (conn_mode != BLE_GAP_CONN_MODE_NON) { + memset(&evt, 0, sizeof evt); + evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE; + evt.status = connect_status; + evt.connection_handle = 2; + evt.role = BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE; + memcpy(evt.peer_addr, peer_addr, 6); + rc = ble_gap_rx_conn_complete(&evt); + TEST_ASSERT(rc == 0); + + if (connect_status == 0 || + connect_status == BLE_ERR_DIR_ADV_TMO) { + + TEST_ASSERT(!ble_gap_adv_active()); + } else { + TEST_ASSERT(ble_gap_adv_active()); + } + } + } +} + +TEST_CASE(ble_gap_test_case_adv_bad_args) +{ + struct ble_gap_adv_params adv_params; + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Invalid discoverable mode. */ + adv_params = ble_hs_test_util_adv_params; + adv_params.disc_mode = 43; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Invalid connectable mode. */ + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = 27; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Invalid peer address type with directed advertisable mode. */ + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = BLE_GAP_CONN_MODE_DIR; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, 12, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(!ble_gap_adv_active()); + + /*** Advertising already in progress. */ + adv_params = ble_hs_test_util_adv_params; + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == 0); + TEST_ASSERT(ble_gap_adv_active()); + + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT(rc == BLE_HS_EALREADY); + TEST_ASSERT(ble_gap_adv_active()); +} + +static void +ble_gap_test_util_adv_verify_dflt_params(uint8_t own_addr_type, + uint8_t peer_addr_type, + const uint8_t *peer_addr, + uint8_t conn_mode, + uint8_t disc_mode) +{ + struct ble_gap_adv_params adv_params; + struct hci_adv_params hci_cmd; + uint8_t *hci_buf; + uint8_t hci_param_len; + int rc; + + ble_gap_test_util_init(); + + TEST_ASSERT(!ble_gap_adv_active()); + + adv_params = ble_hs_test_util_adv_params; + adv_params.conn_mode = conn_mode; + adv_params.disc_mode = disc_mode; + + /* Let stack calculate all default parameters. */ + adv_params.itvl_min = 0; + adv_params.itvl_max = 0; + adv_params.channel_map = 0; + adv_params.filter_policy = 0; + adv_params.high_duty_cycle = 0; + + rc = ble_hs_test_util_adv_start(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, &adv_params, + ble_gap_test_util_connect_cb, NULL, 0, 0); + TEST_ASSERT_FATAL(rc == 0); + + /* Ensure default parameters properly filled in. */ + hci_buf = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_ADV_PARAMS, + &hci_param_len); + TEST_ASSERT_FATAL(hci_buf != NULL); + TEST_ASSERT_FATAL(hci_param_len == BLE_HCI_SET_ADV_PARAM_LEN); + + hci_cmd.adv_itvl_min = le16toh(hci_buf + 0); + hci_cmd.adv_itvl_max = le16toh(hci_buf + 2); + hci_cmd.adv_type = hci_buf[4]; + hci_cmd.own_addr_type = hci_buf[5]; + hci_cmd.peer_addr_type = hci_buf[6]; + memcpy(hci_cmd.peer_addr, hci_buf + 7, 6); + hci_cmd.adv_channel_map = hci_buf[13]; + hci_cmd.adv_filter_policy = hci_buf[14]; + + if (conn_mode == BLE_GAP_CONN_MODE_NON) { + TEST_ASSERT(hci_cmd.adv_itvl_min == BLE_GAP_ADV_FAST_INTERVAL2_MIN); + TEST_ASSERT(hci_cmd.adv_itvl_max == BLE_GAP_ADV_FAST_INTERVAL2_MAX); + } else { + TEST_ASSERT(hci_cmd.adv_itvl_min == BLE_GAP_ADV_FAST_INTERVAL1_MIN); + TEST_ASSERT(hci_cmd.adv_itvl_max == BLE_GAP_ADV_FAST_INTERVAL1_MAX); + } + + if (conn_mode == BLE_GAP_CONN_MODE_NON) { + if (disc_mode == BLE_GAP_DISC_MODE_NON) { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND); + } else { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND); + } + } else if (conn_mode == BLE_GAP_CONN_MODE_UND) { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_IND); + } else { + TEST_ASSERT(hci_cmd.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD); + } +} + +TEST_CASE(ble_gap_test_case_adv_dflt_params) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_adv_verify_dflt_params( + BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, peer_addr, c, d); + } + } +} + +TEST_CASE(ble_gap_test_case_adv_good) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, c, d, BLE_ERR_SUCCESS, -1, 0); + + if (c != BLE_GAP_CONN_MODE_NON) { + TEST_ASSERT(!ble_gap_adv_active()); - TEST_ASSERT(ble_gap_test_conn_event_type == - BLE_GAP_EVENT_CONNECT); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONNECT); + TEST_ASSERT(ble_gap_test_conn_status == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + } + } + } +} + +TEST_CASE(ble_gap_test_case_adv_ctlr_fail) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON + 1; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_PUBLIC, + peer_addr, c, d, BLE_ERR_DIR_ADV_TMO, -1, 0); + + TEST_ASSERT(!ble_gap_adv_active()); - TEST_ASSERT(ble_gap_test_conn_event_type == - BLE_GAP_EVENT_ADV_COMPLETE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_ADV_COMPLETE); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == + BLE_HS_CONN_HANDLE_NONE); + TEST_ASSERT(ble_gap_test_conn_arg == NULL); + } + } +} + +TEST_CASE(ble_gap_test_case_adv_hci_fail) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int num_hci_cmds; + int fail_idx; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + if (c == BLE_GAP_CONN_MODE_DIR) { + num_hci_cmds = 2; + } else { + num_hci_cmds = 5; + } + + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + for (fail_idx = 0; fail_idx < num_hci_cmds; fail_idx++) { + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, + BLE_ADDR_TYPE_PUBLIC, peer_addr, + c, d, 0, fail_idx, BLE_ERR_UNSUPPORTED); + + TEST_ASSERT(!ble_gap_adv_active()); - TEST_ASSERT(ble_gap_test_conn_event_type == -1); ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); + } + } + } +} + +TEST_SUITE(ble_gap_test_suite_adv) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_adv_bad_args(); + ble_gap_test_case_adv_dflt_params(); + ble_gap_test_case_adv_good(); + ble_gap_test_case_adv_ctlr_fail(); + ble_gap_test_case_adv_hci_fail(); +} + +/***************************************************************************** + * $stop advertise * + *****************************************************************************/ + +static void +ble_gap_test_util_stop_adv(uint8_t peer_addr_type, const uint8_t *peer_addr, + uint8_t conn_mode, uint8_t disc_mode, + int cmd_fail_idx, uint8_t fail_status) +{ + uint8_t hci_status; + int rc; + + ble_gap_test_util_init(); + + /* Start advertising; don't rx a successful connection event. */ + ble_gap_test_util_adv(BLE_ADDR_TYPE_PUBLIC, peer_addr_type, peer_addr, + conn_mode, disc_mode, -1, -1, 0); + + TEST_ASSERT(ble_gap_adv_active()); + + /* Stop advertising. */ + hci_status = cmd_fail_idx == 0 ? fail_status : 0; + + rc = ble_hs_test_util_adv_stop(hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + + /* Verify tx of advertising enable command. */ + ble_gap_test_util_verify_tx_adv_enable(0); +} + +TEST_CASE(ble_gap_test_case_stop_adv_good) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_stop_adv(BLE_ADDR_TYPE_PUBLIC, peer_addr, c, d, + -1, 0); + TEST_ASSERT(!ble_gap_adv_active()); - TEST_ASSERT(ble_gap_test_conn_event_type == -1); ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_gap_test_conn_status == -1); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == (uint16_t)-1); + TEST_ASSERT(ble_gap_test_conn_arg == (void *)-1); + } + } +} + +TEST_CASE(ble_gap_test_case_stop_adv_hci_fail) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + int d; + int c; + + for (c = BLE_GAP_CONN_MODE_NON; c < BLE_GAP_CONN_MODE_MAX; c++) { + for (d = BLE_GAP_DISC_MODE_NON; d < BLE_GAP_DISC_MODE_MAX; d++) { + ble_gap_test_util_stop_adv(BLE_ADDR_TYPE_PUBLIC, peer_addr, c, d, + 0, BLE_ERR_UNSUPPORTED); + TEST_ASSERT(ble_gap_adv_active()); - TEST_ASSERT(ble_gap_test_conn_event_type == -1); ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); + TEST_ASSERT(ble_gap_test_conn_status == -1); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == (uint16_t)-1); + TEST_ASSERT(ble_gap_test_conn_arg == (void *)-1); + } + } +} + +TEST_SUITE(ble_gap_test_suite_stop_adv) +{ + tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); + + ble_gap_test_case_stop_adv_good(); + ble_gap_test_case_stop_adv_hci_fail(); +} + +/***************************************************************************** + * $update connection * + *****************************************************************************/ + +static void - ble_gap_test_util_update(struct ble_gap_upd_params *params, - int cmd_fail_idx, uint8_t hci_status, - uint8_t event_status) ++ble_gap_test_util_update_no_l2cap(struct ble_gap_upd_params *params, ++ int master, ++ uint8_t hci_status, int event_status) +{ - int status; ++ struct ble_hs_conn *conn; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + ++ if (!master) { ++ ble_hs_lock(); ++ conn = ble_hs_conn_find(2); ++ TEST_ASSERT_FATAL(conn != NULL); ++ conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; ++ ble_hs_unlock(); ++ } ++ ++ /* Erase callback info reported during connection establishment; we only ++ * care about updates. ++ */ ++ ble_gap_test_util_reset_cb_info(); ++ + TEST_ASSERT(!ble_gap_master_in_progress()); + + rc = ble_hs_test_util_conn_update(2, params, hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of connection update command. */ + ble_gap_test_util_verify_tx_update_conn(params); + + if (rc == 0) { - TEST_ASSERT(ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); ++ ++ /* Receive connection update complete event. */ ++ ble_gap_test_util_rx_update_complete(event_status, params); ++ ++ TEST_ASSERT(!ble_gap_master_in_progress()); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); ++ ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(event_status)); ++ if (event_status == 0) { ++ TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); ++ TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, ++ peer_addr, 6) == 0); ++ TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); ++ TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == ++ params->latency); ++ TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == ++ params->supervision_timeout); ++ } + } else { - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); - return; ++ TEST_ASSERT(!ble_gap_master_in_progress()); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); ++ ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); + } ++} + - /* Receive connection update complete event. */ - ble_gap_test_util_rx_update_complete(event_status, params); ++static void ++ble_gap_test_util_update_l2cap(struct ble_gap_upd_params *params, ++ uint8_t hci_status, int event_status, ++ uint16_t l2cap_result) ++{ ++ struct ble_l2cap_sig_update_params l2cap_params; ++ struct ble_hs_conn *conn; ++ uint8_t id; ++ int rc; ++ ++ uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; ++ ++ ble_gap_test_util_init(); ++ ++ ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, ++ NULL); ++ ++ ble_hs_lock(); ++ conn = ble_hs_conn_find(2); ++ TEST_ASSERT_FATAL(conn != NULL); ++ conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; ++ ble_hs_unlock(); ++ ++ /* Erase callback info reported during connection establishment; we only ++ * care about updates. ++ */ ++ ble_gap_test_util_reset_cb_info(); ++ ++ rc = ble_hs_test_util_conn_update(2, params, hci_status); ++ TEST_ASSERT(rc == 0); ++ ++ /* Verify tx of connection update command. */ ++ ble_gap_test_util_verify_tx_update_conn(params); ++ ++ switch (hci_status) { ++ case 0: ++ /* Receive connection update complete event. */ ++ ble_gap_test_util_rx_update_complete(event_status, params); ++ break; ++ case BLE_ERR_UNKNOWN_HCI_CMD: ++ break; ++ default: ++ TEST_ASSERT_FATAL(0); ++ break; ++ } ++ ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); ++ ++ l2cap_params.itvl_min = params->itvl_min; ++ l2cap_params.itvl_max = params->itvl_max; ++ l2cap_params.slave_latency = params->latency; ++ l2cap_params.timeout_multiplier = params->supervision_timeout; ++ id = ble_hs_test_util_verify_tx_l2cap_update_req(&l2cap_params); + - if (event_status != 0) { - status = BLE_HS_HCI_ERR(event_status); - goto fail; ++ /* Receive l2cap connection parameter update response. */ ++ ble_hs_test_util_rx_l2cap_update_rsp(2, id, l2cap_result); ++ if (l2cap_result == BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT) { ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); ++ ++ /* Receive connection update complete event. */ ++ ble_gap_test_util_rx_update_complete(0, params); ++ } ++ ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); ++ ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); ++ if (l2cap_result != BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT) { ++ TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_EREJECT); ++ } else { ++ TEST_ASSERT(ble_gap_test_conn_status == 0); ++ TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); ++ TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == params->latency); ++ TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == ++ params->supervision_timeout); ++ } ++ ++ TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); ++ TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, ++ peer_addr, 6) == 0); ++} ++ ++static void ++ble_gap_test_util_update_no_l2cap_tmo(struct ble_gap_upd_params *params, ++ int master) ++{ ++ struct ble_hs_conn *conn; ++ int rc; ++ ++ uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; ++ ++ ble_gap_test_util_init(); ++ ++ ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, ++ NULL); ++ ++ if (!master) { ++ ble_hs_lock(); ++ conn = ble_hs_conn_find(2); ++ TEST_ASSERT_FATAL(conn != NULL); ++ conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; ++ ble_hs_unlock(); + } + ++ /* Erase callback info reported during connection establishment; we only ++ * care about updates. ++ */ ++ ble_gap_test_util_reset_cb_info(); ++ + TEST_ASSERT(!ble_gap_master_in_progress()); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); - TEST_ASSERT(ble_gap_test_conn_status == 0); ++ rc = ble_hs_test_util_conn_update(2, params, 0); ++ TEST_ASSERT(rc == 0); ++ TEST_ASSERT(!ble_gap_master_in_progress()); ++ ++ /* Verify tx of connection update command. */ ++ ble_gap_test_util_verify_tx_update_conn(params); ++ ++ /* Ensure no update event reported. */ ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); ++ ++ /* Advance 29 seconds; ensure no timeout reported. */ ++ os_time_advance(29 * OS_TICKS_PER_SEC); ++ ble_gap_heartbeat(); ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); ++ ++ /* Advance 30th second; ensure timeout reported. */ ++ os_time_advance(1 * OS_TICKS_PER_SEC); ++ ++ /* Timeout will result in a terminate HCI command being sent; schedule ack ++ * from controller. ++ */ ++ ble_hs_test_util_set_ack_disconnect(0); ++ ++ ble_gap_heartbeat(); ++ ++ /* Verify terminate was sent. */ ++ ble_gap_test_util_verify_tx_disconnect(); ++ ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_ETIMEOUT); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); - TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); - TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == params->latency); - TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == - params->supervision_timeout); ++} + - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++static void ++ble_gap_test_util_update_l2cap_tmo(struct ble_gap_upd_params *params, ++ uint8_t hci_status, uint8_t event_status, ++ int rx_l2cap) ++{ ++ struct ble_l2cap_sig_update_params l2cap_params; ++ struct ble_hs_conn *conn; ++ uint8_t id; ++ int rc; + - return; ++ uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; ++ ++ ble_gap_test_util_init(); ++ ++ ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, ++ NULL); ++ ++ ble_hs_lock(); ++ conn = ble_hs_conn_find(2); ++ TEST_ASSERT_FATAL(conn != NULL); ++ conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER; ++ ble_hs_unlock(); ++ ++ /* Erase callback info reported during connection establishment; we only ++ * care about updates. ++ */ ++ ble_gap_test_util_reset_cb_info(); ++ ++ rc = ble_hs_test_util_conn_update(2, params, hci_status); ++ TEST_ASSERT(rc == 0); ++ ++ /* Verify tx of connection update command. */ ++ ble_gap_test_util_verify_tx_update_conn(params); ++ ++ switch (hci_status) { ++ case 0: ++ /* Receive connection update complete event. */ ++ ble_gap_test_util_rx_update_complete(event_status, params); ++ break; ++ case BLE_ERR_UNKNOWN_HCI_CMD: ++ break; ++ default: ++ TEST_ASSERT_FATAL(0); ++ break; ++ } ++ ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); ++ ++ if (rx_l2cap) { ++ l2cap_params.itvl_min = params->itvl_min; ++ l2cap_params.itvl_max = params->itvl_max; ++ l2cap_params.slave_latency = params->latency; ++ l2cap_params.timeout_multiplier = params->supervision_timeout; ++ id = ble_hs_test_util_verify_tx_l2cap_update_req(&l2cap_params); ++ ++ /* Receive l2cap connection parameter update response. */ ++ ble_hs_test_util_rx_l2cap_update_rsp( ++ 2, id, BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT); ++ } ++ ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); ++ ++ /* Ensure no update event reported. */ ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); ++ ++ /* Advance 29 seconds; ensure no timeout reported. */ ++ os_time_advance(29 * OS_TICKS_PER_SEC); ++ ble_gap_heartbeat(); ++ ble_l2cap_sig_heartbeat(); ++ TEST_ASSERT(ble_gap_test_event.type == 0xff); ++ ++ /* Advance 30th second; ensure timeout reported. */ ++ os_time_advance(1 * OS_TICKS_PER_SEC); + - fail: - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); - TEST_ASSERT(ble_gap_test_conn_status == status); ++ /* Timeout will result in a terminate HCI command being sent; schedule ack ++ * from controller. ++ */ ++ ble_hs_test_util_set_ack_disconnect(0); ++ ++ ble_gap_heartbeat(); ++ ble_l2cap_sig_heartbeat(); ++ ++ /* Verify terminate was sent. */ ++ ble_gap_test_util_verify_tx_disconnect(); ++ ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_ETIMEOUT); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); - TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == - BLE_GAP_INITIAL_CONN_ITVL_MAX); - TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == - BLE_GAP_INITIAL_CONN_LATENCY); - TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == - BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); +} + +static void +ble_gap_test_util_update_peer(uint8_t status, + struct ble_gap_upd_params *params) +{ + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(status, params); + + TEST_ASSERT(!ble_gap_master_in_progress()); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + + if (status == 0) { + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + params->supervision_timeout); + } + - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); +} + +static void +ble_gap_test_util_update_req_pos(struct ble_gap_upd_params *peer_params, + struct ble_gap_upd_params *self_params, + int cmd_fail_idx, uint8_t hci_status) +{ + int cmd_idx; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + cmd_idx = 0; + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + ble_gap_test_conn_self_params = *self_params; + rc = ble_gap_test_util_rx_param_req(peer_params, 1, &cmd_idx, cmd_fail_idx, + hci_status); + if (rc != 0) { + goto hci_fail; + } + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_util_update_in_progress(2)); ++ ++ /* We don't maintain an update entry when the peer initiates. */ ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + /* Verify tx of connection parameters reply command. */ + ble_gap_test_util_verify_tx_params_reply_pos(); + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(0, self_params); + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == self_params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == self_params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + self_params->supervision_timeout); + + return; + +hci_fail: - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == + BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == + BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); +} + +static void +ble_gap_test_util_update_req_neg(struct ble_gap_upd_params *peer_params, + int cmd_fail_idx, uint8_t hci_status) +{ + int cmd_idx; + int reason; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + cmd_idx = 0; + + reason = BLE_ERR_UNSPECIFIED; + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + &reason); + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + rc = ble_gap_test_util_rx_param_req(peer_params, 0, &cmd_idx, cmd_fail_idx, + hci_status); + if (rc != 0) { + goto hci_fail; + } + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + /* Verify tx of connection parameters negative reply command. */ + ble_gap_test_util_verify_tx_params_reply_neg(reason); + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + return; + +hci_fail: - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(hci_status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == + BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == + BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); +} + +static void +ble_gap_test_util_update_req_concurrent( + struct ble_gap_upd_params *init_params, + struct ble_gap_upd_params *peer_params, + struct ble_gap_upd_params *self_params, + int cmd_fail_idx, + uint8_t fail_status) +{ + uint8_t hci_status; + int cmd_idx; + int rc; + + uint8_t peer_addr[6] = { 1, 2, 3, 4, 5, 6 }; + + ble_gap_test_util_init(); + + ble_hs_test_util_create_conn(2, peer_addr, ble_gap_test_util_connect_cb, + NULL); + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + + hci_status = cmd_fail_idx == 0 ? fail_status : 0; + rc = ble_hs_test_util_conn_update(2, init_params, hci_status); + TEST_ASSERT(rc == BLE_HS_HCI_ERR(hci_status)); + + TEST_ASSERT(!ble_gap_master_in_progress()); + + /* Verify tx of connection update command. */ + ble_gap_test_util_verify_tx_update_conn(init_params); + + if (rc == 0) { - TEST_ASSERT(ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); + } else { - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + return; + } + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); + + /* Receive connection parameter update request from peer. */ + ble_gap_test_conn_self_params = *self_params; + rc = ble_gap_test_util_rx_param_req(peer_params, 1, &cmd_idx, cmd_fail_idx, + hci_status); + if (rc != 0) { + goto hci_fail; + } + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); + + /* Verify tx of connection parameters reply command. */ + ble_gap_test_util_verify_tx_params_reply_pos(); + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(ble_gap_dbg_update_active(2)); + + /* Receive connection update complete event. */ + ble_gap_test_util_rx_update_complete(0, self_params); + + TEST_ASSERT(!ble_gap_master_in_progress()); - TEST_ASSERT(!ble_gap_test_util_update_in_progress(2)); ++ TEST_ASSERT(!ble_gap_dbg_update_active(2)); + - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == self_params->itvl_max); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == self_params->latency); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + self_params->supervision_timeout); + + return; + +hci_fail: - TEST_ASSERT(ble_gap_test_conn_event_type == BLE_GAP_EVENT_CONN_UPDATE); ++ TEST_ASSERT(ble_gap_test_event.type == BLE_GAP_EVENT_CONN_UPDATE); + TEST_ASSERT(ble_gap_test_conn_status == BLE_HS_HCI_ERR(fail_status)); + TEST_ASSERT(ble_gap_test_conn_desc.conn_handle == 2); + TEST_ASSERT(memcmp(ble_gap_test_conn_desc.peer_id_addr, + peer_addr, 6) == 0); + TEST_ASSERT(ble_gap_test_conn_desc.conn_itvl == + BLE_GAP_INITIAL_CONN_ITVL_MAX); + TEST_ASSERT(ble_gap_test_conn_desc.conn_latency == + BLE_GAP_INITIAL_CONN_LATENCY); + TEST_ASSERT(ble_gap_test_conn_desc.supervision_timeout == + BLE_GAP_INITIAL_SUPERVISION_TIMEOUT); +} + +TEST_CASE(ble_gap_test_case_update_conn_good) +{ - ble_gap_test_util_update( ++ ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 0, + .min_ce_len = 123, + .max_ce_len = 456, + }}), - -1, 0, 0); ++ 1, 0, 0); + - ble_gap_test_util_update( ++ ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 100, + .supervision_timeout = 100, + .min_ce_len = 554, + .max_ce_len = 554, + }}), - -1, 0, 0); ++ 1, 0, 0); +} + +TEST_CASE(ble_gap_test_case_update_conn_bad) +{ - ble_gap_test_util_update( ++ ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 0, + .min_ce_len = 123, + .max_ce_len = 456, + }}), - -1, 0, BLE_ERR_LMP_COLLISION); ++ 1, 0, BLE_ERR_LMP_COLLISION); +} + +TEST_CASE(ble_gap_test_case_update_conn_hci_fail) +{ - ble_gap_test_util_update( ++ ble_gap_test_util_update_no_l2cap( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 0, + .min_ce_len = 123, + .max_ce_len = 456, + }}), - 0, BLE_ERR_UNSUPPORTED, 0); ++ 1, BLE_ERR_UNSUPPORTED, 0); ++} ++ ++TEST_CASE(ble_gap_test_case_update_conn_l2cap) ++{ ++ struct ble_gap_upd_params params = { ++ .itvl_min = 10, ++ .itvl_max = 100, ++ .supervision_timeout = 0, ++ .min_ce_len = 123, ++ .max_ce_len = 456, ++ }; ++ ++ /* Accepted L2CAP failover; success. */ ++ ble_gap_test_util_update_l2cap(¶ms, BLE_ERR_UNKNOWN_HCI_CMD, 0, ++ BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT); ++ ble_gap_test_util_update_l2cap(¶ms, 0, BLE_ERR_UNSUPP_REM_FEATURE, ++ BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT); ++ ++ /* Accepted L2CAP failover; failure. */ ++ ble_gap_test_util_update_l2cap(¶ms, BLE_ERR_UNKNOWN_HCI_CMD, 0, ++ BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT); ++ ble_gap_test_util_update_l2cap(¶ms, 0, BLE_ERR_UNSUPP_REM_FEATURE, ++ BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT); ++ ++ /* Rejected L2CAP failovers. */ ++ ble_gap_test_util_update_l2cap(¶ms, BLE_ERR_UNKNOWN_HCI_CMD, 0, ++ BLE_L2CAP_SIG_UPDATE_RSP_RESULT_REJECT); ++ ble_gap_test_util_update_l2cap(¶ms, 0, BLE_ERR_UNSUPP_REM_FEATURE, ++ BLE_L2CAP_SIG_UPDATE_RSP_RESULT_REJECT); ++ ++ /* Don't attempt L2CAP failover on other event status. */ ++ ble_gap_test_util_update_l2cap(¶ms, BLE_ERR_UNKNOWN_HCI_CMD, 0, 0); +} + +TEST_CASE(ble_gap_test_case_update_peer_good) +{ + ble_gap_test_util_update_peer(0, + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .supervision_timeout = 0, + .min_ce_len = 123, + .max_ce_len = 456, + }})); + + ble_gap_test_util_update_peer(0, + ((struct ble_gap_upd_params[]) { { + .itvl_min = 100, + .itvl_max = 100, + .supervision_timeout = 100, + .min_ce_len = 554, + .max_ce_len = 554, + }})); +} + +TEST_CASE(ble_gap_test_case_update_req_good) +{ + ble_gap_test_util_update_req_pos( + ((struct ble_gap_upd_params[]) { { + .itvl_min = 50, + .itvl_max = 500, + .supervision_timeout = 20, + .min_ce_len = 555, + .max_ce_len = 888, + }}), + ((struct ble_gap_upd_params[]) { { + .itvl_min = 10, + .itvl_max = 100, + .su
<TRUNCATED>