2013-07-21 00:17:12

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 0/8] Hook mechanism for discovery tests

This series contains the hook mechanism implementation that will be used for
discovery tests.

The hook mechanism is a way to run custom code from tests before/after
processing HCI commands and building events. It is also possible to "cancel"
events if the post event hook returns false. This is necessary because the
current emulator implementation is sequential and does not let having control
about emulator behaviour.
The hooks will only intercept the events which were registered previously using
the hooks API exported by hciemu. If no hooks are added, the emulator will work
as before.
To simplify implementation, default_cmd() was split in two parts: the command
response (command status/complete events) was kept in default_cmd() and "extra"
events were moved to default_cmd completion().
There are four hooks types:
- pre command: before default_cmd() function.
- post command: before sending packet in command status and command complete.
- pre event: before default_cmd_completion() function.
- post event: in send_event() function, before sending the packet.
They can used in external applications like tools/mgmt-tester.

To illustrate this purpose, the following discovery test was implemented using
this new infrastructure:
- Stop discovery for BR/EDR only: this test sends stop command during inquiry,
checks if inquiry cancel is sent and discovering event is disabled.

Note that in current implementation it is not possible to send a stop discovery
before the discovery is finished due to emulator running sequentially during
same mainloop iteration, i.e., the inquiry complete HCI command is sent
immediately after inquiry command.

Comments and suggestions are welcome.

BR,
Bruna Moreira.

Bruna Moreira (2):
emulator: Add new function for running all hooks
tools/mgmt-tester: Add stop discovery for BR/EDR only

Eder Ruiz Maria (6):
emulator: Add support for pre/post command/event hooks
emulator: Add hook only if there aren't other with same type and
opcode
emulator: Export command and event hooks for hciemu user
emulator: Add support for delete a hook
emulator: Split default_cmd() for better command and event handler
emulator: cmd_status() using send_packet() for run hooks easily

emulator/btdev.c | 271 +++++++++++++++++++++++++++++++++++++++++++--------
emulator/btdev.h | 18 ++++
src/shared/hciemu.c | 58 +++++++++++
src/shared/hciemu.h | 17 ++++
tools/mgmt-tester.c | 72 +++++++++++++-
5 files changed, 395 insertions(+), 41 deletions(-)

--
1.7.9.5



2013-07-24 16:07:57

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH BlueZ 0/8] Hook mechanism for discovery tests

Hi Bruna,

On Sat, Jul 20, 2013, Bruna Moreira wrote:
> This series contains the hook mechanism implementation that will be used for
> discovery tests.
>
> The hook mechanism is a way to run custom code from tests before/after
> processing HCI commands and building events. It is also possible to "cancel"
> events if the post event hook returns false. This is necessary because the
> current emulator implementation is sequential and does not let having control
> about emulator behaviour.
> The hooks will only intercept the events which were registered previously using
> the hooks API exported by hciemu. If no hooks are added, the emulator will work
> as before.
> To simplify implementation, default_cmd() was split in two parts: the command
> response (command status/complete events) was kept in default_cmd() and "extra"
> events were moved to default_cmd completion().
> There are four hooks types:
> - pre command: before default_cmd() function.
> - post command: before sending packet in command status and command complete.
> - pre event: before default_cmd_completion() function.
> - post event: in send_event() function, before sending the packet.
> They can used in external applications like tools/mgmt-tester.
>
> To illustrate this purpose, the following discovery test was implemented using
> this new infrastructure:
> - Stop discovery for BR/EDR only: this test sends stop command during inquiry,
> checks if inquiry cancel is sent and discovering event is disabled.
>
> Note that in current implementation it is not possible to send a stop discovery
> before the discovery is finished due to emulator running sequentially during
> same mainloop iteration, i.e., the inquiry complete HCI command is sent
> immediately after inquiry command.
>
> Comments and suggestions are welcome.
>
> BR,
> Bruna Moreira.
>
> Bruna Moreira (2):
> emulator: Add new function for running all hooks
> tools/mgmt-tester: Add stop discovery for BR/EDR only
>
> Eder Ruiz Maria (6):
> emulator: Add support for pre/post command/event hooks
> emulator: Add hook only if there aren't other with same type and
> opcode
> emulator: Export command and event hooks for hciemu user
> emulator: Add support for delete a hook
> emulator: Split default_cmd() for better command and event handler
> emulator: cmd_status() using send_packet() for run hooks easily
>
> emulator/btdev.c | 271 +++++++++++++++++++++++++++++++++++++++++++--------
> emulator/btdev.h | 18 ++++
> src/shared/hciemu.c | 58 +++++++++++
> src/shared/hciemu.h | 17 ++++
> tools/mgmt-tester.c | 72 +++++++++++++-
> 5 files changed, 395 insertions(+), 41 deletions(-)

