zephyr/tests/bluetooth/tester/src/mesh.c
Carlos Stuart 75f77db432 include: misc: util.h: Rename min/max to MIN/MAX
There are issues using lowercase min and max macros when compiling a C++
application with a third-party toolchain such as GNU ARM Embedded when
using some STL headers i.e. <chrono>.

This is because there are actual C++ functions called min and max
defined in some of the STL headers and these macros interfere with them.
By changing the macros to UPPERCASE, which is consistent with almost all
other pre-processor macros this naming conflict is avoided.

All files that use these macros have been updated.

Signed-off-by: Carlos Stuart <carlosstuart1970@gmail.com>
2019-02-14 22:16:03 -05:00

932 lines
21 KiB
C

/* mesh.c - Bluetooth Mesh Tester */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <bluetooth/bluetooth.h>
#include <errno.h>
#include <bluetooth/mesh.h>
#include <bluetooth/testing.h>
#include <misc/byteorder.h>
#include <logging/log.h>
#define LOG_MODULE_NAME bttester_mesh
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include "bttester.h"
#define CONTROLLER_INDEX 0
#define CID_LOCAL 0xffff
/* Health server data */
#define CUR_FAULTS_MAX 4
#define HEALTH_TEST_ID 0x00
static u8_t cur_faults[CUR_FAULTS_MAX];
static u8_t reg_faults[CUR_FAULTS_MAX * 2];
/* Provision node data */
static u8_t net_key[16];
static u16_t net_key_idx;
static u8_t flags;
static u32_t iv_index;
static u16_t addr;
static u8_t dev_key[16];
static u8_t input_size;
/* Configured provisioning data */
static u8_t dev_uuid[16];
static u8_t static_auth[16];
/* Vendor Model data */
#define VND_MODEL_ID_1 0x1234
/* Model send data */
#define MODEL_BOUNDS_MAX 2
static struct model_data {
struct bt_mesh_model *model;
u16_t addr;
u16_t appkey_idx;
} model_bound[MODEL_BOUNDS_MAX];
static struct {
u16_t local;
u16_t dst;
u16_t net_idx;
} net = {
.local = BT_MESH_ADDR_UNASSIGNED,
.dst = BT_MESH_ADDR_UNASSIGNED,
};
static void supported_commands(u8_t *data, u16_t len)
{
struct net_buf_simple *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE);
net_buf_simple_init(buf, 0);
/* 1st octet */
(void)memset(net_buf_simple_add(buf, 1), 0, 1);
tester_set_bit(buf->data, MESH_READ_SUPPORTED_COMMANDS);
tester_set_bit(buf->data, MESH_CONFIG_PROVISIONING);
tester_set_bit(buf->data, MESH_PROVISION_NODE);
tester_set_bit(buf->data, MESH_INIT);
tester_set_bit(buf->data, MESH_RESET);
tester_set_bit(buf->data, MESH_INPUT_NUMBER);
tester_set_bit(buf->data, MESH_INPUT_STRING);
/* 2nd octet */
tester_set_bit(buf->data, MESH_IVU_TEST_MODE);
tester_set_bit(buf->data, MESH_IVU_TOGGLE_STATE);
tester_set_bit(buf->data, MESH_NET_SEND);
tester_set_bit(buf->data, MESH_HEALTH_GENERATE_FAULTS);
tester_set_bit(buf->data, MESH_HEALTH_CLEAR_FAULTS);
tester_set_bit(buf->data, MESH_LPN);
tester_set_bit(buf->data, MESH_LPN_POLL);
tester_set_bit(buf->data, MESH_MODEL_SEND);
/* 3rd octet */
(void)memset(net_buf_simple_add(buf, 1), 0, 1);
#if defined(CONFIG_BT_TESTING)
tester_set_bit(buf->data, MESH_LPN_SUBSCRIBE);
tester_set_bit(buf->data, MESH_LPN_UNSUBSCRIBE);
tester_set_bit(buf->data, MESH_RPL_CLEAR);
#endif /* CONFIG_BT_TESTING */
tester_set_bit(buf->data, MESH_PROXY_IDENTITY);
tester_send(BTP_SERVICE_ID_MESH, MESH_READ_SUPPORTED_COMMANDS,
CONTROLLER_INDEX, buf->data, buf->len);
}
static struct bt_mesh_cfg_srv cfg_srv = {
.relay = BT_MESH_RELAY_ENABLED,
.beacon = BT_MESH_BEACON_ENABLED,
#if defined(CONFIG_BT_MESH_FRIEND)
.frnd = BT_MESH_FRIEND_DISABLED,
#else
.frnd = BT_MESH_FRIEND_NOT_SUPPORTED,
#endif
#if defined(CONFIG_BT_MESH_GATT_PROXY)
.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
#else
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
.default_ttl = 7,
/* 3 transmissions with 20ms interval */
.net_transmit = BT_MESH_TRANSMIT(2, 20),
.relay_retransmit = BT_MESH_TRANSMIT(2, 20),
};
static void get_faults(u8_t *faults, u8_t faults_size, u8_t *dst, u8_t *count)
{
u8_t i, limit = *count;
for (i = 0U, *count = 0U; i < faults_size && *count < limit; i++) {
if (faults[i]) {
*dst++ = faults[i];
(*count)++;
}
}
}
static int fault_get_cur(struct bt_mesh_model *model, u8_t *test_id,
u16_t *company_id, u8_t *faults, u8_t *fault_count)
{
LOG_DBG("");
*test_id = HEALTH_TEST_ID;
*company_id = CID_LOCAL;
get_faults(cur_faults, sizeof(cur_faults), faults, fault_count);
return 0;
}
static int fault_get_reg(struct bt_mesh_model *model, u16_t company_id,
u8_t *test_id, u8_t *faults, u8_t *fault_count)
{
LOG_DBG("company_id 0x%04x", company_id);
if (company_id != CID_LOCAL) {
return -EINVAL;
}
*test_id = HEALTH_TEST_ID;
get_faults(reg_faults, sizeof(reg_faults), faults, fault_count);
return 0;
}
static int fault_clear(struct bt_mesh_model *model, uint16_t company_id)
{
LOG_DBG("company_id 0x%04x", company_id);
if (company_id != CID_LOCAL) {
return -EINVAL;
}
(void)memset(reg_faults, 0, sizeof(reg_faults));
return 0;
}
static int fault_test(struct bt_mesh_model *model, uint8_t test_id,
uint16_t company_id)
{
LOG_DBG("test_id 0x%02x company_id 0x%04x", test_id, company_id);
if (company_id != CID_LOCAL || test_id != HEALTH_TEST_ID) {
return -EINVAL;
}
return 0;
}
static const struct bt_mesh_health_srv_cb health_srv_cb = {
.fault_get_cur = fault_get_cur,
.fault_get_reg = fault_get_reg,
.fault_clear = fault_clear,
.fault_test = fault_test,
};
static struct bt_mesh_health_srv health_srv = {
.cb = &health_srv_cb,
};
BT_MESH_HEALTH_PUB_DEFINE(health_pub, CUR_FAULTS_MAX);
static struct bt_mesh_cfg_cli cfg_cli = {
};
void show_faults(u8_t test_id, u16_t cid, u8_t *faults, size_t fault_count)
{
size_t i;
if (!fault_count) {
LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x: no faults",
test_id, cid);
return;
}
LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu: ",
test_id, cid, fault_count);
for (i = 0; i < fault_count; i++) {
LOG_DBG("0x%02x", faults[i]);
}
}
static void health_current_status(struct bt_mesh_health_cli *cli, u16_t addr,
u8_t test_id, u16_t cid, u8_t *faults,
size_t fault_count)
{
LOG_DBG("Health Current Status from 0x%04x", addr);
show_faults(test_id, cid, faults, fault_count);
}
static struct bt_mesh_health_cli health_cli = {
.current_status = health_current_status,
};
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
BT_MESH_MODEL_HEALTH_CLI(&health_cli),
};
static struct bt_mesh_model vnd_models[] = {
BT_MESH_MODEL_VND(CID_LOCAL, VND_MODEL_ID_1, BT_MESH_MODEL_NO_OPS, NULL,
NULL),
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, vnd_models),
};
static void link_open(bt_mesh_prov_bearer_t bearer)
{
struct mesh_prov_link_open_ev ev;
LOG_DBG("bearer 0x%02x", bearer);
switch (bearer) {
case BT_MESH_PROV_ADV:
ev.bearer = MESH_PROV_BEARER_PB_ADV;
break;
case BT_MESH_PROV_GATT:
ev.bearer = MESH_PROV_BEARER_PB_GATT;
break;
default:
LOG_ERR("Invalid bearer");
return;
}
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_PROV_LINK_OPEN,
CONTROLLER_INDEX, (u8_t *) &ev, sizeof(ev));
}
static void link_close(bt_mesh_prov_bearer_t bearer)
{
struct mesh_prov_link_closed_ev ev;
LOG_DBG("bearer 0x%02x", bearer);
switch (bearer) {
case BT_MESH_PROV_ADV:
ev.bearer = MESH_PROV_BEARER_PB_ADV;
break;
case BT_MESH_PROV_GATT:
ev.bearer = MESH_PROV_BEARER_PB_GATT;
break;
default:
LOG_ERR("Invalid bearer");
return;
}
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_PROV_LINK_CLOSED,
CONTROLLER_INDEX, (u8_t *) &ev, sizeof(ev));
}
static int output_number(bt_mesh_output_action_t action, u32_t number)
{
struct mesh_out_number_action_ev ev;
LOG_DBG("action 0x%04x number 0x%08x", action, number);
ev.action = sys_cpu_to_le16(action);
ev.number = sys_cpu_to_le32(number);
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_OUT_NUMBER_ACTION,
CONTROLLER_INDEX, (u8_t *) &ev, sizeof(ev));
return 0;
}
static int output_string(const char *str)
{
struct mesh_out_string_action_ev *ev;
struct net_buf_simple *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE);
LOG_DBG("str %s", str);
net_buf_simple_init(buf, 0);
ev = net_buf_simple_add(buf, sizeof(*ev));
ev->string_len = strlen(str);
net_buf_simple_add_mem(buf, str, ev->string_len);
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_OUT_STRING_ACTION,
CONTROLLER_INDEX, buf->data, buf->len);
return 0;
}
static int input(bt_mesh_input_action_t action, u8_t size)
{
struct mesh_in_action_ev ev;
LOG_DBG("action 0x%04x number 0x%02x", action, size);
input_size = size;
ev.action = sys_cpu_to_le16(action);
ev.size = size;
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_IN_ACTION, CONTROLLER_INDEX,
(u8_t *) &ev, sizeof(ev));
return 0;
}
static void prov_complete(u16_t net_idx, u16_t addr)
{
LOG_DBG("net_idx 0x%04x addr 0x%04x", net_idx, addr);
net.net_idx = net_idx,
net.local = addr;
net.dst = addr;
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_PROVISIONED, CONTROLLER_INDEX,
NULL, 0);
}
static void prov_reset(void)
{
LOG_DBG("");
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
}
static const struct bt_mesh_comp comp = {
.cid = CID_LOCAL,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
static struct bt_mesh_prov prov = {
.uuid = dev_uuid,
.static_val = static_auth,
.static_val_len = sizeof(static_auth),
.output_number = output_number,
.output_string = output_string,
.input = input,
.link_open = link_open,
.link_close = link_close,
.complete = prov_complete,
.reset = prov_reset,
};
static void config_prov(u8_t *data, u16_t len)
{
const struct mesh_config_provisioning_cmd *cmd = (void *) data;
LOG_DBG("");
memcpy(dev_uuid, cmd->uuid, sizeof(dev_uuid));
memcpy(static_auth, cmd->static_auth, sizeof(static_auth));
prov.output_size = cmd->out_size;
prov.output_actions = sys_le16_to_cpu(cmd->out_actions);
prov.input_size = cmd->in_size;
prov.input_actions = sys_le16_to_cpu(cmd->in_actions);
tester_rsp(BTP_SERVICE_ID_MESH, MESH_CONFIG_PROVISIONING,
CONTROLLER_INDEX, BTP_STATUS_SUCCESS);
}
static void provision_node(u8_t *data, u16_t len)
{
const struct mesh_provision_node_cmd *cmd = (void *) data;
LOG_DBG("");
memcpy(dev_key, cmd->dev_key, sizeof(dev_key));
memcpy(net_key, cmd->net_key, sizeof(net_key));
addr = sys_le16_to_cpu(cmd->addr);
flags = cmd->flags;
iv_index = sys_le32_to_cpu(cmd->iv_index);
net_key_idx = sys_le16_to_cpu(cmd->net_key_idx);
tester_rsp(BTP_SERVICE_ID_MESH, MESH_PROVISION_NODE,
CONTROLLER_INDEX, BTP_STATUS_SUCCESS);
}
static void init(u8_t *data, u16_t len)
{
u8_t status = BTP_STATUS_SUCCESS;
int err;
LOG_DBG("");
err = bt_mesh_init(&prov, &comp);
if (err) {
status = BTP_STATUS_FAILED;
goto rsp;
}
if (addr) {
err = bt_mesh_provision(net_key, net_key_idx, flags, iv_index,
addr, dev_key);
if (err) {
status = BTP_STATUS_FAILED;
}
} else {
err = bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
if (err) {
status = BTP_STATUS_FAILED;
}
}
/* Set device key for vendor model */
vnd_models[0].keys[0] = BT_MESH_KEY_DEV;
rsp:
tester_rsp(BTP_SERVICE_ID_MESH, MESH_INIT, CONTROLLER_INDEX,
status);
}
static void reset(u8_t *data, u16_t len)
{
LOG_DBG("");
bt_mesh_reset();
tester_rsp(BTP_SERVICE_ID_MESH, MESH_RESET, CONTROLLER_INDEX,
BTP_STATUS_SUCCESS);
}
static void input_number(u8_t *data, u16_t len)
{
const struct mesh_input_number_cmd *cmd = (void *) data;
u8_t status = BTP_STATUS_SUCCESS;
u32_t number;
int err;
number = sys_le32_to_cpu(cmd->number);
LOG_DBG("number 0x%04x", number);
err = bt_mesh_input_number(number);
if (err) {
status = BTP_STATUS_FAILED;
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_INPUT_NUMBER, CONTROLLER_INDEX,
status);
}
static void input_string(u8_t *data, u16_t len)
{
const struct mesh_input_string_cmd *cmd = (void *) data;
u8_t status = BTP_STATUS_SUCCESS;
u8_t str_auth[16];
int err;
LOG_DBG("");
if (cmd->string_len > sizeof(str_auth)) {
LOG_ERR("Too long input (%u chars required)", input_size);
status = BTP_STATUS_FAILED;
goto rsp;
} else if (cmd->string_len < input_size) {
LOG_ERR("Too short input (%u chars required)", input_size);
status = BTP_STATUS_FAILED;
goto rsp;
}
strncpy(str_auth, cmd->string, cmd->string_len);
err = bt_mesh_input_string(str_auth);
if (err) {
status = BTP_STATUS_FAILED;
}
rsp:
tester_rsp(BTP_SERVICE_ID_MESH, MESH_INPUT_STRING, CONTROLLER_INDEX,
status);
}
static void ivu_test_mode(u8_t *data, u16_t len)
{
const struct mesh_ivu_test_mode_cmd *cmd = (void *) data;
LOG_DBG("enable 0x%02x", cmd->enable);
bt_mesh_iv_update_test(cmd->enable ? true : false);
tester_rsp(BTP_SERVICE_ID_MESH, MESH_IVU_TEST_MODE, CONTROLLER_INDEX,
BTP_STATUS_SUCCESS);
}
static void ivu_toggle_state(u8_t *data, u16_t len)
{
bool result;
LOG_DBG("");
result = bt_mesh_iv_update();
if (!result) {
LOG_ERR("Failed to toggle the IV Update state");
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_IVU_TOGGLE_STATE, CONTROLLER_INDEX,
result ? BTP_STATUS_SUCCESS : BTP_STATUS_FAILED);
}
static void lpn(u8_t *data, u16_t len)
{
struct mesh_lpn_set_cmd *cmd = (void *) data;
bool enable;
int err;
LOG_DBG("enable 0x%02x", cmd->enable);
enable = cmd->enable ? true : false;
err = bt_mesh_lpn_set(enable);
if (err) {
LOG_ERR("Failed to toggle LPN (err %d)", err);
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
static void lpn_poll(u8_t *data, u16_t len)
{
int err;
LOG_DBG("");
err = bt_mesh_lpn_poll();
if (err) {
LOG_ERR("Failed to send poll msg (err %d)", err);
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN_POLL, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
static void net_send(u8_t *data, u16_t len)
{
struct mesh_net_send_cmd *cmd = (void *) data;
NET_BUF_SIMPLE_DEFINE(msg, UINT8_MAX);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net.net_idx,
.app_idx = BT_MESH_KEY_DEV,
.addr = sys_le16_to_cpu(cmd->dst),
.send_ttl = cmd->ttl,
};
int err;
LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl,
ctx.addr, cmd->payload_len);
net_buf_simple_add_mem(&msg, cmd->payload, cmd->payload_len);
err = bt_mesh_model_send(&vnd_models[0], &ctx, &msg, NULL, NULL);
if (err) {
LOG_ERR("Failed to send (err %d)", err);
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_NET_SEND, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
static void health_generate_faults(u8_t *data, u16_t len)
{
struct mesh_health_generate_faults_rp *rp;
NET_BUF_SIMPLE_DEFINE(buf, sizeof(*rp) + sizeof(cur_faults) +
sizeof(reg_faults));
u8_t some_faults[] = { 0x01, 0x02, 0x03, 0xff, 0x06 };
u8_t cur_faults_count, reg_faults_count;
rp = net_buf_simple_add(&buf, sizeof(*rp));
cur_faults_count = MIN(sizeof(cur_faults), sizeof(some_faults));
memcpy(cur_faults, some_faults, cur_faults_count);
net_buf_simple_add_mem(&buf, cur_faults, cur_faults_count);
rp->cur_faults_count = cur_faults_count;
reg_faults_count = MIN(sizeof(reg_faults), sizeof(some_faults));
memcpy(reg_faults, some_faults, reg_faults_count);
net_buf_simple_add_mem(&buf, reg_faults, reg_faults_count);
rp->reg_faults_count = reg_faults_count;
bt_mesh_fault_update(&elements[0]);
tester_send(BTP_SERVICE_ID_MESH, MESH_HEALTH_GENERATE_FAULTS,
CONTROLLER_INDEX, buf.data, buf.len);
}
static void health_clear_faults(u8_t *data, u16_t len)
{
LOG_DBG("");
(void)memset(cur_faults, 0, sizeof(cur_faults));
(void)memset(reg_faults, 0, sizeof(reg_faults));
bt_mesh_fault_update(&elements[0]);
tester_rsp(BTP_SERVICE_ID_MESH, MESH_HEALTH_CLEAR_FAULTS,
CONTROLLER_INDEX, BTP_STATUS_SUCCESS);
}
static void model_send(u8_t *data, u16_t len)
{
struct mesh_model_send_cmd *cmd = (void *) data;
NET_BUF_SIMPLE_DEFINE(msg, UINT8_MAX);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net.net_idx,
.app_idx = BT_MESH_KEY_DEV,
.addr = sys_le16_to_cpu(cmd->dst),
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct bt_mesh_model *model = NULL;
int err, i;
u16_t src = sys_le16_to_cpu(cmd->src);
/* Lookup source address */
for (i = 0; i < ARRAY_SIZE(model_bound); i++) {
if (bt_mesh_model_elem(model_bound[i].model)->addr == src) {
model = model_bound[i].model;
ctx.app_idx = model_bound[i].appkey_idx;
break;
}
}
if (!model) {
LOG_ERR("Model not found");
err = -EINVAL;
goto fail;
}
LOG_DBG("src 0x%04x dst 0x%04x model %p payload_len %d", src,
ctx.addr, model, cmd->payload_len);
net_buf_simple_add_mem(&msg, cmd->payload, cmd->payload_len);
err = bt_mesh_model_send(model, &ctx, &msg, NULL, NULL);
if (err) {
LOG_ERR("Failed to send (err %d)", err);
}
fail:
tester_rsp(BTP_SERVICE_ID_MESH, MESH_MODEL_SEND, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
#if defined(CONFIG_BT_TESTING)
static void lpn_subscribe(u8_t *data, u16_t len)
{
struct mesh_lpn_subscribe_cmd *cmd = (void *) data;
u16_t address = sys_le16_to_cpu(cmd->address);
int err;
LOG_DBG("address 0x%04x", address);
err = bt_test_mesh_lpn_group_add(address);
if (err) {
LOG_ERR("Failed to subscribe (err %d)", err);
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN_SUBSCRIBE, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
static void lpn_unsubscribe(u8_t *data, u16_t len)
{
struct mesh_lpn_unsubscribe_cmd *cmd = (void *) data;
u16_t address = sys_le16_to_cpu(cmd->address);
int err;
LOG_DBG("address 0x%04x", address);
err = bt_test_mesh_lpn_group_remove(&address, 1);
if (err) {
LOG_ERR("Failed to unsubscribe (err %d)", err);
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN_UNSUBSCRIBE, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
static void rpl_clear(u8_t *data, u16_t len)
{
int err;
LOG_DBG("");
err = bt_test_mesh_rpl_clear();
if (err) {
LOG_ERR("Failed to clear RPL (err %d)", err);
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_RPL_CLEAR, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
#endif /* CONFIG_BT_TESTING */
static void proxy_identity_enable(u8_t *data, u16_t len)
{
int err;
LOG_DBG("");
err = bt_mesh_proxy_identity_enable();
if (err) {
LOG_ERR("Failed to enable proxy identity (err %d)", err);
}
tester_rsp(BTP_SERVICE_ID_MESH, MESH_PROXY_IDENTITY, CONTROLLER_INDEX,
err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS);
}
void tester_handle_mesh(u8_t opcode, u8_t index, u8_t *data, u16_t len)
{
switch (opcode) {
case MESH_READ_SUPPORTED_COMMANDS:
supported_commands(data, len);
break;
case MESH_CONFIG_PROVISIONING:
config_prov(data, len);
break;
case MESH_PROVISION_NODE:
provision_node(data, len);
break;
case MESH_INIT:
init(data, len);
break;
case MESH_RESET:
reset(data, len);
break;
case MESH_INPUT_NUMBER:
input_number(data, len);
break;
case MESH_INPUT_STRING:
input_string(data, len);
break;
case MESH_IVU_TEST_MODE:
ivu_test_mode(data, len);
break;
case MESH_IVU_TOGGLE_STATE:
ivu_toggle_state(data, len);
break;
case MESH_LPN:
lpn(data, len);
break;
case MESH_LPN_POLL:
lpn_poll(data, len);
break;
case MESH_NET_SEND:
net_send(data, len);
break;
case MESH_HEALTH_GENERATE_FAULTS:
health_generate_faults(data, len);
break;
case MESH_HEALTH_CLEAR_FAULTS:
health_clear_faults(data, len);
break;
case MESH_MODEL_SEND:
model_send(data, len);
break;
#if defined(CONFIG_BT_TESTING)
case MESH_LPN_SUBSCRIBE:
lpn_subscribe(data, len);
break;
case MESH_LPN_UNSUBSCRIBE:
lpn_unsubscribe(data, len);
break;
case MESH_RPL_CLEAR:
rpl_clear(data, len);
break;
#endif /* CONFIG_BT_TESTING */
case MESH_PROXY_IDENTITY:
proxy_identity_enable(data, len);
break;
default:
tester_rsp(BTP_SERVICE_ID_MESH, opcode, index,
BTP_STATUS_UNKNOWN_CMD);
break;
}
}
void net_recv_ev(u8_t ttl, u8_t ctl, u16_t src, u16_t dst, const void *payload,
size_t payload_len)
{
NET_BUF_SIMPLE_DEFINE(buf, UINT8_MAX);
struct mesh_net_recv_ev *ev;
LOG_DBG("ttl 0x%02x ctl 0x%02x src 0x%04x dst 0x%04x payload_len %zu",
ttl, ctl, src, dst, payload_len);
if (payload_len > net_buf_simple_tailroom(&buf)) {
LOG_ERR("Payload size exceeds buffer size");
return;
}
ev = net_buf_simple_add(&buf, sizeof(*ev));
ev->ttl = ttl;
ev->ctl = ctl;
ev->src = sys_cpu_to_le16(src);
ev->dst = sys_cpu_to_le16(dst);
ev->payload_len = payload_len;
net_buf_simple_add_mem(&buf, payload, payload_len);
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_NET_RECV, CONTROLLER_INDEX,
buf.data, buf.len);
}
static void model_bound_cb(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx)
{
int i;
LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p",
addr, key_idx, model);
for (i = 0; i < ARRAY_SIZE(model_bound); i++) {
if (!model_bound[i].model) {
model_bound[i].model = model;
model_bound[i].addr = addr;
model_bound[i].appkey_idx = key_idx;
return;
}
}
LOG_ERR("model_bound is full");
}
static void model_unbound_cb(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx)
{
int i;
LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p",
addr, key_idx, model);
for (i = 0; i < ARRAY_SIZE(model_bound); i++) {
if (model_bound[i].model == model) {
model_bound[i].model = NULL;
model_bound[i].addr = 0x0000;
model_bound[i].appkey_idx = BT_MESH_KEY_UNUSED;
return;
}
}
LOG_INF("model not found");
}
static void invalid_bearer_cb(u8_t opcode)
{
struct mesh_invalid_bearer_ev ev = {
.opcode = opcode,
};
LOG_DBG("opcode 0x%02x", opcode);
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_INVALID_BEARER,
CONTROLLER_INDEX, (u8_t *) &ev, sizeof(ev));
}
static void incomp_timer_exp_cb(void)
{
tester_send(BTP_SERVICE_ID_MESH, MESH_EV_INCOMP_TIMER_EXP,
CONTROLLER_INDEX, NULL, 0);
}
static struct bt_test_cb bt_test_cb = {
.mesh_net_recv = net_recv_ev,
.mesh_model_bound = model_bound_cb,
.mesh_model_unbound = model_unbound_cb,
.mesh_prov_invalid_bearer = invalid_bearer_cb,
.mesh_trans_incomp_timer_exp = incomp_timer_exp_cb,
};
u8_t tester_init_mesh(void)
{
if (IS_ENABLED(CONFIG_BT_TESTING)) {
bt_test_cb_register(&bt_test_cb);
}
return BTP_STATUS_SUCCESS;
}
u8_t tester_unregister_mesh(void)
{
return BTP_STATUS_SUCCESS;
}