You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2020/09/16 07:27:32 UTC

[GitHub] [mynewt-nimble] KKopyscinski opened a new pull request #865: mesh/friend.c - Fixes Friend Add Another Update

KKopyscinski opened a new pull request #865:
URL: https://github.com/apache/mynewt-nimble/pull/865


   According MESH/NODE/FRND/FN/BV-20-C should add another
   Friend Update.
   
   This is port of Zephyr patch:
   commit 355bdf5cd95d9f8bf11fc0f00fb1bcb151ff5cab


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [mynewt-nimble] michal-narajowski merged pull request #865: mesh/friend.c - Fixes Friend Add Another Update

Posted by GitBox <gi...@apache.org>.
michal-narajowski merged pull request #865:
URL: https://github.com/apache/mynewt-nimble/pull/865


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [mynewt-nimble] apache-mynewt-bot commented on pull request #865: mesh/friend.c - Fixes Friend Add Another Update

Posted by GitBox <gi...@apache.org>.
apache-mynewt-bot commented on pull request #865:
URL: https://github.com/apache/mynewt-nimble/pull/865#issuecomment-693238425


   
   <!-- style-bot -->
   
   ## Style check summary
   
   ### Our coding style is [here!](https://github.com/apache/mynewt-core/blob/master/CODING_STANDARDS.md)
   
   
   #### nimble/host/mesh/src/friend.c
   <details>
   
   ```diff
   @@ -125,776 +129,805 @@
     * like the PTS, where the receiver might not have sufficiently compensated
     * for internal latencies required to start scanning.
     */
   -static s32_t recv_delay(struct bt_mesh_friend *frnd)
   +static s32_t
   +recv_delay(struct bt_mesh_friend *frnd)
    {
    #if CONFIG_BT_MESH_FRIEND_RECV_WIN > 50
   -	return (s32_t)frnd->recv_delay + (CONFIG_BT_MESH_FRIEND_RECV_WIN / 5);
   +    return (s32_t)frnd->recv_delay + (CONFIG_BT_MESH_FRIEND_RECV_WIN / 5);
    #else
   -	return frnd->recv_delay;
   +    return frnd->recv_delay;
    #endif
    }
    
   -static void friend_clear(struct bt_mesh_friend *frnd)
   -{
   -	int i;
   -
   -	BT_DBG("LPN 0x%04x", frnd->lpn);
   -
   -	k_delayed_work_cancel(&frnd->timer);
   -
   -	friend_cred_del(frnd->net_idx, frnd->lpn);
   -
   -	if (frnd->last) {
   -		/* Cancel the sending if necessary */
   -		if (frnd->pending_buf) {
   -			BT_MESH_ADV(frnd->last)->busy = 0;
   -		}
   -
   -		net_buf_unref(frnd->last);
   -		frnd->last = NULL;
   -	}
   -
   -	purge_buffers(&frnd->queue);
   -
   -	for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
   -		struct bt_mesh_friend_seg *seg = &frnd->seg[i];
   -
   -		purge_buffers(&seg->queue);
   -		seg->seg_count = 0U;
   -	}
   -
   -	frnd->valid = 0;
   -	frnd->established = 0;
   -	frnd->pending_buf = 0;
   -	frnd->fsn = 0;
   -	frnd->queue_size = 0;
   -	frnd->pending_req = 0;
   -	memset(frnd->sub_list, 0, sizeof(frnd->sub_list));
   -}
   -
   -void bt_mesh_friend_clear_net_idx(u16_t net_idx)
   -{
   -	int i;
   -
   -	BT_DBG("net_idx 0x%04x", net_idx);
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -
   -		if (frnd->net_idx == BT_MESH_KEY_UNUSED) {
   -			continue;
   -		}
   -
   -		if (net_idx == BT_MESH_KEY_ANY || frnd->net_idx == net_idx) {
   -			friend_clear(frnd);
   -		}
   -	}
   +static void
   +friend_clear(struct bt_mesh_friend *frnd)
   +{
   +    int i;
   +
   +    BT_DBG("LPN 0x%04x", frnd->lpn);
   +
   +    k_delayed_work_cancel(&frnd->timer);
   +
   +    friend_cred_del(frnd->net_idx, frnd->lpn);
   +
   +    if (frnd->last) {
   +        /* Cancel the sending if necessary */
   +        if (frnd->pending_buf) {
   +            BT_MESH_ADV(frnd->last)->busy = 0;
   +        }
   +
   +        net_buf_unref(frnd->last);
   +        frnd->last = NULL;
   +    }
   +
   +    purge_buffers(&frnd->queue);
   +
   +    for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
   +        struct bt_mesh_friend_seg *seg = &frnd->seg[i];
   +
   +        purge_buffers(&seg->queue);
   +        seg->seg_count = 0U;
   +    }
   +
   +    frnd->valid = 0;
   +    frnd->established = 0;
   +    frnd->pending_buf = 0;
   +    frnd->fsn = 0;
   +    frnd->queue_size = 0;
   +    frnd->pending_req = 0;
   +    memset(frnd->sub_list, 0, sizeof(frnd->sub_list));
   +}
   +
   +void
   +bt_mesh_friend_clear_net_idx(u16_t net_idx)
   +{
   +    int i;
   +
   +    BT_DBG("net_idx 0x%04x", net_idx);
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +
   +        if (frnd->net_idx == BT_MESH_KEY_UNUSED) {
   +            continue;
   +        }
   +
   +        if (net_idx == BT_MESH_KEY_ANY || frnd->net_idx == net_idx) {
   +            friend_clear(frnd);
   +        }
   +    }
    }
    
    static void enqueue_update(struct bt_mesh_friend *frnd, u8_t md);
    
   -void bt_mesh_friend_sec_update(u16_t net_idx)
   -{
   -	int i;
   -
   -	BT_DBG("net_idx 0x%04x", net_idx);
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -
   -		if (frnd->net_idx == BT_MESH_KEY_UNUSED) {
   -			continue;
   -		}
   -
   -		if (net_idx == BT_MESH_KEY_ANY || frnd->net_idx == net_idx) {
   -			enqueue_update(frnd, 0x00);
   -		}
   -	}
   -}
   -
   -int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
   -{
   -	struct bt_mesh_ctl_friend_clear *msg = (void *)buf->om_data;
   -	struct bt_mesh_friend *frnd;
   -	u16_t lpn_addr, lpn_counter;
   -	struct bt_mesh_net_tx tx = {
   -		.sub  = rx->sub,
   -		.ctx  = &rx->ctx,
   -		.src  = bt_mesh_primary_addr(),
   -		.xmit = bt_mesh_net_transmit_get(),
   -	};
   -	struct bt_mesh_ctl_friend_clear_confirm cfm;
   -
   -	if (buf->om_len < sizeof(*msg)) {
   -		BT_WARN("Too short Friend Clear");
   -		return -EINVAL;
   -	}
   -
   -	lpn_addr = sys_be16_to_cpu(msg->lpn_addr);
   -	lpn_counter = sys_be16_to_cpu(msg->lpn_counter);
   -
   -	BT_DBG("LPN addr 0x%04x counter 0x%04x", lpn_addr, lpn_counter);
   -
   -	frnd = bt_mesh_friend_find(rx->sub->net_idx, lpn_addr, false, false);
   -	if (!frnd) {
   -		BT_WARN("No matching LPN addr 0x%04x", lpn_addr);
   -		return 0;
   -	}
   -
   -	/* A Friend Clear message is considered valid if the result of the
   -	 * subtraction of the value of the LPNCounter field of the Friend
   -	 * Request message (the one that initiated the friendship) from the
   -	 * value of the LPNCounter field of the Friend Clear message, modulo
   -	 * 65536, is in the range 0 to 255 inclusive.
   -	 */
   -	if (lpn_counter - frnd->lpn_counter > 255) {
   -		BT_WARN("LPN Counter out of range (old %u new %u)",
   -			frnd->lpn_counter, lpn_counter);
   -		return 0;
   -	}
   -
   -	tx.ctx->send_ttl = BT_MESH_TTL_MAX;
   -
   -	cfm.lpn_addr    = msg->lpn_addr;
   -	cfm.lpn_counter = msg->lpn_counter;
   -
   -	bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR_CFM, &cfm,
   -			 sizeof(cfm), NULL, NULL, NULL);
   -
   -	friend_clear(frnd);
   -
   -	return 0;
   -}
   -
   -static void friend_sub_add(struct bt_mesh_friend *frnd, u16_t addr)
   -{
   -	int i;
   -
   -	for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
   -		if (frnd->sub_list[i] == BT_MESH_ADDR_UNASSIGNED) {
   -			frnd->sub_list[i] = addr;
   -			return;
   -		}
   -	}
   -
   -	BT_WARN("No space in friend subscription list");
   -}
   -
   -static void friend_sub_rem(struct bt_mesh_friend *frnd, u16_t addr)
   -{
   -	int i;
   -
   -	for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
   -		if (frnd->sub_list[i] == addr) {
   -			frnd->sub_list[i] = BT_MESH_ADDR_UNASSIGNED;
   -			return;
   -		}
   -	}
   -}
   -
   -static struct os_mbuf *create_friend_pdu(struct bt_mesh_friend *frnd,
   -					 struct friend_pdu_info *info,
   -					 struct os_mbuf *sdu)
   -{
   -	struct os_mbuf *buf;
   -
   -	buf = bt_mesh_adv_create_from_pool(&friend_os_mbuf_pool, adv_alloc,
   -					   BT_MESH_ADV_DATA,
   -					   FRIEND_XMIT, K_NO_WAIT);
   -	if (!buf) {
   -		return NULL;
   -	}
   -
   -	net_buf_add_u8(buf, (info->iv_index & 1) << 7); /* Will be reset in encryption */
   -
   -	if (info->ctl) {
   -		net_buf_add_u8(buf, info->ttl | 0x80);
   -	} else {
   -		net_buf_add_u8(buf, info->ttl);
   -	}
   -
   -	net_buf_add_mem(buf, info->seq, sizeof(info->seq));
   -
   -	net_buf_add_be16(buf, info->src);
   -	net_buf_add_be16(buf, info->dst);
   -
   -	net_buf_add_mem(buf, sdu->om_data, sdu->om_len);
   -
   -	return buf;
   +void
   +bt_mesh_friend_sec_update(u16_t net_idx)
   +{
   +    int i;
   +
   +    BT_DBG("net_idx 0x%04x", net_idx);
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +
   +        if (frnd->net_idx == BT_MESH_KEY_UNUSED) {
   +            continue;
   +        }
   +
   +        if (net_idx == BT_MESH_KEY_ANY || frnd->net_idx == net_idx) {
   +            enqueue_update(frnd, 0x00);
   +        }
   +    }
   +}
   +
   +int
   +bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
   +{
   +    struct bt_mesh_ctl_friend_clear *msg = (void *)buf->om_data;
   +    struct bt_mesh_friend *frnd;
   +    u16_t lpn_addr, lpn_counter;
   +    struct bt_mesh_net_tx tx = {
   +        .sub = rx->sub,
   +        .ctx = &rx->ctx,
   +        .src = bt_mesh_primary_addr(),
   +        .xmit = bt_mesh_net_transmit_get(),
   +    };
   +    struct bt_mesh_ctl_friend_clear_confirm cfm;
   +
   +    if (buf->om_len < sizeof(*msg)) {
   +        BT_WARN("Too short Friend Clear");
   +        return -EINVAL;
   +    }
   +
   +    lpn_addr = sys_be16_to_cpu(msg->lpn_addr);
   +    lpn_counter = sys_be16_to_cpu(msg->lpn_counter);
   +
   +    BT_DBG("LPN addr 0x%04x counter 0x%04x", lpn_addr, lpn_counter);
   +
   +    frnd = bt_mesh_friend_find(rx->sub->net_idx, lpn_addr, false, false);
   +    if (!frnd) {
   +        BT_WARN("No matching LPN addr 0x%04x", lpn_addr);
   +        return 0;
   +    }
   +
   +    /* A Friend Clear message is considered valid if the result of the
   +     * subtraction of the value of the LPNCounter field of the Friend
   +     * Request message (the one that initiated the friendship) from the
   +     * value of the LPNCounter field of the Friend Clear message, modulo
   +     * 65536, is in the range 0 to 255 inclusive.
   +     */
   +    if (lpn_counter - frnd->lpn_counter > 255) {
   +        BT_WARN("LPN Counter out of range (old %u new %u)",
   +            frnd->lpn_counter, lpn_counter);
   +        return 0;
   +    }
   +
   +    tx.ctx->send_ttl = BT_MESH_TTL_MAX;
   +
   +    cfm.lpn_addr = msg->lpn_addr;
   +    cfm.lpn_counter = msg->lpn_counter;
   +
   +    bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR_CFM, &cfm,
   +             sizeof(cfm), NULL, NULL, NULL);
   +
   +    friend_clear(frnd);
   +
   +    return 0;
   +}
   +
   +static void
   +friend_sub_add(struct bt_mesh_friend *frnd, u16_t addr)
   +{
   +    int i;
   +
   +    for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
   +        if (frnd->sub_list[i] == BT_MESH_ADDR_UNASSIGNED) {
   +            frnd->sub_list[i] = addr;
   +            return;
   +        }
   +    }
   +
   +    BT_WARN("No space in friend subscription list");
   +}
   +
   +static void
   +friend_sub_rem(struct bt_mesh_friend *frnd, u16_t addr)
   +{
   +    int i;
   +
   +    for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
   +        if (frnd->sub_list[i] == addr) {
   +            frnd->sub_list[i] = BT_MESH_ADDR_UNASSIGNED;
   +            return;
   +        }
   +    }
   +}
   +
   +static struct os_mbuf *
   +create_friend_pdu(struct bt_mesh_friend *frnd,
   +                  struct friend_pdu_info *info,
   +                  struct os_mbuf *sdu)
   +{
   +    struct os_mbuf *buf;
   +
   +    buf = bt_mesh_adv_create_from_pool(&friend_os_mbuf_pool, adv_alloc,
   +                       BT_MESH_ADV_DATA,
   +                       FRIEND_XMIT, K_NO_WAIT);
   +    if (!buf) {
   +        return NULL;
   +    }
   +
   +    net_buf_add_u8(buf, (info->iv_index & 1) << 7); /* Will be reset in encryption */
   +
   +    if (info->ctl) {
   +        net_buf_add_u8(buf, info->ttl | 0x80);
   +    } else {
   +        net_buf_add_u8(buf, info->ttl);
   +    }
   +
   +    net_buf_add_mem(buf, info->seq, sizeof(info->seq));
   +
   +    net_buf_add_be16(buf, info->src);
   +    net_buf_add_be16(buf, info->dst);
   +
   +    net_buf_add_mem(buf, sdu->om_data, sdu->om_len);
   +
   +    return buf;
    }
    
    struct unseg_app_sdu_meta {
   -	struct bt_mesh_net_rx net;
   -	const u8_t *key;
   -	struct bt_mesh_subnet *subnet;
   -	bool is_dev_key;
   -	u8_t aid;
   -	u8_t *ad;
   +    struct bt_mesh_net_rx net;
   +    const u8_t *key;
   +    struct bt_mesh_subnet *subnet;
   +    bool is_dev_key;
   +    u8_t aid;
   +    u8_t *ad;
    };
    
   -static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd,
   -				struct os_mbuf *buf,
   -				struct unseg_app_sdu_meta *meta)
   -{
   -	u16_t app_idx = FRIEND_ADV(buf)->app_idx;
   -	int err;
   -
   -	meta->subnet = bt_mesh_subnet_get(frnd->net_idx);
   -	meta->is_dev_key = (app_idx == BT_MESH_KEY_DEV);
   -	meta->is_dev_key = BT_MESH_IS_DEV_KEY(app_idx);
   -	bt_mesh_net_header_parse(buf, &meta->net);
   -	err = bt_mesh_app_key_get(meta->subnet, app_idx, meta->net.ctx.recv_dst,
   -				  &meta->key, &meta->aid);
   -	if (err) {
   -		return err;
   -	}
   -
   -	if (BT_MESH_ADDR_IS_VIRTUAL(meta->net.ctx.recv_dst)) {
   -		meta->ad = bt_mesh_label_uuid_get(meta->net.ctx.recv_dst);
   -		if (!meta->ad) {
   -			return -ENOENT;
   -		}
   -	} else {
   -		meta->ad = NULL;
   -	}
   -
   -	return 0;
   -}
   -
   -static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd,
   -				 struct os_mbuf *buf,
   -				 const struct unseg_app_sdu_meta *meta)
   -{
   -	struct net_buf_simple_state state;
   -	int err;
   -
   -	BT_DBG("");
   -
   -	net_buf_simple_save(buf, &state);
   -	net_buf_simple_pull_mem(buf, 10);
   -	buf->om_len -= 4;
   -
   -	err = bt_mesh_app_decrypt_in_place(meta->key, meta->is_dev_key,
   -					   0, buf, meta->ad, meta->net.ctx.addr,
   -					   meta->net.ctx.recv_dst, meta->net.seq,
   -					   BT_MESH_NET_IVI_TX);
   -
   -	net_buf_simple_restore(buf, &state);
   -	return err;
   -}
   -
   -static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd,
   -				 struct os_mbuf *buf,
   -				 const struct unseg_app_sdu_meta *meta)
   -{
   -	struct net_buf_simple_state state;
   -	int err;
   -
   -	BT_DBG("");
   -
   -	net_buf_simple_save(buf, &state);
   -	net_buf_simple_pull_mem(buf, 10);
   -	buf->om_len -= 4;
   -
   -	err = bt_mesh_app_encrypt_in_place(meta->key, meta->is_dev_key, 0, buf,
   -					   meta->ad, meta->net.ctx.addr,
   -					   meta->net.ctx.recv_dst, bt_mesh.seq,
   -					   BT_MESH_NET_IVI_TX);
   -
   -	net_buf_simple_restore(buf, &state);
   -	return err;
   -}
   -
   -static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd,
   -				 struct os_mbuf *buf)
   -{
   -	struct unseg_app_sdu_meta meta;
   -	int err;
   -
   -	BT_DBG("");
   -
   -	if (FRIEND_ADV(buf)->app_idx == BT_MESH_KEY_UNUSED) {
   -		return 0;
   -	}
   -
   -	err = unseg_app_sdu_unpack(frnd, buf, &meta);
   -	if (err) {
   -		return err;
   -	}
   -
   -	/* No need to reencrypt the message if the sequence number is
   -	 * unchanged.
   -	 */
   -	if (meta.net.seq == bt_mesh.seq) {
   -		return 0;
   -	}
   -
   -	err = unseg_app_sdu_decrypt(frnd, buf, &meta);
   -	if (err) {
   -		BT_WARN("Decryption failed! %d", err);
   -		return err;
   -	}
   -
   -	err = unseg_app_sdu_encrypt(frnd, buf, &meta);
   -	if (err) {
   -		BT_WARN("Re-encryption failed! %d", err);
   -	}
   -
   -	return err;
   -}
   -
   -static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf,
   -			      bool master_cred)
   -{
   -	struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx);
   -	const u8_t *enc, *priv;
   -	u32_t iv_index;
   -	u16_t src;
   -	u8_t nid;
   -	int err;
   -
   -	if (master_cred) {
   -		enc = sub->keys[sub->kr_flag].enc;
   -		priv = sub->keys[sub->kr_flag].privacy;
   -		nid = sub->keys[sub->kr_flag].nid;
   -	} else {
   -		if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
   -			BT_ERR("friend_cred_get failed");
   -			return -ENOENT;
   -		}
   -	}
   -
   -	src = sys_get_be16(&buf->om_data[5]);
   -
   -	if (bt_mesh_elem_find(src)) {
   -		u32_t seq;
   -
   -		if (FRIEND_ADV(buf)->app_idx != BT_MESH_KEY_UNUSED) {
   -			err = unseg_app_sdu_prepare(frnd, buf);
   -			if (err) {
   -				return err;
   -			}
   -		}
   -
   -		seq = bt_mesh_next_seq();
   -		buf->om_data[2] = seq >> 16;
   -		buf->om_data[3] = seq >> 8;
   -		buf->om_data[4] = seq;
   -
   -		iv_index = BT_MESH_NET_IVI_TX;
   -		FRIEND_ADV(buf)->app_idx = BT_MESH_KEY_UNUSED;
   -	} else {
   -		u8_t ivi = (buf->om_data[0] >> 7);
   -		iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi));
   -	}
   -
   -	buf->om_data[0] = (nid | (iv_index & 1) << 7);
   -
   -	if (bt_mesh_net_encrypt(enc, buf, iv_index, false)) {
   -		BT_ERR("Encrypting failed");
   -		return -EINVAL;
   -	}
   -
   -	if (bt_mesh_net_obfuscate(buf->om_data, iv_index, priv)) {
   -		BT_ERR("Obfuscating failed");
   -		return -EINVAL;
   -	}
   -
   -	return 0;
   -}
   -
   -static struct os_mbuf *encode_friend_ctl(struct bt_mesh_friend *frnd,
   -					 u8_t ctl_op,
   -					 struct os_mbuf *sdu)
   -{
   -	struct friend_pdu_info info;
   -
   -	BT_DBG("LPN 0x%04x", frnd->lpn);
   -
   -	net_buf_simple_push_u8(sdu, TRANS_CTL_HDR(ctl_op, 0));
   -
   -	info.src = bt_mesh_primary_addr();
   -	info.dst = frnd->lpn;
   -
   -	info.ctl = 1;
   -	info.ttl = 0;
   -
   -	memset(info.seq, 0, sizeof(info.seq));
   -
   -	info.iv_index = BT_MESH_NET_IVI_TX;
   -
   -	return create_friend_pdu(frnd, &info, sdu);
   -}
   -
   -static struct os_mbuf *encode_update(struct bt_mesh_friend *frnd, u8_t md)
   -{
   -	struct bt_mesh_ctl_friend_update *upd;
   -	struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*upd));
   -	struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx);
   -	struct os_mbuf *buf;
   -
   -	__ASSERT_NO_MSG(sub != NULL);
   -
   -	BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md);
   -
   -	net_buf_simple_init(sdu, 1);
   -
   -	upd = net_buf_simple_add(sdu, sizeof(*upd));
   -	upd->flags = bt_mesh_net_flags(sub);
   -	upd->iv_index = sys_cpu_to_be32(bt_mesh.iv_index);
   -	upd->md = md;
   -
   -	buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_UPDATE, sdu);
   -
   -	os_mbuf_free_chain(sdu);
   -	return buf;
   -}
   -
   -static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, u8_t xact)
   -{
   -	struct bt_mesh_ctl_friend_sub_confirm *cfm;
   -	struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*cfm));
   -	struct os_mbuf *buf;
   -
   -	BT_DBG("lpn 0x%04x xact 0x%02x", frnd->lpn, xact);
   -
   -	net_buf_simple_init(sdu, 1);
   -
   -	cfm = net_buf_simple_add(sdu, sizeof(*cfm));
   -	cfm->xact = xact;
   -
   -	buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_SUB_CFM, sdu);
   -	if (!buf) {
   -		BT_ERR("Unable to encode Subscription List Confirmation");
   -		goto done;
   -	}
   -
   -	if (encrypt_friend_pdu(frnd, buf, false)) {
   -		return;
   -	}
   -
   -	if (frnd->last) {
   -		BT_DBG("Discarding last PDU");
   -		net_buf_unref(frnd->last);
   -	}
   -
   -	frnd->last = buf;
   -	frnd->send_last = 1;
   +static int
   +unseg_app_sdu_unpack(struct bt_mesh_friend *frnd,
   +                     struct os_mbuf *buf,
   +                     struct unseg_app_sdu_meta *meta)
   +{
   +    u16_t app_idx = FRIEND_ADV(buf)->app_idx;
   +    int err;
   +
   +    meta->subnet = bt_mesh_subnet_get(frnd->net_idx);
   +    meta->is_dev_key = (app_idx == BT_MESH_KEY_DEV);
   +    meta->is_dev_key = BT_MESH_IS_DEV_KEY(app_idx);
   +    bt_mesh_net_header_parse(buf, &meta->net);
   +    err = bt_mesh_app_key_get(meta->subnet, app_idx, meta->net.ctx.recv_dst,
   +                  &meta->key, &meta->aid);
   +    if (err) {
   +        return err;
   +    }
   +
   +    if (BT_MESH_ADDR_IS_VIRTUAL(meta->net.ctx.recv_dst)) {
   +        meta->ad = bt_mesh_label_uuid_get(meta->net.ctx.recv_dst);
   +        if (!meta->ad) {
   +            return -ENOENT;
   +        }
   +    } else {
   +        meta->ad = NULL;
   +    }
   +
   +    return 0;
   +}
   +
   +static int
   +unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd,
   +                      struct os_mbuf *buf,
   +                      const struct unseg_app_sdu_meta *meta)
   +{
   +    struct net_buf_simple_state state;
   +    int err;
   +
   +    BT_DBG("");
   +
   +    net_buf_simple_save(buf, &state);
   +    net_buf_simple_pull_mem(buf, 10);
   +    buf->om_len -= 4;
   +
   +    err = bt_mesh_app_decrypt_in_place(meta->key, meta->is_dev_key,
   +                       0, buf, meta->ad, meta->net.ctx.addr,
   +                       meta->net.ctx.recv_dst, meta->net.seq,
   +                       BT_MESH_NET_IVI_TX);
   +
   +    net_buf_simple_restore(buf, &state);
   +    return err;
   +}
   +
   +static int
   +unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd,
   +                      struct os_mbuf *buf,
   +                      const struct unseg_app_sdu_meta *meta)
   +{
   +    struct net_buf_simple_state state;
   +    int err;
   +
   +    BT_DBG("");
   +
   +    net_buf_simple_save(buf, &state);
   +    net_buf_simple_pull_mem(buf, 10);
   +    buf->om_len -= 4;
   +
   +    err = bt_mesh_app_encrypt_in_place(meta->key, meta->is_dev_key, 0, buf,
   +                       meta->ad, meta->net.ctx.addr,
   +                       meta->net.ctx.recv_dst, bt_mesh.seq,
   +                       BT_MESH_NET_IVI_TX);
   +
   +    net_buf_simple_restore(buf, &state);
   +    return err;
   +}
   +
   +static int
   +unseg_app_sdu_prepare(struct bt_mesh_friend *frnd,
   +                      struct os_mbuf *buf)
   +{
   +    struct unseg_app_sdu_meta meta;
   +    int err;
   +
   +    BT_DBG("");
   +
   +    if (FRIEND_ADV(buf)->app_idx == BT_MESH_KEY_UNUSED) {
   +        return 0;
   +    }
   +
   +    err = unseg_app_sdu_unpack(frnd, buf, &meta);
   +    if (err) {
   +        return err;
   +    }
   +
   +    /* No need to reencrypt the message if the sequence number is
   +     * unchanged.
   +     */
   +    if (meta.net.seq == bt_mesh.seq) {
   +        return 0;
   +    }
   +
   +    err = unseg_app_sdu_decrypt(frnd, buf, &meta);
   +    if (err) {
   +        BT_WARN("Decryption failed! %d", err);
   +        return err;
   +    }
   +
   +    err = unseg_app_sdu_encrypt(frnd, buf, &meta);
   +    if (err) {
   +        BT_WARN("Re-encryption failed! %d", err);
   +    }
   +
   +    return err;
   +}
   +
   +static int
   +encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf,
   +                   bool master_cred)
   +{
   +    struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx);
   +    const u8_t *enc, *priv;
   +    u32_t iv_index;
   +    u16_t src;
   +    u8_t nid;
   +    int err;
   +
   +    if (master_cred) {
   +        enc = sub->keys[sub->kr_flag].enc;
   +        priv = sub->keys[sub->kr_flag].privacy;
   +        nid = sub->keys[sub->kr_flag].nid;
   +    } else {
   +        if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
   +            BT_ERR("friend_cred_get failed");
   +            return -ENOENT;
   +        }
   +    }
   +
   +    src = sys_get_be16(&buf->om_data[5]);
   +
   +    if (bt_mesh_elem_find(src)) {
   +        u32_t seq;
   +
   +        if (FRIEND_ADV(buf)->app_idx != BT_MESH_KEY_UNUSED) {
   +            err = unseg_app_sdu_prepare(frnd, buf);
   +            if (err) {
   +                return err;
   +            }
   +        }
   +
   +        seq = bt_mesh_next_seq();
   +        buf->om_data[2] = seq >> 16;
   +        buf->om_data[3] = seq >> 8;
   +        buf->om_data[4] = seq;
   +
   +        iv_index = BT_MESH_NET_IVI_TX;
   +        FRIEND_ADV(buf)->app_idx = BT_MESH_KEY_UNUSED;
   +    } else {
   +        u8_t ivi = (buf->om_data[0] >> 7);
   +        iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi));
   +    }
   +
   +    buf->om_data[0] = (nid | (iv_index & 1) << 7);
   +
   +    if (bt_mesh_net_encrypt(enc, buf, iv_index, false)) {
   +        BT_ERR("Encrypting failed");
   +        return -EINVAL;
   +    }
   +
   +    if (bt_mesh_net_obfuscate(buf->om_data, iv_index, priv)) {
   +        BT_ERR("Obfuscating failed");
   +        return -EINVAL;
   +    }
   +
   +    return 0;
   +}
   +
   +static struct os_mbuf *
   +encode_friend_ctl(struct bt_mesh_friend *frnd,
   +                  u8_t ctl_op,
   +                  struct os_mbuf *sdu)
   +{
   +    struct friend_pdu_info info;
   +
   +    BT_DBG("LPN 0x%04x", frnd->lpn);
   +
   +    net_buf_simple_push_u8(sdu, TRANS_CTL_HDR(ctl_op, 0));
   +
   +    info.src = bt_mesh_primary_addr();
   +    info.dst = frnd->lpn;
   +
   +    info.ctl = 1;
   +    info.ttl = 0;
   +
   +    memset(info.seq, 0, sizeof(info.seq));
   +
   +    info.iv_index = BT_MESH_NET_IVI_TX;
   +
   +    return create_friend_pdu(frnd, &info, sdu);
   +}
   +
   +static struct os_mbuf *
   +encode_update(struct bt_mesh_friend *frnd, u8_t md)
   +{
   +    struct bt_mesh_ctl_friend_update *upd;
   +    struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*upd));
   +    struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx);
   +    struct os_mbuf *buf;
   +
   +    __ASSERT_NO_MSG(sub != NULL);
   +
   +    BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md);
   +
   +    net_buf_simple_init(sdu, 1);
   +
   +    upd = net_buf_simple_add(sdu, sizeof(*upd));
   +    upd->flags = bt_mesh_net_flags(sub);
   +    upd->iv_index = sys_cpu_to_be32(bt_mesh.iv_index);
   +    upd->md = md;
   +
   +    buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_UPDATE, sdu);
   +
   +    os_mbuf_free_chain(sdu);
   +    return buf;
   +}
   +
   +static void
   +enqueue_sub_cfm(struct bt_mesh_friend *frnd, u8_t xact)
   +{
   +    struct bt_mesh_ctl_friend_sub_confirm *cfm;
   +    struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*cfm));
   +    struct os_mbuf *buf;
   +
   +    BT_DBG("lpn 0x%04x xact 0x%02x", frnd->lpn, xact);
   +
   +    net_buf_simple_init(sdu, 1);
   +
   +    cfm = net_buf_simple_add(sdu, sizeof(*cfm));
   +    cfm->xact = xact;
   +
   +    buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_SUB_CFM, sdu);
   +    if (!buf) {
   +        BT_ERR("Unable to encode Subscription List Confirmation");
   +        goto done;
   +    }
   +
   +    if (encrypt_friend_pdu(frnd, buf, false)) {
   +        return;
   +    }
   +
   +    if (frnd->last) {
   +        BT_DBG("Discarding last PDU");
   +        net_buf_unref(frnd->last);
   +    }
   +
   +    frnd->last = buf;
   +    frnd->send_last = 1;
    
    done:
   -	os_mbuf_free_chain(sdu);
   -}
   -
   -static void friend_recv_delay(struct bt_mesh_friend *frnd)
   -{
   -	frnd->pending_req = 1;
   -	k_delayed_work_submit(&frnd->timer, recv_delay(frnd));
   -	BT_DBG("Waiting RecvDelay of %d ms", (int) recv_delay(frnd));
   -}
   -
   -int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx,
   -			   struct os_mbuf *buf)
   -{
   -	struct bt_mesh_friend *frnd;
   -	u8_t xact;
   -
   -	if (buf->om_len < BT_MESH_FRIEND_SUB_MIN_LEN) {
   -		BT_WARN("Too short Friend Subscription Add");
   -		return -EINVAL;
   -	}
   -
   -	frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true);
   -	if (!frnd) {
   -		BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr);
   -		return 0;
   -	}
   -
   -	if (frnd->pending_buf) {
   -		BT_WARN("Previous buffer not yet sent!");
   -		return 0;
   -	}
   -
   -	friend_recv_delay(frnd);
   -
   -	xact = net_buf_simple_pull_u8(buf);
   -
   -	while (buf->om_len >= 2) {
   -		friend_sub_add(frnd, net_buf_simple_pull_be16(buf));
   -	}
   -
   -	enqueue_sub_cfm(frnd, xact);
   -
   -	return 0;
   -}
   -
   -int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx,
   -			   struct os_mbuf *buf)
   -{
   -	struct bt_mesh_friend *frnd;
   -	u8_t xact;
   -
   -	if (buf->om_len < BT_MESH_FRIEND_SUB_MIN_LEN) {
   -		BT_WARN("Too short Friend Subscription Remove");
   -		return -EINVAL;
   -	}
   -
   -	frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true);
   -	if (!frnd) {
   -		BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr);
   -		return 0;
   -	}
   -
   -	if (frnd->pending_buf) {
   -		BT_WARN("Previous buffer not yet sent!");
   -		return 0;
   -	}
   -
   -	friend_recv_delay(frnd);
   -
   -	xact = net_buf_simple_pull_u8(buf);
   -
   -	while (buf->om_len >= 2) {
   -		friend_sub_rem(frnd, net_buf_simple_pull_be16(buf));
   -	}
   -
   -	enqueue_sub_cfm(frnd, xact);
   -
   -	return 0;
   -}
   -
   -static void enqueue_buf(struct bt_mesh_friend *frnd, struct os_mbuf *buf)
   -{
   -	net_buf_slist_put(&frnd->queue, buf);
   -	frnd->queue_size++;
   -}
   -
   -static void enqueue_update(struct bt_mesh_friend *frnd, u8_t md)
   -{
   -	struct os_mbuf *buf;
   -
   -	buf = encode_update(frnd, md);
   -	if (!buf) {
   -		BT_ERR("Unable to encode Friend Update");
   -		return;
   -	}
   -
   -	enqueue_buf(frnd, buf);
   -}
   -
   -int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
   -{
   -	struct bt_mesh_ctl_friend_poll *msg = (void *)buf->om_data;
   -	struct bt_mesh_friend *frnd;
   -
   -	if (buf->om_len < sizeof(*msg)) {
   -		BT_WARN("Too short Friend Poll");
   -		return -EINVAL;
   -	}
   -
   -	frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false);
   -	if (!frnd) {
   -		BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr);
   -		return 0;
   -	}
   -
   -	if (msg->fsn & ~1) {
   -		BT_WARN("Prohibited (non-zero) padding bits");
   -		return -EINVAL;
   -	}
   -
   -	if (frnd->pending_buf) {
   -		BT_WARN("Previous buffer not yet sent");
   -		return 0;
   -	}
   -
   -	BT_DBG("msg->fsn %u frnd->fsn %u", (msg->fsn & 1), frnd->fsn);
   -
   -	friend_recv_delay(frnd);
   -
   -	if (!frnd->established) {
   -		BT_DBG("Friendship established with 0x%04x", frnd->lpn);
   -		frnd->established = 1;
   -	}
   -
   -	if (msg->fsn == frnd->fsn && frnd->last) {
   -		BT_DBG("Re-sending last PDU");
   -		frnd->send_last = 1;
   -	} else {
   -		if (frnd->last) {
   -			net_buf_unref(frnd->last);
   -			frnd->last = NULL;
   -		}
   -
   -		frnd->fsn = msg->fsn;
   -
   -		if (net_buf_slist_is_empty(&frnd->queue)) {
   -			enqueue_update(frnd, 0);
   -			BT_DBG("Enqueued Friend Update to empty queue");
   -		}
   -	}
   -
   -	return 0;
   -}
   -
   -static struct bt_mesh_friend *find_clear(u16_t prev_friend)
   -{
   -	int i;
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -
   -		if (frnd->clear.frnd == prev_friend) {
   -			return frnd;
   -		}
   -	}
   -
   -	return NULL;
   -}
   -
   -static void friend_clear_sent(int err, void *user_data)
   -{
   -	struct bt_mesh_friend *frnd = user_data;
   -
   -	k_delayed_work_submit(&frnd->clear.timer,
   -			      K_SECONDS(frnd->clear.repeat_sec));
   -	frnd->clear.repeat_sec *= 2;
   +    os_mbuf_free_chain(sdu);
   +}
   +
   +static void
   +friend_recv_delay(struct bt_mesh_friend *frnd)
   +{
   +    frnd->pending_req = 1;
   +    k_delayed_work_submit(&frnd->timer, recv_delay(frnd));
   +    BT_DBG("Waiting RecvDelay of %d ms", (int) recv_delay(frnd));
   +}
   +
   +int
   +bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx,
   +                       struct os_mbuf *buf)
   +{
   +    struct bt_mesh_friend *frnd;
   +    u8_t xact;
   +
   +    if (buf->om_len < BT_MESH_FRIEND_SUB_MIN_LEN) {
   +        BT_WARN("Too short Friend Subscription Add");
   +        return -EINVAL;
   +    }
   +
   +    frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true);
   +    if (!frnd) {
   +        BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr);
   +        return 0;
   +    }
   +
   +    if (frnd->pending_buf) {
   +        BT_WARN("Previous buffer not yet sent!");
   +        return 0;
   +    }
   +
   +    friend_recv_delay(frnd);
   +
   +    xact = net_buf_simple_pull_u8(buf);
   +
   +    while (buf->om_len >= 2) {
   +        friend_sub_add(frnd, net_buf_simple_pull_be16(buf));
   +    }
   +
   +    enqueue_sub_cfm(frnd, xact);
   +
   +    return 0;
   +}
   +
   +int
   +bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx,
   +                       struct os_mbuf *buf)
   +{
   +    struct bt_mesh_friend *frnd;
   +    u8_t xact;
   +
   +    if (buf->om_len < BT_MESH_FRIEND_SUB_MIN_LEN) {
   +        BT_WARN("Too short Friend Subscription Remove");
   +        return -EINVAL;
   +    }
   +
   +    frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true);
   +    if (!frnd) {
   +        BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr);
   +        return 0;
   +    }
   +
   +    if (frnd->pending_buf) {
   +        BT_WARN("Previous buffer not yet sent!");
   +        return 0;
   +    }
   +
   +    friend_recv_delay(frnd);
   +
   +    xact = net_buf_simple_pull_u8(buf);
   +
   +    while (buf->om_len >= 2) {
   +        friend_sub_rem(frnd, net_buf_simple_pull_be16(buf));
   +    }
   +
   +    enqueue_sub_cfm(frnd, xact);
   +
   +    return 0;
   +}
   +
   +static void
   +enqueue_buf(struct bt_mesh_friend *frnd, struct os_mbuf *buf)
   +{
   +    net_buf_slist_put(&frnd->queue, buf);
   +    frnd->queue_size++;
   +}
   +
   +static void
   +enqueue_update(struct bt_mesh_friend *frnd, u8_t md)
   +{
   +    struct os_mbuf *buf;
   +
   +    buf = encode_update(frnd, md);
   +    if (!buf) {
   +        BT_ERR("Unable to encode Friend Update");
   +        return;
   +    }
   +
   +    enqueue_buf(frnd, buf);
   +}
   +
   +int
   +bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
   +{
   +    struct bt_mesh_ctl_friend_poll *msg = (void *)buf->om_data;
   +    struct bt_mesh_friend *frnd;
   +
   +    if (buf->om_len < sizeof(*msg)) {
   +        BT_WARN("Too short Friend Poll");
   +        return -EINVAL;
   +    }
   +
   +    frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false);
   +    if (!frnd) {
   +        BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr);
   +        return 0;
   +    }
   +
   +    if (msg->fsn & ~1) {
   +        BT_WARN("Prohibited (non-zero) padding bits");
   +        return -EINVAL;
   +    }
   +
   +    if (frnd->pending_buf) {
   +        BT_WARN("Previous buffer not yet sent");
   +        return 0;
   +    }
   +
   +    BT_DBG("msg->fsn %u frnd->fsn %u", (msg->fsn & 1), frnd->fsn);
   +
   +    friend_recv_delay(frnd);
   +
   +    if (!frnd->established) {
   +        BT_DBG("Friendship established with 0x%04x", frnd->lpn);
   +        frnd->established = 1;
   +    }
   +
   +    if (msg->fsn == frnd->fsn && frnd->last) {
   +        BT_DBG("Re-sending last PDU");
   +        frnd->send_last = 1;
   +    } else {
   +        if (frnd->last) {
   +            net_buf_unref(frnd->last);
   +            frnd->last = NULL;
   +        }
   +
   +        frnd->fsn = msg->fsn;
   +
   +        if (net_buf_slist_is_empty(&frnd->queue)) {
   +            enqueue_update(frnd, 0);
   +            BT_DBG("Enqueued Friend Update to empty queue");
   +        }
   +    }
   +
   +    return 0;
   +}
   +
   +static struct bt_mesh_friend *
   +find_clear(u16_t prev_friend)
   +{
   +    int i;
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +
   +        if (frnd->clear.frnd == prev_friend) {
   +            return frnd;
   +        }
   +    }
   +
   +    return NULL;
   +}
   +
   +static void
   +friend_clear_sent(int err, void *user_data)
   +{
   +    struct bt_mesh_friend *frnd = user_data;
   +
   +    k_delayed_work_submit(&frnd->clear.timer,
   +                  K_SECONDS(frnd->clear.repeat_sec));
   +    frnd->clear.repeat_sec *= 2;
    }
    
    static const struct bt_mesh_send_cb clear_sent_cb = {
   -	.end = friend_clear_sent,
   +    .end = friend_clear_sent,
    };
    
   -static void send_friend_clear(struct bt_mesh_friend *frnd)
   -{
   -	struct bt_mesh_msg_ctx ctx = {
   -		.net_idx  = frnd->net_idx,
   -		.app_idx  = BT_MESH_KEY_UNUSED,
   -		.addr     = frnd->clear.frnd,
   -		.send_ttl = BT_MESH_TTL_MAX,
   -	};
   -	struct bt_mesh_net_tx tx = {
   -		.sub  = &bt_mesh.sub[0],
   -		.ctx  = &ctx,
   -		.src  = bt_mesh_primary_addr(),
   -		.xmit = bt_mesh_net_transmit_get(),
   -	};
   -	struct bt_mesh_ctl_friend_clear req = {
   -		.lpn_addr    = sys_cpu_to_be16(frnd->lpn),
   -		.lpn_counter = sys_cpu_to_be16(frnd->lpn_counter),
   -	};
   -
   -	BT_DBG("");
   -
   -	bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req,
   -			 sizeof(req), NULL, &clear_sent_cb, frnd);
   -}
   -
   -static void clear_timeout(struct ble_npl_event *work)
   -{
   -	struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work);
   -	u32_t duration;
   -
   -	BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd);
   -
   -	duration = k_uptime_get_32() - frnd->clear.start;
   -	if (duration > 2 * frnd->poll_to) {
   -		BT_DBG("Clear Procedure timer expired");
   -		frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED;
   -		return;
   -	}
   -
   -	send_friend_clear(frnd);
   -}
   -
   -static void clear_procedure_start(struct bt_mesh_friend *frnd)
   -{
   -	BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd);
   -
   -	frnd->clear.start = k_uptime_get_32();
   -	frnd->clear.repeat_sec = 1U;
   -
   -	send_friend_clear(frnd);
   -}
   -
   -int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx,
   -			     struct os_mbuf *buf)
   -{
   -	struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->om_data;
   -	struct bt_mesh_friend *frnd;
   -	u16_t lpn_addr, lpn_counter;
   -
   -	BT_DBG("");
   -
   -	if (buf->om_len < sizeof(*msg)) {
   -		BT_WARN("Too short Friend Clear Confirm");
   -		return -EINVAL;
   -	}
   -
   -	frnd = find_clear(rx->ctx.addr);
   -	if (!frnd) {
   -		BT_WARN("No pending clear procedure for 0x%02x", rx->ctx.addr);
   -		return 0;
   -	}
   -
   -	lpn_addr = sys_be16_to_cpu(msg->lpn_addr);
   -	if (lpn_addr != frnd->lpn) {
   -		BT_WARN("LPN address mismatch (0x%04x != 0x%04x)",
   -			lpn_addr, frnd->lpn);
   -		return 0;
   -	}
   -
   -	lpn_counter = sys_be16_to_cpu(msg->lpn_counter);
   -	if (lpn_counter != frnd->lpn_counter) {
   -		BT_WARN("LPN counter mismatch (0x%04x != 0x%04x)",
   -			lpn_counter, frnd->lpn_counter);
   -		return 0;
   -	}
   -
   -	k_delayed_work_cancel(&frnd->clear.timer);
   -	frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED;
   -
   -	return 0;
   -}
   -
   -static void enqueue_offer(struct bt_mesh_friend *frnd, s8_t rssi)
   -{
   -	struct bt_mesh_ctl_friend_offer *off;
   -	struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*off));
   -	struct os_mbuf *buf;
   -
   -	BT_DBG("");
   -
   -	net_buf_simple_init(sdu, 1);
   -
   -	off = net_buf_simple_add(sdu, sizeof(*off));
   -
   -	off->recv_win = CONFIG_BT_MESH_FRIEND_RECV_WIN,
   -	off->queue_size = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE,
   -	off->sub_list_size = ARRAY_SIZE(frnd->sub_list),
   -	off->rssi = rssi,
   -	off->frnd_counter = sys_cpu_to_be16(frnd->counter);
   -
   -	buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_OFFER, sdu);
   -	if (!buf) {
   -		BT_ERR("Unable to encode Friend Offer");
   -		goto done;
   -	}
   -
   -	if (encrypt_friend_pdu(frnd, buf, true)) {
   -		return;
   -	}
   -
   -	frnd->counter++;
   -
   -	if (frnd->last) {
   -		net_buf_unref(frnd->last);
   -	}
   -
   -	frnd->last = buf;
   -	frnd->send_last = 1;
   +static void
   +send_friend_clear(struct bt_mesh_friend *frnd)
   +{
   +    struct bt_mesh_msg_ctx ctx = {
   +        .net_idx = frnd->net_idx,
   +        .app_idx = BT_MESH_KEY_UNUSED,
   +        .addr = frnd->clear.frnd,
   +        .send_ttl = BT_MESH_TTL_MAX,
   +    };
   +    struct bt_mesh_net_tx tx = {
   +        .sub = &bt_mesh.sub[0],
   +        .ctx = &ctx,
   +        .src = bt_mesh_primary_addr(),
   +        .xmit = bt_mesh_net_transmit_get(),
   +    };
   +    struct bt_mesh_ctl_friend_clear req = {
   +        .lpn_addr = sys_cpu_to_be16(frnd->lpn),
   +        .lpn_counter = sys_cpu_to_be16(frnd->lpn_counter),
   +    };
   +
   +    BT_DBG("");
   +
   +    bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req,
   +             sizeof(req), NULL, &clear_sent_cb, frnd);
   +}
   +
   +static void
   +clear_timeout(struct ble_npl_event *work)
   +{
   +    struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work);
   +    u32_t duration;
   +
   +    BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd);
   +
   +    duration = k_uptime_get_32() - frnd->clear.start;
   +    if (duration > 2 * frnd->poll_to) {
   +        BT_DBG("Clear Procedure timer expired");
   +        frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED;
   +        return;
   +    }
   +
   +    send_friend_clear(frnd);
   +}
   +
   +static void
   +clear_procedure_start(struct bt_mesh_friend *frnd)
   +{
   +    BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd);
   +
   +    frnd->clear.start = k_uptime_get_32();
   +    frnd->clear.repeat_sec = 1U;
   +
   +    send_friend_clear(frnd);
   +}
   +
   +int
   +bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx,
   +                         struct os_mbuf *buf)
   +{
   +    struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->om_data;
   +    struct bt_mesh_friend *frnd;
   +    u16_t lpn_addr, lpn_counter;
   +
   +    BT_DBG("");
   +
   +    if (buf->om_len < sizeof(*msg)) {
   +        BT_WARN("Too short Friend Clear Confirm");
   +        return -EINVAL;
   +    }
   +
   +    frnd = find_clear(rx->ctx.addr);
   +    if (!frnd) {
   +        BT_WARN("No pending clear procedure for 0x%02x", rx->ctx.addr);
   +        return 0;
   +    }
   +
   +    lpn_addr = sys_be16_to_cpu(msg->lpn_addr);
   +    if (lpn_addr != frnd->lpn) {
   +        BT_WARN("LPN address mismatch (0x%04x != 0x%04x)",
   +            lpn_addr, frnd->lpn);
   +        return 0;
   +    }
   +
   +    lpn_counter = sys_be16_to_cpu(msg->lpn_counter);
   +    if (lpn_counter != frnd->lpn_counter) {
   +        BT_WARN("LPN counter mismatch (0x%04x != 0x%04x)",
   +            lpn_counter, frnd->lpn_counter);
   +        return 0;
   +    }
   +
   +    k_delayed_work_cancel(&frnd->clear.timer);
   +    frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED;
   +
   +    return 0;
   +}
   +
   +static void
   +enqueue_offer(struct bt_mesh_friend *frnd, s8_t rssi)
   +{
   +    struct bt_mesh_ctl_friend_offer *off;
   +    struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*off));
   +    struct os_mbuf *buf;
   +
   +    BT_DBG("");
   +
   +    net_buf_simple_init(sdu, 1);
   +
   +    off = net_buf_simple_add(sdu, sizeof(*off));
   +
   +    off->recv_win = CONFIG_BT_MESH_FRIEND_RECV_WIN,
   +    off->queue_size = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE,
   +    off->sub_list_size = ARRAY_SIZE(frnd->sub_list),
   +    off->rssi = rssi,
   +    off->frnd_counter = sys_cpu_to_be16(frnd->counter);
   +
   +    buf = encode_friend_ctl(frnd, TRANS_CTL_OP_FRIEND_OFFER, sdu);
   +    if (!buf) {
   +        BT_ERR("Unable to encode Friend Offer");
   +        goto done;
   +    }
   +
   +    if (encrypt_friend_pdu(frnd, buf, true)) {
   +        return;
   +    }
   +
   +    frnd->counter++;
   +
   +    if (frnd->last) {
   +        net_buf_unref(frnd->last);
   +    }
   +
   +    frnd->last = buf;
   +    frnd->send_last = 1;
    
    done:
   -	os_mbuf_free_chain(sdu);
   +    os_mbuf_free_chain(sdu);
    }
    
    #define RECV_WIN                  CONFIG_BT_MESH_FRIEND_RECV_WIN
   @@ -903,785 +936,807 @@
    #define MIN_QUEUE_SIZE_LOG(crit)  ((crit) & (u8_t)BIT_MASK(3))
    #define MIN_QUEUE_SIZE(crit)      ((u32_t)BIT(MIN_QUEUE_SIZE_LOG(crit)))
    
   -static s32_t offer_delay(struct bt_mesh_friend *frnd, s8_t rssi, u8_t crit)
   -{
   -	/* Scaling factors. The actual values are 1, 1.5, 2 & 2.5, but we
   -	 * want to avoid floating-point arithmetic.
   -	 */
   -	static const u8_t fact[] = { 10, 15, 20, 25 };
   -	s32_t delay;
   -
   -	BT_DBG("ReceiveWindowFactor %u ReceiveWindow %u RSSIFactor %u RSSI %d",
   -	       fact[RECV_WIN_FACT(crit)], RECV_WIN,
   -	       fact[RSSI_FACT(crit)], rssi);
   -
   -	/* Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI */
   -	delay = (s32_t)fact[RECV_WIN_FACT(crit)] * RECV_WIN;
   -	delay -= (s32_t)fact[RSSI_FACT(crit)] * rssi;
   -	delay /= 10;
   -
   -	BT_DBG("Local Delay calculated as %d ms", (int) delay);
   -
   -	if (delay < 100) {
   -		return K_MSEC(100);
   -	}
   -
   -	return K_MSEC(delay);
   -}
   -
   -int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
   -{
   -	struct bt_mesh_ctl_friend_req *msg = (void *)buf->om_data;
   -	struct bt_mesh_friend *frnd = NULL;
   -	u32_t poll_to;
   -	int i;
   -
   -	if (rx->net_if == BT_MESH_NET_IF_LOCAL) {
   -		BT_WARN("Ignoring Friend request from local interface");
   -		return 0;
   -	}
   -
   -	if (buf->om_len < sizeof(*msg)) {
   -		BT_WARN("Too short Friend Request");
   -		return -EINVAL;
   -	}
   -
   -	if (msg->recv_delay <= 0x09) {
   -		BT_WARN("Prohibited ReceiveDelay (0x%02x)", msg->recv_delay);
   -		return -EINVAL;
   -	}
   -
   -	poll_to = (((u32_t)msg->poll_to[0] << 16) |
   -		   ((u32_t)msg->poll_to[1] << 8) |
   -		   ((u32_t)msg->poll_to[2]));
   -
   -	if (poll_to <= 0x000009 || poll_to >= 0x34bc00) {
   -		BT_WARN("Prohibited PollTimeout (0x%06x)", (unsigned) poll_to);
   -		return -EINVAL;
   -	}
   -
   -	if (msg->num_elem == 0x00) {
   -		BT_WARN("Prohibited NumElements value (0x00)");
   -		return -EINVAL;
   -	}
   -
   -	if (!BT_MESH_ADDR_IS_UNICAST(rx->ctx.addr + msg->num_elem - 1)) {
   -		BT_WARN("LPN elements stretch outside of unicast range");
   -		return -EINVAL;
   -	}
   -
   -	if (!MIN_QUEUE_SIZE_LOG(msg->criteria)) {
   -		BT_WARN("Prohibited Minimum Queue Size in Friend Request");
   -		return -EINVAL;
   -	}
   -
   -	if (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE < MIN_QUEUE_SIZE(msg->criteria)) {
   -		BT_WARN("We have a too small Friend Queue size (%u < %u)",
   -			CONFIG_BT_MESH_FRIEND_QUEUE_SIZE,
   -			(unsigned) MIN_QUEUE_SIZE(msg->criteria));
   -		return 0;
   -	}
   -
   -	frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false);
   -	if (frnd) {
   -		BT_WARN("Existing LPN re-requesting Friendship");
   -		friend_clear(frnd);
   -		goto init_friend;
   -	}
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		if (!bt_mesh.frnd[i].valid) {
   -			frnd = &bt_mesh.frnd[i];
   -			frnd->valid = 1;
   -			break;
   -		}
   -	}
   -
   -	if (!frnd) {
   -		BT_WARN("No free Friend contexts for new LPN");
   -		return -ENOMEM;
   -	}
   +static s32_t
   +offer_delay(struct bt_mesh_friend *frnd, s8_t rssi, u8_t crit)
   +{
   +    /* Scaling factors. The actual values are 1, 1.5, 2 & 2.5, but we
   +     * want to avoid floating-point arithmetic.
   +     */
   +    static const u8_t fact[] = { 10, 15, 20, 25 };
   +    s32_t delay;
   +
   +    BT_DBG("ReceiveWindowFactor %u ReceiveWindow %u RSSIFactor %u RSSI %d",
   +           fact[RECV_WIN_FACT(crit)], RECV_WIN,
   +           fact[RSSI_FACT(crit)], rssi);
   +
   +    /* Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI */
   +    delay = (s32_t)fact[RECV_WIN_FACT(crit)] * RECV_WIN;
   +    delay -= (s32_t)fact[RSSI_FACT(crit)] * rssi;
   +    delay /= 10;
   +
   +    BT_DBG("Local Delay calculated as %d ms", (int) delay);
   +
   +    if (delay < 100) {
   +        return K_MSEC(100);
   +    }
   +
   +    return K_MSEC(delay);
   +}
   +
   +int
   +bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
   +{
   +    struct bt_mesh_ctl_friend_req *msg = (void *)buf->om_data;
   +    struct bt_mesh_friend *frnd = NULL;
   +    u32_t poll_to;
   +    int i;
   +
   +    if (rx->net_if == BT_MESH_NET_IF_LOCAL) {
   +        BT_WARN("Ignoring Friend request from local interface");
   +        return 0;
   +    }
   +
   +    if (buf->om_len < sizeof(*msg)) {
   +        BT_WARN("Too short Friend Request");
   +        return -EINVAL;
   +    }
   +
   +    if (msg->recv_delay <= 0x09) {
   +        BT_WARN("Prohibited ReceiveDelay (0x%02x)", msg->recv_delay);
   +        return -EINVAL;
   +    }
   +
   +    poll_to = (((u32_t)msg->poll_to[0] << 16) |
   +               ((u32_t)msg->poll_to[1] << 8) |
   +               ((u32_t)msg->poll_to[2]));
   +
   +    if (poll_to <= 0x000009 || poll_to >= 0x34bc00) {
   +        BT_WARN("Prohibited PollTimeout (0x%06x)", (unsigned) poll_to);
   +        return -EINVAL;
   +    }
   +
   +    if (msg->num_elem == 0x00) {
   +        BT_WARN("Prohibited NumElements value (0x00)");
   +        return -EINVAL;
   +    }
   +
   +    if (!BT_MESH_ADDR_IS_UNICAST(rx->ctx.addr + msg->num_elem - 1)) {
   +        BT_WARN("LPN elements stretch outside of unicast range");
   +        return -EINVAL;
   +    }
   +
   +    if (!MIN_QUEUE_SIZE_LOG(msg->criteria)) {
   +        BT_WARN("Prohibited Minimum Queue Size in Friend Request");
   +        return -EINVAL;
   +    }
   +
   +    if (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE < MIN_QUEUE_SIZE(msg->criteria)) {
   +        BT_WARN("We have a too small Friend Queue size (%u < %u)",
   +            CONFIG_BT_MESH_FRIEND_QUEUE_SIZE,
   +                (unsigned) MIN_QUEUE_SIZE(msg->criteria));
   +        return 0;
   +    }
   +
   +    frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false);
   +    if (frnd) {
   +        BT_WARN("Existing LPN re-requesting Friendship");
   +        friend_clear(frnd);
   +        goto init_friend;
   +    }
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        if (!bt_mesh.frnd[i].valid) {
   +            frnd = &bt_mesh.frnd[i];
   +            frnd->valid = 1;
   +            break;
   +        }
   +    }
   +
   +    if (!frnd) {
   +        BT_WARN("No free Friend contexts for new LPN");
   +        return -ENOMEM;
   +    }
    
    init_friend:
   -	frnd->lpn = rx->ctx.addr;
   -	frnd->num_elem = msg->num_elem;
   -	frnd->net_idx = rx->sub->net_idx;
   -	frnd->recv_delay = msg->recv_delay;
   -	frnd->poll_to = poll_to * 100;
   -	frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter);
   -	frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr);
   -
   -	BT_DBG("LPN 0x%04x rssi %d recv_delay %u poll_to %ums",
   -	       frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay,
   -	       (unsigned) frnd->poll_to);
   -
   -	if (BT_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) &&
   -	    !bt_mesh_elem_find(frnd->clear.frnd)) {
   -		clear_procedure_start(frnd);
   -	}
   -
   -	k_delayed_work_submit(&frnd->timer,
   -			      offer_delay(frnd, rx->ctx.recv_rssi,
   -					  msg->criteria));
   -
   -	friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter,
   -			   frnd->counter);
   -
   -	enqueue_offer(frnd, rx->ctx.recv_rssi);
   -
   -	return 0;
   -}
   -
   -static bool is_seg(struct bt_mesh_friend_seg *seg, u16_t src, u16_t seq_zero)
   -{
   -	struct os_mbuf *buf = (void *)net_buf_slist_peek_head(&seg->queue);
   -	struct net_buf_simple_state state;
   -	u16_t buf_seq_zero;
   -	u16_t buf_src;
   -
   -	if (!buf) {
   -		return false;
   -	}
   -
   -	net_buf_simple_save(buf, &state);
   -	net_buf_skip(buf, 5);   /* skip IVI, NID, CTL, TTL, SEQ */
   -	buf_src = net_buf_pull_be16(buf);
   -	net_buf_skip(buf, 3);   /* skip DST, OP/AID */
   -	buf_seq_zero = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK);
   -	net_buf_simple_restore(buf, &state);
   -
   -	return ((src == buf_src) && (seq_zero == buf_seq_zero));
   -}
   -
   -static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
   -					  u16_t src, u16_t seq_zero,
   -					  u8_t seg_count)
   -{
   -	struct bt_mesh_friend_seg *unassigned = NULL;
   -	int i;
   -
   -	for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
   -		struct bt_mesh_friend_seg *seg = &frnd->seg[i];
   -
   -		if (is_seg(seg, src, seq_zero)) {
   -			return seg;
   -		}
   -
   -		if (!unassigned && !net_buf_slist_peek_head(&seg->queue)) {
   -			unassigned = seg;
   -		}
   -	}
   -
   -	if (unassigned) {
   -		unassigned->seg_count = seg_count;
   -	}
   -
   -	return unassigned;
   -}
   -
   -static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
   -			       enum bt_mesh_friend_pdu_type type,
   -			       u16_t src, u8_t seg_count,
   -			       struct os_mbuf *buf)
   -{
   -	struct bt_mesh_friend_seg *seg;
   -
   -	BT_DBG("type %u", type);
   -
   -	if (type == BT_MESH_FRIEND_PDU_SINGLE) {
   -		enqueue_buf(frnd, buf);
   -		return;
   -	}
   -
   -	u16_t seq_zero = (((buf->om_data[10] << 8 | buf->om_data[11]) >> 2) & TRANS_SEQ_ZERO_MASK);
   -
   -	seg = get_seg(frnd, src, seq_zero, seg_count);
   -	if (!seg) {
   -		BT_ERR("No free friend segment RX contexts for 0x%04x", src);
   -		net_buf_unref(buf);
   -		return;
   -	}
   -
   -	net_buf_slist_put(&seg->queue, buf);
   -
   -	if (type == BT_MESH_FRIEND_PDU_COMPLETE) {
   -		net_buf_slist_merge_slist(&frnd->queue, &seg->queue);
   -
   -		frnd->queue_size += seg->seg_count;
   -		seg->seg_count = 0U;
   -	} else {
   -		/* Mark the buffer as having more to come after it */
   -		BT_MESH_ADV(buf)->flags |= NET_BUF_FRAGS;
   -	}
   -}
   -
   -static void buf_send_start(u16_t duration, int err, void *user_data)
   -{
   -	struct bt_mesh_friend *frnd = user_data;
   -
   -	BT_DBG("err %d", err);
   -
   -	frnd->pending_buf = 0;
   -
   -	/* Friend Offer doesn't follow the re-sending semantics */
   -	if (!frnd->established) {
   -		net_buf_unref(frnd->last);
   -		frnd->last = NULL;
   -	}
   -}
   -
   -static void buf_send_end(int err, void *user_data)
   -{
   -	struct bt_mesh_friend *frnd = user_data;
   -
   -	BT_DBG("err %d", err);
   -
   -	if (frnd->pending_req) {
   -		BT_WARN("Another request before previous completed sending");
   -		return;
   -	}
   -
   -	if (frnd->established) {
   -		k_delayed_work_submit(&frnd->timer, frnd->poll_to);
   -		BT_DBG("Waiting %u ms for next poll",
   -		       (unsigned) frnd->poll_to);
   -	} else {
   -		/* Friend offer timeout is 1 second */
   -		k_delayed_work_submit(&frnd->timer, K_SECONDS(1));
   -		BT_DBG("Waiting for first poll");
   -	}
   -}
   -
   -static void update_overwrite(struct os_mbuf *buf, u8_t md)
   -{
   -	struct net_buf_simple_state state;
   -	struct bt_mesh_ctl_friend_update *upd;
   -
   -	if (buf->om_len != 16) {
   -		return;
   -	}
   -
   -	net_buf_simple_save(buf, &state);
   -
   -	net_buf_skip(buf, 1); /* skip IVI, NID */
   -
   -	if (!(net_buf_pull_u8(buf) >> 7)) {
   -		goto end;
   -	}
   -
   -	net_buf_skip(buf, 7); /* skip seqnum src dec*/
   -
   -	if (TRANS_CTL_OP((u8_t *) net_buf_pull_mem(buf, 1))
   -			!= TRANS_CTL_OP_FRIEND_UPDATE) {
   -		goto end;
   -	}
   -
   -	upd = net_buf_pull_mem(buf, sizeof(*upd));
   -	BT_DBG("Update Previous Friend Update MD 0x%02x -> 0x%02x", upd->md, md);
   -	upd->md = md;
   +    frnd->lpn = rx->ctx.addr;
   +    frnd->num_elem = msg->num_elem;
   +    frnd->net_idx = rx->sub->net_idx;
   +    frnd->recv_delay = msg->recv_delay;
   +    frnd->poll_to = poll_to * 100;
   +    frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter);
   +    frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr);
   +
   +    BT_DBG("LPN 0x%04x rssi %d recv_delay %u poll_to %ums",
   +           frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay,
   +           (unsigned) frnd->poll_to);
   +
   +    if (BT_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) &&
   +        !bt_mesh_elem_find(frnd->clear.frnd)) {
   +        clear_procedure_start(frnd);
   +    }
   +
   +    k_delayed_work_submit(&frnd->timer,
   +                  offer_delay(frnd, rx->ctx.recv_rssi,
   +                      msg->criteria));
   +
   +    friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter,
   +               frnd->counter);
   +
   +    enqueue_offer(frnd, rx->ctx.recv_rssi);
   +
   +    return 0;
   +}
   +
   +static bool
   +is_seg(struct bt_mesh_friend_seg *seg, u16_t src, u16_t seq_zero)
   +{
   +    struct os_mbuf *buf = (void *)net_buf_slist_peek_head(&seg->queue);
   +    struct net_buf_simple_state state;
   +    u16_t buf_seq_zero;
   +    u16_t buf_src;
   +
   +    if (!buf) {
   +        return false;
   +    }
   +
   +    net_buf_simple_save(buf, &state);
   +    net_buf_skip(buf, 5);   /* skip IVI, NID, CTL, TTL, SEQ */
   +    buf_src = net_buf_pull_be16(buf);
   +    net_buf_skip(buf, 3);   /* skip DST, OP/AID */
   +    buf_seq_zero = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK);
   +    net_buf_simple_restore(buf, &state);
   +
   +    return ((src == buf_src) && (seq_zero == buf_seq_zero));
   +}
   +
   +static struct bt_mesh_friend_seg *
   +get_seg(struct bt_mesh_friend *frnd,
   +        u16_t src, u16_t seq_zero,
   +        u8_t seg_count)
   +{
   +    struct bt_mesh_friend_seg *unassigned = NULL;
   +    int i;
   +
   +    for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
   +        struct bt_mesh_friend_seg *seg = &frnd->seg[i];
   +
   +        if (is_seg(seg, src, seq_zero)) {
   +            return seg;
   +        }
   +
   +        if (!unassigned && !net_buf_slist_peek_head(&seg->queue)) {
   +            unassigned = seg;
   +        }
   +    }
   +
   +    if (unassigned) {
   +        unassigned->seg_count = seg_count;
   +    }
   +
   +    return unassigned;
   +}
   +
   +static void
   +enqueue_friend_pdu(struct bt_mesh_friend *frnd,
   +                   enum bt_mesh_friend_pdu_type type,
   +                   u16_t src, u8_t seg_count,
   +                   struct os_mbuf *buf)
   +{
   +    struct bt_mesh_friend_seg *seg;
   +
   +    BT_DBG("type %u", type);
   +
   +    if (type == BT_MESH_FRIEND_PDU_SINGLE) {
   +        enqueue_buf(frnd, buf);
   +        return;
   +    }
   +
   +    u16_t seq_zero = (((buf->om_data[10] << 8 | buf->om_data[11]) >> 2) & TRANS_SEQ_ZERO_MASK);
   +
   +    seg = get_seg(frnd, src, seq_zero, seg_count);
   +    if (!seg) {
   +        BT_ERR("No free friend segment RX contexts for 0x%04x", src);
   +        net_buf_unref(buf);
   +        return;
   +    }
   +
   +    net_buf_slist_put(&seg->queue, buf);
   +
   +    if (type == BT_MESH_FRIEND_PDU_COMPLETE) {
   +        net_buf_slist_merge_slist(&frnd->queue, &seg->queue);
   +
   +        frnd->queue_size += seg->seg_count;
   +        seg->seg_count = 0U;
   +    } else {
   +        /* Mark the buffer as having more to come after it */
   +        BT_MESH_ADV(buf)->flags |= NET_BUF_FRAGS;
   +    }
   +}
   +
   +static void
   +buf_send_start(u16_t duration, int err, void *user_data)
   +{
   +    struct bt_mesh_friend *frnd = user_data;
   +
   +    BT_DBG("err %d", err);
   +
   +    frnd->pending_buf = 0;
   +
   +    /* Friend Offer doesn't follow the re-sending semantics */
   +    if (!frnd->established) {
   +        net_buf_unref(frnd->last);
   +        frnd->last = NULL;
   +    }
   +}
   +
   +static void
   +buf_send_end(int err, void *user_data)
   +{
   +    struct bt_mesh_friend *frnd = user_data;
   +
   +    BT_DBG("err %d", err);
   +
   +    if (frnd->pending_req) {
   +        BT_WARN("Another request before previous completed sending");
   +        return;
   +    }
   +
   +    if (frnd->established) {
   +        k_delayed_work_submit(&frnd->timer, frnd->poll_to);
   +        BT_DBG("Waiting %u ms for next poll",
   +               (unsigned) frnd->poll_to);
   +    } else {
   +        /* Friend offer timeout is 1 second */
   +        k_delayed_work_submit(&frnd->timer, K_SECONDS(1));
   +        BT_DBG("Waiting for first poll");
   +    }
   +}
   +
   +static void
   +update_overwrite(struct os_mbuf *buf, u8_t md)
   +{
   +    struct net_buf_simple_state state;
   +    struct bt_mesh_ctl_friend_update *upd;
   +
   +    if (buf->om_len != 16) {
   +        return;
   +    }
   +
   +    net_buf_simple_save(buf, &state);
   +
   +    net_buf_skip(buf, 1); /* skip IVI, NID */
   +
   +    if (!(net_buf_pull_u8(buf) >> 7)) {
   +        goto end;
   +    }
   +
   +    net_buf_skip(buf, 7); /* skip seqnum src dec*/
   +
   +    if (TRANS_CTL_OP((u8_t *) net_buf_pull_mem(buf, 1))
   +        != TRANS_CTL_OP_FRIEND_UPDATE) {
   +        goto end;
   +    }
   +
   +    upd = net_buf_pull_mem(buf, sizeof(*upd));
   +    BT_DBG("Update Previous Friend Update MD 0x%02x -> 0x%02x", upd->md, md);
   +    upd->md = md;
    
    end:
   -	net_buf_simple_restore(buf, &state);
   -}
   -
   -static void friend_timeout(struct ble_npl_event *work)
   -{
   -	struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work);
   -	static const struct bt_mesh_send_cb buf_sent_cb = {
   -		.start = buf_send_start,
   -		.end = buf_send_end,
   -	};
   -
   -	u8_t md;
   -
   -	__ASSERT_NO_MSG(frnd->pending_buf == 0);
   -
   -	BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn,
   -	       frnd->send_last, frnd->last);
   -
   -	if (frnd->send_last && frnd->last) {
   -		BT_DBG("Sending frnd->last %p", frnd->last);
   -		frnd->send_last = 0;
   -		goto send_last;
   -	}
   -
   -	if (frnd->established && !frnd->pending_req) {
   -		BT_WARN("Friendship lost with 0x%04x", frnd->lpn);
   -		friend_clear(frnd);
   -		return;
   -	}
   -
   -	frnd->last = (void *)net_buf_slist_get(&frnd->queue);
   -	if (!frnd->last) {
   -		BT_WARN("Friendship not established with 0x%04x",
   -			frnd->lpn);
   -		friend_clear(frnd);
   -		return;
   -	}
   -
   -	md = (u8_t)(net_buf_slist_peek_head(&frnd->queue) != NULL);
   -
   -	update_overwrite(frnd->last, md);
   -
   -	if (encrypt_friend_pdu(frnd, frnd->last, false)) {
   -		return;
   -	}
   -
   -	/* Clear the flag we use for segment tracking */
   -	BT_MESH_ADV(frnd->last)->flags &= ~NET_BUF_FRAGS;
   -
   -	BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x",
   -	       frnd->last, frnd->lpn);
   -	frnd->queue_size--;
   +    net_buf_simple_restore(buf, &state);
   +}
   +
   +static void
   +friend_timeout(struct ble_npl_event *work)
   +{
   +    struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work);
   +    static const struct bt_mesh_send_cb buf_sent_cb = {
   +        .start = buf_send_start,
   +        .end = buf_send_end,
   +    };
   +
   +    u8_t md;
   +
   +    __ASSERT_NO_MSG(frnd->pending_buf == 0);
   +
   +    BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn,
   +           frnd->send_last, frnd->last);
   +
   +    if (frnd->send_last && frnd->last) {
   +        BT_DBG("Sending frnd->last %p", frnd->last);
   +        frnd->send_last = 0;
   +        goto send_last;
   +    }
   +
   +    if (frnd->established && !frnd->pending_req) {
   +        BT_WARN("Friendship lost with 0x%04x", frnd->lpn);
   +        friend_clear(frnd);
   +        return;
   +    }
   +
   +    frnd->last = (void *)net_buf_slist_get(&frnd->queue);
   +    if (!frnd->last) {
   +        BT_WARN("Friendship not established with 0x%04x",
   +            frnd->lpn);
   +        friend_clear(frnd);
   +        return;
   +    }
   +
   +    md = (u8_t)(net_buf_slist_peek_head(&frnd->queue) != NULL);
   +
   +    update_overwrite(frnd->last, md);
   +
   +    if (encrypt_friend_pdu(frnd, frnd->last, false)) {
   +        return;
   +    }
   +
   +    /* Clear the flag we use for segment tracking */
   +    BT_MESH_ADV(frnd->last)->flags &= ~NET_BUF_FRAGS;
   +
   +    BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x",
   +           frnd->last, frnd->lpn);
   +    frnd->queue_size--;
    
    send_last:
   -	frnd->pending_req = 0;
   -	frnd->pending_buf = 1;
   -	bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd);
   -}
   -
   -int bt_mesh_friend_init(void)
   -{
   -	int rc;
   -	int i;
   -
   -	rc = os_mempool_init(&friend_buf_mempool, FRIEND_BUF_COUNT,
   -			BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
   -			friend_buf_mem, "friend_buf_pool");
   -	assert(rc == 0);
   -
   -	rc = os_mbuf_pool_init(&friend_os_mbuf_pool, &friend_buf_mempool,
   -			BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
   -			FRIEND_BUF_COUNT);
   -	assert(rc == 0);
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -		int j;
   -
   -		frnd->net_idx = BT_MESH_KEY_UNUSED;
   -
   -		net_buf_slist_init(&frnd->queue);
   -
   -		k_delayed_work_init(&frnd->timer, friend_timeout);
   -		k_delayed_work_add_arg(&frnd->timer, frnd);
   -		k_delayed_work_init(&frnd->clear.timer, clear_timeout);
   -		k_delayed_work_add_arg(&frnd->clear.timer, frnd);
   -
   -		for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
   -			net_buf_slist_init(&frnd->seg[j].queue);
   -		}
   -	}
   -
   -	return 0;
   -}
   -
   -static bool is_segack(struct os_mbuf *buf, u64_t *seqauth, u16_t src)
   -{
   -	struct net_buf_simple_state state;
   -	bool found = false;
   -
   -	if (buf->om_len != 16) {
   -		return false;
   -	}
   -
   -	net_buf_simple_save(buf, &state);
   -
   -	net_buf_skip(buf, 1); /* skip IVI, NID */
   -
   -	if (!(net_buf_pull_u8(buf) >> 7)) {
   -		goto end;
   -	}
   -
   -	net_buf_pull(buf, 3); /* skip SEQNUM */
   -
   -	if (src != net_buf_pull_be16(buf)) {
   -		goto end;
   -	}
   -
   -	net_buf_skip(buf, 2); /* skip dst */
   -
   -	if (TRANS_CTL_OP((u8_t *) net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) {
   -		goto end;
   -	}
   -
   -	found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) ==
   -		(*seqauth & TRANS_SEQ_ZERO_MASK);
   +    frnd->pending_req = 0;
   +    frnd->pending_buf = 1;
   +    bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd);
   +}
   +
   +int
   +bt_mesh_friend_init(void)
   +{
   +    int rc;
   +    int i;
   +
   +    rc = os_mempool_init(&friend_buf_mempool, FRIEND_BUF_COUNT,
   +            BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
   +            friend_buf_mem, "friend_buf_pool");
   +    assert(rc == 0);
   +
   +    rc = os_mbuf_pool_init(&friend_os_mbuf_pool, &friend_buf_mempool,
   +            BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE,
   +            FRIEND_BUF_COUNT);
   +    assert(rc == 0);
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +        int j;
   +
   +        frnd->net_idx = BT_MESH_KEY_UNUSED;
   +
   +        net_buf_slist_init(&frnd->queue);
   +
   +        k_delayed_work_init(&frnd->timer, friend_timeout);
   +        k_delayed_work_add_arg(&frnd->timer, frnd);
   +        k_delayed_work_init(&frnd->clear.timer, clear_timeout);
   +        k_delayed_work_add_arg(&frnd->clear.timer, frnd);
   +
   +        for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
   +            net_buf_slist_init(&frnd->seg[j].queue);
   +        }
   +    }
   +
   +    return 0;
   +}
   +
   +static bool
   +is_segack(struct os_mbuf *buf, u64_t *seqauth, u16_t src)
   +{
   +    struct net_buf_simple_state state;
   +    bool found = false;
   +
   +    if (buf->om_len != 16) {
   +        return false;
   +    }
   +
   +    net_buf_simple_save(buf, &state);
   +
   +    net_buf_skip(buf, 1); /* skip IVI, NID */
   +
   +    if (!(net_buf_pull_u8(buf) >> 7)) {
   +        goto end;
   +    }
   +
   +    net_buf_pull(buf, 3); /* skip SEQNUM */
   +
   +    if (src != net_buf_pull_be16(buf)) {
   +        goto end;
   +    }
   +
   +    net_buf_skip(buf, 2); /* skip dst */
   +
   +    if (TRANS_CTL_OP((u8_t *) net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) {
   +        goto end;
   +    }
   +
   +    found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) ==
   +            (*seqauth & TRANS_SEQ_ZERO_MASK);
    end:
   -	net_buf_simple_restore(buf, &state);
   -	return found;
   -}
   -
   -static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
   -				 u16_t src)
   -{
   -	struct os_mbuf *cur, *prev = NULL;
   -
   -	BT_DBG("SeqAuth %llx src 0x%04x", *seq_auth, src);
   -
   -	for (cur = net_buf_slist_peek_head(&frnd->queue);
   -	     cur != NULL; prev = cur, cur = net_buf_slist_peek_next(cur)) {
   -		struct os_mbuf *buf = (void *)cur;
   -
   -		if (is_segack(buf, seq_auth, src)) {
   -			BT_DBG("Removing old ack from Friend Queue");
   -
   -			net_buf_slist_remove(&frnd->queue, prev, cur);
   -			frnd->queue_size--;
   -
   -			net_buf_unref(buf);
   -			break;
   -		}
   -	}
   -}
   -
   -static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
   -				  struct bt_mesh_net_rx *rx,
   -				  enum bt_mesh_friend_pdu_type type,
   -				  u64_t *seq_auth, u8_t seg_count,
   -				  struct os_mbuf *sbuf)
   -{
   -	struct friend_pdu_info info;
   -	struct os_mbuf *buf;
   -
   -	/* Because of network loopback, tx packets will also be passed into
   -	 * this rx function. These packets have already been added to the
   -	 * queue, and should be ignored.
   -	 */
   -	if (bt_mesh_elem_find(rx->ctx.addr)) {
   -		return;
   -	}
   -
   -	BT_DBG("LPN 0x%04x queue_size %u", frnd->lpn,
   -	       (unsigned) frnd->queue_size);
   -
   -	if (type == BT_MESH_FRIEND_PDU_SINGLE && seq_auth) {
   -		friend_purge_old_ack(frnd, seq_auth, rx->ctx.addr);
   -	}
   -
   -	info.src = rx->ctx.addr;
   -	info.dst = rx->ctx.recv_dst;
   -
   -	if (rx->net_if == BT_MESH_NET_IF_LOCAL) {
   -		info.ttl = rx->ctx.recv_ttl;
   -	} else {
   -		info.ttl = rx->ctx.recv_ttl - 1;
   -	}
   -
   -	info.ctl = rx->ctl;
   -
   -	info.seq[0] = (rx->seq >> 16);
   -	info.seq[1] = (rx->seq >> 8);
   -	info.seq[2] = rx->seq;
   -
   -	info.iv_index = BT_MESH_NET_IVI_RX(rx);
   -
   -	buf = create_friend_pdu(frnd, &info, sbuf);
   -	if (!buf) {
   -		BT_ERR("Failed to encode Friend buffer");
   -		return;
   -	}
   -
   -	enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
   -
   -	BT_DBG("Queued message for LPN 0x%04x, queue_size %u",
   -	       frnd->lpn, (unsigned) frnd->queue_size);
   -}
   -
   -static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
   -				  struct bt_mesh_net_tx *tx,
   -				  enum bt_mesh_friend_pdu_type type,
   -				  u64_t *seq_auth, u8_t seg_count,
   -				  struct os_mbuf *sbuf)
   -{
   -	struct friend_pdu_info info;
   -	struct os_mbuf *buf;
   -
   -	BT_DBG("LPN 0x%04x", frnd->lpn);
   -
   -	if (type == BT_MESH_FRIEND_PDU_SINGLE && seq_auth) {
   -		friend_purge_old_ack(frnd, seq_auth, tx->src);
   -	}
   -
   -	info.src = tx->src;
   -	info.dst = tx->ctx->addr;
   -
   -	info.ttl = tx->ctx->send_ttl;
   -	info.ctl = (tx->ctx->app_idx == BT_MESH_KEY_UNUSED);
   -
   -	info.seq[0] = (bt_mesh.seq >> 16);
   -	info.seq[1] = (bt_mesh.seq >> 8);
   -	info.seq[2] = bt_mesh.seq;
   -
   -	info.iv_index = BT_MESH_NET_IVI_TX;
   -
   -	buf = create_friend_pdu(frnd, &info, sbuf);
   -	if (!buf) {
   -		BT_ERR("Failed to encode Friend buffer");
   -		return;
   -	}
   -
   -	if (type == BT_MESH_FRIEND_PDU_SINGLE && !info.ctl) {
   -		/* Unsegmented application packets may be reencrypted later,
   -		 * as they depend on the the sequence number being the same
   -		 * when encrypting in transport and network.
   -		 */
   -		FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx;
   -	}
   -
   -	enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
   -
   -	BT_DBG("Queued message for LPN 0x%04x", frnd->lpn);
   -}
   -
   -static bool friend_lpn_matches(struct bt_mesh_friend *frnd, u16_t net_idx,
   -			       u16_t addr)
   -{
   -	int i;
   -
   -	if (!frnd->established) {
   -		return false;
   -	}
   -
   -	if (net_idx != frnd->net_idx) {
   -		return false;
   -	}
   -
   -	if (BT_MESH_ADDR_IS_UNICAST(addr)) {
   -		return is_lpn_unicast(frnd, addr);
   -	}
   -
   -	for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
   -		if (frnd->sub_list[i] == addr) {
   -			return true;
   -		}
   -	}
   -
   -	return false;
   -}
   -
   -bool bt_mesh_friend_match(u16_t net_idx, u16_t addr)
   -{
   -	int i;
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -
   -		if (friend_lpn_matches(frnd, net_idx, addr)) {
   -			BT_DBG("LPN 0x%04x matched address 0x%04x",
   -			       frnd->lpn, addr);
   -			return true;
   -		}
   -	}
   -
   -	BT_DBG("No matching LPN for address 0x%04x", addr);
   -
   -	return false;
   -}
   -
   -static bool friend_queue_has_space(struct bt_mesh_friend *frnd, u16_t addr,
   -				   u64_t *seq_auth, u8_t seg_count)
   -{
   -	u32_t total = 0;
   -	int i;
   -
   -	if (seg_count > CONFIG_BT_MESH_FRIEND_QUEUE_SIZE) {
   -		return false;
   -	}
   -
   -	for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
   -		struct bt_mesh_friend_seg *seg = &frnd->seg[i];
   -
   -		if (seq_auth && is_seg(seg, addr, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
   -			/* If there's a segment queue for this message then the
   -			 * space verification has already happened.
   -			 */
   -			return true;
   -		}
   -
   -		total += seg->seg_count;
   -	}
   -
   -	/* If currently pending segments combined with this segmented message
   -	 * are more than the Friend Queue Size, then there's no space. This
   -	 * is because we don't have a mechanism of aborting already pending
   -	 * segmented messages to free up buffers.
   -	 */
   -	return (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - total) > seg_count;
   -}
   -
   -bool bt_mesh_friend_queue_has_space(u16_t net_idx, u16_t src, u16_t dst,
   -				    u64_t *seq_auth, u8_t seg_count)
   -{
   -	bool someone_has_space = false, friend_match = false;
   -	int i;
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -
   -		if (!friend_lpn_matches(frnd, net_idx, dst)) {
   -			continue;
   -		}
   -
   -		friend_match = true;
   -
   -		if (friend_queue_has_space(frnd, src, seq_auth, seg_count)) {
   -			someone_has_space = true;
   -		}
   -	}
   -
   -	/* If there were no matched LPNs treat this as success, so the
   -	 * transport layer can continue its work.
   -	 */
   -	if (!friend_match) {
   -		return true;
   -	}
   -
   -	/* From the transport layers perspective it's good enough that at
   -	 * least one Friend Queue has space. If there were multiple Friend
   -	 * matches then the destination must be a group address, in which
   -	 * case e.g. segment acks are not sent.
   -	 */
   -	return someone_has_space;
   -}
   -
   -static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, u16_t addr,
   -				       u64_t *seq_auth, u8_t seg_count)
   -{
   -	bool pending_segments;
   -	u8_t avail_space;
   -
   -	if (!friend_queue_has_space(frnd, addr, seq_auth, seg_count)) {
   -		return false;
   -	}
   -
   -	avail_space = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - frnd->queue_size;
   -	pending_segments = false;
   -
   -	while (pending_segments || avail_space < seg_count) {
   -		struct os_mbuf *buf = (void *)net_buf_slist_get(&frnd->queue);
   -
   -		if (!buf) {
   -			BT_ERR("Unable to free up enough buffers");
   -			return false;
   -		}
   -
   -		frnd->queue_size--;
   -		avail_space++;
   -
   -		pending_segments = (BT_MESH_ADV(buf)->flags & NET_BUF_FRAGS);
   -		BT_DBG("PENDING SEGMENTS %d", pending_segments);
   -
   -		/* Make sure old slist entry state doesn't remain */
   -		BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS;
   -
   -		net_buf_unref(buf);
   -	}
   -
   -	return true;
   -}
   -
   -void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
   -			       enum bt_mesh_friend_pdu_type type,
   -			       u64_t *seq_auth, u8_t seg_count,
   -			       struct os_mbuf *sbuf)
   -{
   -	int i;
   -
   -	if (!rx->friend_match ||
   -	    (rx->ctx.recv_ttl <= 1 && rx->net_if != BT_MESH_NET_IF_LOCAL) ||
   -	    bt_mesh_friend_get() != BT_MESH_FRIEND_ENABLED) {
   -		return;
   -	}
   -
   -	BT_DBG("recv_ttl %u net_idx 0x%04x src 0x%04x dst 0x%04x",
   -	       rx->ctx.recv_ttl, rx->sub->net_idx, rx->ctx.addr,
   -	       rx->ctx.recv_dst);
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -
   -		if (!friend_lpn_matches(frnd, rx->sub->net_idx,
   -					rx->ctx.recv_dst)) {
   -			continue;
   -		}
   -
   -		if (!friend_queue_prepare_space(frnd, rx->ctx.addr, seq_auth,
   -						seg_count)) {
   -			continue;
   -		}
   -
   -		friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count,
   -				      sbuf);
   -	}
   -}
   -
   -bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx,
   -			       enum bt_mesh_friend_pdu_type type,
   -			       u64_t *seq_auth, u8_t seg_count,
   -			       struct os_mbuf *sbuf)
   -{
   -	bool matched = false;
   -	int i;
   -
   -	if (!bt_mesh_friend_match(tx->sub->net_idx, tx->ctx->addr) ||
   -	    bt_mesh_friend_get() != BT_MESH_FRIEND_ENABLED) {
   -		return matched;
   -	}
   -
   -	BT_DBG("net_idx 0x%04x dst 0x%04x src 0x%04x", tx->sub->net_idx,
   -	       tx->ctx->addr, tx->src);
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -
   -		if (!friend_lpn_matches(frnd, tx->sub->net_idx,
   -					tx->ctx->addr)) {
   -			continue;
   -		}
   -
   -		if (!friend_queue_prepare_space(frnd, tx->src, seq_auth,
   -						seg_count)) {
   -			continue;
   -		}
   -
   -		friend_lpn_enqueue_tx(frnd, tx, type, seq_auth, seg_count,
   -				      sbuf);
   -		matched = true;
   -	}
   -
   -	return matched;
   -}
   -
   -void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
   -				     u16_t dst, u64_t *seq_auth)
   -{
   -	int i;
   -
   -	BT_DBG("");
   -
   -	for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   -		struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   -		int j;
   -
   -		if (!friend_lpn_matches(frnd, sub->net_idx, dst)) {
   -			continue;
   -		}
   -
   -		for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
   -			struct bt_mesh_friend_seg *seg = &frnd->seg[j];
   -
   -			if (!is_seg(seg, src, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
   -				continue;
   -			}
   -
   -			BT_WARN("Clearing incomplete segments for 0x%04x", src);
   -
   -			purge_buffers(&seg->queue);
   -			seg->seg_count = 0U;
   -			break;
   -		}
   -	}
   +    net_buf_simple_restore(buf, &state);
   +    return found;
   +}
   +
   +static void
   +friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
   +                     u16_t src)
   +{
   +    struct os_mbuf *cur, *prev = NULL;
   +
   +    BT_DBG("SeqAuth %llx src 0x%04x", *seq_auth, src);
   +
   +    for (cur = net_buf_slist_peek_head(&frnd->queue);
   +         cur != NULL; prev = cur, cur = net_buf_slist_peek_next(cur)) {
   +        struct os_mbuf *buf = (void *)cur;
   +
   +        if (is_segack(buf, seq_auth, src)) {
   +            BT_DBG("Removing old ack from Friend Queue");
   +
   +            net_buf_slist_remove(&frnd->queue, prev, cur);
   +            frnd->queue_size--;
   +
   +            net_buf_unref(buf);
   +            break;
   +        }
   +    }
   +}
   +
   +static void
   +friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
   +                      struct bt_mesh_net_rx *rx,
   +                      enum bt_mesh_friend_pdu_type type,
   +                      u64_t *seq_auth, u8_t seg_count,
   +                      struct os_mbuf *sbuf)
   +{
   +    struct friend_pdu_info info;
   +    struct os_mbuf *buf;
   +
   +    /* Because of network loopback, tx packets will also be passed into
   +     * this rx function. These packets have already been added to the
   +     * queue, and should be ignored.
   +     */
   +    if (bt_mesh_elem_find(rx->ctx.addr)) {
   +        return;
   +    }
   +
   +    BT_DBG("LPN 0x%04x queue_size %u", frnd->lpn,
   +           (unsigned) frnd->queue_size);
   +
   +    if (type == BT_MESH_FRIEND_PDU_SINGLE && seq_auth) {
   +        friend_purge_old_ack(frnd, seq_auth, rx->ctx.addr);
   +    }
   +
   +    info.src = rx->ctx.addr;
   +    info.dst = rx->ctx.recv_dst;
   +
   +    if (rx->net_if == BT_MESH_NET_IF_LOCAL) {
   +        info.ttl = rx->ctx.recv_ttl;
   +    } else {
   +        info.ttl = rx->ctx.recv_ttl - 1;
   +    }
   +
   +    info.ctl = rx->ctl;
   +
   +    info.seq[0] = (rx->seq >> 16);
   +    info.seq[1] = (rx->seq >> 8);
   +    info.seq[2] = rx->seq;
   +
   +    info.iv_index = BT_MESH_NET_IVI_RX(rx);
   +
   +    buf = create_friend_pdu(frnd, &info, sbuf);
   +    if (!buf) {
   +        BT_ERR("Failed to encode Friend buffer");
   +        return;
   +    }
   +
   +    enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
   +
   +    BT_DBG("Queued message for LPN 0x%04x, queue_size %u",
   +           frnd->lpn, (unsigned) frnd->queue_size);
   +}
   +
   +static void
   +friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
   +                      struct bt_mesh_net_tx *tx,
   +                      enum bt_mesh_friend_pdu_type type,
   +                      u64_t *seq_auth, u8_t seg_count,
   +                      struct os_mbuf *sbuf)
   +{
   +    struct friend_pdu_info info;
   +    struct os_mbuf *buf;
   +
   +    BT_DBG("LPN 0x%04x", frnd->lpn);
   +
   +    if (type == BT_MESH_FRIEND_PDU_SINGLE && seq_auth) {
   +        friend_purge_old_ack(frnd, seq_auth, tx->src);
   +    }
   +
   +    info.src = tx->src;
   +    info.dst = tx->ctx->addr;
   +
   +    info.ttl = tx->ctx->send_ttl;
   +    info.ctl = (tx->ctx->app_idx == BT_MESH_KEY_UNUSED);
   +
   +    info.seq[0] = (bt_mesh.seq >> 16);
   +    info.seq[1] = (bt_mesh.seq >> 8);
   +    info.seq[2] = bt_mesh.seq;
   +
   +    info.iv_index = BT_MESH_NET_IVI_TX;
   +
   +    buf = create_friend_pdu(frnd, &info, sbuf);
   +    if (!buf) {
   +        BT_ERR("Failed to encode Friend buffer");
   +        return;
   +    }
   +
   +    if (type == BT_MESH_FRIEND_PDU_SINGLE && !info.ctl) {
   +        /* Unsegmented application packets may be reencrypted later,
   +         * as they depend on the the sequence number being the same
   +         * when encrypting in transport and network.
   +         */
   +        FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx;
   +    }
   +
   +    enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
   +
   +    BT_DBG("Queued message for LPN 0x%04x", frnd->lpn);
   +}
   +
   +static bool
   +friend_lpn_matches(struct bt_mesh_friend *frnd, u16_t net_idx,
   +                   u16_t addr)
   +{
   +    int i;
   +
   +    if (!frnd->established) {
   +        return false;
   +    }
   +
   +    if (net_idx != frnd->net_idx) {
   +        return false;
   +    }
   +
   +    if (BT_MESH_ADDR_IS_UNICAST(addr)) {
   +        return is_lpn_unicast(frnd, addr);
   +    }
   +
   +    for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
   +        if (frnd->sub_list[i] == addr) {
   +            return true;
   +        }
   +    }
   +
   +    return false;
   +}
   +
   +bool
   +bt_mesh_friend_match(u16_t net_idx, u16_t addr)
   +{
   +    int i;
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +
   +        if (friend_lpn_matches(frnd, net_idx, addr)) {
   +            BT_DBG("LPN 0x%04x matched address 0x%04x",
   +                   frnd->lpn, addr);
   +            return true;
   +        }
   +    }
   +
   +    BT_DBG("No matching LPN for address 0x%04x", addr);
   +
   +    return false;
   +}
   +
   +static bool
   +friend_queue_has_space(struct bt_mesh_friend *frnd, u16_t addr,
   +                       u64_t *seq_auth, u8_t seg_count)
   +{
   +    u32_t total = 0;
   +    int i;
   +
   +    if (seg_count > CONFIG_BT_MESH_FRIEND_QUEUE_SIZE) {
   +        return false;
   +    }
   +
   +    for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
   +        struct bt_mesh_friend_seg *seg = &frnd->seg[i];
   +
   +        if (seq_auth && is_seg(seg, addr, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
   +            /* If there's a segment queue for this message then the
   +             * space verification has already happened.
   +             */
   +            return true;
   +        }
   +
   +        total += seg->seg_count;
   +    }
   +
   +    /* If currently pending segments combined with this segmented message
   +     * are more than the Friend Queue Size, then there's no space. This
   +     * is because we don't have a mechanism of aborting already pending
   +     * segmented messages to free up buffers.
   +     */
   +    return (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - total) > seg_count;
   +}
   +
   +bool
   +bt_mesh_friend_queue_has_space(u16_t net_idx, u16_t src, u16_t dst,
   +                               u64_t *seq_auth, u8_t seg_count)
   +{
   +    bool someone_has_space = false, friend_match = false;
   +    int i;
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +
   +        if (!friend_lpn_matches(frnd, net_idx, dst)) {
   +            continue;
   +        }
   +
   +        friend_match = true;
   +
   +        if (friend_queue_has_space(frnd, src, seq_auth, seg_count)) {
   +            someone_has_space = true;
   +        }
   +    }
   +
   +    /* If there were no matched LPNs treat this as success, so the
   +     * transport layer can continue its work.
   +     */
   +    if (!friend_match) {
   +        return true;
   +    }
   +
   +    /* From the transport layers perspective it's good enough that at
   +     * least one Friend Queue has space. If there were multiple Friend
   +     * matches then the destination must be a group address, in which
   +     * case e.g. segment acks are not sent.
   +     */
   +    return someone_has_space;
   +}
   +
   +static bool
   +friend_queue_prepare_space(struct bt_mesh_friend *frnd, u16_t addr,
   +                           u64_t *seq_auth, u8_t seg_count)
   +{
   +    bool pending_segments;
   +    u8_t avail_space;
   +
   +    if (!friend_queue_has_space(frnd, addr, seq_auth, seg_count)) {
   +        return false;
   +    }
   +
   +    avail_space = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - frnd->queue_size;
   +    pending_segments = false;
   +
   +    while (pending_segments || avail_space < seg_count) {
   +        struct os_mbuf *buf = (void *)net_buf_slist_get(&frnd->queue);
   +
   +        if (!buf) {
   +            BT_ERR("Unable to free up enough buffers");
   +            return false;
   +        }
   +
   +        frnd->queue_size--;
   +        avail_space++;
   +
   +        pending_segments = (BT_MESH_ADV(buf)->flags & NET_BUF_FRAGS);
   +        BT_DBG("PENDING SEGMENTS %d", pending_segments);
   +
   +        /* Make sure old slist entry state doesn't remain */
   +        BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS;
   +
   +        net_buf_unref(buf);
   +    }
   +
   +    return true;
   +}
   +
   +void
   +bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
   +                          enum bt_mesh_friend_pdu_type type,
   +                          u64_t *seq_auth, u8_t seg_count,
   +                          struct os_mbuf *sbuf)
   +{
   +    int i;
   +
   +    if (!rx->friend_match ||
   +        (rx->ctx.recv_ttl <= 1 && rx->net_if != BT_MESH_NET_IF_LOCAL) ||
   +        bt_mesh_friend_get() != BT_MESH_FRIEND_ENABLED) {
   +        return;
   +    }
   +
   +    BT_DBG("recv_ttl %u net_idx 0x%04x src 0x%04x dst 0x%04x",
   +           rx->ctx.recv_ttl, rx->sub->net_idx, rx->ctx.addr,
   +           rx->ctx.recv_dst);
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +
   +        if (!friend_lpn_matches(frnd, rx->sub->net_idx,
   +                    rx->ctx.recv_dst)) {
   +            continue;
   +        }
   +
   +        if (!friend_queue_prepare_space(frnd, rx->ctx.addr, seq_auth,
   +                        seg_count)) {
   +            continue;
   +        }
   +
   +        friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count,
   +                      sbuf);
   +    }
   +}
   +
   +bool
   +bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx,
   +                          enum bt_mesh_friend_pdu_type type,
   +                          u64_t *seq_auth, u8_t seg_count,
   +                          struct os_mbuf *sbuf)
   +{
   +    bool matched = false;
   +    int i;
   +
   +    if (!bt_mesh_friend_match(tx->sub->net_idx, tx->ctx->addr) ||
   +        bt_mesh_friend_get() != BT_MESH_FRIEND_ENABLED) {
   +        return matched;
   +    }
   +
   +    BT_DBG("net_idx 0x%04x dst 0x%04x src 0x%04x", tx->sub->net_idx,
   +           tx->ctx->addr, tx->src);
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +
   +        if (!friend_lpn_matches(frnd, tx->sub->net_idx,
   +                    tx->ctx->addr)) {
   +            continue;
   +        }
   +
   +        if (!friend_queue_prepare_space(frnd, tx->src, seq_auth,
   +                        seg_count)) {
   +            continue;
   +        }
   +
   +        friend_lpn_enqueue_tx(frnd, tx, type, seq_auth, seg_count,
   +                      sbuf);
   +        matched = true;
   +    }
   +
   +    return matched;
   +}
   +
   +void
   +bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
   +                                u16_t dst, u64_t *seq_auth)
   +{
   +    int i;
   +
   +    BT_DBG("");
   +
   +    for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
   +        struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
   +        int j;
   +
   +        if (!friend_lpn_matches(frnd, sub->net_idx, dst)) {
   +            continue;
   +        }
   +
   +        for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
   +            struct bt_mesh_friend_seg *seg = &frnd->seg[j];
   +
   +            if (!is_seg(seg, src, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
   +                continue;
   +            }
   +
   +            BT_WARN("Clearing incomplete segments for 0x%04x", src);
   +
   +            purge_buffers(&seg->queue);
   +            seg->seg_count = 0U;
   +            break;
   +        }
   +    }
    }
    
    #endif /* MYNEWT_VAL(BLE_MESH_FRIEND) */
   ```
   
   </details>


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org