All patches in the set have been applied. Thanks.

Johan

2013-07-21 00:17:16

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 4/8] emulator: Add support for delete a hook

From: Eder Ruiz Maria <[email protected]>

---
emulator/btdev.c | 25 +++++++++++++++++++++++++
emulator/btdev.h | 3 +++
src/shared/hciemu.c | 28 ++++++++++++++++++++++++++++
src/shared/hciemu.h | 3 +++
4 files changed, 59 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index 30022d1..b8ac8f6 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -1746,3 +1746,28 @@ int btdev_add_hook(struct btdev *btdev, enum btdev_hook_type type,

return -1;
}
+
+bool btdev_del_hook(struct btdev *btdev, enum btdev_hook_type type,
+ uint16_t opcode)
+{
+ int i;
+
+ if (!btdev)
+ return false;
+
+ for (i = 0; i < MAX_HOOK_ENTRIES; i++) {
+ if (btdev->hook_list[i] == NULL)
+ continue;
+
+ if (btdev->hook_list[i]->type != type ||
+ btdev->hook_list[i]->opcode != opcode)
+ continue;
+
+ free(btdev->hook_list[i]);
+ btdev->hook_list[i] = NULL;
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/emulator/btdev.h b/emulator/btdev.h
index 085093f..5118a4a 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -89,3 +89,6 @@ 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,
uint16_t opcode, btdev_hook_func handler,
void *user_data);
+
+bool btdev_del_hook(struct btdev *btdev, enum btdev_hook_type type,
+ uint16_t opcode);
diff --git a/src/shared/hciemu.c b/src/shared/hciemu.c
index 76fd449..f5648a5 100644
--- a/src/shared/hciemu.c
+++ b/src/shared/hciemu.c
@@ -419,3 +419,31 @@ int hciemu_add_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
return btdev_add_hook(hciemu->master_dev, hook_type, opcode, function,
user_data);
}
+
+bool hciemu_del_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+ uint16_t opcode)
+{
+ enum btdev_hook_type hook_type;
+
+ if (!hciemu)
+ return false;
+
+ switch (type) {
+ case HCIEMU_HOOK_PRE_CMD:
+ hook_type = BTDEV_HOOK_PRE_CMD;
+ break;
+ case HCIEMU_HOOK_POST_CMD:
+ hook_type = BTDEV_HOOK_POST_CMD;
+ break;
+ case HCIEMU_HOOK_PRE_EVT:
+ hook_type = BTDEV_HOOK_PRE_EVT;
+ break;
+ case HCIEMU_HOOK_POST_EVT:
+ hook_type = BTDEV_HOOK_POST_EVT;
+ break;
+ default:
+ return false;
+ }
+
+ return btdev_del_hook(hciemu->master_dev, hook_type, opcode);
+}
diff --git a/src/shared/hciemu.h b/src/shared/hciemu.h
index 899acb0..7f17831 100644
--- a/src/shared/hciemu.h
+++ b/src/shared/hciemu.h
@@ -63,3 +63,6 @@ bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
int hciemu_add_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
uint16_t opcode, hciemu_hook_func_t function,
void *user_data);
+
+bool hciemu_del_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+ uint16_t opcode);
--
1.7.9.5


2013-07-21 00:17:20

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 8/8] tools/mgmt-tester: Add stop discovery for BR/EDR only

