2018-02-09 17:26:24

by Łukasz Rymanowski

[permalink] [raw]
Subject: [PATCH BlueZ 0/3] mgmt-tested: Advertising while connected testcases

This set adds testcases which tests kernel patch:

9e1e9f20ca96 Bluetooth: Add support to advertise when connected
and fix to above:
[PATCH] Bluetooth: Fix incorrect bits for LE states

Not sure if it fits to mgmt-tester. If not let me know where it
should go.

Łukasz Rymanowski (3):
emulator: Add initial LE states to btdev and API to set new one
mgmt-tester: Add test_le_full
mgmt-tester: Add testcases for advertising while connected

emulator/btdev.c | 18 +++
emulator/btdev.h | 3 +-
emulator/hciemu.c | 8 ++
emulator/hciemu.h | 3 +
tools/mgmt-tester.c | 372 ++++++++++++++++++++++++++++++++++++++++++++--------
5 files changed, 346 insertions(+), 58 deletions(-)

--
2.14.1



2018-02-12 09:09:09

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH BlueZ 1/3] emulator: Add initial LE states to btdev and API to set new one

Hi =C5=81ukasz,

On Friday, 9 February 2018 18:26:25 CET =C5=81ukasz Rymanowski wrote:
> ---
> emulator/btdev.c | 18 ++++++++++++++++++
> emulator/btdev.h | 3 ++-
> emulator/hciemu.c | 8 ++++++++
> emulator/hciemu.h | 3 +++
> 4 files changed, 31 insertions(+), 1 deletion(-)
>=20
> diff --git a/emulator/btdev.c b/emulator/btdev.c
> index a9b225a24..69d84a5fc 100644
> --- a/emulator/btdev.c
> +++ b/emulator/btdev.c
> @@ -570,6 +570,17 @@ static void set_le_features(struct btdev *btdev)
> btdev->le_features[0] |=3D 0x08; /* Slave-initiated Features Exchange */
> }
>=20
> +static void set_le_states(struct btdev *btdev)
> +{
> + /* Set all 41 bits as per Bluetooth 5.0 specification */
> + btdev->le_states[0] =3D 0xff;
> + btdev->le_states[1] =3D 0xff;
> + btdev->le_states[2] =3D 0xff;
> + btdev->le_states[3] =3D 0xff;
> + btdev->le_states[4] =3D 0xff;
> + btdev->le_states[5] =3D 0x03;
> +}
> +
> static void set_amp_features(struct btdev *btdev)
> {
> }
> @@ -603,6 +614,7 @@ struct btdev *btdev_create(enum btdev_type type,
> uint16_t id) btdev->version =3D 0x09;
> set_bredrle_features(btdev);
> set_bredrle_commands(btdev);
> + set_le_states(btdev);
> break;
> case BTDEV_TYPE_BREDR:
> btdev->version =3D 0x05;
> @@ -613,6 +625,7 @@ struct btdev *btdev_create(enum btdev_type type,
> uint16_t id) btdev->version =3D 0x09;
> set_le_features(btdev);
> set_le_commands(btdev);
> + set_le_states(btdev);
> break;
> case BTDEV_TYPE_AMP:
> btdev->version =3D 0x01;
> @@ -685,6 +698,11 @@ uint8_t btdev_get_le_scan_enable(struct btdev *btdev)
> return btdev->le_scan_enable;
> }
>=20
> +void btdev_set_le_states(struct btdev *btdev, const uint8_t *le_states)
> +{
> + memcpy(btdev->le_states, le_states, sizeof(btdev->le_states));
> +}
> +
> static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
> {
> if (btdev1->auth_enable || btdev2->auth_enable)
> diff --git a/emulator/btdev.h b/emulator/btdev.h
> index 40c72199b..ba06a1015 100644
> --- a/emulator/btdev.h
> +++ b/emulator/btdev.h
> @@ -84,12 +84,13 @@ uint8_t btdev_get_scan_enable(struct btdev *btdev);
>=20
> uint8_t btdev_get_le_scan_enable(struct btdev *btdev);
>=20
> +void btdev_set_le_states(struct btdev *btdev, const uint8_t *le_states);
> +
> void btdev_set_command_handler(struct btdev *btdev, btdev_command_func
> handler, void *user_data);
>=20
> void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
> void *user_data);
> -
> void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t le=
n);
>=20
> int btdev_add_hook(struct btdev *btdev, enum btdev_hook_type type,
> diff --git a/emulator/hciemu.c b/emulator/hciemu.c
> index 7debb8f27..1787a6c0d 100644
> --- a/emulator/hciemu.c
> +++ b/emulator/hciemu.c
> @@ -444,6 +444,14 @@ uint8_t hciemu_get_master_le_scan_enable(struct hcie=
mu
> *hciemu) return btdev_get_le_scan_enable(hciemu->master_dev);
> }
>=20
> +void hciemu_set_master_le_states(struct hciemu *hciemu, const uint8_t
> *le_states) +{
> + if (!hciemu || !hciemu->master_dev)
> + return;
> +
> + btdev_set_le_states(hciemu->master_dev, le_states);
> +}
> +
> bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
> hciemu_command_func_t function, void *user_data)
> {
> diff --git a/emulator/hciemu.h b/emulator/hciemu.h
> index 783f99cf1..5c0c4c306 100644
> --- a/emulator/hciemu.h
> +++ b/emulator/hciemu.h
> @@ -57,6 +57,9 @@ uint8_t hciemu_get_master_scan_enable(struct hciemu
> *hciemu);
>=20
> uint8_t hciemu_get_master_le_scan_enable(struct hciemu *hciemu);
>=20
> +void hciemu_set_master_le_states(struct hciemu *hciemu,
> + const uint8_t *le_states);
> +
> typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
> uint8_t len, void *user_data);

