Bluetooth: Mesh: Fix & clean up Friendship Credential handling

Pass the subnet to some friend_cred_* APIs since it contains all
necessary information for choosing the right keys to generate them
from. Also shorten the API names to avoid awkward line splitting -
these are internal APIs so it's an acceptable compromise. One bug that
this fixes as part of the cleanup is using the right NetKey Index when
clearing Friendship: previously the code was always using the index of
the first subnet, regardless of which subnet the Friendship was based
on.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-11-27 17:14:01 +02:00 committed by Johan Hedberg
commit 2d63f5e480
5 changed files with 73 additions and 86 deletions

View file

@ -1999,7 +1999,7 @@ static void net_key_update(struct bt_mesh_model *model,
err = bt_mesh_net_keys_create(&sub->keys[1], buf->data);
if (!err && (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) ||
IS_ENABLED(CONFIG_BT_MESH_FRIEND))) {
err = bt_mesh_friend_cred_update(ctx->net_idx, 1, buf->data);
err = friend_cred_update(sub);
}
if (err) {
@ -2608,7 +2608,7 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
bt_mesh_net_revoke_keys(sub);
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) ||
IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
bt_mesh_friend_cred_refresh(ctx->net_idx);
friend_cred_refresh(ctx->net_idx);
}
sub->kr_phase = BT_MESH_KR_NORMAL;
sub->kr_flag = 0;

View file

@ -160,7 +160,7 @@ static void friend_clear(struct bt_mesh_friend *frnd)
k_delayed_work_cancel(&frnd->timer);
bt_mesh_friend_cred_del(bt_mesh.sub[0].net_idx, frnd->lpn);
friend_cred_del(frnd->net_idx, frnd->lpn);
if (frnd->last) {
net_buf_unref(frnd->last);
@ -325,9 +325,8 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd,
priv = sub->keys[sub->kr_flag].privacy;
nid = sub->keys[sub->kr_flag].nid;
} else {
if (bt_mesh_friend_cred_get(sub, frnd->lpn, &nid, &enc,
&priv)) {
BT_ERR("bt_mesh_friend_cred_get failed");
if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
BT_ERR("friend_cred_get failed");
goto failed;
}
}
@ -861,8 +860,7 @@ init_friend:
k_delayed_work_submit(&frnd->timer,
offer_delay(frnd, rx->rssi, msg->criteria));
bt_mesh_friend_cred_add(sub->net_idx, sub->keys[0].net, 0,
frnd->lpn, frnd->lpn_counter, frnd->counter);
friend_cred_create(sub, frnd->lpn, frnd->lpn_counter, frnd->counter);
enqueue_offer(frnd, rx->rssi);

View file