Send stop command during inquiry. Check if inquiry cancel is sent and
discovering event is disabled.
---
tools/mgmt-tester.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 70 insertions(+), 2 deletions(-)

diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 844f7db..2222ca9 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -352,6 +352,9 @@ static void controller_setup(const void *test_data)
}

struct generic_data {
+ uint16_t setup_expect_hci_command;
+ const void *setup_expect_hci_param;
+ uint8_t setup_expect_hci_len;
bool send_index_none;
uint16_t send_opcode;
const void *send_param;
@@ -1125,6 +1128,9 @@ static const char stop_discovery_bredrle_param[] = { 0x07 };
static const char stop_discovery_bredrle_invalid_param[] = { 0x06 };
static const char stop_discovery_valid_hci[] = { 0x00, 0x00 };
static const char stop_discovery_evt[] = { 0x07, 0x00 };
+static const char stop_discovery_bredr_param[] = { 0x01 };
+static const char stop_discovery_bredr_discovering[] = { 0x01, 0x00 };
+static const char stop_discovery_inq_param[] = { 0x33, 0x8b, 0x9e, 0x08, 0x00 };

static const struct generic_data stop_discovery_success_test_1 = {
.send_opcode = MGMT_OP_STOP_DISCOVERY,
@@ -1141,6 +1147,22 @@ static const struct generic_data stop_discovery_success_test_1 = {
.expect_alt_ev_len = sizeof(stop_discovery_evt),
};

+static const struct generic_data stop_discovery_bredr_success_test_1 = {
+ .setup_expect_hci_command = BT_HCI_CMD_INQUIRY,
+ .setup_expect_hci_param = stop_discovery_inq_param,
+ .setup_expect_hci_len = sizeof(stop_discovery_inq_param),
+ .send_opcode = MGMT_OP_STOP_DISCOVERY,
+ .send_param = stop_discovery_bredr_param,
+ .send_len = sizeof(stop_discovery_bredr_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = stop_discovery_bredr_param,
+ .expect_len = sizeof(stop_discovery_bredr_param),
+ .expect_hci_command = BT_HCI_CMD_INQUIRY_CANCEL,
+ .expect_alt_ev = MGMT_EV_DISCOVERING,
+ .expect_alt_ev_param = stop_discovery_bredr_discovering,
+ .expect_alt_ev_len = sizeof(stop_discovery_bredr_discovering),
+};
+
static const struct generic_data stop_discovery_rejected_test_1 = {
.send_opcode = MGMT_OP_STOP_DISCOVERY,
.send_param = stop_discovery_bredrle_param,
@@ -1833,11 +1855,41 @@ static void setup_discovery_callback(uint8_t status, uint16_t length,
tester_setup_complete();
}

+static bool setup_command_hci_callback(const void *data, uint16_t len,
+ void *user_data)
+{
+ struct test_data *tdata = tester_get_data();
+ const struct generic_data *test = tdata->test_data;
+
+ tester_print("HCI Command 0x%04x length %u (setup)",
+ test->setup_expect_hci_command, len);
+
+ if (len != test->setup_expect_hci_len) {
+ tester_warn("Invalid parameter size for HCI command (setup)");
+ tester_setup_failed();
+ goto done;
+ }
+
+ if (memcmp(data, test->setup_expect_hci_param, len) != 0) {
+ tester_warn("Unexpected HCI command parameter value (setup)");
+ tester_setup_failed();
+ goto done;
+ }
+
+ tester_setup_complete();
+
+done:
+ hciemu_del_hook(tdata->hciemu, HCIEMU_HOOK_PRE_EVT,
+ test->setup_expect_hci_command);
+
+ return false;
+}
+
static void setup_start_discovery_callback(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
struct test_data *data = tester_get_data();
- unsigned char disc_param[] = { 0x07 };
+ const struct generic_data *test = data->test_data;

if (status != MGMT_STATUS_SUCCESS) {
tester_setup_failed();
@@ -1846,9 +1898,22 @@ static void setup_start_discovery_callback(uint8_t status, uint16_t length,

tester_print("Controller powered on");

- mgmt_send(data->mgmt, MGMT_OP_START_DISCOVERY, data->mgmt_index,
+ if (test->setup_expect_hci_command) {
+ tester_print("Registering HCI command callback (setup)");
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_EVT,
+ test->setup_expect_hci_command,
+ setup_command_hci_callback,
+ NULL);
+ mgmt_send(data->mgmt, MGMT_OP_START_DISCOVERY, data->mgmt_index,
+ test->send_len, test->send_param,
+ NULL, NULL, NULL);
+ } else {
+ unsigned char disc_param[] = { 0x07 };
+
+ mgmt_send(data->mgmt, MGMT_OP_START_DISCOVERY, data->mgmt_index,
sizeof(disc_param), disc_param,
setup_discovery_callback, NULL, NULL);
+ }

if (option_wait_powered)
tester_wait(1, NULL, NULL);
@@ -2653,6 +2718,9 @@ int main(int argc, char *argv[])
test_bredrle("Stop Discovery - Success 1",
&stop_discovery_success_test_1,
setup_start_discovery, test_command_generic);
+ test_bredr("Stop Discovery - BR/EDR (Inquiry) Success 1",
+ &stop_discovery_bredr_success_test_1,
+ setup_start_discovery, test_command_generic);
test_bredrle("Stop Discovery - Rejected 1",
&stop_discovery_rejected_test_1,
setup_le_powered, test_command_generic);
--
1.7.9.5


2013-07-21 00:17:19

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 7/8] emulator: Add new function for running all hooks

It was defined four hook types and they are run before/after the first
part of default command processing and send event. Note that hook return
will define if the emulator will process/send next events (calling the
default_cmd_completion() function or not).
---
emulator/btdev.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index 006db8c..cc63658 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -132,6 +132,17 @@ static int get_hook_index(struct btdev *btdev, enum btdev_hook_type type,
return -1;
}

+static bool run_hooks(struct btdev *btdev, enum btdev_hook_type type,
+ uint16_t opcode, const void *data, uint16_t len)
+{
+ int index = get_hook_index(btdev, type, opcode);
+ if (index < 0)
+ return true;
+
+ return btdev->hook_list[index]->handler(data, len,
+ btdev->hook_list[index]->user_data);
+}
+
static inline int add_btdev(struct btdev *btdev)
{
int i, index = -1;
@@ -532,7 +543,8 @@ static void send_event(struct btdev *btdev, uint8_t event,
if (len > 0)
memcpy(pkt_data + 1 + sizeof(*hdr), data, len);

- send_packet(btdev, pkt_data, pkt_len);
+ if (run_hooks(btdev, BTDEV_HOOK_POST_EVT, event, pkt_data, pkt_len))
+ send_packet(btdev, pkt_data, pkt_len);

free(pkt_data);
}
@@ -564,7 +576,8 @@ static void cmd_complete(struct btdev *btdev, uint16_t opcode,
if (len > 0)
memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len);

- send_packet(btdev, pkt_data, pkt_len);
+ if (run_hooks(btdev, BTDEV_HOOK_POST_CMD, opcode, pkt_data, pkt_len))
+ send_packet(btdev, pkt_data, pkt_len);

free(pkt_data);
}
@@ -593,7 +606,8 @@ static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
cs->ncmd = 0x01;
cs->opcode = cpu_to_le16(opcode);

- send_packet(btdev, pkt_data, pkt_len);
+ if (run_hooks(btdev, BTDEV_HOOK_POST_CMD, opcode, pkt_data, pkt_len))
+ send_packet(btdev, pkt_data, pkt_len);

free(pkt_data);
}
@@ -1730,8 +1744,15 @@ static void handler_callback(btdev_callback callback, uint8_t response,

switch (response) {
case BTDEV_RESPONSE_DEFAULT:
+ if (!run_hooks(btdev, BTDEV_HOOK_PRE_CMD, callback->opcode,
+ callback->data, callback->len))
+ return;
default_cmd(btdev, callback->opcode,
callback->data, callback->len);
+
+ if (!run_hooks(btdev, BTDEV_HOOK_PRE_EVT, callback->opcode,
+ callback->data, callback->len))
+ return;
default_cmd_completion(btdev, callback->opcode,
callback->data, callback->len);
break;
@@ -1767,8 +1788,15 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
callback.data, callback.len,
&callback, btdev->command_data);
else {
+ if (!run_hooks(btdev, BTDEV_HOOK_PRE_CMD, callback.opcode,
+ callback.data, callback.len))
+ return;
default_cmd(btdev, callback.opcode,
callback.data, callback.len);
+
+ if (!run_hooks(btdev, BTDEV_HOOK_PRE_EVT, callback.opcode,
+ callback.data, callback.len))
+ return;
default_cmd_completion(btdev, callback.opcode,
callback.data, callback.len);
}
--
1.7.9.5


2013-07-21 00:17:18

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 6/8] emulator: cmd_status() using send_packet() for run hooks easily

From: Eder Ruiz Maria <[email protected]>

Now like cmd_command(), cmd_status() directly uses send_packet() instead
of send_event(), consequently cmd_status() must build the hci packet
without help of send_event(). With this change the events sent by
default_cmd() no more use send_event(), who is a good place to run hooks
for BTDEV_HOOK_POST_EVT. And the functions cmd_command() and
cmd_status() can run hooks for BTDEV_HOOK_POST_CMD.
---
emulator/btdev.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index e863b5f..006db8c 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -571,13 +571,31 @@ static void cmd_complete(struct btdev *btdev, uint16_t opcode,

static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
{
- struct bt_hci_evt_cmd_status cs;
+ struct bt_hci_evt_hdr *hdr;
+ struct bt_hci_evt_cmd_status *cs;
+ uint16_t pkt_len;
+ void *pkt_data;
+
+ pkt_len = 1 + sizeof(*hdr) + sizeof(*cs);

- cs.status = status;
- cs.ncmd = 0x01;
- cs.opcode = cpu_to_le16(opcode);
+ pkt_data = malloc(pkt_len);
+ if (!pkt_data)
+ return;

- send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs));
+ ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
+
+ hdr = pkt_data + 1;
+ hdr->evt = BT_HCI_EVT_CMD_STATUS;
+ hdr->plen = sizeof(*cs);
+
+ cs = pkt_data + 1 + sizeof(*hdr);
+ cs->status = status;
+ cs->ncmd = 0x01;
+ cs->opcode = cpu_to_le16(opcode);
+
+ send_packet(btdev, pkt_data, pkt_len);
+
+ free(pkt_data);
}

static void num_completed_packets(struct btdev *btdev)
--
1.7.9.5


2013-07-21 00:17:17

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 5/8] emulator: Split default_cmd() for better command and event handler

From: Eder Ruiz Maria <[email protected]>

Now except for command complete event and command status event, all
other are handled by default_cmd_completion(). With this we can easily
add hooks in some points.
---
emulator/btdev.c | 129 ++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 97 insertions(+), 32 deletions(-)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index b8ac8f6..e863b5f 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -896,16 +896,7 @@ static void le_set_scan_enable_complete(struct btdev *btdev)
static void default_cmd(struct btdev *btdev, uint16_t opcode,
const void *data, uint8_t len)
{
- const struct bt_hci_cmd_create_conn *cc;
- const struct bt_hci_cmd_disconnect *dc;
- const struct bt_hci_cmd_create_conn_cancel *ccc;
- const struct bt_hci_cmd_accept_conn_request *acr;
- const struct bt_hci_cmd_reject_conn_request *rcr;
- const struct bt_hci_cmd_remote_name_request *rnr;
const struct bt_hci_cmd_remote_name_request_cancel *rnrc;
- const struct bt_hci_cmd_read_remote_features *rrf;
- const struct bt_hci_cmd_read_remote_ext_features *rref;
- const struct bt_hci_cmd_read_remote_version *rrv;
const struct bt_hci_cmd_write_default_link_policy *wdlp;
const struct bt_hci_cmd_set_event_mask *sem;
const struct bt_hci_cmd_set_event_filter *sef;
@@ -970,7 +961,6 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
break;

case BT_HCI_CMD_INQUIRY_CANCEL:
@@ -983,47 +973,35 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
case BT_HCI_CMD_CREATE_CONN:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
- cc = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_request(btdev, cc->bdaddr);
break;

case BT_HCI_CMD_DISCONNECT:
- dc = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
break;

case BT_HCI_CMD_CREATE_CONN_CANCEL:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
- ccc = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
break;

case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
- acr = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
break;

case BT_HCI_CMD_REJECT_CONN_REQUEST:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
- rcr = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
break;

case BT_HCI_CMD_REMOTE_NAME_REQUEST:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
- rnr = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
break;

case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
@@ -1033,31 +1011,22 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
rnrc_rsp.status = BT_HCI_ERR_SUCCESS;
memcpy(rnrc_rsp.bdaddr, rnrc->bdaddr, 6);
cmd_complete(btdev, opcode, &rnrc_rsp, sizeof(rnrc_rsp));
- name_request_complete(btdev, rnrc->bdaddr,
- BT_HCI_ERR_UNKNOWN_CONN_ID);
break;

case BT_HCI_CMD_READ_REMOTE_FEATURES:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
- rrf = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- remote_features_complete(btdev, le16_to_cpu(rrf->handle));
break;

case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
if (btdev->type == BTDEV_TYPE_LE)
goto unsupported;
- rref = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
- rref->page);
break;

case BT_HCI_CMD_READ_REMOTE_VERSION:
- rrv = data;
cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- remote_version_complete(btdev, le16_to_cpu(rrv->handle));
break;

case BT_HCI_CMD_READ_DEFAULT_LINK_POLICY:
@@ -1630,6 +1599,97 @@ unsupported:
cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
}

+static void default_cmd_completion(struct btdev *btdev, uint16_t opcode,
+ const void *data, uint8_t len)
+{
+ const struct bt_hci_cmd_create_conn *cc;
+ const struct bt_hci_cmd_disconnect *dc;
+ const struct bt_hci_cmd_create_conn_cancel *ccc;
+ const struct bt_hci_cmd_accept_conn_request *acr;
+ const struct bt_hci_cmd_reject_conn_request *rcr;
+ const struct bt_hci_cmd_remote_name_request *rnr;
+ const struct bt_hci_cmd_remote_name_request_cancel *rnrc;
+ const struct bt_hci_cmd_read_remote_features *rrf;
+ const struct bt_hci_cmd_read_remote_ext_features *rref;
+ const struct bt_hci_cmd_read_remote_version *rrv;
+
+ switch (opcode) {
+ case BT_HCI_CMD_INQUIRY:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
+ break;
+
+ case BT_HCI_CMD_CREATE_CONN:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ cc = data;
+ conn_request(btdev, cc->bdaddr);
+ break;
+
+ case BT_HCI_CMD_DISCONNECT:
+ dc = data;
+ disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
+ break;
+
+ case BT_HCI_CMD_CREATE_CONN_CANCEL:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ ccc = data;
+ conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+
+ case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ acr = data;
+ conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
+ break;
+
+ case BT_HCI_CMD_REJECT_CONN_REQUEST:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ rcr = data;
+ conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+
+ case BT_HCI_CMD_REMOTE_NAME_REQUEST:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ rnr = data;
+ name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
+ break;
+
+ case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ rnrc = data;
+ name_request_complete(btdev, rnrc->bdaddr,
+ BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+
+ case BT_HCI_CMD_READ_REMOTE_FEATURES:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ rrf = data;
+ remote_features_complete(btdev, le16_to_cpu(rrf->handle));
+ break;
+
+ case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
+ if (btdev->type == BTDEV_TYPE_LE)
+ return;
+ rref = data;
+ remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
+ rref->page);
+ break;
+
+ case BT_HCI_CMD_READ_REMOTE_VERSION:
+ rrv = data;
+ remote_version_complete(btdev, le16_to_cpu(rrv->handle));
+ break;
+ }
+}
+
struct btdev_callback {
void (*function)(btdev_callback callback, uint8_t response,
uint8_t status, const void *data, uint8_t len);
@@ -1654,6 +1714,8 @@ static void handler_callback(btdev_callback callback, uint8_t response,
case BTDEV_RESPONSE_DEFAULT:
default_cmd(btdev, callback->opcode,
callback->data, callback->len);
+ default_cmd_completion(btdev, callback->opcode,
+ callback->data, callback->len);
break;
case BTDEV_RESPONSE_COMMAND_STATUS:
cmd_status(btdev, status, callback->opcode);
@@ -1686,9 +1748,12 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
btdev->command_handler(callback.opcode,
callback.data, callback.len,
&callback, btdev->command_data);
- else
+ else {
default_cmd(btdev, callback.opcode,
callback.data, callback.len);
+ default_cmd_completion(btdev, callback.opcode,
+ callback.data, callback.len);
+ }
}

void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
--
1.7.9.5


2013-07-21 00:17:15

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 3/8] emulator: Export command and event hooks for hciemu user

From: Eder Ruiz Maria <[email protected]>

---
src/shared/hciemu.c | 30 ++++++++++++++++++++++++++++++
src/shared/hciemu.h | 14 ++++++++++++++
2 files changed, 44 insertions(+)

diff --git a/src/shared/hciemu.c b/src/shared/hciemu.c
index a0b347c..76fd449 100644
--- a/src/shared/hciemu.c
+++ b/src/shared/hciemu.c
@@ -389,3 +389,33 @@ bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,

return true;
}
+
+int hciemu_add_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+ uint16_t opcode, hciemu_hook_func_t function,
+ void *user_data)
+{
+ enum btdev_hook_type hook_type;
+
+ if (!hciemu)
+ return -1;
+
+ switch (type) {
+ case HCIEMU_HOOK_PRE_CMD:
+ hook_type = BTDEV_HOOK_PRE_CMD;
+ break;
+ case HCIEMU_HOOK_POST_CMD:
+ hook_type = BTDEV_HOOK_POST_CMD;
+ break;
+ case HCIEMU_HOOK_PRE_EVT:
+ hook_type = BTDEV_HOOK_PRE_EVT;
+ break;
+ case HCIEMU_HOOK_POST_EVT:
+ hook_type = BTDEV_HOOK_POST_EVT;
+ break;
+ default:
+ return -1;
+ }
+
+ return btdev_add_hook(hciemu->master_dev, hook_type, opcode, function,
+ user_data);
+}
diff --git a/src/shared/hciemu.h b/src/shared/hciemu.h
index a473c0e..899acb0 100644
--- a/src/shared/hciemu.h
+++ b/src/shared/hciemu.h
@@ -32,6 +32,13 @@ enum hciemu_type {
HCIEMU_TYPE_LE,
};