Patches 1 and 2 are now applied, thanks.

=2D-=20
pozdrawiam
Szymon Janc



2018-02-12 09:06:13

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH BlueZ 3/3] mgmt-tester: Add testcases for advertising while connected

Hi =C5=81ukasz,

On Friday, 9 February 2018 18:26:27 CET =C5=81ukasz Rymanowski wrote:
> This patch adds testcases which verifies if Linux Kernel properly
> enables advertising while is connected (LE) based on supported LE states
> in the controller
> ---
> tools/mgmt-tester.c | 365
> ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 310
> insertions(+), 55 deletions(-)
>=20
> diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
> index 191c1cd4d..1be245c84 100644
> --- a/tools/mgmt-tester.c
> +++ b/tools/mgmt-tester.c
> @@ -28,6 +28,8 @@
> #include <stdlib.h>
> #include <stdbool.h>
> #include <sys/ioctl.h>
> +#include <errno.h>
> +#include <unistd.h>
>=20
> #include <glib.h>
>=20
> @@ -35,6 +37,7 @@
> #include "lib/hci.h"
> #include "lib/hci_lib.h"
> #include "lib/mgmt.h"
> +#include "lib/l2cap.h"
>=20
> #include "monitor/bt.h"
> #include "emulator/bthost.h"
> @@ -64,6 +67,7 @@ struct test_data {
> enum hciemu_type hciemu_type;
> int unmet_conditions;
> int unmet_setup_conditions;
> + int sk;
> };
>=20
> static void mgmt_debug(const char *str, void *user_data)
> @@ -211,10 +215,68 @@ static void index_removed_callback(uint16_t index,
> uint16_t length, tester_post_teardown_complete();
> }
>=20
> +struct generic_data {
> + bool setup_le_states;
> + const uint8_t *le_states;
> + const uint16_t *setup_settings;
> + bool setup_nobredr;
> + bool setup_limited_discov;
> + uint16_t setup_expect_hci_command;
> + const void *setup_expect_hci_param;
> + uint8_t setup_expect_hci_len;
> + uint16_t setup_send_opcode;
> + const void *setup_send_param;
> + uint16_t setup_send_len;
> + const struct setup_mgmt_cmd *setup_mgmt_cmd_arr;
> + bool send_index_none;
> + uint16_t send_opcode;
> + const void *send_param;
> + uint16_t send_len;
> + const void * (*send_func)(uint16_t *len);
> + uint8_t expect_status;
> + bool expect_ignore_param;
> + const void *expect_param;
> + uint16_t expect_len;
> + const void * (*expect_func)(uint16_t *len);
> + uint32_t expect_settings_set;
> + uint32_t expect_settings_unset;
> + uint16_t expect_alt_ev;
> + const void *expect_alt_ev_param;
> + bool (*verify_alt_ev_func)(const void *param, uint16_t length);
> + uint16_t expect_alt_ev_len;
> + uint16_t expect_hci_command;
> + const void *expect_hci_param;
> + uint8_t expect_hci_len;
> + const void * (*expect_hci_func)(uint8_t *len);
> + bool expect_pin;
> + uint8_t pin_len;
> + const void *pin;
> + uint8_t client_pin_len;
> + const void *client_pin;
> + bool client_enable_ssp;
> + uint8_t io_cap;
> + uint8_t client_io_cap;
> + uint8_t client_auth_req;
> + bool reject_confirm;
> + bool client_reject_confirm;
> + bool just_works;
> + bool client_enable_le;
> + bool client_enable_sc;
> + bool client_enable_adv;
> + bool expect_sc_key;
> + bool force_power_off;
> + bool addr_type_avail;
> + uint8_t addr_type;
> + bool set_adv;
> + const uint8_t *adv_data;
> + uint8_t adv_data_len;
> +};
> +
> static void read_index_list_callback(uint8_t status, uint16_t length,
> const void *param, void *user_data)
> {
> struct test_data *data =3D tester_get_data();
> + const struct generic_data *test =3D data->test_data;
>=20
> tester_print("Read Index List callback");
> tester_print(" Status: %s (0x%02x)", mgmt_errstr(status), status);
> @@ -235,6 +297,9 @@ static void read_index_list_callback(uint8_t status,
> uint16_t length, tester_warn("Failed to setup HCI emulation");
> tester_pre_setup_failed();
> }
> +
> + if (test && test->setup_le_states)
> + hciemu_set_master_le_states(data->hciemu, test->le_states);
> }
>=20
> static void test_pre_setup(const void *test_data)
> @@ -271,12 +336,17 @@ static void test_pre_setup(const void *test_data)
>=20
> mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
> read_index_list_callback, NULL, NULL);
> +
> + data->sk =3D -1;
> }
>=20
> static void test_post_teardown(const void *test_data)
> {
> struct test_data *data =3D tester_get_data();
>=20
> + if (data->sk >=3D 0)
> + close(data->sk);
> +
> hciemu_unref(data->hciemu);
> data->hciemu =3D NULL;
> }
> @@ -403,61 +473,6 @@ struct setup_mgmt_cmd {
> uint16_t send_len;
> };
>=20
> -struct generic_data {
> - const uint16_t *setup_settings;
> - bool setup_nobredr;
> - bool setup_limited_discov;
> - uint16_t setup_expect_hci_command;
> - const void *setup_expect_hci_param;
> - uint8_t setup_expect_hci_len;
> - uint16_t setup_send_opcode;
> - const void *setup_send_param;
> - uint16_t setup_send_len;
> - const struct setup_mgmt_cmd *setup_mgmt_cmd_arr;
> - bool send_index_none;
> - uint16_t send_opcode;
> - const void *send_param;
> - uint16_t send_len;
> - const void * (*send_func)(uint16_t *len);
> - uint8_t expect_status;
> - bool expect_ignore_param;
> - const void *expect_param;
> - uint16_t expect_len;
> - const void * (*expect_func)(uint16_t *len);
> - uint32_t expect_settings_set;
> - uint32_t expect_settings_unset;
> - uint16_t expect_alt_ev;
> - const void *expect_alt_ev_param;
> - bool (*verify_alt_ev_func)(const void *param, uint16_t length);
> - uint16_t expect_alt_ev_len;
> - uint16_t expect_hci_command;
> - const void *expect_hci_param;
> - uint8_t expect_hci_len;
> - const void * (*expect_hci_func)(uint8_t *len);
> - bool expect_pin;
> - uint8_t pin_len;
> - const void *pin;
> - uint8_t client_pin_len;
> - const void *client_pin;
> - bool client_enable_ssp;
> - uint8_t io_cap;
> - uint8_t client_io_cap;
> - uint8_t client_auth_req;
> - bool reject_confirm;
> - bool client_reject_confirm;
> - bool just_works;
> - bool client_enable_le;
> - bool client_enable_sc;
> - bool client_enable_adv;
> - bool expect_sc_key;
> - bool force_power_off;
> - bool addr_type_avail;
> - uint8_t addr_type;
> - bool set_adv;
> - const uint8_t *adv_data;
> - uint8_t adv_data_len;
> -};
> -
> static const char dummy_data[] =3D { 0x00 };
>=20
> static const struct generic_data invalid_command_test =3D {
> @@ -5002,6 +5017,45 @@ static const struct generic_data
> read_local_oob_success_sc_test =3D { .expect_hci_command =3D
> BT_HCI_CMD_READ_LOCAL_OOB_EXT_DATA,
> };
>=20
> +static uint8_t le_states_conn_slave_adv_connectable[] =3D {
> + 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x00};
> +static uint8_t le_states_conn_slave_adv_non_connectable[] =3D {
> + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00};
> +static uint8_t le_states_conn_master_adv_connectable[] =3D {
> + 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00};
> +static uint8_t le_states_conn_master_adv_non_connectable[] =3D {
> + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
> +

Could be static const.


> +static const struct generic_data conn_slave_adv_conneactable_test =3D {
> + .setup_le_states =3D true,
> + .le_states =3D le_states_conn_slave_adv_connectable,
> + .setup_settings =3D settings_powered_le,
> + .client_enable_le =3D true
> +};
> +
> +static const struct generic_data conn_slave_adv_non_conneactable_test =
=3D {
> + .setup_le_states =3D true,
> + .le_states =3D le_states_conn_slave_adv_non_connectable,
> + .setup_settings =3D settings_powered_le,
> + .client_enable_le =3D true
> +};
> +
> +static const struct generic_data conn_master_adv_conneactable_test =3D {
> + .setup_le_states =3D true,
> + .le_states =3D le_states_conn_master_adv_connectable,
> + .setup_settings =3D settings_powered_le,
> + .client_enable_le =3D true,
> + .client_enable_adv =3D 1
> +};
> +
> +static const struct generic_data conn_master_adv_non_conneactable_test =
=3D {
> + .setup_le_states =3D true,
> + .le_states =3D le_states_conn_master_adv_non_connectable,
> + .setup_settings =3D settings_powered_le,
> + .client_enable_le =3D true,
> + .client_enable_adv =3D 1
> +};
> +
> static const char ext_ctrl_info1[] =3D {
> 0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, /* btaddr */
> 0x09, /* version */
> @@ -5671,6 +5725,77 @@ static void setup_add_advertising_connectable(const
> void *test_data) NULL, NULL);
> }
>=20
> +static int create_le_att_sock(struct test_data *data)
> +{
> + struct sockaddr_l2 addr;
> + int sk, err;
> +
> + sk =3D socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK,
> + BTPROTO_L2CAP);
> + if (sk < 0) {
> + err =3D -errno;
> + tester_warn("Can't create socket: %s (%d)", strerror(errno),
> + errno);
> + return err;
> + }
> +
> + memset(&addr, 0, sizeof(addr));
> + addr.l2_family =3D AF_BLUETOOTH;
> + addr.l2_psm =3D 0;
> + addr.l2_cid =3D htobs(0x0004);
> + addr.l2_bdaddr_type =3D BDADDR_LE_PUBLIC;
> +
> + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> + err =3D -errno;
> + tester_warn("Can't bind socket: %s (%d)", strerror(errno),
> + errno);
> + close(sk);
> + return err;
> + }
> +
> + if (listen(sk, 1) < 0) {
> + err =3D -errno;
> + tester_warn("Can't bind socket: %s (%d)", strerror(errno),
> + errno);
> + close(sk);
> + return err;
> + }
> +
> + data->sk =3D sk;
> +
> + return sk;
> +}
> +
> +static void setup_advertise_while_connected(const void *test_data)
> +{
> + struct test_data *data =3D tester_get_data();
> + struct mgmt_cp_add_advertising *cp;
> + unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];