@ -213,7 +213,7 @@ static void clear_friendship(bool force, bool disable)
k_delayed_work_cancel(&lpn->timer);
bt_mesh_friend_cred_del(bt_mesh.sub[0].net_idx, lpn->frnd);
friend_cred_del(bt_mesh.sub[0].net_idx, lpn->frnd);
if (lpn->clear_success) {
lpn->old_friend = BT_MESH_ADDR_UNASSIGNED;
@ -482,7 +482,7 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
struct bt_mesh_ctl_friend_offer *msg = (void *)buf->data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
struct bt_mesh_subnet *sub = rx->sub;
struct bt_mesh_friend_cred *cred;
struct friend_cred *cred;
u16_t frnd_counter;
int err;
@ -509,22 +509,12 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
lpn->frnd = rx->ctx.addr;
cred = bt_mesh_friend_cred_add(sub->net_idx, sub->keys[0].net, 0,
lpn->frnd, lpn->counter, frnd_counter);
cred = friend_cred_create(sub, lpn->frnd, lpn->counter, frnd_counter);
if (!cred) {
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
return -ENOMEM;
}
if (sub->kr_flag) {
err = bt_mesh_friend_cred_set(cred, 1, sub->keys[1].net);
if (err) {
bt_mesh_friend_cred_clear(cred);
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
return err;
}
}
/* TODO: Add offer acceptance criteria check */
k_delayed_work_cancel(&lpn->timer);
@ -534,7 +524,7 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
err = send_friend_poll();
if (err) {
bt_mesh_friend_cred_clear(cred);
friend_cred_clear(cred);
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
lpn->recv_win = 0;
lpn->queue_size = 0;

View file

@ -64,7 +64,7 @@
#endif
#if FRIEND_CRED_COUNT > 0
static struct bt_mesh_friend_cred friend_cred[FRIEND_CRED_COUNT];
static struct friend_cred friend_cred[FRIEND_CRED_COUNT];
#endif
static u64_t msg_cache[CONFIG_BT_MESH_MSG_CACHE_SIZE];
@ -208,8 +208,7 @@ int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys,
#if (defined(CONFIG_BT_MESH_LOW_POWER) || \
defined(CONFIG_BT_MESH_FRIEND))
int bt_mesh_friend_cred_set(struct bt_mesh_friend_cred *cred, u8_t idx,
const u8_t net_key[16])
int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16])
{
u16_t lpn_addr, frnd_addr;
int err;
@ -252,12 +251,12 @@ int bt_mesh_friend_cred_set(struct bt_mesh_friend_cred *cred, u8_t idx,
return 0;
}
void bt_mesh_friend_cred_refresh(u16_t net_idx)
void friend_cred_refresh(u16_t net_idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct bt_mesh_friend_cred *cred = &friend_cred[i];
struct friend_cred *cred = &friend_cred[i];
if (cred->addr != BT_MESH_ADDR_UNASSIGNED &&
cred->net_idx == net_idx) {
@ -267,21 +266,21 @@ void bt_mesh_friend_cred_refresh(u16_t net_idx)
}
}
int bt_mesh_friend_cred_update(u16_t net_idx, u8_t idx, const u8_t net_key[16])
int friend_cred_update(struct bt_mesh_subnet *sub)
{
int err, i;
BT_DBG("net_idx 0x%04x idx %u", net_idx, idx);
BT_DBG("net_idx 0x%04x", sub->net_idx);
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct bt_mesh_friend_cred *cred = &friend_cred[i];
struct friend_cred *cred = &friend_cred[i];
if (cred->addr == BT_MESH_ADDR_UNASSIGNED ||
cred->net_idx != net_idx) {
cred->net_idx != sub->net_idx) {
continue;
}
err = bt_mesh_friend_cred_set(cred, idx, net_key);
err = friend_cred_set(cred, 1, sub->keys[1].net);
if (err) {
return err;
}
@ -290,21 +289,18 @@ int bt_mesh_friend_cred_update(u16_t net_idx, u8_t idx, const u8_t net_key[16])
return 0;
}
struct bt_mesh_friend_cred *bt_mesh_friend_cred_add(u16_t net_idx,
const u8_t net_key[16],
u8_t idx, u16_t addr,
u16_t lpn_counter,
u16_t frnd_counter)
struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
u16_t lpn_counter, u16_t frnd_counter)
{
struct bt_mesh_friend_cred *cred;
struct friend_cred *cred;
int i, err;
BT_DBG("net_idx 0x%04x addr 0x%04x idx %u", net_idx, addr, idx);
BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr);
for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) {
if ((friend_cred[i].addr == BT_MESH_ADDR_UNASSIGNED) ||
(friend_cred[i].addr == addr &&
friend_cred[i].net_idx == net_idx)) {
friend_cred[i].net_idx == sub->net_idx)) {
cred = &friend_cred[i];
break;
}
@ -315,21 +311,29 @@ struct bt_mesh_friend_cred *bt_mesh_friend_cred_add(u16_t net_idx,
return NULL;
}
cred->net_idx = net_idx;
cred->net_idx = sub->net_idx;
cred->addr = addr;
cred->lpn_counter = lpn_counter;
cred->frnd_counter = frnd_counter;
err = bt_mesh_friend_cred_set(cred, idx, net_key);
err = friend_cred_set(cred, 0, sub->keys[0].net);
if (err) {
bt_mesh_friend_cred_clear(cred);
friend_cred_clear(cred);
return NULL;
}
if (sub->kr_flag) {
err = friend_cred_set(cred, 1, sub->keys[1].net);
if (err) {
friend_cred_clear(cred);
return NULL;
}
}
return cred;
}
void bt_mesh_friend_cred_clear(struct bt_mesh_friend_cred *cred)
void friend_cred_clear(struct friend_cred *cred)
{
cred->net_idx = BT_MESH_KEY_UNUSED;
cred->addr = BT_MESH_ADDR_UNASSIGNED;
@ -338,15 +342,15 @@ void bt_mesh_friend_cred_clear(struct bt_mesh_friend_cred *cred)
memset(cred->cred, 0, sizeof(cred->cred));
}
int bt_mesh_friend_cred_del(u16_t net_idx, u16_t addr)
int friend_cred_del(u16_t net_idx, u16_t addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct bt_mesh_friend_cred *cred = &friend_cred[i];
struct friend_cred *cred = &friend_cred[i];
if (cred->addr == addr && cred->net_idx == net_idx) {
bt_mesh_friend_cred_clear(cred);
friend_cred_clear(cred);
return 0;
}
}
@ -354,15 +358,15 @@ int bt_mesh_friend_cred_del(u16_t net_idx, u16_t addr)
return -ENOENT;
}
int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv)
int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv)
{
int i;
BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr);
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct bt_mesh_friend_cred *cred = &friend_cred[i];
struct friend_cred *cred = &friend_cred[i];
if (cred->net_idx != sub->net_idx) {
continue;
@ -390,8 +394,8 @@ int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
return -ENOENT;
}
#else
int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv)
int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv)
{
return -ENOENT;
}
@ -541,7 +545,7 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, u8_t new_kr, bool new_key)
bt_mesh_net_revoke_keys(sub);
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) ||
IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
bt_mesh_friend_cred_refresh(sub->net_idx);
friend_cred_refresh(sub->net_idx);
}
sub->kr_phase = BT_MESH_KR_NORMAL;
return true;
@ -801,8 +805,8 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf,
}
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && tx->friend_cred) {
if (bt_mesh_friend_cred_get(tx->sub, BT_MESH_ADDR_UNASSIGNED,
&nid, &enc, &priv)) {
if (friend_cred_get(tx->sub, BT_MESH_ADDR_UNASSIGNED,
&nid, &enc, &priv)) {
BT_WARN("Falling back to master credentials");
tx->friend_cred = 0;
@ -993,7 +997,7 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const u8_t *data,
BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx);
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct bt_mesh_friend_cred *cred = &friend_cred[i];
struct friend_cred *cred = &friend_cred[i];
if (cred->net_idx != sub->net_idx) {
continue;

View file

@ -27,21 +27,6 @@ struct bt_mesh_app_key {
} keys[2];
};
/* Friendship Credentials */
struct bt_mesh_friend_cred {
u16_t net_idx;
u16_t addr;
u16_t lpn_counter;
u16_t frnd_counter;
struct {
u8_t nid; /* NID */
u8_t enc[16]; /* EncKey */
u8_t privacy[16]; /* PrivacyKey */
} cred[2];
};
struct bt_mesh_subnet {
u32_t beacon_sent; /* Timestamp of last sent beacon */
u8_t beacons_last; /* Number of beacons during last
@ -279,21 +264,6 @@ int bt_mesh_net_create(u16_t idx, u8_t flags, const u8_t key[16],
u8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub);
int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv);
int bt_mesh_friend_cred_set(struct bt_mesh_friend_cred *cred, u8_t idx,
const u8_t net_key[16]);
void bt_mesh_friend_cred_refresh(u16_t net_idx);
int bt_mesh_friend_cred_update(u16_t net_idx, u8_t idx,
const u8_t net_key[16]);
struct bt_mesh_friend_cred *bt_mesh_friend_cred_add(u16_t net_idx,
const u8_t net_key[16],
u8_t idx, u16_t addr,
u16_t lpn_counter,
u16_t frnd_counter);
void bt_mesh_friend_cred_clear(struct bt_mesh_friend_cred *cred);
int bt_mesh_friend_cred_del(u16_t net_idx, u16_t addr);
bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, u8_t new_kr, bool new_key);
void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub);
@ -327,3 +297,28 @@ void bt_mesh_net_recv(struct net_buf_simple *data, s8_t rssi,
enum bt_mesh_net_if net_if);
void bt_mesh_net_init(void);
/* Friendship Credential Management */
struct friend_cred {
u16_t net_idx;
u16_t addr;
u16_t lpn_counter;
u16_t frnd_counter;
struct {
u8_t nid; /* NID */
u8_t enc[16]; /* EncKey */
u8_t privacy[16]; /* PrivacyKey */
} cred[2];
};
int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv);
int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16]);
void friend_cred_refresh(u16_t net_idx);
int friend_cred_update(struct bt_mesh_subnet *sub);
struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
u16_t lpn_counter, u16_t frnd_counter);
void friend_cred_clear(struct friend_cred *cred);
int friend_cred_del(u16_t net_idx, u16_t addr);