+enum hciemu_hook_type {
+ HCIEMU_HOOK_PRE_CMD,
+ HCIEMU_HOOK_POST_CMD,
+ HCIEMU_HOOK_PRE_EVT,
+ HCIEMU_HOOK_POST_EVT,
+};
+
struct hciemu *hciemu_new(enum hciemu_type type);

struct hciemu *hciemu_ref(struct hciemu *hciemu);
@@ -47,5 +54,12 @@ const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
uint8_t len, void *user_data);

+typedef bool (*hciemu_hook_func_t)(const void *data, uint16_t len,
+ void *user_data);
+
bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
hciemu_command_func_t function, void *user_data);
+
+int hciemu_add_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+ uint16_t opcode, hciemu_hook_func_t function,
+ void *user_data);
--
1.7.9.5


2013-07-21 00:17:14

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 2/8] emulator: Add hook only if there aren't other with same type and opcode

From: Eder Ruiz Maria <[email protected]>

---
emulator/btdev.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index 52b58ce..30022d1 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -115,6 +115,23 @@ struct btdev {

static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { };

+static int get_hook_index(struct btdev *btdev, enum btdev_hook_type type,
+ uint16_t opcode)
+{
+ int i;
+
+ for (i = 0; i < MAX_HOOK_ENTRIES; i++) {
+ if (btdev->hook_list[i] == NULL)
+ continue;
+
+ if (btdev->hook_list[i]->type == type &&
+ btdev->hook_list[i]->opcode == opcode)
+ return i;
+ }
+
+ return -1;
+}
+
static inline int add_btdev(struct btdev *btdev)
{
int i, index = -1;
@@ -1710,6 +1727,9 @@ int btdev_add_hook(struct btdev *btdev, enum btdev_hook_type type,
if (!btdev)
return -1;

+ if (get_hook_index(btdev, type, opcode) > 0)
+ return -1;
+
for (i = 0; i < MAX_HOOK_ENTRIES; i++) {
if (btdev->hook_list[i] == NULL) {
btdev->hook_list[i] = malloc(sizeof(struct hook));
--
1.7.9.5


2013-07-21 00:17:13

by Bruna Moreira

[permalink] [raw]
Subject: [PATCH BlueZ 1/8] emulator: Add support for pre/post command/event hooks

From: Eder Ruiz Maria <[email protected]>

Now who use emulator can add hooks to manipulate hci packets before
and after process commands and send events.
---
emulator/btdev.c | 37 +++++++++++++++++++++++++++++++++++++
emulator/btdev.h | 15 +++++++++++++++
2 files changed, 52 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index 79d2f0e..52b58ce 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -42,6 +42,15 @@
#define has_bredr(btdev) (!((btdev)->features[4] & 0x20))
#define has_le(btdev) (!!((btdev)->features[4] & 0x40))

+struct hook {
+ btdev_hook_func handler;
+ void *user_data;
+ enum btdev_hook_type type;
+ uint16_t opcode;
+};
+
+#define MAX_HOOK_ENTRIES 16
+
struct btdev {
enum btdev_type type;

@@ -53,6 +62,8 @@ struct btdev {
btdev_send_func send_handler;
void *send_data;

+ struct hook *hook_list[MAX_HOOK_ENTRIES];
+
uint16_t manufacturer;
uint8_t version;
uint16_t revision;
@@ -1689,3 +1700,29 @@ void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
break;
}
}
+
+int btdev_add_hook(struct btdev *btdev, enum btdev_hook_type type,
+ uint16_t opcode, btdev_hook_func handler,
+ void *user_data)
+{
+ int i;
+
+ if (!btdev)
+ return -1;
+
+ for (i = 0; i < MAX_HOOK_ENTRIES; i++) {
+ if (btdev->hook_list[i] == NULL) {
+ btdev->hook_list[i] = malloc(sizeof(struct hook));
+ if (btdev->hook_list[i] == NULL)
+ return -1;
+
+ btdev->hook_list[i]->handler = handler;
+ btdev->hook_list[i]->user_data = user_data;
+ btdev->hook_list[i]->opcode = opcode;
+ btdev->hook_list[i]->type = type;
+ return i;
+ }
+ }
+
+ return -1;
+}
diff --git a/emulator/btdev.h b/emulator/btdev.h
index 9fb023c..085093f 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -23,6 +23,7 @@
*/

#include <stdint.h>
+#include <stdbool.h>

#define BTDEV_RESPONSE_DEFAULT 0
#define BTDEV_RESPONSE_COMMAND_STATUS 1
@@ -53,6 +54,9 @@ typedef void (*btdev_command_func) (uint16_t opcode,
typedef void (*btdev_send_func) (const void *data, uint16_t len,
void *user_data);

+typedef bool (*btdev_hook_func) (const void *data, uint16_t len,
+ void *user_data);
+
enum btdev_type {
BTDEV_TYPE_BREDRLE,
BTDEV_TYPE_BREDR,
@@ -60,6 +64,13 @@ enum btdev_type {
BTDEV_TYPE_AMP,
};

+enum btdev_hook_type {
+ BTDEV_HOOK_PRE_CMD,
+ BTDEV_HOOK_POST_CMD,
+ BTDEV_HOOK_PRE_EVT,
+ BTDEV_HOOK_POST_EVT,
+};
+
struct btdev;

struct btdev *btdev_create(enum btdev_type type, uint16_t id);
@@ -74,3 +85,7 @@ 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,
+ uint16_t opcode, btdev_hook_func handler,
+ void *user_data);
--
1.7.9.5