uint8_t

> +
> + tester_print("Adding advertising instances");
> +
> + cp =3D (struct mgmt_cp_add_advertising *) adv_param;
> + setup_add_adv_param(cp, 1);
> +
> + cp->flags |=3D MGMT_ADV_FLAG_CONNECTABLE;
> + mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
> + sizeof(adv_param), adv_param,
> + NULL, NULL, NULL);
> +
> + cp->flags &=3D ~MGMT_ADV_FLAG_CONNECTABLE;
> + cp->instance =3D 2;
> +
> + mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
> + sizeof(adv_param), adv_param,
> + setup_add_advertising_callback,
> + NULL, NULL);
> +
> + /* Listen on the socket so Kernel does not drop connection just after
> + * connect. Socket is closed in test_post_teardown
> + */
> + create_le_att_sock(data);
> +}
> +
> static void setup_add_advertising_timeout(const void *test_data)
> {
> struct test_data *data =3D tester_get_data();
> @@ -6982,6 +7107,116 @@ static void test_command_generic_connect(const vo=
id
> *test_data) bthost_hci_connect(bthost, master_bdaddr, addr_type);
> }
>=20
> +static bool test_adv_enable_hook(const void *data, uint16_t len,
> + void *user_data)
> +{
> + struct test_data *test_data =3D user_data;
> + const uint8_t *status =3D data;
> +
> + if (*status =3D=3D 0) {
> + tester_print("Advertising enabled");
> + test_condition_complete(test_data);
> + } else {
> + tester_print("Advertising enabled error 0x%02x", *status);
> + }
> +
> + return true;
> +}
> +
> +static void disconnected_event(uint16_t index, uint16_t length,
> + const void *param, void *user_data)
> +{
> + tester_test_failed();
> +}
> +
> +static void le_connected_event(uint16_t index, uint16_t length,
> + const void *param, void *user_data)
> +{
> + struct test_data *data =3D tester_get_data();
> +
> + tester_print("Device connected");
> +
> + test_add_condition(data);
> + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_CMD,
> + BT_HCI_CMD_LE_SET_ADV_ENABLE,
> + test_adv_enable_hook, data);
> +
> + /* Make sure we get not disconnected during the testaces */
> + mgmt_register(data->mgmt_alt, MGMT_EV_DEVICE_DISCONNECTED,
> + data->mgmt_index, disconnected_event,
> +
> + NULL, NULL);
> +
> + test_condition_complete(data);
> +}
> +
> +static void add_device_callback(uint8_t status, uint16_t len, const void
> *param, + void *user_data)
> +{
> + struct test_data *data =3D user_data;
> + const struct generic_data *test =3D data->test_data;
> + struct bthost *bthost;
> + const uint8_t *master_bdaddr;
> +
> + if (status !=3D 0)
> + tester_test_failed();

missign return here?

> +
> + tester_print("Device added");
> +
> + /* If advertising is enabled on client that means we can stop here and
> + * just wait for connection
> + */
> + if (test->client_enable_adv)
> + return;
> +
> + master_bdaddr =3D hciemu_get_master_bdaddr(data->hciemu);
> + if (!master_bdaddr) {
> + tester_warn("No master bdaddr");
> + tester_test_failed();
> + return;
> + }
> +
> + bthost =3D hciemu_client_get_host(data->hciemu);
> + bthost_hci_connect(bthost, master_bdaddr, BDADDR_LE_PUBLIC);
> +}
> +
> +static void test_connected_and_advertising(const void *test_data)
> +{
> + struct test_data *data =3D tester_get_data();
> + const struct generic_data *test =3D data->test_data;
> + const uint8_t *client_bdaddr;
> + struct mgmt_cp_add_device cp;
> +
> + tester_print("Registering %s notification",
> + mgmt_evstr(MGMT_EV_DEVICE_CONNECTED));
> +
> + test_add_condition(data);
> + mgmt_register(data->mgmt_alt, MGMT_EV_DEVICE_CONNECTED,
> + data->mgmt_index, le_connected_event,
> + NULL, NULL);
> +
> + client_bdaddr =3D hciemu_get_client_bdaddr(data->hciemu);
> + if (!client_bdaddr) {
> + tester_warn("No client bdaddr");
> + tester_test_failed();
> + return;
> + }
> +
> + memset(&cp, 0, sizeof(cp));
> + memcpy(&cp.addr.bdaddr, client_bdaddr, 6);
> + cp.addr.type =3D BDADDR_LE_PUBLIC;
> +
> + if (test->client_enable_adv)
> + cp.action =3D 0x02; // Auto connect
> + else
> + cp.action =3D 0x01; // Allow incoming connection

No C++ style comments.

> +
> + mgmt_send(data->mgmt_alt, MGMT_OP_ADD_DEVICE, data->mgmt_index,
> + sizeof(cp), &cp,
> + add_device_callback,
> + data, NULL);
> +}
> +
> int main(int argc, char *argv[])
> {
> tester_init(&argc, &argv);
> @@ -8004,6 +8239,26 @@ int main(int argc, char *argv[])
> setup_command_generic,
> test_command_generic);
>=20
> + test_le_full("Adv. connectable & connected (slave) - Success",
> + &conn_slave_adv_conneactable_test,
> + setup_advertise_while_connected,
> + test_connected_and_advertising, 10);
> +
> + test_le_full("Adv. non-connectable & connected (slave) - Success",
> + &conn_slave_adv_non_conneactable_test,
> + setup_advertise_while_connected,
> + test_connected_and_advertising, 10);
> +
> + test_le_full("Adv. connectable & connected (master) - Success",
> + &conn_master_adv_conneactable_test,
> + setup_advertise_while_connected,
> + test_connected_and_advertising, 10);
> +
> + test_le_full("Adv. non-connectable & connected (master) - Success",
> + &conn_master_adv_non_conneactable_test,
> + setup_advertise_while_connected,
> + test_connected_and_advertising, 10);
> +
> test_bredrle("Remove Advertising - Invalid Params 1",
> &remove_advertising_fail_1,
> NULL, test_command_generic);


