blob: c02c9dd00f665b8bccaa17bb033745af19d8fa3f [file] [log] [blame]
/*
* 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"
#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 int handle_beacon_status(struct bt_mesh_model *mod,
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)) {
LOG_WRN("Unexpected beacon status from 0x%04x", ctx->addr);
return -EINVAL;
}
rsp->enabled = beacon;
rsp->rand_interval = rand_int;
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
return 0;
}
static int handle_gatt_proxy_status(struct bt_mesh_model *mod,
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)) {
LOG_WRN("Unexpected proxy status from 0x%04x", ctx->addr);
return -EINVAL;
}
*rsp = proxy;
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
return 0;
}
static int handle_node_id_status(struct bt_mesh_model *mod,
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)) {
LOG_WRN("Unexpected node ID status from 0x%04x", ctx->addr);
return -EINVAL;
}
rsp->status = status;
rsp->state = node_id;
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
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(struct bt_mesh_model *mod)
{
if (!bt_mesh_model_in_primary(mod)) {
LOG_ERR("Private Beacon Client only allowed in primary element");
return -EINVAL;
}
cli = mod->user_data;
cli->mod = mod;
cli->timeout = 2 * MSEC_PER_SEC;
mod->keys[0] = BT_MESH_KEY_DEV_ANY;
mod->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,
};
static int send(struct bt_mesh_priv_beacon_cli *cli, uint16_t net_idx,
uint16_t addr, struct net_buf_simple *buf)
{
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
return bt_mesh_model_send(cli->mod, &ctx, buf, NULL, NULL);
}
int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val)
{
int err;
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_BEACON_STATUS, addr, val);
if (err) {
return err;
}
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);
}
err = send(cli, net_idx, addr, &buf);
if (err) {
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}
int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val)
{
int err;
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_BEACON_STATUS, addr, val);
if (err) {
return err;
}
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_GET, 0);
bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_GET);
err = send(cli, net_idx, addr, &buf);
if (err) {
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}
int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t *val)
{
int err;
if (!val || (*val != BT_MESH_GATT_PROXY_DISABLED &&
*val != BT_MESH_GATT_PROXY_ENABLED)) {
return -EINVAL;
}
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_GATT_PROXY_STATUS, addr, val);
if (err) {
return err;
}
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);
err = send(cli, net_idx, addr, &buf);
if (err) {
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}
int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *val)
{
int err;
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_GATT_PROXY_STATUS, addr, val);
if (err) {
return err;
}
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_GET, 0);
bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_GET);
err = send(cli, net_idx, addr, &buf);
if (err) {
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}
int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr,
struct bt_mesh_priv_node_id *val)
{
int err;
if (!val || val->net_idx > 0xfff ||
(val->state != BT_MESH_NODE_IDENTITY_STOPPED &&
val->state != BT_MESH_NODE_IDENTITY_RUNNING)) {
return -EINVAL;
}
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_NODE_ID_STATUS, addr, val);
if (err) {
return err;
}
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);
err = send(cli, net_idx, addr, &buf);
if (err) {
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}
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)
{
int err;
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_NODE_ID_STATUS, addr, val);
if (err) {
return err;
}
val->net_idx = key_net_idx;
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);
err = send(cli, net_idx, addr, &buf);
if (err) {
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
return err;
}
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
}