blob: c9fa91fc7e02c3fb652f0a2e65feab46150227ee [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <misc/util.h>
#include <misc/byteorder.h>
#include <settings/settings.h>
#include <net/buf.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_SETTINGS)
#include "common/log.h"
#include "../settings.h"
#include "mesh.h"
#include "net.h"
#include "crypto.h"
#include "transport.h"
#include "access.h"
#include "foundation.h"
#include "proxy.h"
#include "settings.h"
/* Mesh network storage information */
struct net_val {
u16_t primary_addr;
u8_t dev_key[16];
} __packed;
/* Sequence number storage */
struct seq_val {
u8_t val[3];
} __packed;
/* IV Index & IV Update storage */
struct iv_val {
u32_t iv_index;
bool iv_update;
} __packed;
/* Replay Protection List storage */
struct rpl_val {
u32_t seq:24,
old_iv:1;
};
/* NetKey storage information */
struct net_key_val {
u8_t kr_flag:1,
kr_phase:7;
u8_t val[2][16];
} __packed;
/* AppKey storage information */
struct app_key_val {
u16_t net_idx;
bool updated;
u8_t val[2][16];
} __packed;
static int net_set(int argc, char **argv, char *val)
{
struct net_val net;
int len, err;
BT_DBG("val %s", val ? val : "(null)");
if (!val) {
bt_mesh_comp_unprovision();
memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
return 0;
}
len = sizeof(net);
err = settings_bytes_from_str(val, &net, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return err;
}
if (len != sizeof(net)) {
BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net));
return -EINVAL;
}
memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key));
bt_mesh_comp_provision(net.primary_addr);
BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr);
BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16));
return 0;
}
static int iv_set(int argc, char **argv, char *val)
{
struct iv_val iv;
int len, err;
BT_DBG("val %s", val ? val : "(null)");
if (!val) {
bt_mesh.iv_index = 0;
bt_mesh.iv_update = 0;
return 0;
}
len = sizeof(iv);
err = settings_bytes_from_str(val, &iv, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return err;
}
if (len != sizeof(iv)) {
BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv));
return -EINVAL;
}
bt_mesh.iv_index = iv.iv_index;
bt_mesh.iv_update = iv.iv_update;
BT_DBG("IV Index 0x%04x (IV Update Flag %u)", bt_mesh.iv_index,
bt_mesh.iv_update);
return 0;
}
static int seq_set(int argc, char **argv, char *val)
{
struct seq_val seq;
int len, err;
BT_DBG("val %s", val ? val : "(null)");
if (!val) {
bt_mesh.seq = 0;
return 0;
}
len = sizeof(seq);
err = settings_bytes_from_str(val, &seq, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return err;
}
if (len != sizeof(seq)) {
BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq));
return -EINVAL;
}
bt_mesh.seq = ((u32_t)seq.val[0] | ((u32_t)seq.val[1] << 8) |
((u32_t)seq.val[2] << 16));
BT_DBG("Sequence Number 0x%06x", bt_mesh.seq);
return 0;
}
static struct bt_mesh_rpl *rpl_find(u16_t src)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) {
if (bt_mesh.rpl[i].src == src) {
return &bt_mesh.rpl[i];
}
}
return NULL;
}
static struct bt_mesh_rpl *rpl_alloc(u16_t src)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) {
if (!bt_mesh.rpl[i].src) {
bt_mesh.rpl[i].src = src;
return &bt_mesh.rpl[i];
}
}
return NULL;
}
static int rpl_set(int argc, char **argv, char *val)
{
struct bt_mesh_rpl *entry;
struct rpl_val rpl;
int len, err;
u16_t src;
if (argc < 1) {
BT_ERR("Invalid argc (%d)", argc);
return -ENOENT;
}
BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)");
src = strtol(argv[0], NULL, 16);
entry = rpl_find(src);
if (!val) {
if (entry) {
memset(entry, 0, sizeof(*entry));
} else {
BT_WARN("Unable to find RPL entry for 0x%04x", src);
}
return 0;
}
if (!entry) {
entry = rpl_alloc(src);
if (!entry) {
BT_ERR("Unable to allocate RPL entry for 0x%04x", src);
return -ENOMEM;
}
}
len = sizeof(rpl);
err = settings_bytes_from_str(val, &rpl, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return err;
}
if (len != sizeof(rpl)) {
BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(rpl));
return -EINVAL;
}
entry->seq = rpl.seq;
entry->old_iv = rpl.old_iv;
BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src,
entry->seq, entry->old_iv);
return 0;
}
static int net_key_set(int argc, char **argv, char *val)
{
struct bt_mesh_subnet *sub;
struct net_key_val key;
int len, i, err;
u16_t net_idx;
BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)");
net_idx = strtol(argv[0], NULL, 16);
sub = bt_mesh_subnet_get(net_idx);
if (!val) {
if (!sub) {
BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx);
return -ENOENT;
}
BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx);
bt_mesh_subnet_del(sub);
return 0;
}
len = sizeof(key);
err = settings_bytes_from_str(val, &key, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return err;
}
if (len != sizeof(key)) {
BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(key));
return -EINVAL;
}
if (sub) {
BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx);
sub->kr_flag = key.kr_flag;
sub->kr_phase = key.kr_phase;
memcpy(sub->keys[0].net, &key.val[0], 16);
memcpy(sub->keys[1].net, &key.val[1], 16);
return 0;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
if (bt_mesh.sub[i].net_idx == BT_MESH_KEY_UNUSED) {
sub = &bt_mesh.sub[i];
break;
}
}
if (!sub) {
BT_ERR("No space to allocate a new subnet");
return -ENOMEM;
}
sub->net_idx = net_idx;
sub->kr_flag = key.kr_flag;
sub->kr_phase = key.kr_phase;
memcpy(sub->keys[0].net, &key.val[0], 16);
memcpy(sub->keys[1].net, &key.val[1], 16);
BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx);
return 0;
}
static int app_key_set(int argc, char **argv, char *val)
{
struct bt_mesh_app_key *app;
struct bt_mesh_subnet *sub;
struct app_key_val key;
u16_t app_idx;
int len, err;
BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)");
app_idx = strtol(argv[0], NULL, 16);
if (!val) {
BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx);
app = bt_mesh_app_key_find(app_idx);
if (app) {
bt_mesh_app_key_del(app);
}
return 0;
}
len = sizeof(key);
err = settings_bytes_from_str(val, &key, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return err;
}
if (len != sizeof(key)) {
BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(key));
return -EINVAL;
}
sub = bt_mesh_subnet_get(key.net_idx);
if (!sub) {
BT_ERR("Failed to find subnet 0x%03x", key.net_idx);
return -ENOENT;
}
app = bt_mesh_app_key_find(app_idx);
if (!app) {
app = bt_mesh_app_key_alloc(app_idx);
}
if (!app) {
BT_ERR("No space for a new app key");
return -ENOMEM;
}
app->net_idx = key.net_idx;
app->app_idx = app_idx;
app->updated = key.updated;
memcpy(app->keys[0].val, key.val[0], 16);
memcpy(app->keys[1].val, key.val[1], 16);
bt_mesh_app_id(app->keys[0].val, &app->keys[0].id);
bt_mesh_app_id(app->keys[1].val, &app->keys[1].id);
BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx);
return 0;
}
const struct mesh_setting {
const char *name;
int (*func)(int argc, char **argv, char *val);
} settings[] = {
{ "Net", net_set },
{ "IV", iv_set },
{ "Seq", seq_set },
{ "RPL", rpl_set },
{ "NetKey", net_key_set },
{ "AppKey", app_key_set },
};
static int mesh_set(int argc, char **argv, char *val)
{
int i;
if (argc < 1) {
BT_ERR("Insufficient number of arguments");
return -EINVAL;
}
BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)");
for (i = 0; i < ARRAY_SIZE(settings); i++) {
if (!strcmp(settings[i].name, argv[0])) {
argc--;
argv++;
return settings[i].func(argc, argv, val);
}
}
BT_WARN("No matching handler for key %s", argv[0]);
return -ENOENT;
}
static int subnet_init(struct bt_mesh_subnet *sub)
{
int err;
err = bt_mesh_net_keys_create(&sub->keys[0], sub->keys[0].net);
if (err) {
BT_ERR("Unable to generate keys for subnet");
return -EIO;
}
if (sub->kr_phase != BT_MESH_KR_NORMAL) {
err = bt_mesh_net_keys_create(&sub->keys[1], sub->keys[1].net);
if (err) {
BT_ERR("Unable to generate keys for subnet");
memset(&sub->keys[0], 0, sizeof(sub->keys[0]));
return -EIO;
}
}
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
} else {
sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED;
}
/* Make sure we have valid beacon data to be sent */
bt_mesh_net_beacon_update(sub);
return 0;
}
static int mesh_commit(void)
{
int i;
BT_DBG("sub[0].net_idx 0x%03x", bt_mesh.sub[0].net_idx);
if (bt_mesh.sub[0].net_idx == BT_MESH_KEY_UNUSED) {
/* Nothing to do since we're not yet provisioned */
return 0;
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
bt_mesh_proxy_prov_disable();
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
int err;
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
err = subnet_init(sub);
if (err) {
BT_ERR("Failed to init subnet 0x%03x", sub->net_idx);
}
}
/* Set initial IV Update procedure state time-stamp */
bt_mesh.last_update = BT_MESH_NET_IVU_UNKNOWN;
/* Set a timer to transition back to normal mode */
if (bt_mesh.iv_update) {
k_delayed_work_submit(&bt_mesh.ivu_complete,
BT_MESH_NET_IVU_TIMEOUT);
}
bt_mesh.valid = 1;
return 0;
}
BT_SETTINGS_DEFINE(mesh, mesh_set, mesh_commit, NULL);
void bt_mesh_store_net(u16_t primary_addr, const u8_t dev_key[16])
{
char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))];
struct net_val net;
char *str;
BT_DBG("addr 0x%04x DevKey %s", primary_addr, bt_hex(dev_key, 16));
net.primary_addr = primary_addr;
memcpy(net.dev_key, dev_key, 16);
str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode Network as value");
return;
}
BT_DBG("Saving Network as value %s", str);
settings_save_one("bt/mesh/Net", str);
}
void bt_mesh_store_iv(void)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))];
struct iv_val iv;
char *str;
iv.iv_index = bt_mesh.iv_index;
iv.iv_update = bt_mesh.iv_update;
str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode IV as value");
return;
}
BT_DBG("Saving IV as value %s", str);
settings_save_one("bt/mesh/IV", str);
}
void bt_mesh_store_seq(void)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))];
struct seq_val seq;
char *str;
seq.val[0] = bt_mesh.seq;
seq.val[1] = bt_mesh.seq >> 8;
seq.val[2] = bt_mesh.seq >> 16;
str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode Seq as value");
return;
}
BT_DBG("Saving Seq as value %s", str);
settings_save_one("bt/mesh/Seq", str);
}
void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct rpl_val))];
struct rpl_val rpl;
char path[18];
char *str;
BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, entry->seq,
entry->old_iv);
rpl.seq = entry->seq;
rpl.old_iv = entry->old_iv;
str = settings_str_from_bytes(&rpl, sizeof(rpl), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode RPL as value");
return;
}
snprintk(path, sizeof(path), "bt/mesh/RPL/%x", entry->src);
BT_DBG("Saving RPL %s as value %s", path, str);
settings_save_one(path, str);
}
void bt_mesh_store_subnet(struct bt_mesh_subnet *sub)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))];
struct net_key_val key;
char path[20];
char *str;
BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx,
bt_hex(sub->keys[0].net, 16));
memcpy(&key.val[0], sub->keys[0].net, 16);
memcpy(&key.val[1], sub->keys[1].net, 16);
key.kr_flag = sub->kr_flag;
key.kr_phase = sub->kr_phase;
str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode NetKey as value");
return;
}
snprintk(path, sizeof(path), "bt/mesh/NetKey/%x", sub->net_idx);
BT_DBG("Saving NetKey %s as value %s", path, str);
settings_save_one(path, str);
}
void bt_mesh_store_app_key(struct bt_mesh_app_key *app)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))];
struct app_key_val key;
char path[20];
char *str;
key.net_idx = app->net_idx;
key.updated = app->updated;
memcpy(key.val[0], app->keys[0].val, 16);
memcpy(key.val[1], app->keys[1].val, 16);
str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode AppKey as value");
return;
}
snprintk(path, sizeof(path), "bt/mesh/AppKey/%x", app->app_idx);
BT_DBG("Saving AppKey %s as value %s", path, str);
settings_save_one(path, str);
}