=2D-=20
pozdrawiam
Szymon Janc



2018-02-09 17:26:27

by Łukasz Rymanowski

[permalink] [raw]
Subject: [PATCH BlueZ 3/3] mgmt-tester: Add testcases for advertising while connected

This patch adds testcases which verifies if Linux Kernel properly
enables advertising while is connected (LE) based on supported LE states
in the controller
---
tools/mgmt-tester.c | 365 ++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 310 insertions(+), 55 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 191c1cd4d..1be245c84 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -28,6 +28,8 @@
#include <stdlib.h>
#include <stdbool.h>
#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>

#include <glib.h>

@@ -35,6 +37,7 @@
#include "lib/hci.h"
#include "lib/hci_lib.h"
#include "lib/mgmt.h"
+#include "lib/l2cap.h"

#include "monitor/bt.h"
#include "emulator/bthost.h"
@@ -64,6 +67,7 @@ struct test_data {
enum hciemu_type hciemu_type;
int unmet_conditions;
int unmet_setup_conditions;
+ int sk;
};

static void mgmt_debug(const char *str, void *user_data)
@@ -211,10 +215,68 @@ static void index_removed_callback(uint16_t index, uint16_t length,
tester_post_teardown_complete();
}

+struct generic_data {
+ bool setup_le_states;
+ const uint8_t *le_states;
+ const uint16_t *setup_settings;
+ bool setup_nobredr;
+ bool setup_limited_discov;
+ uint16_t setup_expect_hci_command;
+ const void *setup_expect_hci_param;
+ uint8_t setup_expect_hci_len;
+ uint16_t setup_send_opcode;
+ const void *setup_send_param;
+ uint16_t setup_send_len;
+ const struct setup_mgmt_cmd *setup_mgmt_cmd_arr;
+ bool send_index_none;
+ uint16_t send_opcode;
+ const void *send_param;
+ uint16_t send_len;
+ const void * (*send_func)(uint16_t *len);
+ uint8_t expect_status;
+ bool expect_ignore_param;
+ const void *expect_param;
+ uint16_t expect_len;
+ const void * (*expect_func)(uint16_t *len);
+ uint32_t expect_settings_set;
+ uint32_t expect_settings_unset;
+ uint16_t expect_alt_ev;
+ const void *expect_alt_ev_param;
+ bool (*verify_alt_ev_func)(const void *param, uint16_t length);
+ uint16_t expect_alt_ev_len;
+ uint16_t expect_hci_command;
+ const void *expect_hci_param;
+ uint8_t expect_hci_len;
+ const void * (*expect_hci_func)(uint8_t *len);
+ bool expect_pin;
+ uint8_t pin_len;
+ const void *pin;
+ uint8_t client_pin_len;
+ const void *client_pin;
+ bool client_enable_ssp;
+ uint8_t io_cap;
+ uint8_t client_io_cap;
+ uint8_t client_auth_req;
+ bool reject_confirm;
+ bool client_reject_confirm;
+ bool just_works;
+ bool client_enable_le;
+ bool client_enable_sc;
+ bool client_enable_adv;
+ bool expect_sc_key;
+ bool force_power_off;
+ bool addr_type_avail;
+ uint8_t addr_type;
+ bool set_adv;
+ const uint8_t *adv_data;
+ uint8_t adv_data_len;
+};
+
static void read_index_list_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;

