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); err = bt_mesh_net_keys_create(&sub->keys[1], buf->data);
if (!err && (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || if (!err && (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) ||
IS_ENABLED(CONFIG_BT_MESH_FRIEND))) { 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) { 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); bt_mesh_net_revoke_keys(sub);
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) ||
IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { 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_phase = BT_MESH_KR_NORMAL;
sub->kr_flag = 0; 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); 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) { if (frnd->last) {
net_buf_unref(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; priv = sub->keys[sub->kr_flag].privacy;
nid = sub->keys[sub->kr_flag].nid; nid = sub->keys[sub->kr_flag].nid;
} else { } else {
if (bt_mesh_friend_cred_get(sub, frnd->lpn, &nid, &enc, if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
&priv)) { BT_ERR("friend_cred_get failed");
BT_ERR("bt_mesh_friend_cred_get failed");
goto failed; goto failed;
} }
} }
@ -861,8 +860,7 @@ init_friend:
k_delayed_work_submit(&frnd->timer, k_delayed_work_submit(&frnd->timer,
offer_delay(frnd, rx->rssi, msg->criteria)); offer_delay(frnd, rx->rssi, msg->criteria));
bt_mesh_friend_cred_add(sub->net_idx, sub->keys[0].net, 0, friend_cred_create(sub, frnd->lpn, frnd->lpn_counter, frnd->counter);
frnd->lpn, frnd->lpn_counter, frnd->counter);
enqueue_offer(frnd, rx->rssi); 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); 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) { if (lpn->clear_success) {
lpn->old_friend = BT_MESH_ADDR_UNASSIGNED; 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_ctl_friend_offer *msg = (void *)buf->data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn; struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
struct bt_mesh_subnet *sub = rx->sub; struct bt_mesh_subnet *sub = rx->sub;
struct bt_mesh_friend_cred *cred; struct friend_cred *cred;
u16_t frnd_counter; u16_t frnd_counter;
int err; int err;
@ -509,22 +509,12 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
lpn->frnd = rx->ctx.addr; lpn->frnd = rx->ctx.addr;
cred = bt_mesh_friend_cred_add(sub->net_idx, sub->keys[0].net, 0, cred = friend_cred_create(sub, lpn->frnd, lpn->counter, frnd_counter);
lpn->frnd, lpn->counter, frnd_counter);
if (!cred) { if (!cred) {
lpn->frnd = BT_MESH_ADDR_UNASSIGNED; lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
return -ENOMEM; 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 */ /* TODO: Add offer acceptance criteria check */
k_delayed_work_cancel(&lpn->timer); 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(); err = send_friend_poll();
if (err) { if (err) {
bt_mesh_friend_cred_clear(cred); friend_cred_clear(cred);
lpn->frnd = BT_MESH_ADDR_UNASSIGNED; lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
lpn->recv_win = 0; lpn->recv_win = 0;
lpn->queue_size = 0; lpn->queue_size = 0;

View file

@ -64,7 +64,7 @@
#endif #endif
#if FRIEND_CRED_COUNT > 0 #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 #endif
static u64_t msg_cache[CONFIG_BT_MESH_MSG_CACHE_SIZE]; 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) || \ #if (defined(CONFIG_BT_MESH_LOW_POWER) || \
defined(CONFIG_BT_MESH_FRIEND)) defined(CONFIG_BT_MESH_FRIEND))
int bt_mesh_friend_cred_set(struct bt_mesh_friend_cred *cred, u8_t idx, int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16])
const u8_t net_key[16])
{ {
u16_t lpn_addr, frnd_addr; u16_t lpn_addr, frnd_addr;
int err; int err;
@ -252,12 +251,12 @@ int bt_mesh_friend_cred_set(struct bt_mesh_friend_cred *cred, u8_t idx,
return 0; return 0;
} }
void bt_mesh_friend_cred_refresh(u16_t net_idx) void friend_cred_refresh(u16_t net_idx)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(friend_cred); 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 && if (cred->addr != BT_MESH_ADDR_UNASSIGNED &&
cred->net_idx == net_idx) { 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; 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++) { 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 || if (cred->addr == BT_MESH_ADDR_UNASSIGNED ||
cred->net_idx != net_idx) { cred->net_idx != sub->net_idx) {
continue; continue;
} }
err = bt_mesh_friend_cred_set(cred, idx, net_key); err = friend_cred_set(cred, 1, sub->keys[1].net);
if (err) { if (err) {
return 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; return 0;
} }
struct bt_mesh_friend_cred *bt_mesh_friend_cred_add(u16_t net_idx, struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
const u8_t net_key[16], u16_t lpn_counter, u16_t frnd_counter)
u8_t idx, u16_t addr,
u16_t lpn_counter,
u16_t frnd_counter)
{ {
struct bt_mesh_friend_cred *cred; struct friend_cred *cred;
int i, err; 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++) { for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) {
if ((friend_cred[i].addr == BT_MESH_ADDR_UNASSIGNED) || if ((friend_cred[i].addr == BT_MESH_ADDR_UNASSIGNED) ||
(friend_cred[i].addr == addr && (friend_cred[i].addr == addr &&
friend_cred[i].net_idx == net_idx)) { friend_cred[i].net_idx == sub->net_idx)) {
cred = &friend_cred[i]; cred = &friend_cred[i];
break; break;
} }
@ -315,21 +311,29 @@ struct bt_mesh_friend_cred *bt_mesh_friend_cred_add(u16_t net_idx,
return NULL; return NULL;
} }
cred->net_idx = net_idx; cred->net_idx = sub->net_idx;
cred->addr = addr; cred->addr = addr;
cred->lpn_counter = lpn_counter; cred->lpn_counter = lpn_counter;
cred->frnd_counter = frnd_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) { if (err) {
bt_mesh_friend_cred_clear(cred); friend_cred_clear(cred);
return NULL; 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; 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->net_idx = BT_MESH_KEY_UNUSED;
cred->addr = BT_MESH_ADDR_UNASSIGNED; 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)); 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; int i;
for (i = 0; i < ARRAY_SIZE(friend_cred); 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) { if (cred->addr == addr && cred->net_idx == net_idx) {
bt_mesh_friend_cred_clear(cred); friend_cred_clear(cred);
return 0; return 0;
} }
} }
@ -354,7 +358,7 @@ int bt_mesh_friend_cred_del(u16_t net_idx, u16_t addr)
return -ENOENT; return -ENOENT;
} }
int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid, int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv) const u8_t **enc, const u8_t **priv)
{ {
int i; int i;
@ -362,7 +366,7 @@ int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr);
for (i = 0; i < ARRAY_SIZE(friend_cred); 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->net_idx != sub->net_idx) { if (cred->net_idx != sub->net_idx) {
continue; continue;
@ -390,7 +394,7 @@ int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
return -ENOENT; return -ENOENT;
} }
#else #else
int bt_mesh_friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid, int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv) const u8_t **enc, const u8_t **priv)
{ {
return -ENOENT; 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); bt_mesh_net_revoke_keys(sub);
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) ||
IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { 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; sub->kr_phase = BT_MESH_KR_NORMAL;
return true; return true;
@ -801,7 +805,7 @@ 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 (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && tx->friend_cred) {
if (bt_mesh_friend_cred_get(tx->sub, BT_MESH_ADDR_UNASSIGNED, if (friend_cred_get(tx->sub, BT_MESH_ADDR_UNASSIGNED,
&nid, &enc, &priv)) { &nid, &enc, &priv)) {
BT_WARN("Falling back to master credentials"); BT_WARN("Falling back to master credentials");
@ -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); BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx);
for (i = 0; i < ARRAY_SIZE(friend_cred); 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->net_idx != sub->net_idx) { if (cred->net_idx != sub->net_idx) {
continue; continue;

View file

@ -27,21 +27,6 @@ struct bt_mesh_app_key {
} keys[2]; } 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 { struct bt_mesh_subnet {
u32_t beacon_sent; /* Timestamp of last sent beacon */ u32_t beacon_sent; /* Timestamp of last sent beacon */
u8_t beacons_last; /* Number of beacons during last 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); 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); 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); 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); enum bt_mesh_net_if net_if);
void bt_mesh_net_init(void); 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);