in nimble/host/mesh/src/lpn.c [952:1032]
int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
struct os_mbuf *buf)
{
struct bt_mesh_ctl_friend_update *msg = (void *)buf->om_data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
struct bt_mesh_subnet *sub = rx->sub;
uint32_t iv_index;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Update");
return -EINVAL;
}
if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) {
BT_WARN("Unexpected friend update");
return 0;
}
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !rx->new_key) {
BT_WARN("Ignoring Phase 2 KR Update secured using old key");
return 0;
}
if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&
(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==
BT_MESH_IV_UPDATE(msg->flags))) {
bt_mesh_beacon_ivu_initiator(false);
}
if (!lpn->established) {
/* This is normally checked on the transport layer, however
* in this state we're also still accepting flooding
* credentials so we need to ensure the right ones (Friend
* Credentials) were used for this message.
*/
if (!rx->friend_cred) {
BT_WARN("Friend Update with wrong credentials");
return -EINVAL;
}
lpn->established = 1;
BT_INFO("Friendship established with 0x%04x", lpn->frnd);
bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER);
if (lpn_cb) {
lpn_cb(lpn->frnd, true);
}
/* Set initial poll timeout */
lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn),
POLL_TIMEOUT_INIT);
}
friend_response_received(lpn);
iv_index = sys_be32_to_cpu(msg->iv_index);
BT_DBG("flags 0x%02x iv_index 0x%08x md %u", msg->flags,
(unsigned) iv_index, msg->md);
bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(msg->flags), rx->new_key);
bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(msg->flags));
if (lpn->groups_changed) {
sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
if (!lpn->sent_req) {
lpn->groups_changed = 0;
}
}
if (msg->md) {
BT_DBG("Requesting for more messages");
send_friend_poll();
}
return 0;
}