tester_print("Read Index List callback");
tester_print(" Status: %s (0x%02x)", mgmt_errstr(status), status);
@@ -235,6 +297,9 @@ static void read_index_list_callback(uint8_t status, uint16_t length,
tester_warn("Failed to setup HCI emulation");
tester_pre_setup_failed();
}
+
+ if (test && test->setup_le_states)
+ hciemu_set_master_le_states(data->hciemu, test->le_states);
}

static void test_pre_setup(const void *test_data)
@@ -271,12 +336,17 @@ static void test_pre_setup(const void *test_data)

mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
read_index_list_callback, NULL, NULL);
+
+ data->sk = -1;
}

static void test_post_teardown(const void *test_data)
{
struct test_data *data = tester_get_data();

+ if (data->sk >= 0)
+ close(data->sk);
+
hciemu_unref(data->hciemu);
data->hciemu = NULL;
}
@@ -403,61 +473,6 @@ struct setup_mgmt_cmd {
uint16_t send_len;
};

-struct generic_data {
- const uint16_t *setup_settings;
- bool setup_nobredr;
- bool setup_limited_discov;
- uint16_t setup_expect_hci_command;
- const void *setup_expect_hci_param;
- uint8_t setup_expect_hci_len;
- uint16_t setup_send_opcode;
- const void *setup_send_param;
- uint16_t setup_send_len;
- const struct setup_mgmt_cmd *setup_mgmt_cmd_arr;
- bool send_index_none;
- uint16_t send_opcode;
- const void *send_param;
- uint16_t send_len;
- const void * (*send_func)(uint16_t *len);
- uint8_t expect_status;
- bool expect_ignore_param;
- const void *expect_param;
- uint16_t expect_len;
- const void * (*expect_func)(uint16_t *len);
- uint32_t expect_settings_set;
- uint32_t expect_settings_unset;
- uint16_t expect_alt_ev;
- const void *expect_alt_ev_param;
- bool (*verify_alt_ev_func)(const void *param, uint16_t length);
- uint16_t expect_alt_ev_len;
- uint16_t expect_hci_command;
- const void *expect_hci_param;
- uint8_t expect_hci_len;
- const void * (*expect_hci_func)(uint8_t *len);
- bool expect_pin;
- uint8_t pin_len;
- const void *pin;
- uint8_t client_pin_len;
- const void *client_pin;
- bool client_enable_ssp;
- uint8_t io_cap;
- uint8_t client_io_cap;
- uint8_t client_auth_req;
- bool reject_confirm;
- bool client_reject_confirm;
- bool just_works;
- bool client_enable_le;
- bool client_enable_sc;
- bool client_enable_adv;
- bool expect_sc_key;
- bool force_power_off;
- bool addr_type_avail;
- uint8_t addr_type;
- bool set_adv;
- const uint8_t *adv_data;
- uint8_t adv_data_len;
-};
-
static const char dummy_data[] = { 0x00 };

