Pushes all work done in the topic-ble-llcp branch into main branch This is a refactoring of the LL control procedures; the refactored control procedures are hidden behind a KConfig option and per default disabled Goal of the refactoring: close issue Link Layer Control Procedure overhaul #15256 make it easier to add/update control procedures Refactoring consists in principal of writing explicit state machines for the control procedures. To reduce the risk of regression errors unit-tests have been added Following control procedures are implemented: Connection update procedure Channel map update procedure Encryption procedure Feature exchange procedure Version exchange procedure ACL termination procedure Connection parameters request procedure LE Ping procedure Data Length Update procedure PHY update procedure Min. nr. Of channels used procedure Constant Tone extension request procedure This is a joined work by the people listed in the signed-off-by list (in alphabetical order) Signed-off-by: Andries Kruithof Andries.Kruithof@nordicsemi.no Signed-off-by: Erik Brockhoff erbr@oticon.com Signed-off-by: Piotr Pryga piotr.pryga@nordicsemi.no Signed-off-by: Szymon Janc szymon.janc@codecoup.pl Signed-off-by: Thomas Ebert Hansen thoh@oticon.com Signed-off-by: Tommie Skriver tosk@demant.com Signed-off-by: Andries Kruithof <Andries.Kruithof@nordicsemi.no>
371 lines
11 KiB
C
371 lines
11 KiB
C
/*
|
|
* Copyright (c) 2020 Demant
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/types.h>
|
|
#include <ztest.h>
|
|
#include "kconfig.h"
|
|
|
|
/* Kconfig Cheats */
|
|
|
|
#include <bluetooth/hci.h>
|
|
#include <sys/byteorder.h>
|
|
#include <sys/slist.h>
|
|
#include <sys/util.h>
|
|
#include "hal/ccm.h"
|
|
|
|
#include "util/util.h"
|
|
#include "util/mem.h"
|
|
#include "util/memq.h"
|
|
|
|
#include "pdu.h"
|
|
#include "ll.h"
|
|
#include "ll_settings.h"
|
|
#include "ll_feat.h"
|
|
|
|
#include "lll.h"
|
|
#include "lll_df_types.h"
|
|
#include "lll_conn.h"
|
|
#include "ull_tx_queue.h"
|
|
|
|
#include "ull_conn_types.h"
|
|
#include "ull_llcp.h"
|
|
#include "ull_llcp_internal.h"
|
|
|
|
#include "helper_pdu.h"
|
|
#include "helper_util.h"
|
|
|
|
struct ll_conn conn;
|
|
|
|
static void setup(void)
|
|
{
|
|
test_setup(&conn);
|
|
}
|
|
|
|
/* +-----+ +-------+ +-----+
|
|
* | UT | | LL_A | | LT |
|
|
* +-----+ +-------+ +-----+
|
|
* | | |
|
|
* | Start | |
|
|
* | Version Exchange Proc. | |
|
|
* |--------------------------->| |
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |------------------>|
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |<------------------|
|
|
* | | |
|
|
* | Version Exchange Proc. | |
|
|
* | Complete | |
|
|
* |<---------------------------| |
|
|
* | | |
|
|
*/
|
|
void test_version_exchange_mas_loc(void)
|
|
{
|
|
uint8_t err;
|
|
struct node_tx *tx;
|
|
struct node_rx_pdu *ntf;
|
|
|
|
struct pdu_data_llctrl_version_ind local_version_ind = {
|
|
.version_number = LL_VERSION_NUMBER,
|
|
.company_id = CONFIG_BT_CTLR_COMPANY_ID,
|
|
.sub_version_number = CONFIG_BT_CTLR_SUBVERSION_NUMBER,
|
|
};
|
|
|
|
struct pdu_data_llctrl_version_ind remote_version_ind = {
|
|
.version_number = 0x55,
|
|
.company_id = 0xABCD,
|
|
.sub_version_number = 0x1234,
|
|
};
|
|
|
|
/* Role */
|
|
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
|
|
|
/* Connect */
|
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
|
|
|
/* Initiate a Version Exchange Procedure */
|
|
err = ull_cp_version_exchange(&conn);
|
|
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
|
|
|
/* Prepare */
|
|
event_prepare(&conn);
|
|
|
|
/* Tx Queue should have one LL Control PDU */
|
|
lt_rx(LL_VERSION_IND, &conn, &tx, &local_version_ind);
|
|
lt_rx_q_is_empty(&conn);
|
|
|
|
/* Rx */
|
|
lt_tx(LL_VERSION_IND, &conn, &remote_version_ind);
|
|
|
|
/* Done */
|
|
event_done(&conn);
|
|
|
|
/* There should be one host notification */
|
|
ut_rx_pdu(LL_VERSION_IND, &ntf, &remote_version_ind);
|
|
ut_rx_q_is_empty();
|
|
|
|
zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM,
|
|
"Free CTX buffers %d", ctx_buffers_free());
|
|
}
|
|
|
|
void test_version_exchange_mas_loc_2(void)
|
|
{
|
|
uint8_t err;
|
|
|
|
ull_cp_init();
|
|
ull_tx_q_init(&conn.tx_q);
|
|
ull_llcp_init(&conn);
|
|
|
|
err = ull_cp_version_exchange(&conn);
|
|
|
|
for (int i = 0U; i < CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM; i++) {
|
|
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
|
err = ull_cp_version_exchange(&conn);
|
|
}
|
|
|
|
zassert_not_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
|
|
|
zassert_equal(ctx_buffers_free(), 0, "Free CTX buffers %d", ctx_buffers_free());
|
|
}
|
|
|
|
/* +-----+ +-------+ +-----+
|
|
* | UT | | LL_A | | LT |
|
|
* +-----+ +-------+ +-----+
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |<------------------|
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |------------------>|
|
|
* | | |
|
|
*/
|
|
void test_version_exchange_mas_rem(void)
|
|
{
|
|
struct node_tx *tx;
|
|
|
|
struct pdu_data_llctrl_version_ind local_version_ind = {
|
|
.version_number = LL_VERSION_NUMBER,
|
|
.company_id = CONFIG_BT_CTLR_COMPANY_ID,
|
|
.sub_version_number = CONFIG_BT_CTLR_SUBVERSION_NUMBER,
|
|
};
|
|
|
|
struct pdu_data_llctrl_version_ind remote_version_ind = {
|
|
.version_number = 0x55,
|
|
.company_id = 0xABCD,
|
|
.sub_version_number = 0x1234,
|
|
};
|
|
|
|
/* Role */
|
|
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
|
|
|
/* Connect */
|
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
|
|
|
/* Prepare */
|
|
event_prepare(&conn);
|
|
|
|
/* Rx */
|
|
lt_tx(LL_VERSION_IND, &conn, &remote_version_ind);
|
|
|
|
/* Done */
|
|
event_done(&conn);
|
|
|
|
/* Prepare */
|
|
event_prepare(&conn);
|
|
|
|
/* Tx Queue should have one LL Control PDU */
|
|
lt_rx(LL_VERSION_IND, &conn, &tx, &local_version_ind);
|
|
lt_rx_q_is_empty(&conn);
|
|
|
|
/* Done */
|
|
event_done(&conn);
|
|
|
|
/* There should not be a host notifications */
|
|
ut_rx_q_is_empty();
|
|
|
|
zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM,
|
|
"Free CTX buffers %d", ctx_buffers_free());
|
|
}
|
|
|
|
/* +-----+ +-------+ +-----+
|
|
* | UT | | LL_A | | LT |
|
|
* +-----+ +-------+ +-----+
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |<------------------|
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |------------------>|
|
|
* | | |
|
|
* | Start | |
|
|
* | Version Exchange Proc. | |
|
|
* |--------------------------->| |
|
|
* | | |
|
|
* | Version Exchange Proc. | |
|
|
* | Complete | |
|
|
* |<---------------------------| |
|
|
* | | |
|
|
*/
|
|
void test_version_exchange_mas_rem_2(void)
|
|
{
|
|
uint8_t err;
|
|
struct node_tx *tx;
|
|
struct node_rx_pdu *ntf;
|
|
|
|
struct pdu_data_llctrl_version_ind local_version_ind = {
|
|
.version_number = LL_VERSION_NUMBER,
|
|
.company_id = CONFIG_BT_CTLR_COMPANY_ID,
|
|
.sub_version_number = CONFIG_BT_CTLR_SUBVERSION_NUMBER,
|
|
};
|
|
|
|
struct pdu_data_llctrl_version_ind remote_version_ind = {
|
|
.version_number = 0x55,
|
|
.company_id = 0xABCD,
|
|
.sub_version_number = 0x1234,
|
|
};
|
|
|
|
/* Role */
|
|
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
|
|
|
/* Connect */
|
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
|
|
|
/* Rx */
|
|
lt_tx(LL_VERSION_IND, &conn, &remote_version_ind);
|
|
|
|
/* Initiate a Version Exchange Procedure */
|
|
err = ull_cp_version_exchange(&conn);
|
|
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
|
|
|
/* Prepare */
|
|
event_prepare(&conn);
|
|
|
|
/* Tx Queue should have one LL Control PDU */
|
|
lt_rx(LL_VERSION_IND, &conn, &tx, &local_version_ind);
|
|
lt_rx_q_is_empty(&conn);
|
|
|
|
/* Done */
|
|
event_done(&conn);
|
|
|
|
/* There should be one host notification */
|
|
ut_rx_pdu(LL_VERSION_IND, &ntf, &remote_version_ind);
|
|
ut_rx_q_is_empty();
|
|
|
|
zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM,
|
|
"Free CTX buffers %d", ctx_buffers_free());
|
|
}
|
|
|
|
/* +-----+ +-------+ +-----+
|
|
* | UT | | LL_A | | LT |
|
|
* +-----+ +-------+ +-----+
|
|
* | | |
|
|
* | Start | |
|
|
* | Version Exchange Proc. | |
|
|
* |--------------------------->| |
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |------------------>|
|
|
* | | |
|
|
* | | LL_VERSION_IND |
|
|
* | |<------------------|
|
|
* | | |
|
|
* | Version Exchange Proc. | |
|
|
* | Complete | |
|
|
* |<---------------------------| |
|
|
* | Start | |
|
|
* | Version Exchange Proc. | |
|
|
* |--------------------------->| |
|
|
* | | |
|
|
* | Version Exchange Proc. | |
|
|
* | Complete | |
|
|
* |<---------------------------| |
|
|
* | | |
|
|
*/
|
|
void test_version_exchange_mas_loc_twice(void)
|
|
{
|
|
uint8_t err;
|
|
struct node_tx *tx;
|
|
struct node_rx_pdu *ntf;
|
|
|
|
struct pdu_data_llctrl_version_ind local_version_ind = {
|
|
.version_number = LL_VERSION_NUMBER,
|
|
.company_id = CONFIG_BT_CTLR_COMPANY_ID,
|
|
.sub_version_number = CONFIG_BT_CTLR_SUBVERSION_NUMBER,
|
|
};
|
|
|
|
struct pdu_data_llctrl_version_ind remote_version_ind = {
|
|
.version_number = 0x55,
|
|
.company_id = 0xABCD,
|
|
.sub_version_number = 0x1234,
|
|
};
|
|
|
|
/* Role */
|
|
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
|
|
|
/* Connect */
|
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
|
|
|
/* Initiate a Version Exchange Procedure */
|
|
err = ull_cp_version_exchange(&conn);
|
|
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
|
|
|
/* Initiate a Version Exchange Procedure */
|
|
err = ull_cp_version_exchange(&conn);
|
|
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
|
|
|
/* Prepare */
|
|
event_prepare(&conn);
|
|
|
|
/* Tx Queue should have one LL Control PDU */
|
|
lt_rx(LL_VERSION_IND, &conn, &tx, &local_version_ind);
|
|
lt_rx_q_is_empty(&conn);
|
|
|
|
/* Rx */
|
|
lt_tx(LL_VERSION_IND, &conn, &remote_version_ind);
|
|
|
|
/* Done */
|
|
event_done(&conn);
|
|
|
|
/* There should be one host notification */
|
|
ut_rx_pdu(LL_VERSION_IND, &ntf, &remote_version_ind);
|
|
ut_rx_q_is_empty();
|
|
|
|
/* Prepare */
|
|
event_prepare(&conn);
|
|
|
|
/* Done */
|
|
event_done(&conn);
|
|
|
|
/* Cached values should be used, no over the air comm */
|
|
lt_rx_q_is_empty(&conn);
|
|
|
|
/* There should be one host notification */
|
|
ut_rx_pdu(LL_VERSION_IND, &ntf, &remote_version_ind);
|
|
ut_rx_q_is_empty();
|
|
|
|
/* Note that one context buffer is not freed for this test */
|
|
zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1,
|
|
"Free CTX buffers %d", ctx_buffers_free());
|
|
}
|
|
|
|
void test_main(void)
|
|
{
|
|
ztest_test_suite(version_exchange,
|
|
ztest_unit_test_setup_teardown(test_version_exchange_mas_loc, setup,
|
|
unit_test_noop),
|
|
ztest_unit_test_setup_teardown(test_version_exchange_mas_loc_2, setup,
|
|
unit_test_noop),
|
|
ztest_unit_test_setup_teardown(test_version_exchange_mas_rem, setup,
|
|
unit_test_noop),
|
|
ztest_unit_test_setup_teardown(test_version_exchange_mas_rem_2, setup,
|
|
unit_test_noop),
|
|
ztest_unit_test_setup_teardown(test_version_exchange_mas_loc_twice, setup,
|
|
unit_test_noop));
|
|
|
|
ztest_run_test_suite(version_exchange);
|
|
}
|