| /* |
| * Copyright (c) 2020 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/bluetooth/mesh.h> |
| #include "net.h" |
| #include "foundation.h" |
| #include "access.h" |
| #include "msg.h" |
| |
| #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(bt_mesh_priv_beacon_cli); |
| |
| static struct bt_mesh_priv_beacon_cli *cli; |
| |
| static int32_t msg_timeout; |
| |
| static int handle_beacon_status(const struct bt_mesh_model *model, |
| struct bt_mesh_msg_ctx *ctx, |
| struct net_buf_simple *buf) |
| { |
| struct bt_mesh_priv_beacon *rsp; |
| uint8_t beacon, rand_int; |
| |
| beacon = net_buf_simple_pull_u8(buf); |
| rand_int = net_buf_simple_pull_u8(buf); |
| |
| if (beacon != BT_MESH_BEACON_DISABLED && |
| beacon != BT_MESH_BEACON_ENABLED) { |
| LOG_WRN("Invalid beacon value 0x%02x", beacon); |
| return -EINVAL; |
| } |
| |
| LOG_DBG("0x%02x (%u s)", beacon, 10U * rand_int); |
| |
| if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_BEACON_STATUS, ctx->addr, |
| (void **)&rsp)) { |
| rsp->enabled = beacon; |
| rsp->rand_interval = rand_int; |
| |
| bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); |
| } |
| |
| if (cli->cb && cli->cb->priv_beacon_status) { |
| struct bt_mesh_priv_beacon state = { |
| .enabled = beacon, |
| .rand_interval = rand_int, |
| }; |
| |
| cli->cb->priv_beacon_status(cli, ctx->addr, &state); |
| } |
| |
| return 0; |
| } |
| |
| static int handle_gatt_proxy_status(const struct bt_mesh_model *model, |
| struct bt_mesh_msg_ctx *ctx, |
| struct net_buf_simple *buf) |
| { |
| uint8_t *rsp; |
| uint8_t proxy; |
| |
| proxy = net_buf_simple_pull_u8(buf); |
| |
| if (proxy != BT_MESH_GATT_PROXY_DISABLED && |
| proxy != BT_MESH_GATT_PROXY_ENABLED && |
| proxy != BT_MESH_GATT_PROXY_NOT_SUPPORTED) { |
| LOG_WRN("Invalid GATT proxy value 0x%02x", proxy); |
| return -EINVAL; |
| } |
| |
| if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_GATT_PROXY_STATUS, ctx->addr, |
| (void **)&rsp)) { |
| *rsp = proxy; |
| |
| bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); |
| } |
| |
| if (cli->cb && cli->cb->priv_gatt_proxy_status) { |
| cli->cb->priv_gatt_proxy_status(cli, ctx->addr, proxy); |
| } |
| |
| return 0; |
| } |
| |
| static int handle_node_id_status(const struct bt_mesh_model *model, |
| struct bt_mesh_msg_ctx *ctx, |
| struct net_buf_simple *buf) |
| { |
| struct bt_mesh_priv_node_id *rsp; |
| uint8_t status, node_id; |
| uint16_t net_idx; |
| |
| status = net_buf_simple_pull_u8(buf); |
| net_idx = net_buf_simple_pull_le16(buf); |
| node_id = net_buf_simple_pull_u8(buf); |
| |
| if (node_id != BT_MESH_NODE_IDENTITY_STOPPED && |
| node_id != BT_MESH_NODE_IDENTITY_RUNNING && |
| node_id != BT_MESH_NODE_IDENTITY_NOT_SUPPORTED) { |
| LOG_WRN("Invalid node ID value 0x%02x", node_id); |
| return -EINVAL; |
| } |
| |
| if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_NODE_ID_STATUS, ctx->addr, |
| (void **)&rsp)) { |
| rsp->net_idx = net_idx; |
| rsp->status = status; |
| rsp->state = node_id; |
| |
| bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); |
| } |
| |
| if (cli->cb && cli->cb->priv_node_id_status) { |
| struct bt_mesh_priv_node_id state = { |
| .net_idx = net_idx, |
| .status = status, |
| .state = node_id, |
| }; |
| |
| cli->cb->priv_node_id_status(cli, ctx->addr, &state); |
| } |
| |
| return 0; |
| } |
| |
| const struct bt_mesh_model_op bt_mesh_priv_beacon_cli_op[] = { |
| { OP_PRIV_BEACON_STATUS, BT_MESH_LEN_EXACT(2), handle_beacon_status }, |
| { OP_PRIV_GATT_PROXY_STATUS, BT_MESH_LEN_EXACT(1), handle_gatt_proxy_status }, |
| { OP_PRIV_NODE_ID_STATUS, BT_MESH_LEN_EXACT(4), handle_node_id_status }, |
| BT_MESH_MODEL_OP_END, |
| }; |
| |
| static int priv_beacon_cli_init(const struct bt_mesh_model *model) |
| { |
| if (!bt_mesh_model_in_primary(model)) { |
| LOG_ERR("Private Beacon Client only allowed in primary element"); |
| return -EINVAL; |
| } |
| |
| cli = model->rt->user_data; |
| cli->model = model; |
| msg_timeout = 2 * MSEC_PER_SEC; |
| model->keys[0] = BT_MESH_KEY_DEV_ANY; |
| model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY; |
| |
| bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); |
| |
| return 0; |
| } |
| |
| const struct bt_mesh_model_cb bt_mesh_priv_beacon_cli_cb = { |
| .init = priv_beacon_cli_init, |
| }; |
| |
| int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val, |
| struct bt_mesh_priv_beacon *rsp) |
| { |
| struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); |
| const struct bt_mesh_msg_rsp_ctx rsp_ctx = { |
| .ack = &cli->ack_ctx, |
| .op = OP_PRIV_BEACON_STATUS, |
| .user_data = rsp, |
| .timeout = msg_timeout, |
| }; |
| |
| BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_SET, 2); |
| bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_SET); |
| |
| net_buf_simple_add_u8(&buf, val->enabled); |
| if (val->rand_interval) { |
| net_buf_simple_add_u8(&buf, val->rand_interval); |
| } |
| |
| return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL); |
| } |
| |
| int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val) |
| { |
| struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); |
| const struct bt_mesh_msg_rsp_ctx rsp_ctx = { |
| .ack = &cli->ack_ctx, |
| .op = OP_PRIV_BEACON_STATUS, |
| .user_data = val, |
| .timeout = msg_timeout, |
| }; |
| |
| BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_GET, 0); |
| bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_GET); |
| |
| return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL); |
| } |
| |
| int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t val, |
| uint8_t *rsp) |
| { |
| struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); |
| const struct bt_mesh_msg_rsp_ctx rsp_ctx = { |
| .ack = &cli->ack_ctx, |
| .op = OP_PRIV_GATT_PROXY_STATUS, |
| .user_data = rsp, |
| .timeout = msg_timeout, |
| }; |
| |
| if ((val != BT_MESH_GATT_PROXY_DISABLED && |
| val != BT_MESH_GATT_PROXY_ENABLED)) { |
| return -EINVAL; |
| } |
| |
| BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_SET, 1); |
| bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_SET); |
| |
| net_buf_simple_add_u8(&buf, val); |
| |
| return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL); |
| } |
| |
| int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *val) |
| { |
| struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); |
| const struct bt_mesh_msg_rsp_ctx rsp_ctx = { |
| .ack = &cli->ack_ctx, |
| .op = OP_PRIV_GATT_PROXY_STATUS, |
| .user_data = val, |
| .timeout = msg_timeout, |
| }; |
| |
| BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_GET, 0); |
| bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_GET); |
| |
| return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL); |
| } |
| |
| int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr, |
| struct bt_mesh_priv_node_id *val, |
| struct bt_mesh_priv_node_id *rsp) |
| { |
| struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); |
| const struct bt_mesh_msg_rsp_ctx rsp_ctx = { |
| .ack = &cli->ack_ctx, |
| .op = OP_PRIV_NODE_ID_STATUS, |
| .user_data = rsp, |
| .timeout = msg_timeout, |
| }; |
| |
| if (val->net_idx > 0xfff || |
| (val->state != BT_MESH_NODE_IDENTITY_STOPPED && |
| val->state != BT_MESH_NODE_IDENTITY_RUNNING)) { |
| return -EINVAL; |
| } |
| |
| BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_NODE_ID_SET, 3); |
| bt_mesh_model_msg_init(&buf, OP_PRIV_NODE_ID_SET); |
| |
| net_buf_simple_add_le16(&buf, val->net_idx); |
| net_buf_simple_add_u8(&buf, val->state); |
| |
| return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, rsp ? &rsp_ctx : NULL); |
| } |
| |
| int bt_mesh_priv_beacon_cli_node_id_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, |
| struct bt_mesh_priv_node_id *val) |
| { |
| struct bt_mesh_msg_ctx ctx = BT_MESH_MSG_CTX_INIT_DEV(net_idx, addr); |
| const struct bt_mesh_msg_rsp_ctx rsp_ctx = { |
| .ack = &cli->ack_ctx, |
| .op = OP_PRIV_NODE_ID_STATUS, |
| .user_data = val, |
| .timeout = msg_timeout, |
| }; |
| |
| BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_NODE_ID_GET, 2); |
| bt_mesh_model_msg_init(&buf, OP_PRIV_NODE_ID_GET); |
| |
| net_buf_simple_add_le16(&buf, key_net_idx); |
| |
| return bt_mesh_msg_ackd_send(cli->model, &ctx, &buf, val ? &rsp_ctx : NULL); |
| } |