static const struct generic_data invalid_command_test = {
@@ -5002,6 +5017,45 @@ static const struct generic_data read_local_oob_success_sc_test = {
.expect_hci_command = BT_HCI_CMD_READ_LOCAL_OOB_EXT_DATA,
};

+static uint8_t le_states_conn_slave_adv_connectable[] = {
+ 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x00};
+static uint8_t le_states_conn_slave_adv_non_connectable[] = {
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00};
+static uint8_t le_states_conn_master_adv_connectable[] = {
+ 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00};
+static uint8_t le_states_conn_master_adv_non_connectable[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const struct generic_data conn_slave_adv_conneactable_test = {
+ .setup_le_states = true,
+ .le_states = le_states_conn_slave_adv_connectable,
+ .setup_settings = settings_powered_le,
+ .client_enable_le = true
+};
+
+static const struct generic_data conn_slave_adv_non_conneactable_test = {
+ .setup_le_states = true,
+ .le_states = le_states_conn_slave_adv_non_connectable,
+ .setup_settings = settings_powered_le,
+ .client_enable_le = true
+};
+
+static const struct generic_data conn_master_adv_conneactable_test = {
+ .setup_le_states = true,
+ .le_states = le_states_conn_master_adv_connectable,
+ .setup_settings = settings_powered_le,
+ .client_enable_le = true,
+ .client_enable_adv = 1
+};
+
+static const struct generic_data conn_master_adv_non_conneactable_test = {
+ .setup_le_states = true,
+ .le_states = le_states_conn_master_adv_non_connectable,
+ .setup_settings = settings_powered_le,
+ .client_enable_le = true,
+ .client_enable_adv = 1
+};
+
static const char ext_ctrl_info1[] = {
0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, /* btaddr */
0x09, /* version */
@@ -5671,6 +5725,77 @@ static void setup_add_advertising_connectable(const void *test_data)
NULL, NULL);
}

+static int create_le_att_sock(struct test_data *data)
+{
+ struct sockaddr_l2 addr;
+ int sk, err;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK,
+ BTPROTO_L2CAP);
+ if (sk < 0) {
+ err = -errno;
+ tester_warn("Can't create socket: %s (%d)", strerror(errno),
+ errno);
+ return err;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ addr.l2_psm = 0;
+ addr.l2_cid = htobs(0x0004);
+ addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = -errno;
+ tester_warn("Can't bind socket: %s (%d)", strerror(errno),
+ errno);
+ close(sk);
+ return err;
+ }
+
+ if (listen(sk, 1) < 0) {
+ err = -errno;
+ tester_warn("Can't bind socket: %s (%d)", strerror(errno),
+ errno);
+ close(sk);
+ return err;
+ }
+
+ data->sk = sk;
+
+ return sk;
+}
+
+static void setup_advertise_while_connected(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct mgmt_cp_add_advertising *cp;
+ unsigned char adv_param[sizeof(*cp) + TESTER_ADD_ADV_DATA_LEN];
+
+ tester_print("Adding advertising instances");
+
+ cp = (struct mgmt_cp_add_advertising *) adv_param;
+ setup_add_adv_param(cp, 1);
+
+ cp->flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ NULL, NULL, NULL);
+
+ cp->flags &= ~MGMT_ADV_FLAG_CONNECTABLE;
+ cp->instance = 2;
+
+ mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+ sizeof(adv_param), adv_param,
+ setup_add_advertising_callback,
+ NULL, NULL);
+
+ /* Listen on the socket so Kernel does not drop connection just after
+ * connect. Socket is closed in test_post_teardown
+ */
+ create_le_att_sock(data);
+}
+
static void setup_add_advertising_timeout(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -6982,6 +7107,116 @@ static void test_command_generic_connect(const void *test_data)
bthost_hci_connect(bthost, master_bdaddr, addr_type);
}

+static bool test_adv_enable_hook(const void *data, uint16_t len,
+ void *user_data)
+{
+ struct test_data *test_data = user_data;
+ const uint8_t *status = data;
+
+ if (*status == 0) {
+ tester_print("Advertising enabled");
+ test_condition_complete(test_data);
+ } else {
+ tester_print("Advertising enabled error 0x%02x", *status);
+ }
+
+ return true;
+}
+
+static void disconnected_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ tester_test_failed();
+}
+
+static void le_connected_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Device connected");
+
+ test_add_condition(data);
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_CMD,
+ BT_HCI_CMD_LE_SET_ADV_ENABLE,
+ test_adv_enable_hook, data);
+
+ /* Make sure we get not disconnected during the testaces */
+ mgmt_register(data->mgmt_alt, MGMT_EV_DEVICE_DISCONNECTED,
+ data->mgmt_index, disconnected_event,
+
+ NULL, NULL);
+
+ test_condition_complete(data);
+}
+
+static void add_device_callback(uint8_t status, uint16_t len, const void *param,
+ void *user_data)
+{
+ struct test_data *data = user_data;
+ const struct generic_data *test = data->test_data;
+ struct bthost *bthost;
+ const uint8_t *master_bdaddr;
+
+ if (status != 0)
+ tester_test_failed();
+
+ tester_print("Device added");
+
+ /* If advertising is enabled on client that means we can stop here and
+ * just wait for connection
+ */
+ if (test->client_enable_adv)
+ return;
+
+ master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
+ if (!master_bdaddr) {
+ tester_warn("No master bdaddr");
+ tester_test_failed();
+ return;
+ }
+
+ bthost = hciemu_client_get_host(data->hciemu);
+ bthost_hci_connect(bthost, master_bdaddr, BDADDR_LE_PUBLIC);
+}
+
+static void test_connected_and_advertising(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
+ const uint8_t *client_bdaddr;
+ struct mgmt_cp_add_device cp;
+
+ tester_print("Registering %s notification",
+ mgmt_evstr(MGMT_EV_DEVICE_CONNECTED));
+
+ test_add_condition(data);
+ mgmt_register(data->mgmt_alt, MGMT_EV_DEVICE_CONNECTED,
+ data->mgmt_index, le_connected_event,
+ NULL, NULL);
+
+ client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+ if (!client_bdaddr) {
+ tester_warn("No client bdaddr");
+ tester_test_failed();
+ return;
+ }
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.addr.bdaddr, client_bdaddr, 6);
+ cp.addr.type = BDADDR_LE_PUBLIC;
+
+ if (test->client_enable_adv)
+ cp.action = 0x02; // Auto connect
+ else
+ cp.action = 0x01; // Allow incoming connection
+
+ mgmt_send(data->mgmt_alt, MGMT_OP_ADD_DEVICE, data->mgmt_index,
+ sizeof(cp), &cp,
+ add_device_callback,
+ data, NULL);
+}
+
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
@@ -8004,6 +8239,26 @@ int main(int argc, char *argv[])
setup_command_generic,
test_command_generic);

+ test_le_full("Adv. connectable & connected (slave) - Success",
+ &conn_slave_adv_conneactable_test,
+ setup_advertise_while_connected,
+ test_connected_and_advertising, 10);
+
+ test_le_full("Adv. non-connectable & connected (slave) - Success",
+ &conn_slave_adv_non_conneactable_test,
+ setup_advertise_while_connected,
+ test_connected_and_advertising, 10);
+
+ test_le_full("Adv. connectable & connected (master) - Success",
+ &conn_master_adv_conneactable_test,
+ setup_advertise_while_connected,
+ test_connected_and_advertising, 10);
+
+ test_le_full("Adv. non-connectable & connected (master) - Success",
+ &conn_master_adv_non_conneactable_test,
+ setup_advertise_while_connected,
+ test_connected_and_advertising, 10);
+
test_bredrle("Remove Advertising - Invalid Params 1",
&remove_advertising_fail_1,
NULL, test_command_generic);
--
2.14.1


2018-02-09 17:26:26

by Łukasz Rymanowski

[permalink] [raw]
Subject: [PATCH BlueZ 2/3] mgmt-tester: Add test_le_full

---
tools/mgmt-tester.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 1078d185e..191c1cd4d 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -373,7 +373,7 @@ static void test_condition_complete(struct test_data *data)
test_post_teardown, 2, user, free); \
} while (0)

-#define test_le(name, data, setup, func) \
+#define test_le_full(name, data, setup, func, timeout) \
do { \
struct test_data *user; \
user = new0(struct test_data, 1); \
@@ -386,9 +386,12 @@ static void test_condition_complete(struct test_data *data)
user->initial_settings = 0x00000200; \
tester_add_full(name, data, \
test_pre_setup, test_setup, func, NULL, \
- test_post_teardown, 2, user, free); \
+ test_post_teardown, timeout, user, free); \
} while (0)

+#define test_le(name, data, setup, func) \
+ test_le_full(name, data, setup, func, 2)
+
static void controller_setup(const void *test_data)
{
tester_test_passed();
--
2.14.1


2018-02-09 17:26:25

by Łukasz Rymanowski

[permalink] [raw]
Subject: [PATCH BlueZ 1/3] emulator: Add initial LE states to btdev and API to set new one

---
emulator/btdev.c | 18 ++++++++++++++++++
emulator/btdev.h | 3 ++-
emulator/hciemu.c | 8 ++++++++
emulator/hciemu.h | 3 +++
4 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index a9b225a24..69d84a5fc 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -570,6 +570,17 @@ static void set_le_features(struct btdev *btdev)
btdev->le_features[0] |= 0x08; /* Slave-initiated Features Exchange */
}

+static void set_le_states(struct btdev *btdev)
+{
+ /* Set all 41 bits as per Bluetooth 5.0 specification */
+ btdev->le_states[0] = 0xff;
+ btdev->le_states[1] = 0xff;
+ btdev->le_states[2] = 0xff;
+ btdev->le_states[3] = 0xff;
+ btdev->le_states[4] = 0xff;
+ btdev->le_states[5] = 0x03;
+}
+
static void set_amp_features(struct btdev *btdev)
{
}
@@ -603,6 +614,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
btdev->version = 0x09;
set_bredrle_features(btdev);
set_bredrle_commands(btdev);
+ set_le_states(btdev);
break;
case BTDEV_TYPE_BREDR:
btdev->version = 0x05;
@@ -613,6 +625,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
btdev->version = 0x09;
set_le_features(btdev);
set_le_commands(btdev);
+ set_le_states(btdev);
break;
case BTDEV_TYPE_AMP:
btdev->version = 0x01;
@@ -685,6 +698,11 @@ uint8_t btdev_get_le_scan_enable(struct btdev *btdev)
return btdev->le_scan_enable;
}

+void btdev_set_le_states(struct btdev *btdev, const uint8_t *le_states)
+{
+ memcpy(btdev->le_states, le_states, sizeof(btdev->le_states));
+}
+
static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
{
if (btdev1->auth_enable || btdev2->auth_enable)
diff --git a/emulator/btdev.h b/emulator/btdev.h
index 40c72199b..ba06a1015 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -84,12 +84,13 @@ uint8_t btdev_get_scan_enable(struct btdev *btdev);

uint8_t btdev_get_le_scan_enable(struct btdev *btdev);

+void btdev_set_le_states(struct btdev *btdev, const uint8_t *le_states);
+
void btdev_set_command_handler(struct btdev *btdev, btdev_command_func handler,
void *user_data);

void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
void *user_data);
-
void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len);

int btdev_add_hook(struct btdev *btdev, enum btdev_hook_type type,
diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index 7debb8f27..1787a6c0d 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -444,6 +444,14 @@ uint8_t hciemu_get_master_le_scan_enable(struct hciemu *hciemu)
return btdev_get_le_scan_enable(hciemu->master_dev);
}

+void hciemu_set_master_le_states(struct hciemu *hciemu, const uint8_t *le_states)
+{
+ if (!hciemu || !hciemu->master_dev)
+ return;
+
+ btdev_set_le_states(hciemu->master_dev, le_states);
+}
+
bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
hciemu_command_func_t function, void *user_data)
{
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index 783f99cf1..5c0c4c306 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -57,6 +57,9 @@ uint8_t hciemu_get_master_scan_enable(struct hciemu *hciemu);

uint8_t hciemu_get_master_le_scan_enable(struct hciemu *hciemu);

+void hciemu_set_master_le_states(struct hciemu *hciemu,
+ const uint8_t *le_states);
+
typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
uint8_t len, void *user_data);

--
2.14.1