mynewt-nimble icon indicating copy to clipboard operation
mynewt-nimble copied to clipboard

fixed bug of find cli with CONTAINER_OF() in bt_mesh_proxy_addr_add

Open chinli opened this issue 2 years ago • 1 comments

the ptr of CONTAINER_OF() macro should be field position address of type, so, the buf parameter of bt_mesh_proxy_addr_add should be position address.

chinli avatar Jul 11 '22 08:07 chinli

Style check summary

Our coding style is here!

nimble/host/mesh/src/adv.c

@@ -45,205 +45,212 @@
 
 static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT];
 
-static struct bt_mesh_adv *adv_alloc(int id)
-{
-	return &adv_pool[id];
-}
-
-struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
-					     bt_mesh_adv_alloc_t get_id,
-					     enum bt_mesh_adv_type type,
-					     uint8_t xmit, int32_t timeout)
-{
-	struct bt_mesh_adv *adv;
-	struct os_mbuf *buf;
-
-	if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
-		BT_WARN("Refusing to allocate buffer while suspended");
-		return NULL;
-	}
-
-	buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE);
-	if (!buf) {
-		return NULL;
-	}
-
-	adv = get_id(net_buf_id(buf));
-	BT_MESH_ADV(buf) = adv;
-
-	memset(adv, 0, sizeof(*adv));
-
-	adv->type         = type;
-	adv->xmit         = xmit;
-
-	adv->ref_cnt = 1;
-	ble_npl_event_set_arg(&adv->ev, buf);
-
-	return buf;
-}
-
-struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit,
-				   int32_t timeout)
-{
-	return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type,
-					    xmit, timeout);
-}
-
-void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
-		      void *cb_data)
-{
-	BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len,
-	       bt_hex(buf->om_data, buf->om_len));
-
-	BT_MESH_ADV(buf)->cb = cb;
-	BT_MESH_ADV(buf)->cb_data = cb_data;
-	BT_MESH_ADV(buf)->busy = 1;
-
-	net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf));
-	bt_mesh_adv_buf_ready();
-}
-
-static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
-			    uint8_t adv_type, struct os_mbuf *buf)
-{
-	if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
-		return;
-	}
+static struct bt_mesh_adv *
+adv_alloc(int id)
+{
+    return &adv_pool[id];
+}
+
+struct os_mbuf *
+bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
+                             bt_mesh_adv_alloc_t get_id,
+                             enum bt_mesh_adv_type type,
+                             uint8_t xmit, int32_t timeout)
+{
+    struct bt_mesh_adv *adv;
+    struct os_mbuf *buf;
+
+    if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
+        BT_WARN("Refusing to allocate buffer while suspended");
+        return NULL;
+    }
+
+    buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE);
+    if (!buf) {
+        return NULL;
+    }
+
+    adv = get_id(net_buf_id(buf));
+    BT_MESH_ADV(buf) = adv;
+
+    memset(adv, 0, sizeof(*adv));
+
+    adv->type = type;
+    adv->xmit = xmit;
+
+    adv->ref_cnt = 1;
+    ble_npl_event_set_arg(&adv->ev, buf);
+
+    return buf;
+}
+
+struct os_mbuf *
+bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit,
+                   int32_t timeout)
+{
+    return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type,
+                        xmit, timeout);
+}
+
+void
+bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
+                 void *cb_data)
+{
+    BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len,
+           bt_hex(buf->om_data, buf->om_len));
+
+    BT_MESH_ADV(buf)->cb = cb;
+    BT_MESH_ADV(buf)->cb_data = cb_data;
+    BT_MESH_ADV(buf)->busy = 1;
+
+    net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf));
+    bt_mesh_adv_buf_ready();
+}
+
+static void
+bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
+                uint8_t adv_type, struct os_mbuf *buf)
+{
+    if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
+        return;
+    }
 
 #if BT_MESH_EXTENDED_DEBUG
-	BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
-#endif
-
-	while (buf->om_len > 1) {
-		struct net_buf_simple_state state;
-		uint8_t len, type;
-
-		len = net_buf_simple_pull_u8(buf);
-		/* Check for early termination */
-		if (len == 0) {
-			return;
-		}
-
-		if (len > buf->om_len) {
-			BT_WARN("AD malformed");
-			return;
-		}
-
-		net_buf_simple_save(buf, &state);
-
-		type = net_buf_simple_pull_u8(buf);
-
-		switch (type) {
-		case BLE_HS_ADV_TYPE_MESH_MESSAGE:
-			bt_mesh_net_recv(&buf, rssi, BT_MESH_NET_IF_ADV);
-			break;
+    BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
+#endif
+
+    while (buf->om_len > 1) {
+        struct net_buf_simple_state state;
+        uint8_t len, type;
+
+        len = net_buf_simple_pull_u8(buf);
+        /* Check for early termination */
+        if (len == 0) {
+            return;
+        }
+
+        if (len > buf->om_len) {
+            BT_WARN("AD malformed");
+            return;
+        }
+
+        net_buf_simple_save(buf, &state);
+
+        type = net_buf_simple_pull_u8(buf);
+
+        switch (type) {
+        case BLE_HS_ADV_TYPE_MESH_MESSAGE:
+            bt_mesh_net_recv(&buf, rssi, BT_MESH_NET_IF_ADV);
+            break;
 #if MYNEWT_VAL(BLE_MESH_PB_ADV)
-		case BLE_HS_ADV_TYPE_MESH_PROV:
-			bt_mesh_pb_adv_recv(buf);
-			break;
-#endif
-		case BLE_HS_ADV_TYPE_MESH_BEACON:
-			bt_mesh_beacon_recv(buf);
-			break;
-		default:
-			break;
-		}
-
-		net_buf_simple_restore(buf, &state);
-		net_buf_simple_pull_mem(buf, len);
-	}
+        case BLE_HS_ADV_TYPE_MESH_PROV:
+            bt_mesh_pb_adv_recv(buf);
+            break;
+#endif
+        case BLE_HS_ADV_TYPE_MESH_BEACON:
+            bt_mesh_beacon_recv(buf);
+            break;
+        default:
+            break;
+        }
+
+        net_buf_simple_restore(buf, &state);
+        net_buf_simple_pull_mem(buf, len);
+    }
 }
 
 int
 ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg)
 {
 #if MYNEWT_VAL(BLE_EXT_ADV)
-	struct ble_gap_ext_disc_desc *ext_desc;
-#endif
-	struct ble_gap_disc_desc *desc;
-	struct os_mbuf *buf = NULL;
+    struct ble_gap_ext_disc_desc *ext_desc;
+#endif
+    struct ble_gap_disc_desc *desc;
+    struct os_mbuf *buf = NULL;
 
 #if BT_MESH_EXTENDED_DEBUG
-	BT_DBG("event->type %d", event->type);
-#endif
-
-	switch (event->type) {
+    BT_DBG("event->type %d", event->type);
+#endif
+
+    switch (event->type) {
 #if MYNEWT_VAL(BLE_EXT_ADV)
-	case BLE_GAP_EVENT_EXT_DISC:
-		ext_desc = &event->ext_disc;
-		buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
-		if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) {
-			BT_ERR("Could not append data");
-			goto done;
-		}
-		bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi,
-				ext_desc->legacy_event_type, buf);
-		break;
-#endif
-	case BLE_GAP_EVENT_DISC:
-		desc = &event->disc;
-		buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
-		if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) {
-			BT_ERR("Could not append data");
-			goto done;
-		}
-
-		bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf);
-		break;
-	default:
-		break;
-	}
+    case BLE_GAP_EVENT_EXT_DISC:
+        ext_desc = &event->ext_disc;
+        buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
+        if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) {
+            BT_ERR("Could not append data");
+            goto done;
+        }
+        bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi,
+                ext_desc->legacy_event_type, buf);
+        break;
+#endif
+    case BLE_GAP_EVENT_DISC:
+        desc = &event->disc;
+        buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
+        if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) {
+            BT_ERR("Could not append data");
+            goto done;
+        }
+
+        bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf);
+        break;
+    default:
+        break;
+    }
 
 done:
-	if (buf) {
-		os_mbuf_free_chain(buf);
-	}
-
-	return 0;
-}
-
-int bt_mesh_scan_enable(void)
-{
-	int err;
+    if (buf) {
+        os_mbuf_free_chain(buf);
+    }
+
+    return 0;
+}
+
+int
+bt_mesh_scan_enable(void)
+{
+    int err;
 
 #if MYNEWT_VAL(BLE_EXT_ADV)
-	struct ble_gap_ext_disc_params uncoded_params =
-		{ .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW,
-		.passive = 1 };
-
-	BT_DBG("");
-
-	err =  ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
-				&uncoded_params, NULL, NULL, NULL);
+    struct ble_gap_ext_disc_params uncoded_params =
+    { .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW,
+      .passive = 1 };
+
+    BT_DBG("");
+
+    err = ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
+                &uncoded_params, NULL, NULL, NULL);
 #else
-	struct ble_gap_disc_params scan_param =
-		{ .passive = 1, .filter_duplicates = 0, .itvl =
-		  MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW };
-
-	BT_DBG("");
-
-	err =  ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param,
-			    NULL, NULL);
-#endif
-	if (err && err != BLE_HS_EALREADY) {
-		BT_ERR("starting scan failed (err %d)", err);
-		return err;
-	}
-
-	return 0;
-}
-
-int bt_mesh_scan_disable(void)
-{
-	int err;
-
-	BT_DBG("");
-
-	err = ble_gap_disc_cancel();
-	if (err && err != BLE_HS_EALREADY) {
-		BT_ERR("stopping scan failed (err %d)", err);
-		return err;
-	}
-
-	return 0;
-}
+    struct ble_gap_disc_params scan_param =
+    { .passive = 1, .filter_duplicates = 0, .itvl =
+          MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW };
+
+    BT_DBG("");
+
+    err = ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param,
+                NULL, NULL);
+#endif
+    if (err && err != BLE_HS_EALREADY) {
+        BT_ERR("starting scan failed (err %d)", err);
+        return err;
+    }
+
+    return 0;
+}
+
+int
+bt_mesh_scan_disable(void)
+{
+    int err;
+
+    BT_DBG("");
+
+    err = ble_gap_disc_cancel();
+    if (err && err != BLE_HS_EALREADY) {
+        BT_ERR("stopping scan failed (err %d)", err);
+        return err;
+    }
+
+    return 0;
+}

nimble/host/mesh/src/net.c

@@ -640,584 +659,603 @@
  * get sent to the advertising bearer. If the packet came in through GATT,
  * then we should only relay it if the GATT Proxy state is enabled.
  */
-static bool relay_to_adv(enum bt_mesh_net_if net_if)
-{
-	switch (net_if) {
-	case BT_MESH_NET_IF_ADV:
-		return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
-	case BT_MESH_NET_IF_PROXY:
-		return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
-	default:
-		return false;
-	}
-}
-
-static void bt_mesh_net_relay(struct os_mbuf *sbuf,
-			      struct bt_mesh_net_rx *rx)
-{
-	const struct bt_mesh_net_cred *cred;
-	struct os_mbuf *buf;
-	uint8_t transmit;
-
-	if (rx->ctx.recv_ttl <= 1U) {
-		return;
-	}
-
-	if (rx->net_if == BT_MESH_NET_IF_ADV &&
-	    !rx->friend_cred &&
-	    bt_mesh_relay_get() != BT_MESH_RELAY_ENABLED &&
-	    bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_ENABLED) {
-		return;
-	}
-
-	BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl,
-	       rx->ctx.recv_dst);
-
-	/* The Relay Retransmit state is only applied to adv-adv relaying.
-	 * Anything else (like GATT to adv, or locally originated packets)
-	 * use the Network Transmit state.
-	 */
-	if (rx->net_if == BT_MESH_NET_IF_ADV && !rx->friend_cred) {
-		transmit = bt_mesh_relay_retransmit_get();
-	} else {
-		transmit = bt_mesh_net_transmit_get();
-	}
-
-	buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, transmit, K_NO_WAIT);
-	if (!buf) {
-		BT_ERR("Out of relay buffers");
-		return;
-	}
-
-	/* Leave CTL bit intact */
-	sbuf->om_data[1] &= 0x80;
-	sbuf->om_data[1] |= rx->ctx.recv_ttl - 1U;
-
-	net_buf_add_mem(buf, sbuf->om_data, sbuf->om_len);
-
-	cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg;
-
-	BT_DBG("Relaying packet. TTL is now %u", TTL(buf->om_data));
-
-	/* Update NID if RX or RX was with friend credentials */
-	if (rx->friend_cred) {
-		buf->om_data[0] &= 0x80; /* Clear everything except IVI */
-		buf->om_data[0] |= cred->nid;
-	}
-
-	/* We re-encrypt and obfuscate using the received IVI rather than
-	 * the normal TX IVI (which may be different) since the transport
-	 * layer nonce includes the IVI.
-	 */
-	if (net_encrypt(buf, cred, BT_MESH_NET_IVI_RX(rx), false)) {
-		BT_ERR("Re-encrypting failed");
-		goto done;
-	}
-
-	BT_DBG("encoded %u bytes: %s", buf->om_len,
-	       bt_hex(buf->om_data, buf->om_len));
-
-	/* When the Friend node relays message for lpn, the message will be
-	 * retransmitted using the managed flooding security credentials and
-	 * the Network PDU shall be retransmitted to all network interfaces.
-	 */
-	if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
-	    (rx->friend_cred ||
-	     bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) {
-		bt_mesh_proxy_relay(buf, rx->ctx.recv_dst);
-	}
-
-	if (relay_to_adv(rx->net_if) || rx->friend_cred) {
-		bt_mesh_adv_send(buf, NULL, NULL);
-	}
+static bool
+relay_to_adv(enum bt_mesh_net_if net_if)
+{
+    switch (net_if) {
+    case BT_MESH_NET_IF_ADV:
+        return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
+    case BT_MESH_NET_IF_PROXY:
+        return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
+    default:
+        return false;
+    }
+}
+
+static void
+bt_mesh_net_relay(struct os_mbuf *sbuf,
+                  struct bt_mesh_net_rx *rx)
+{
+    const struct bt_mesh_net_cred *cred;
+    struct os_mbuf *buf;
+    uint8_t transmit;
+
+    if (rx->ctx.recv_ttl <= 1U) {
+        return;
+    }
+
+    if (rx->net_if == BT_MESH_NET_IF_ADV &&
+        !rx->friend_cred &&
+        bt_mesh_relay_get() != BT_MESH_RELAY_ENABLED &&
+        bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_ENABLED) {
+        return;
+    }
+
+    BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl,
+           rx->ctx.recv_dst);
+
+    /* The Relay Retransmit state is only applied to adv-adv relaying.
+     * Anything else (like GATT to adv, or locally originated packets)
+     * use the Network Transmit state.
+     */
+    if (rx->net_if == BT_MESH_NET_IF_ADV && !rx->friend_cred) {
+        transmit = bt_mesh_relay_retransmit_get();
+    } else {
+        transmit = bt_mesh_net_transmit_get();
+    }
+
+    buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, transmit, K_NO_WAIT);
+    if (!buf) {
+        BT_ERR("Out of relay buffers");
+        return;
+    }
+
+    /* Leave CTL bit intact */
+    sbuf->om_data[1] &= 0x80;
+    sbuf->om_data[1] |= rx->ctx.recv_ttl - 1U;
+
+    net_buf_add_mem(buf, sbuf->om_data, sbuf->om_len);
+
+    cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg;
+
+    BT_DBG("Relaying packet. TTL is now %u", TTL(buf->om_data));
+
+    /* Update NID if RX or RX was with friend credentials */
+    if (rx->friend_cred) {
+        buf->om_data[0] &= 0x80; /* Clear everything except IVI */
+        buf->om_data[0] |= cred->nid;
+    }
+
+    /* We re-encrypt and obfuscate using the received IVI rather than
+     * the normal TX IVI (which may be different) since the transport
+     * layer nonce includes the IVI.
+     */
+    if (net_encrypt(buf, cred, BT_MESH_NET_IVI_RX(rx), false)) {
+        BT_ERR("Re-encrypting failed");
+        goto done;
+    }
+
+    BT_DBG("encoded %u bytes: %s", buf->om_len,
+           bt_hex(buf->om_data, buf->om_len));
+
+    /* When the Friend node relays message for lpn, the message will be
+     * retransmitted using the managed flooding security credentials and
+     * the Network PDU shall be retransmitted to all network interfaces.
+     */
+    if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
+        (rx->friend_cred ||
+         bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) {
+        bt_mesh_proxy_relay(buf, rx->ctx.recv_dst);
+    }
+
+    if (relay_to_adv(rx->net_if) || rx->friend_cred) {
+        bt_mesh_adv_send(buf, NULL, NULL);
+    }
 
 done:
-	net_buf_unref(buf);
-}
-
-void bt_mesh_net_header_parse(struct os_mbuf *buf,
-			      struct bt_mesh_net_rx *rx)
-{
-	rx->old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01));
-	rx->ctl = CTL(buf->om_data);
-	rx->ctx.recv_ttl = TTL(buf->om_data);
-	rx->seq = SEQ(buf->om_data);
-	rx->ctx.addr = SRC(buf->om_data);
-	rx->ctx.recv_dst = DST(buf->om_data);
-}
-
-int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if,
-		       struct bt_mesh_net_rx *rx, struct os_mbuf *out)
-{
-	if (in->om_len < BT_MESH_NET_MIN_PDU_LEN) {
-		BT_WARN("Dropping too short mesh packet (len %u)", in->om_len);
-		BT_WARN("%s", bt_hex(in->om_data, in->om_len));
-		return -EINVAL;
-	}
-
-	if (in->om_len > BT_MESH_NET_MAX_PDU_LEN) {
-		BT_WARN("Dropping too long mesh packet (len %u)", in->om_len);
-		return -EINVAL;
-	}
-
-	if (net_if == BT_MESH_NET_IF_ADV && check_dup(in)) {
-		BT_DBG("duplicate packet; dropping %u bytes: %s", in->om_len,
-			   bt_hex(in->om_data, in->om_len));
-		return -EINVAL;
-	}
-
-	BT_DBG("%u bytes: %s", in->om_len, bt_hex(in->om_data, in->om_len));
-
-	rx->net_if = net_if;
-
-	if (!bt_mesh_net_cred_find(rx, in, out, net_decrypt)) {
-		BT_DBG("Unable to find matching net for packet");
-		return -ENOENT;
-	}
-
-	/* Initialize AppIdx to a sane value */
-	rx->ctx.app_idx = BT_MESH_KEY_UNUSED;
-
-	rx->ctx.recv_ttl = TTL(out->om_data);
-
-	/* Default to responding with TTL 0 for non-routed messages */
-	if (rx->ctx.recv_ttl == 0) {
-		rx->ctx.send_ttl = 0;
-	} else {
-		rx->ctx.send_ttl = BT_MESH_TTL_DEFAULT;
-	}
-
-	rx->ctl = CTL(out->om_data);
-	rx->seq = SEQ(out->om_data);
-	rx->ctx.recv_dst = DST(out->om_data);
-
-	BT_DBG("Decryption successful. Payload len %u: %s", out->om_len,
-		   bt_hex(out->om_data, out->om_len));
-
-	if (net_if != BT_MESH_NET_IF_PROXY_CFG &&
-	    rx->ctx.recv_dst == BT_MESH_ADDR_UNASSIGNED) {
-		BT_ERR("Destination address is unassigned; dropping packet");
-		return -EBADMSG;
-	}
-
-	BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst,
-	       rx->ctx.recv_ttl);
-	BT_DBG("PDU: %s", bt_hex(out->om_data, out->om_len));
-
-	msg_cache_add(rx);
-
-	return 0;
-}
-
-void bt_mesh_net_recv(struct os_mbuf **data, int8_t rssi,
-		      enum bt_mesh_net_if net_if)
-{
-	struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
-	struct bt_mesh_net_rx rx = { .ctx.recv_rssi = rssi };
-	struct net_buf_simple_state state;
-
-	BT_DBG("rssi %d net_if %u", rssi, net_if);
-
-	if (!bt_mesh_is_provisioned()) {
-		BT_ERR("Not provisioned; dropping packet");
-		goto done;
-	}
-
-	if (bt_mesh_net_decode(*data, net_if, &rx, buf)) {
-		goto done;
-	}
-
-	/* Save the state so the buffer can later be relayed */
-	net_buf_simple_save(buf, &state);
-
-	rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) ||
-			  bt_mesh_has_addr(rx.ctx.recv_dst));
-
-	if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) &&
-	    net_if == BT_MESH_NET_IF_PROXY) {
-		bt_mesh_proxy_addr_add(data, rx.ctx.addr);
-
-		if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_DISABLED &&
-		    !rx.local_match) {
-			BT_INFO("Proxy is disabled; ignoring message");
-			goto done;
-		}
-	}
-
-	/* The transport layer has indicated that it has rejected the message,
-	 * but would like to see it again if it is received in the future.
-	 * This can happen if a message is received when the device is in
-	 * Low Power mode, but the message was not encrypted with the friend
-	 * credentials. Remove it from the message cache so that we accept
-	 * it again in the future.
-	 */
-	if (bt_mesh_trans_recv(buf, &rx) == -EAGAIN) {
-		BT_WARN("Removing rejected message from Network Message Cache");
-		msg_cache[rx.msg_cache_idx].src = BT_MESH_ADDR_UNASSIGNED;
-		/* Rewind the next index now that we're not using this entry */
-		msg_cache_next = rx.msg_cache_idx;
-	}
-
-	/* Relay if this was a group/virtual address, or if the destination
-	 * was neither a local element nor an LPN we're Friends for.
-	 */
-	if (!BT_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) ||
-	    (!rx.local_match && !rx.friend_match)) {
-		net_buf_simple_restore(buf, &state);
-		bt_mesh_net_relay(buf, &rx);
-	}
+    net_buf_unref(buf);
+}
+
+void
+bt_mesh_net_header_parse(struct os_mbuf *buf,
+                         struct bt_mesh_net_rx *rx)
+{
+    rx->old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01));
+    rx->ctl = CTL(buf->om_data);
+    rx->ctx.recv_ttl = TTL(buf->om_data);
+    rx->seq = SEQ(buf->om_data);
+    rx->ctx.addr = SRC(buf->om_data);
+    rx->ctx.recv_dst = DST(buf->om_data);
+}
+
+int
+bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if,
+                   struct bt_mesh_net_rx *rx, struct os_mbuf *out)
+{
+    if (in->om_len < BT_MESH_NET_MIN_PDU_LEN) {
+        BT_WARN("Dropping too short mesh packet (len %u)", in->om_len);
+        BT_WARN("%s", bt_hex(in->om_data, in->om_len));
+        return -EINVAL;
+    }
+
+    if (in->om_len > BT_MESH_NET_MAX_PDU_LEN) {
+        BT_WARN("Dropping too long mesh packet (len %u)", in->om_len);
+        return -EINVAL;
+    }
+
+    if (net_if == BT_MESH_NET_IF_ADV && check_dup(in)) {
+        BT_DBG("duplicate packet; dropping %u bytes: %s", in->om_len,
+               bt_hex(in->om_data, in->om_len));
+        return -EINVAL;
+    }
+
+    BT_DBG("%u bytes: %s", in->om_len, bt_hex(in->om_data, in->om_len));
+
+    rx->net_if = net_if;
+
+    if (!bt_mesh_net_cred_find(rx, in, out, net_decrypt)) {
+        BT_DBG("Unable to find matching net for packet");
+        return -ENOENT;
+    }
+
+    /* Initialize AppIdx to a sane value */
+    rx->ctx.app_idx = BT_MESH_KEY_UNUSED;
+
+    rx->ctx.recv_ttl = TTL(out->om_data);
+
+    /* Default to responding with TTL 0 for non-routed messages */
+    if (rx->ctx.recv_ttl == 0) {
+        rx->ctx.send_ttl = 0;
+    } else {
+        rx->ctx.send_ttl = BT_MESH_TTL_DEFAULT;
+    }
+
+    rx->ctl = CTL(out->om_data);
+    rx->seq = SEQ(out->om_data);
+    rx->ctx.recv_dst = DST(out->om_data);
+
+    BT_DBG("Decryption successful. Payload len %u: %s", out->om_len,
+           bt_hex(out->om_data, out->om_len));
+
+    if (net_if != BT_MESH_NET_IF_PROXY_CFG &&
+        rx->ctx.recv_dst == BT_MESH_ADDR_UNASSIGNED) {
+        BT_ERR("Destination address is unassigned; dropping packet");
+        return -EBADMSG;
+    }
+
+    BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst,
+           rx->ctx.recv_ttl);
+    BT_DBG("PDU: %s", bt_hex(out->om_data, out->om_len));
+
+    msg_cache_add(rx);
+
+    return 0;
+}
+
+void
+bt_mesh_net_recv(struct os_mbuf **data, int8_t rssi,
+                 enum bt_mesh_net_if net_if)
+{
+    struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
+    struct bt_mesh_net_rx rx = { .ctx.recv_rssi = rssi };
+    struct net_buf_simple_state state;
+
+    BT_DBG("rssi %d net_if %u", rssi, net_if);
+
+    if (!bt_mesh_is_provisioned()) {
+        BT_ERR("Not provisioned; dropping packet");
+        goto done;
+    }
+
+    if (bt_mesh_net_decode(*data, net_if, &rx, buf)) {
+        goto done;
+    }
+
+    /* Save the state so the buffer can later be relayed */
+    net_buf_simple_save(buf, &state);
+
+    rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) ||
+                      bt_mesh_has_addr(rx.ctx.recv_dst));
+
+    if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) &&
+        net_if == BT_MESH_NET_IF_PROXY) {
+        bt_mesh_proxy_addr_add(data, rx.ctx.addr);
+
+        if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_DISABLED &&
+            !rx.local_match) {
+            BT_INFO("Proxy is disabled; ignoring message");
+            goto done;
+        }
+    }
+
+    /* The transport layer has indicated that it has rejected the message,
+     * but would like to see it again if it is received in the future.
+     * This can happen if a message is received when the device is in
+     * Low Power mode, but the message was not encrypted with the friend
+     * credentials. Remove it from the message cache so that we accept
+     * it again in the future.
+     */
+    if (bt_mesh_trans_recv(buf, &rx) == -EAGAIN) {
+        BT_WARN("Removing rejected message from Network Message Cache");
+        msg_cache[rx.msg_cache_idx].src = BT_MESH_ADDR_UNASSIGNED;
+        /* Rewind the next index now that we're not using this entry */
+        msg_cache_next = rx.msg_cache_idx;
+    }
+
+    /* Relay if this was a group/virtual address, or if the destination
+     * was neither a local element nor an LPN we're Friends for.
+     */
+    if (!BT_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) ||
+        (!rx.local_match && !rx.friend_match)) {
+        net_buf_simple_restore(buf, &state);
+        bt_mesh_net_relay(buf, &rx);
+    }
 
 done:
     os_mbuf_free_chain(buf);
 }
 
-static void ivu_refresh(struct ble_npl_event *work)
-{
-	if (!bt_mesh_is_provisioned()) {
-		return;
-	}
-
-	bt_mesh.ivu_duration = MIN(UINT8_MAX,
-	       bt_mesh.ivu_duration + BT_MESH_IVU_HOURS);
-
-	BT_DBG("%s for %u hour%s",
-	       atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ?
-	       "IVU in Progress" : "IVU Normal mode",
-	       bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1 ? "" : "s");
-
-	if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
-		if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
-			store_iv(true);
-		}
-
-		k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
-		return;
-	}
-
-	if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) {
-		bt_mesh_beacon_ivu_initiator(true);
-		bt_mesh_net_iv_update(bt_mesh.iv_index, false);
-	} else if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
-		store_iv(true);
-	}
+static void
+ivu_refresh(struct ble_npl_event *work)
+{
+    if (!bt_mesh_is_provisioned()) {
+        return;
+    }
+
+    bt_mesh.ivu_duration = MIN(UINT8_MAX,
+           bt_mesh.ivu_duration + BT_MESH_IVU_HOURS);
+
+    BT_DBG("%s for %u hour%s",
+           atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ?
+           "IVU in Progress" : "IVU Normal mode",
+           bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1 ? "" : "s");
+
+    if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
+        if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
+            store_iv(true);
+        }
+
+        k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
+        return;
+    }
+
+    if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) {
+        bt_mesh_beacon_ivu_initiator(true);
+        bt_mesh_net_iv_update(bt_mesh.iv_index, false);
+    } else if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
+        store_iv(true);
+    }
 }
 
 #if MYNEWT_VAL(BLE_MESH_SETTINGS)
-static int net_set(int argc, char **argv, char *val)
-{
-	struct net_val net;
-	int len, err;
-
-	BT_DBG("val %s", val ? val : "(null)");
-
-	if (!val) {
-		bt_mesh_comp_unprovision();
-		memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
-		return 0;
-	}
-
-	len = sizeof(net);
-	err = settings_bytes_from_str(val, &net, &len);
-	if (err) {
-		BT_ERR("Failed to decode value %s (err %d)", val, err);
-		return err;
-	}
-
-	if (len != sizeof(net)) {
-		BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net));
-		return -EINVAL;
-	}
-
-	memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key));
-	bt_mesh_comp_provision(net.primary_addr);
-
-	BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr);
-	BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16));
-
-	return 0;
-}
-
-static int iv_set(int argc, char **argv, char *val)
-{
-	struct iv_val iv;
-	int len, err;
-
-	BT_DBG("val %s", val ? val : "(null)");
-
-	if (!val) {
-		bt_mesh.iv_index = 0U;
-		atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
-		return 0;
-	}
-
-	len = sizeof(iv);
-	err = settings_bytes_from_str(val, &iv, &len);
-	if (err) {
-		BT_ERR("Failed to decode value %s (err %d)", val, err);
-		return err;
-	}
-
-	if (len != sizeof(iv)) {
-		BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv));
-		return -EINVAL;
-	}
-
-	bt_mesh.iv_index = iv.iv_index;
-	atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update);
-	bt_mesh.ivu_duration = iv.iv_duration;
-
-	BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours",
-			       (unsigned) iv.iv_index, iv.iv_update, iv.iv_duration);
-
-	return 0;
-}
-
-static int seq_set(int argc, char **argv, char *val)
-{
-	struct seq_val seq;
-	int len, err;
-
-	BT_DBG("val %s", val ? val : "(null)");
-
-	if (!val) {
-		bt_mesh.seq = 0;
-		return 0;
-	}
-
-	len = sizeof(seq);
-	err = settings_bytes_from_str(val, &seq, &len);
-	if (err) {
-		BT_ERR("Failed to decode value %s (err %d)", val, err);
-		return err;
-	}
-
-	if (len != sizeof(seq)) {
-		BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq));
-		return -EINVAL;
-	}
-
-	bt_mesh.seq = sys_get_le24(seq.val);
-
-	if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) {
-	/* Make sure we have a large enough sequence number. We
-	 * subtract 1 so that the first transmission causes a write
-	 * to the settings storage.
-	 */
-		bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE -
-					(bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE));
-		bt_mesh.seq--;
-	}
-
-	BT_DBG("Sequence Number 0x%06x", bt_mesh.seq);
-
-	return 0;
+static int
+net_set(int argc, char **argv, char *val)
+{
+    struct net_val net;
+    int len, err;
+
+    BT_DBG("val %s", val ? val : "(null)");
+
+    if (!val) {
+        bt_mesh_comp_unprovision();
+        memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
+        return 0;
+    }
+
+    len = sizeof(net);
+    err = settings_bytes_from_str(val, &net, &len);
+    if (err) {
+        BT_ERR("Failed to decode value %s (err %d)", val, err);
+        return err;
+    }
+
+    if (len != sizeof(net)) {
+        BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net));
+        return -EINVAL;
+    }
+
+    memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key));
+    bt_mesh_comp_provision(net.primary_addr);
+
+    BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr);
+    BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16));
+
+    return 0;
+}
+
+static int
+iv_set(int argc, char **argv, char *val)
+{
+    struct iv_val iv;
+    int len, err;
+
+    BT_DBG("val %s", val ? val : "(null)");
+
+    if (!val) {
+        bt_mesh.iv_index = 0U;
+        atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
+        return 0;
+    }
+
+    len = sizeof(iv);
+    err = settings_bytes_from_str(val, &iv, &len);
+    if (err) {
+        BT_ERR("Failed to decode value %s (err %d)", val, err);
+        return err;
+    }
+
+    if (len != sizeof(iv)) {
+        BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv));
+        return -EINVAL;
+    }
+
+    bt_mesh.iv_index = iv.iv_index;
+    atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update);
+    bt_mesh.ivu_duration = iv.iv_duration;
+
+    BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours",
+           (unsigned) iv.iv_index, iv.iv_update, iv.iv_duration);
+
+    return 0;
+}
+
+static int
+seq_set(int argc, char **argv, char *val)
+{
+    struct seq_val seq;
+    int len, err;
+
+    BT_DBG("val %s", val ? val : "(null)");
+
+    if (!val) {
+        bt_mesh.seq = 0;
+        return 0;
+    }
+
+    len = sizeof(seq);
+    err = settings_bytes_from_str(val, &seq, &len);
+    if (err) {
+        BT_ERR("Failed to decode value %s (err %d)", val, err);
+        return err;
+    }
+
+    if (len != sizeof(seq)) {
+        BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq));
+        return -EINVAL;
+    }
+
+    bt_mesh.seq = sys_get_le24(seq.val);
+
+    if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) {
+        /* Make sure we have a large enough sequence number. We
+         * subtract 1 so that the first transmission causes a write
+         * to the settings storage.
+         */
+        bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE -
+                        (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE));
+        bt_mesh.seq--;
+    }
+
+    BT_DBG("Sequence Number 0x%06x", bt_mesh.seq);
+
+    return 0;
 }
 
 static struct conf_handler bt_mesh_net_conf_handler = {
-	.ch_name = "bt_mesh",
-	.ch_get = NULL,
-	.ch_set = net_set,
-	.ch_commit = NULL,
-	.ch_export = NULL,
+    .ch_name = "bt_mesh",
+    .ch_get = NULL,
+    .ch_set = net_set,
+    .ch_commit = NULL,
+    .ch_export = NULL,
 };
 
 static struct conf_handler bt_mesh_iv_conf_handler = {
-	.ch_name = "bt_mesh",
-	.ch_get = NULL,
-	.ch_set = iv_set,
-	.ch_commit = NULL,
-	.ch_export = NULL,
+    .ch_name = "bt_mesh",
+    .ch_get = NULL,
+    .ch_set = iv_set,
+    .ch_commit = NULL,
+    .ch_export = NULL,
 };
 
 static struct conf_handler bt_mesh_seq_conf_handler = {
-	.ch_name = "bt_mesh",
-	.ch_get = NULL,
-	.ch_set = seq_set,
-	.ch_commit = NULL,
-	.ch_export = NULL,
+    .ch_name = "bt_mesh",
+    .ch_get = NULL,
+    .ch_set = seq_set,
+    .ch_commit = NULL,
+    .ch_export = NULL,
 };
 #endif
 
-void bt_mesh_net_init(void)
-{
-	int rc;
+void
+bt_mesh_net_init(void)
+{
+    int rc;
 
 #if MYNEWT_VAL(BLE_MESH_SETTINGS)
-	rc = conf_register(&bt_mesh_net_conf_handler);
-
-	SYSINIT_PANIC_ASSERT_MSG(rc == 0,
-				 "Failed to register bt_mesh_net conf");
-
-
-	rc = conf_register(&bt_mesh_iv_conf_handler);
-
-	SYSINIT_PANIC_ASSERT_MSG(rc == 0,
-			 "Failed to register bt_mesh_iv conf");
-
-	rc = conf_register(&bt_mesh_seq_conf_handler);
-
-	SYSINIT_PANIC_ASSERT_MSG(rc == 0,
-				 "Failed to register bt_mesh_seq conf");
+    rc = conf_register(&bt_mesh_net_conf_handler);
+
+    SYSINIT_PANIC_ASSERT_MSG(rc == 0,
+                 "Failed to register bt_mesh_net conf");
+
+
+    rc = conf_register(&bt_mesh_iv_conf_handler);
+
+    SYSINIT_PANIC_ASSERT_MSG(rc == 0,
+             "Failed to register bt_mesh_iv conf");
+
+    rc = conf_register(&bt_mesh_seq_conf_handler);
+
+    SYSINIT_PANIC_ASSERT_MSG(rc == 0,
+                 "Failed to register bt_mesh_seq conf");
 #endif
 
-	k_work_init_delayable(&bt_mesh.ivu_timer, ivu_refresh);
-
-	k_work_init(&bt_mesh.local_work, bt_mesh_net_local);
-	net_buf_slist_init(&bt_mesh.local_queue);
-
-	rc = os_mempool_init(&loopback_buf_mempool, MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS),
-			     LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
-			     &loopback_mbuf_membuf[0], "loopback_buf_pool");
-	assert(rc == 0);
-
-	rc = os_mbuf_pool_init(&loopback_os_mbuf_pool, &loopback_buf_mempool,
-			       LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
-			       MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS));
-	assert(rc == 0);
+    k_work_init_delayable(&bt_mesh.ivu_timer, ivu_refresh);
+
+    k_work_init(&bt_mesh.local_work, bt_mesh_net_local);
+    net_buf_slist_init(&bt_mesh.local_queue);
+
+    rc = os_mempool_init(&loopback_buf_mempool, MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS),
+                 LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
+                 &loopback_mbuf_membuf[0], "loopback_buf_pool");
+    assert(rc == 0);
+
+    rc = os_mbuf_pool_init(&loopback_os_mbuf_pool, &loopback_buf_mempool,
+                   LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
+                   MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS));
+    assert(rc == 0);
 }
 
 #if MYNEWT_VAL(BLE_MESH_SETTINGS)
-static void clear_iv(void)
-{
-	int err;
-
-	err = settings_save_one("bt_mesh/IV", NULL);
-	if (err) {
-		BT_ERR("Failed to clear IV");
-	} else {
-		BT_DBG("Cleared IV");
-	}
-}
-
-static void store_pending_iv(void)
-{
-	char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))];
-	struct iv_val iv;
-	char *str;
-	int err;
-
-	iv.iv_index = bt_mesh.iv_index;
-	iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
-	iv.iv_duration = bt_mesh.ivu_duration;
-
-	str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf));
-	if (!str) {
-		BT_ERR("Unable to encode IV as value");
-		return;
-	}
-
-	BT_DBG("Saving IV as value %s", str);
-	err = settings_save_one("bt_mesh/IV", str);
-	if (err) {
-		BT_ERR("Failed to store IV");
-	} else {
-		BT_DBG("Stored IV");
-	}
-}
-
-void bt_mesh_net_pending_iv_store(void)
-{
-	if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
-		store_pending_iv();
-	} else {
-		clear_iv();
-	}
-}
-
-static void clear_net(void)
-{
-	int err;
-
-	err = settings_save_one("bt_mesh/Net", NULL);
-	if (err) {
-		BT_ERR("Failed to clear Network");
-	} else {
-		BT_DBG("Cleared Network");
-	}
-}
-
-static void store_pending_net(void)
-{
-	char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))];
-	struct net_val net;
-	char *str;
-	int err;
-
-	BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(),
-	       bt_hex(bt_mesh.dev_key, 16));
-
-	net.primary_addr = bt_mesh_primary_addr();
-	memcpy(net.dev_key, bt_mesh.dev_key, 16);
-
-	str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf));
-	if (!str) {
-		BT_ERR("Unable to encode Network as value");
-		return;
-	}
-
-	BT_DBG("Saving Network as value %s", str);
-	err = settings_save_one("bt_mesh/Net", str);
-	if (err) {
-		BT_ERR("Failed to store Network");
-	} else {
-		BT_DBG("Stored Network");
-	}
-}
-
-void bt_mesh_net_pending_net_store(void)
-{
-	if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
-		store_pending_net();
-	} else {
-		clear_net();
-	}
-}
-
-void bt_mesh_net_pending_seq_store(void)
-{
-	char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))];
-	char *str;
-	struct seq_val seq;
-	int err;
-
-	if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
-		sys_put_le24(bt_mesh.seq, seq.val);
-
-		str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf));
-		if (!str) {
-			BT_ERR("Unable to encode Network as value");
-			return;
-		}
-
-		BT_DBG("Saving Network as value %s", str);
-		err = settings_save_one("bt_mesh/Seq", str);
-		if (err) {
-			BT_ERR("Failed to stor Seq value");
-		} else {
-			BT_DBG("Stored Seq value");
-		}
-	} else {
-		err = settings_save_one("bt_mesh/Seq", NULL);
-		if (err) {
-			BT_ERR("Failed to clear Seq value");
-		} else {
-			BT_DBG("Cleared Seq value");
-		}
-	}
-}
-
-void bt_mesh_net_clear(void)
-{
-	bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_PENDING);
-	bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING);
-	bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
-	bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING);
+static void
+clear_iv(void)
+{
+    int err;
+
+    err = settings_save_one("bt_mesh/IV", NULL);
+    if (err) {
+        BT_ERR("Failed to clear IV");
+    } else {
+        BT_DBG("Cleared IV");
+    }
+}
+
+static void
+store_pending_iv(void)
+{
+    char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))];
+    struct iv_val iv;
+    char *str;
+    int err;
+
+    iv.iv_index = bt_mesh.iv_index;
+    iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
+    iv.iv_duration = bt_mesh.ivu_duration;
+
+    str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf));
+    if (!str) {
+        BT_ERR("Unable to encode IV as value");
+        return;
+    }
+
+    BT_DBG("Saving IV as value %s", str);
+    err = settings_save_one("bt_mesh/IV", str);
+    if (err) {
+        BT_ERR("Failed to store IV");
+    } else {
+        BT_DBG("Stored IV");
+    }
+}
+
+void
+bt_mesh_net_pending_iv_store(void)
+{
+    if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
+        store_pending_iv();
+    } else {
+        clear_iv();
+    }
+}
+
+static void
+clear_net(void)
+{
+    int err;
+
+    err = settings_save_one("bt_mesh/Net", NULL);
+    if (err) {
+        BT_ERR("Failed to clear Network");
+    } else {
+        BT_DBG("Cleared Network");
+    }
+}
+
+static void
+store_pending_net(void)
+{
+    char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))];
+    struct net_val net;
+    char *str;
+    int err;
+
+    BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(),
+           bt_hex(bt_mesh.dev_key, 16));
+
+    net.primary_addr = bt_mesh_primary_addr();
+    memcpy(net.dev_key, bt_mesh.dev_key, 16);
+
+    str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf));
+    if (!str) {
+        BT_ERR("Unable to encode Network as value");
+        return;
+    }
+
+    BT_DBG("Saving Network as value %s", str);
+    err = settings_save_one("bt_mesh/Net", str);
+    if (err) {
+        BT_ERR("Failed to store Network");
+    } else {
+        BT_DBG("Stored Network");
+    }
+}
+
+void
+bt_mesh_net_pending_net_store(void)
+{
+    if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
+        store_pending_net();
+    } else {
+        clear_net();
+    }
+}
+
+void
+bt_mesh_net_pending_seq_store(void)
+{
+    char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))];
+    char *str;
+    struct seq_val seq;
+    int err;
+
+    if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
+        sys_put_le24(bt_mesh.seq, seq.val);
+
+        str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf));
+        if (!str) {
+            BT_ERR("Unable to encode Network as value");
+            return;
+        }
+
+        BT_DBG("Saving Network as value %s", str);
+        err = settings_save_one("bt_mesh/Seq", str);
+        if (err) {
+            BT_ERR("Failed to stor Seq value");
+        } else {
+            BT_DBG("Stored Seq value");
+        }
+    } else {
+        err = settings_save_one("bt_mesh/Seq", NULL);
+        if (err) {
+            BT_ERR("Failed to clear Seq value");
+        } else {
+            BT_DBG("Cleared Seq value");
+        }
+    }
+}
+
+void
+bt_mesh_net_clear(void)
+{
+    bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_PENDING);
+    bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING);
+    bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
+    bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING);
 }
 #endif
 
-void bt_mesh_net_settings_commit(void)
-{
-	if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
-		k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
-	}
-}
+void
+bt_mesh_net_settings_commit(void)
+{
+    if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
+        k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
+    }
+}

nimble/host/mesh/src/net.h

@@ -280,21 +281,21 @@
 }
 
 int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16],
-		       uint32_t iv_index);
+                       uint32_t iv_index);
 
 bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update);
 
 int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
-		       bool proxy);
+                       bool proxy);
 
 int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if,
-		       struct bt_mesh_net_rx *rx, struct os_mbuf *out);
+                       struct bt_mesh_net_rx *rx, struct os_mbuf *out);
 
 int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
-		     const struct bt_mesh_send_cb *cb, void *cb_data);
+                     const struct bt_mesh_send_cb *cb, void *cb_data);
 
 void bt_mesh_net_recv(struct os_mbuf **data, int8_t rssi,
-		      enum bt_mesh_net_if net_if);
+                      enum bt_mesh_net_if net_if);
 
 void bt_mesh_net_loopback_clear(uint16_t net_idx);
 

nimble/host/mesh/src/proxy_srv.c

@@ -60,325 +60,342 @@
 
 static int conn_count;
 
-struct bt_mesh_proxy_client *find_client(uint16_t conn_handle)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(clients); i++) {
-		if (clients[i].conn_handle == conn_handle) {
-			return &clients[i];
-		}
-	}
-	return NULL;
-}
-
-static struct bt_mesh_proxy_client *get_client(uint16_t conn_handle)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(clients); i++) {
-		if (clients[i].conn_handle == 0xffff) {
-			clients[i].conn_handle = conn_handle;
-			return &clients[i];
-		}
-	}
-	return NULL;
+struct bt_mesh_proxy_client *
+find_client(uint16_t conn_handle)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(clients); i++) {
+        if (clients[i].conn_handle == conn_handle) {
+            return &clients[i];
+        }
+    }
+    return NULL;
+}
+
+static struct bt_mesh_proxy_client *
+get_client(uint16_t conn_handle)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(clients); i++) {
+        if (clients[i].conn_handle == 0xffff) {
+            clients[i].conn_handle = conn_handle;
+            return &clients[i];
+        }
+    }
+    return NULL;
 }
 
 /* Next subnet in queue to be advertised */
 static struct bt_mesh_subnet *beacon_sub;
 
-static int filter_set(struct bt_mesh_proxy_client *client,
-		      struct os_mbuf *buf)
-{
-	uint8_t type;
-
-	if (buf->om_len < 1) {
-		BT_WARN("Too short Filter Set message");
-		return -EINVAL;
-	}
-
-	type = net_buf_simple_pull_u8(buf);
-	BT_DBG("type 0x%02x", type);
-
-	switch (type) {
-		case 0x00:
-			(void)memset(client->filter, 0, sizeof(client->filter));
-			client->filter_type = ACCEPT;
-			break;
-		case 0x01:
-			(void)memset(client->filter, 0, sizeof(client->filter));
-			client->filter_type = REJECT;
-			break;
-		default:
-			BT_WARN("Prohibited Filter Type 0x%02x", type);
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void filter_add(struct bt_mesh_proxy_client *client, uint16_t addr)
-{
-	int i;
-
-	BT_DBG("addr 0x%04x", addr);
-
-	if (addr == BT_MESH_ADDR_UNASSIGNED) {
-		return;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
-		if (client->filter[i] == addr) {
-			return;
-		}
-	}
-
-	for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
-		if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) {
-			client->filter[i] = addr;
-			return;
-		}
-	}
-}
-
-static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr)
-{
-	int i;
-
-	BT_DBG("addr 0x%04x", addr);
-
-	if (addr == BT_MESH_ADDR_UNASSIGNED) {
-		return;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
-		if (client->filter[i] == addr) {
-			client->filter[i] = BT_MESH_ADDR_UNASSIGNED;
-			return;
-		}
-	}
-}
-
-static void send_filter_status(struct bt_mesh_proxy_client *client,
-			       struct bt_mesh_net_rx *rx,
-			       struct os_mbuf *buf)
-{
-	struct bt_mesh_net_tx tx = {
-		.sub = rx->sub,
-		.ctx = &rx->ctx,
-		.src = bt_mesh_primary_addr(),
-	};
-	uint16_t filter_size;
-	int i, err;
-
-	/* Configuration messages always have dst unassigned */
-	tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED;
-
-	net_buf_simple_init(buf, 10);
-
-	net_buf_simple_add_u8(buf, CFG_FILTER_STATUS);
-
-	if (client->filter_type == ACCEPT) {
-		net_buf_simple_add_u8(buf, 0x00);
-	} else {
-		net_buf_simple_add_u8(buf, 0x01);
-	}
-
-	for (filter_size = 0U, i = 0; i < ARRAY_SIZE(client->filter); i++) {
-		if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) {
-			filter_size++;
-		}
-	}
-
-	net_buf_simple_add_be16(buf, filter_size);
-
-	BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
-
-	err = bt_mesh_net_encode(&tx, buf, true);
-	if (err) {
-		BT_ERR("Encoding Proxy cfg message failed (err %d)", err);
-		return;
-	}
-
-	err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_CONFIG, buf);
-	if (err) {
-		BT_ERR("Failed to send proxy cfg message (err %d)", err);
-	}
-}
-
-static void proxy_filter_recv(uint16_t conn_handle,
-			      struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
-{
-	struct bt_mesh_proxy_client *client;
-	uint8_t opcode;
-
-	client = find_client(conn_handle);
-
-	opcode = net_buf_simple_pull_u8(buf);
-	switch (opcode) {
-	case CFG_FILTER_SET:
-		filter_set(client, buf);
-		send_filter_status(client, rx, buf);
-		break;
-		case CFG_FILTER_ADD:
-			while (buf->om_len >= 2) {
-				uint16_t addr;
-
-				addr = net_buf_simple_pull_be16(buf);
-				filter_add(client, addr);
-			}
-			send_filter_status(client, rx, buf);
-			break;
-		case CFG_FILTER_REMOVE:
-			while (buf->om_len >= 2) {
-				uint16_t addr;
-
-				addr = net_buf_simple_pull_be16(buf);
-				filter_remove(client, addr);
-			}
-			send_filter_status(client, rx, buf);
-			break;
-		default:
-			BT_WARN("Unhandled configuration OpCode 0x%02x", opcode);
-			break;
-	}
-}
-
-static void proxy_cfg(struct bt_mesh_proxy_role *role)
-{
-	struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
-	struct bt_mesh_net_rx rx;
-	int err;
-
-	err = bt_mesh_net_decode(role->buf, BT_MESH_NET_IF_PROXY_CFG,
-				 &rx, buf);
-	if (err) {
-		BT_ERR("Failed to decode Proxy Configuration (err %d)", err);
-		return;
-	}
-
-	rx.local_match = 1U;
-
-	if (bt_mesh_rpl_check(&rx, NULL)) {
-		BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x",
-			rx.ctx.addr, rx.ctx.recv_dst, rx.seq);
-		return;
-	}
-
-	/* Remove network headers */
-	net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN);
-
-	BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
-
-	if (buf->om_len < 1) {
-		BT_WARN("Too short proxy configuration PDU");
-		return;
-	}
-
-	proxy_filter_recv(role->conn_handle, &rx, buf);
-}
-
-static void proxy_msg_recv(struct bt_mesh_proxy_role *role)
-{
-	switch (role->msg_type) {
-	case BT_MESH_PROXY_NET_PDU:
-		BT_DBG("Mesh Network PDU");
-		bt_mesh_net_recv(&(role->buf), 0, BT_MESH_NET_IF_PROXY);
-		break;
-	case BT_MESH_PROXY_BEACON:
-		BT_DBG("Mesh Beacon PDU");
-		bt_mesh_beacon_recv(role->buf);
-		break;
-	case BT_MESH_PROXY_CONFIG:
-		BT_DBG("Mesh Configuration PDU");
-		proxy_cfg(role);
-		break;
-	default:
-		BT_WARN("Unhandled Message Type 0x%02x", role->msg_type);
-		break;
-	}
-}
-
-static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subnet *sub)
-{
-	struct os_mbuf *buf = NET_BUF_SIMPLE(23);
-	int rc;
-
-	net_buf_simple_init(buf, 1);
-	bt_mesh_beacon_create(sub, buf);
-
-	rc = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_BEACON, buf);
-	os_mbuf_free_chain(buf);
-	return rc;
-}
-
-static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data)
-{
-	struct bt_mesh_proxy_client *client = cb_data;
-
-	return beacon_send(client, sub);
-}
-
-static void proxy_send_beacons(struct ble_npl_event *work)
-{
-	struct bt_mesh_proxy_client *client;
-
-	client = ble_npl_event_get_arg(work);
-
-	(void)bt_mesh_subnet_find(send_beacon_cb, client);
-}
-
-void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
-{
-	int i;
-
-	if (!sub) {
-		/* NULL means we send on all subnets */
-		bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send);
-		return;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(clients); i++) {
-		if (clients[i].cli) {
-			beacon_send(&clients[i], sub);
-		}
-	}
-}
-
-static void node_id_start(struct bt_mesh_subnet *sub)
-{
-	sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING;
-	sub->node_id_start = k_uptime_get_32();
-}
-
-void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
-{
-	node_id_start(sub);
-
-	/* Prioritize the recently enabled subnet */
-	beacon_sub = sub;
-}
-
-void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub)
-	{
-	sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
-	sub->node_id_start = 0U;
-}
-
-int bt_mesh_proxy_identity_enable(void)
-{
-	BT_DBG("");
-
-	if (!bt_mesh_is_provisioned()) {
-		return -EAGAIN;
-	}
-
-	if (bt_mesh_subnet_foreach(node_id_start)) {
-		bt_mesh_adv_update();
-	}
-
-	return 0;
+static int
+filter_set(struct bt_mesh_proxy_client *client,
+           struct os_mbuf *buf)
+{
+    uint8_t type;
+
+    if (buf->om_len < 1) {
+        BT_WARN("Too short Filter Set message");
+        return -EINVAL;
+    }
+
+    type = net_buf_simple_pull_u8(buf);
+    BT_DBG("type 0x%02x", type);
+
+    switch (type) {
+    case 0x00:
+        (void)memset(client->filter, 0, sizeof(client->filter));
+        client->filter_type = ACCEPT;
+        break;
+    case 0x01:
+        (void)memset(client->filter, 0, sizeof(client->filter));
+        client->filter_type = REJECT;
+        break;
+    default:
+        BT_WARN("Prohibited Filter Type 0x%02x", type);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static void
+filter_add(struct bt_mesh_proxy_client *client, uint16_t addr)
+{
+    int i;
+
+    BT_DBG("addr 0x%04x", addr);
+
+    if (addr == BT_MESH_ADDR_UNASSIGNED) {
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+        if (client->filter[i] == addr) {
+            return;
+        }
+    }
+
+    for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+        if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) {
+            client->filter[i] = addr;
+            return;
+        }
+    }
+}
+
+static void
+filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr)
+{
+    int i;
+
+    BT_DBG("addr 0x%04x", addr);
+
+    if (addr == BT_MESH_ADDR_UNASSIGNED) {
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+        if (client->filter[i] == addr) {
+            client->filter[i] = BT_MESH_ADDR_UNASSIGNED;
+            return;
+        }
+    }
+}
+
+static void
+send_filter_status(struct bt_mesh_proxy_client *client,
+                   struct bt_mesh_net_rx *rx,
+                   struct os_mbuf *buf)
+{
+    struct bt_mesh_net_tx tx = {
+        .sub = rx->sub,
+        .ctx = &rx->ctx,
+        .src = bt_mesh_primary_addr(),
+    };
+    uint16_t filter_size;
+    int i, err;
+
+    /* Configuration messages always have dst unassigned */
+    tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED;
+
+    net_buf_simple_init(buf, 10);
+
+    net_buf_simple_add_u8(buf, CFG_FILTER_STATUS);
+
+    if (client->filter_type == ACCEPT) {
+        net_buf_simple_add_u8(buf, 0x00);
+    } else {
+        net_buf_simple_add_u8(buf, 0x01);
+    }
+
+    for (filter_size = 0U, i = 0; i < ARRAY_SIZE(client->filter); i++) {
+        if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) {
+            filter_size++;
+        }
+    }
+
+    net_buf_simple_add_be16(buf, filter_size);
+
+    BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
+
+    err = bt_mesh_net_encode(&tx, buf, true);
+    if (err) {
+        BT_ERR("Encoding Proxy cfg message failed (err %d)", err);
+        return;
+    }
+
+    err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_CONFIG, buf);
+    if (err) {
+        BT_ERR("Failed to send proxy cfg message (err %d)", err);
+    }
+}
+
+static void
+proxy_filter_recv(uint16_t conn_handle,
+                  struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
+{
+    struct bt_mesh_proxy_client *client;
+    uint8_t opcode;
+
+    client = find_client(conn_handle);
+
+    opcode = net_buf_simple_pull_u8(buf);
+    switch (opcode) {
+    case CFG_FILTER_SET:
+        filter_set(client, buf);
+        send_filter_status(client, rx, buf);
+        break;
+    case CFG_FILTER_ADD:
+        while (buf->om_len >= 2) {
+            uint16_t addr;
+
+            addr = net_buf_simple_pull_be16(buf);
+            filter_add(client, addr);
+        }
+        send_filter_status(client, rx, buf);
+        break;
+    case CFG_FILTER_REMOVE:
+        while (buf->om_len >= 2) {
+            uint16_t addr;
+
+            addr = net_buf_simple_pull_be16(buf);
+            filter_remove(client, addr);
+        }
+        send_filter_status(client, rx, buf);
+        break;
+    default:
+        BT_WARN("Unhandled configuration OpCode 0x%02x", opcode);
+        break;
+    }
+}
+
+static void
+proxy_cfg(struct bt_mesh_proxy_role *role)
+{
+    struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
+    struct bt_mesh_net_rx rx;
+    int err;
+
+    err = bt_mesh_net_decode(role->buf, BT_MESH_NET_IF_PROXY_CFG,
+                 &rx, buf);
+    if (err) {
+        BT_ERR("Failed to decode Proxy Configuration (err %d)", err);
+        return;
+    }
+
+    rx.local_match = 1U;
+
+    if (bt_mesh_rpl_check(&rx, NULL)) {
+        BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x",
+            rx.ctx.addr, rx.ctx.recv_dst, rx.seq);
+        return;
+    }
+
+    /* Remove network headers */
+    net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN);
+
+    BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
+
+    if (buf->om_len < 1) {
+        BT_WARN("Too short proxy configuration PDU");
+        return;
+    }
+
+    proxy_filter_recv(role->conn_handle, &rx, buf);
+}
+
+static void
+proxy_msg_recv(struct bt_mesh_proxy_role *role)
+{
+    switch (role->msg_type) {
+    case BT_MESH_PROXY_NET_PDU:
+        BT_DBG("Mesh Network PDU");
+        bt_mesh_net_recv(&(role->buf), 0, BT_MESH_NET_IF_PROXY);
+        break;
+    case BT_MESH_PROXY_BEACON:
+        BT_DBG("Mesh Beacon PDU");
+        bt_mesh_beacon_recv(role->buf);
+        break;
+    case BT_MESH_PROXY_CONFIG:
+        BT_DBG("Mesh Configuration PDU");
+        proxy_cfg(role);
+        break;
+    default:
+        BT_WARN("Unhandled Message Type 0x%02x", role->msg_type);
+        break;
+    }
+}
+
+static int
+beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subnet *sub)
+{
+    struct os_mbuf *buf = NET_BUF_SIMPLE(23);
+    int rc;
+
+    net_buf_simple_init(buf, 1);
+    bt_mesh_beacon_create(sub, buf);
+
+    rc = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_BEACON, buf);
+    os_mbuf_free_chain(buf);
+    return rc;
+}
+
+static int
+send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data)
+{
+    struct bt_mesh_proxy_client *client = cb_data;
+
+    return beacon_send(client, sub);
+}
+
+static void
+proxy_send_beacons(struct ble_npl_event *work)
+{
+    struct bt_mesh_proxy_client *client;
+
+    client = ble_npl_event_get_arg(work);
+
+    (void)bt_mesh_subnet_find(send_beacon_cb, client);
+}
+
+void
+bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
+{
+    int i;
+
+    if (!sub) {
+        /* NULL means we send on all subnets */
+        bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send);
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(clients); i++) {
+        if (clients[i].cli) {
+            beacon_send(&clients[i], sub);
+        }
+    }
+}
+
+static void
+node_id_start(struct bt_mesh_subnet *sub)
+{
+    sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING;
+    sub->node_id_start = k_uptime_get_32();
+}
+
+void
+bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
+{
+    node_id_start(sub);
+
+    /* Prioritize the recently enabled subnet */
+    beacon_sub = sub;
+}
+
+void
+bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub)
+{
+    sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
+    sub->node_id_start = 0U;
+}
+
+int
+bt_mesh_proxy_identity_enable(void)
+{
+    BT_DBG("");
+
+    if (!bt_mesh_is_provisioned()) {
+        return -EAGAIN;
+    }
+
+    if (bt_mesh_subnet_foreach(node_id_start)) {
+        bt_mesh_adv_update();
+    }
+
+    return 0;
 }
 
 #define ID_TYPE_NET  0x00
@@ -390,616 +407,639 @@
 #define NODE_ID_TIMEOUT (CONFIG_BT_MESH_NODE_ID_TIMEOUT * MSEC_PER_SEC)
 
 static uint8_t proxy_svc_data[NODE_ID_LEN] = {
-	BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL),
+    BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL),
 };
 
 static const struct bt_data node_id_ad[] = {
-	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
-	BT_DATA_BYTES(BT_DATA_UUID16_ALL,
-		      BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
-		      BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN),
+    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+    BT_DATA_BYTES(BT_DATA_UUID16_ALL,
+              BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
+    BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN),
 };
 
 static const struct bt_data net_id_ad[] = {
-	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
-	BT_DATA_BYTES(BT_DATA_UUID16_ALL,
-		      BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
-		      BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
+    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+    BT_DATA_BYTES(BT_DATA_UUID16_ALL,
+              BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
+    BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
 };
 
-static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
-{
-	struct ble_gap_adv_params fast_adv_param = {
-		ADV_OPT_PROXY
-		ADV_FAST_INT
-	};
+static int
+node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
+{
+    struct ble_gap_adv_params fast_adv_param = {
+        ADV_OPT_PROXY
+        ADV_FAST_INT
+    };
 #if ADV_OPT_USE_NAME
-	const char *name = CONFIG_BT_DEVICE_NAME;
-	size_t name_len = strlen(name);
-	struct bt_data sd = {
-		.type = BT_DATA_NAME_COMPLETE,
-		.data_len = name_len,
-		.data = (void *)name
-	};
+    const char *name = CONFIG_BT_DEVICE_NAME;
+    size_t name_len = strlen(name);
+    struct bt_data sd = {
+        .type = BT_DATA_NAME_COMPLETE,
+        .data_len = name_len,
+        .data = (void *)name
+    };
 #else
-	struct bt_data *sd = NULL;
+    struct bt_data *sd = NULL;
 #endif
-	uint8_t tmp[16];
-	int err;
-
-	BT_DBG("");
-
-	proxy_svc_data[2] = ID_TYPE_NODE;
-
-	err = bt_rand(proxy_svc_data + 11, 8);
-	if (err) {
-		return err;
-	}
-
-	(void)memset(tmp, 0, 6);
-	memcpy(tmp + 6, proxy_svc_data + 11, 8);
-	sys_put_be16(bt_mesh_primary_addr(), tmp + 14);
-
-	err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp,
-			    tmp);
-	if (err) {
-		return err;
-	}
-
-	memcpy(proxy_svc_data + 3, tmp + 8, 8);
-
-	err = bt_mesh_adv_start(&fast_adv_param, duration, node_id_ad,
-			      ARRAY_SIZE(node_id_ad), sd, 0);
-	if (err) {
-		BT_WARN("Failed to advertise using Node ID (err %d)", err);
-		return err;
-	}
-
-	return 0;
-}
-
-static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
-{
-	struct ble_gap_adv_params slow_adv_param = {
-		ADV_OPT_PROXY
-		ADV_SLOW_INT
-	};
+    uint8_t tmp[16];
+    int err;
+
+    BT_DBG("");
+
+    proxy_svc_data[2] = ID_TYPE_NODE;
+
+    err = bt_rand(proxy_svc_data + 11, 8);
+    if (err) {
+        return err;
+    }
+
+    (void)memset(tmp, 0, 6);
+    memcpy(tmp + 6, proxy_svc_data + 11, 8);
+    sys_put_be16(bt_mesh_primary_addr(), tmp + 14);
+
+    err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp,
+                tmp);
+    if (err) {
+        return err;
+    }
+
+    memcpy(proxy_svc_data + 3, tmp + 8, 8);
+
+    err = bt_mesh_adv_start(&fast_adv_param, duration, node_id_ad,
+                  ARRAY_SIZE(node_id_ad), sd, 0);
+    if (err) {
+        BT_WARN("Failed to advertise using Node ID (err %d)", err);
+        return err;
+    }
+
+    return 0;
+}
+
+static int
+net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
+{
+    struct ble_gap_adv_params slow_adv_param = {
+        ADV_OPT_PROXY
+        ADV_SLOW_INT
+    };
 #if ADV_OPT_USE_NAME
-	const char *name = CONFIG_BT_DEVICE_NAME;
-	size_t name_len = strlen(name);
-	struct bt_data sd = {
-		.type = BT_DATA_NAME_COMPLETE,
-		.data_len = name_len,
-		.data = (void *)name
-	};
+    const char *name = CONFIG_BT_DEVICE_NAME;
+    size_t name_len = strlen(name);
+    struct bt_data sd = {
+        .type = BT_DATA_NAME_COMPLETE,
+        .data_len = name_len,
+        .data = (void *)name
+    };
 #else
-	struct bt_data *sd = NULL;
+    struct bt_data *sd = NULL;
 #endif
-	int err;
-
-	BT_DBG("");
-
-	proxy_svc_data[2] = ID_TYPE_NET;
-
-	BT_DBG("Advertising with NetId %s",
-	       bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
-
-	memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8);
-
-	err = bt_mesh_adv_start(&slow_adv_param, duration, net_id_ad,
-			      ARRAY_SIZE(net_id_ad), sd, 0);
-	if (err) {
-		BT_WARN("Failed to advertise using Network ID (err %d)", err);
-		return err;
-	}
-
-	return 0;
-}
-
-static bool advertise_subnet(struct bt_mesh_subnet *sub)
-{
-	if (sub->net_idx == BT_MESH_KEY_UNUSED) {
-		return false;
-	}
-
-	return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
-	bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
-}
-
-static struct bt_mesh_subnet *next_sub(void)
-{
-	struct bt_mesh_subnet *sub = NULL;
-
-	if (!beacon_sub) {
-		beacon_sub = bt_mesh_subnet_next(NULL);
-		if (!beacon_sub) {
-			/* No valid subnets */
-			return NULL;
-		}
-	}
-
-	sub = beacon_sub;
-	do {
-		if (advertise_subnet(sub)) {
-			beacon_sub = sub;
-			return sub;
-		}
-
-		sub = bt_mesh_subnet_next(sub);
-	} while (sub != beacon_sub);
-
-	/* No subnets to advertise on */
-	return NULL;
-}
-
-static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data)
-{
-	int *count = cb_data;
-
-	if (advertise_subnet(sub)) {
-		(*count)++;
-	}
-
-	return 0;
-}
-
-static int sub_count(void)
-{
-	int count = 0;
-
-	(void)bt_mesh_subnet_find(sub_count_cb, &count);
-
-	return count;
-}
-
-static int gatt_proxy_advertise(struct bt_mesh_subnet *sub)
-{
-	int32_t remaining = K_FOREVER;
-	int subnet_count;
-	int err = -EBUSY;
-
-	BT_DBG("");
-
-	if (conn_count == CONFIG_BT_MAX_CONN) {
-		BT_DBG("Connectable advertising deferred (max connections %d)", conn_count);
-		return -ENOMEM;
-	}
-
-	sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub);
-	if (!sub) {
-		BT_WARN("No subnets to advertise on");
-		return -ENOENT;
-	}
-
-	subnet_count = sub_count();
-	BT_DBG("sub_count %u", subnet_count);
-	if (subnet_count > 1) {
-		int32_t max_timeout;
-
-		/* We use NODE_ID_TIMEOUT as a starting point since it may
-		 * be less than 60 seconds. Divide this period into at least
-		 * 6 slices, but make sure that a slice is at least one
-		 * second long (to avoid excessive rotation).
-		 */
-		max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6);
-		max_timeout = max(max_timeout, K_SECONDS(1));
-
-		if (remaining > max_timeout || remaining < 0) {
-			remaining = max_timeout;
-		}
-	}
-
-	if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
-		uint32_t active = k_uptime_get_32() - sub->node_id_start;
-
-		if (active < NODE_ID_TIMEOUT) {
-			remaining = NODE_ID_TIMEOUT - active;
-			BT_DBG("Node ID active for %u ms, %d ms remaining",
-			       active, remaining);
-			err = node_id_adv(sub, remaining);
-		} else {
-			bt_mesh_proxy_identity_stop(sub);
-			BT_DBG("Node ID stopped");
-		}
-	}
-
-	if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
-		err = net_id_adv(sub, remaining);
-	}
-
-	BT_DBG("Advertising %d ms for net_idx 0x%04x",
-	       (int) remaining, sub->net_idx);
-
-	beacon_sub = bt_mesh_subnet_next(beacon_sub);
-
-	return err;
-}
-
-static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
-{
-	if (evt == BT_MESH_KEY_DELETED) {
-		if (sub == beacon_sub) {
-			beacon_sub = NULL;
-		}
-	} else {
-		bt_mesh_proxy_beacon_send(sub);
-	}
-}
-
-static void proxy_ccc_write(uint16_t conn_handle)
-{
-	struct bt_mesh_proxy_client *client;
-
-	BT_DBG("conn_handle %d", conn_handle);
-
-	client = find_client(conn_handle);
-
-	if (client->filter_type == NONE) {
-		client->filter_type = ACCEPT;
-		k_work_add_arg(&client->send_beacons, client);
-		k_work_submit(&client->send_beacons);
-	}
-}
-
-int bt_mesh_proxy_gatt_enable(void)
-{
-	uint16_t handle;
-	int rc;
-	int i;
-
-	BT_DBG("");
-
-	if (!bt_mesh_is_provisioned()) {
-		return -ENOTSUP;
-	}
-
-	if (service_registered) {
-		return -EBUSY;
-	}
-
-	rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
-	assert(rc == 0);
-	ble_gatts_svc_set_visibility(handle, 1);
-	/* FIXME: figure out end handle */
-	ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
-
-	service_registered = true;
-
-	for (i = 0; i < ARRAY_SIZE(clients); i++) {
-		if (clients[i].cli) {
-			clients[i].filter_type = ACCEPT;
-		}
-	}
-	return 0;
-}
-
-void bt_mesh_proxy_gatt_disconnect(void)
-{
-	int rc;
-	int i;
-
-	BT_DBG("");
-
-	for (i = 0; i < ARRAY_SIZE(clients); i++) {
-		struct bt_mesh_proxy_client *client = &clients[i];
-
-		if ((client->cli) &&
-		    (client->filter_type == ACCEPT ||
-		    client->filter_type == REJECT)) {
-			client->filter_type = NONE;
-			rc = ble_gap_terminate(client->cli->conn_handle,
-			                       BLE_ERR_REM_USER_CONN_TERM);
-			assert(rc == 0);
-		}
-	}
-}
-
-int bt_mesh_proxy_gatt_disable(void)
-{
-	uint16_t handle;
-	int rc;
-	BT_DBG("");
-
-	if (!service_registered) {
-		return -EALREADY;
-	}
-
-	bt_mesh_proxy_gatt_disconnect();
-
-	rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
-	assert(rc == 0);
-	ble_gatts_svc_set_visibility(handle, 0);
-	/* FIXME: figure out end handle */
-	ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
-	service_registered = false;
-
-	return 0;
-}
-
-void bt_mesh_proxy_addr_add(struct os_mbuf **buf, uint16_t addr)
-{
-	struct bt_mesh_proxy_client *client;
-	struct bt_mesh_proxy_role *cli =
-		CONTAINER_OF(buf, struct bt_mesh_proxy_role, buf);
-
-	client = find_client(cli->conn_handle);
-
-	BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
-
-	if (client->filter_type == ACCEPT) {
-		filter_add(client, addr);
-	} else if (client->filter_type == REJECT) {
-		filter_remove(client, addr);
-	}
-}
-
-static bool client_filter_match(struct bt_mesh_proxy_client *client,
-				uint16_t addr)
-{
-	int i;
-
-	BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
-
-	if (client->filter_type == REJECT) {
-		for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
-			if (client->filter[i] == addr) {
-				return false;
-			}
-		}
-
-		return true;
-	}
-
-	if (addr == BT_MESH_ADDR_ALL_NODES) {
-		return true;
-	}
-
-	if (client->filter_type == ACCEPT) {
-		for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
-			if (client->filter[i] == addr) {
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
-bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst)
-{
-	const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
-	void *cb_data = BT_MESH_ADV(buf)->cb_data;
-	bool relayed = false;
-	int i, err;
-
-	BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst);
-
-	for (i = 0; i < ARRAY_SIZE(clients); i++) {
-		struct bt_mesh_proxy_client *client = &clients[i];
-		struct os_mbuf *msg;
-
-		if (!client->cli) {
-			continue;
-		}
-
-		if (!client_filter_match(client, dst)) {
-			continue;
-		}
-
-		/* Proxy PDU sending modifies the original buffer,
-		 * so we need to make a copy.
-		 */
-		msg = NET_BUF_SIMPLE(32);
-		net_buf_simple_init(msg, 1);
-		net_buf_simple_add_mem(msg, buf->om_data, buf->om_len);
-
-		err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_NET_PDU,
-					     msg);
-
-		adv_send_start(0, err, cb, cb_data);
-		if (err) {
-			BT_ERR("Failed to send proxy message (err %d)", err);
-
-			/* If segment_and_send() fails the buf_send_end() callback will
-			 * not be called, so we need to clear the user data (net_buf,
-			 * which is just opaque data to segment_and send) reference given
-			 * to segment_and_send() here.
-			 */
-			net_buf_unref(buf);
-			continue;
-		}
-		os_mbuf_free_chain(msg);
-		relayed = true;
-	}
-
-	return relayed;
-}
-
-static void gatt_connected(uint16_t conn_handle)
-{
-	struct bt_mesh_proxy_client *client;
-	struct ble_gap_conn_desc info;
-	struct ble_hs_conn *conn;
-
-	conn = ble_hs_conn_find(conn_handle);
-	bt_conn_get_info(conn, &info);
-	if (info.role != BLE_GAP_ROLE_SLAVE ||
-	    !service_registered) {
-		return;
-	}
-	BT_DBG("conn %d", conn_handle);
-
-	conn_count++;
-
-	client = get_client(conn_handle);
-	assert(client);
-
-	client->filter_type = NONE;
-	(void)memset(client->filter, 0, sizeof(client->filter));
-
-	client->cli = bt_mesh_proxy_role_setup(conn_handle, proxy_send,
-					       proxy_msg_recv);
-
-	/* Try to re-enable advertising in case it's possible */
-	if (conn_count < CONFIG_BT_MAX_CONN) {
-		bt_mesh_adv_update();
-	}
-}
-
-static void gatt_disconnected(struct ble_gap_conn_desc conn, uint8_t reason)
-{
-	struct bt_mesh_proxy_client *client;
-
-	if (conn.role != BLE_GAP_ROLE_SLAVE) {
-		return;
-	}
-
-	if (!service_registered && bt_mesh_is_provisioned()) {
-		(void)bt_mesh_proxy_gatt_enable();
-		return;
-	}
-
-	conn_count--;
-	client = find_client(conn.conn_handle);
-	if (client->cli) {
-		bt_mesh_proxy_role_cleanup(client->cli);
-		client->cli = NULL;
-	}
-
-	client->conn_handle = 0xffff;
-}
-
-void notify_complete(void)
-{
-	sys_snode_t *n;
-
-	if (atomic_dec(&pending_notifications) > 1) {
-		return;
-	}
-
-	BT_DBG("");
-
-	while ((n = sys_slist_get(&idle_waiters))) {
-		CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb();
-	}
-}
-
-static int proxy_send(uint16_t conn_handle,
-		      const void *data, uint16_t len)
-{
-	struct os_mbuf *om;
-	int err = 0;
-
-	BT_DBG("%u bytes: %s", len, bt_hex(data, len));
-
-	om = ble_hs_mbuf_from_flat(data, len);
-	assert(om);
-	err = ble_gatts_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om);
-	notify_complete();
-
-	if (!err) {
-		atomic_inc(&pending_notifications);
-	}
-
-	return err;
-}
-
-int bt_mesh_proxy_adv_start(void)
-{
-	BT_DBG("");
-
-	if (!service_registered || !bt_mesh_is_provisioned()) {
-		return -ENOTSUP;
-	}
-
-	return gatt_proxy_advertise(next_sub());
-}
-
-
-static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg)
+    int err;
+
+    BT_DBG("");
+
+    proxy_svc_data[2] = ID_TYPE_NET;
+
+    BT_DBG("Advertising with NetId %s",
+           bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
+
+    memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8);
+
+    err = bt_mesh_adv_start(&slow_adv_param, duration, net_id_ad,
+                  ARRAY_SIZE(net_id_ad), sd, 0);
+    if (err) {
+        BT_WARN("Failed to advertise using Network ID (err %d)", err);
+        return err;
+    }
+
+    return 0;
+}
+
+static bool
+advertise_subnet(struct bt_mesh_subnet *sub)
+{
+    if (sub->net_idx == BT_MESH_KEY_UNUSED) {
+        return false;
+    }
+
+    return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
+            bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
+}
+
+static struct bt_mesh_subnet *
+next_sub(void)
+{
+    struct bt_mesh_subnet *sub = NULL;
+
+    if (!beacon_sub) {
+        beacon_sub = bt_mesh_subnet_next(NULL);
+        if (!beacon_sub) {
+            /* No valid subnets */
+            return NULL;
+        }
+    }
+
+    sub = beacon_sub;
+    do {
+        if (advertise_subnet(sub)) {
+            beacon_sub = sub;
+            return sub;
+        }
+
+        sub = bt_mesh_subnet_next(sub);
+    } while (sub != beacon_sub);
+
+    /* No subnets to advertise on */
+    return NULL;
+}
+
+static int
+sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data)
+{
+    int *count = cb_data;
+
+    if (advertise_subnet(sub)) {
+        (*count)++;
+    }
+
+    return 0;
+}
+
+static int
+sub_count(void)
+{
+    int count = 0;
+
+    (void)bt_mesh_subnet_find(sub_count_cb, &count);
+
+    return count;
+}
+
+static int
+gatt_proxy_advertise(struct bt_mesh_subnet *sub)
+{
+    int32_t remaining = K_FOREVER;
+    int subnet_count;
+    int err = -EBUSY;
+
+    BT_DBG("");
+
+    if (conn_count == CONFIG_BT_MAX_CONN) {
+        BT_DBG("Connectable advertising deferred (max connections %d)", conn_count);
+        return -ENOMEM;
+    }
+
+    sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub);
+    if (!sub) {
+        BT_WARN("No subnets to advertise on");
+        return -ENOENT;
+    }
+
+    subnet_count = sub_count();
+    BT_DBG("sub_count %u", subnet_count);
+    if (subnet_count > 1) {
+        int32_t max_timeout;
+
+        /* We use NODE_ID_TIMEOUT as a starting point since it may
+         * be less than 60 seconds. Divide this period into at least
+         * 6 slices, but make sure that a slice is at least one
+         * second long (to avoid excessive rotation).
+         */
+        max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6);
+        max_timeout = max(max_timeout, K_SECONDS(1));
+
+        if (remaining > max_timeout || remaining < 0) {
+            remaining = max_timeout;
+        }
+    }
+
+    if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
+        uint32_t active = k_uptime_get_32() - sub->node_id_start;
+
+        if (active < NODE_ID_TIMEOUT) {
+            remaining = NODE_ID_TIMEOUT - active;
+            BT_DBG("Node ID active for %u ms, %d ms remaining",
+                   active, remaining);
+            err = node_id_adv(sub, remaining);
+        } else {
+            bt_mesh_proxy_identity_stop(sub);
+            BT_DBG("Node ID stopped");
+        }
+    }
+
+    if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
+        err = net_id_adv(sub, remaining);
+    }
+
+    BT_DBG("Advertising %d ms for net_idx 0x%04x",
+           (int) remaining, sub->net_idx);
+
+    beacon_sub = bt_mesh_subnet_next(beacon_sub);
+
+    return err;
+}
+
+static void
+subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
+{
+    if (evt == BT_MESH_KEY_DELETED) {
+        if (sub == beacon_sub) {
+            beacon_sub = NULL;
+        }
+    } else {
+        bt_mesh_proxy_beacon_send(sub);
+    }
+}
+
+static void
+proxy_ccc_write(uint16_t conn_handle)
+{
+    struct bt_mesh_proxy_client *client;
+
+    BT_DBG("conn_handle %d", conn_handle);
+
+    client = find_client(conn_handle);
+
+    if (client->filter_type == NONE) {
+        client->filter_type = ACCEPT;
+        k_work_add_arg(&client->send_beacons, client);
+        k_work_submit(&client->send_beacons);
+    }
+}
+
+int
+bt_mesh_proxy_gatt_enable(void)
+{
+    uint16_t handle;
+    int rc;
+    int i;
+
+    BT_DBG("");
+
+    if (!bt_mesh_is_provisioned()) {
+        return -ENOTSUP;
+    }
+
+    if (service_registered) {
+        return -EBUSY;
+    }
+
+    rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
+    assert(rc == 0);
+    ble_gatts_svc_set_visibility(handle, 1);
+    /* FIXME: figure out end handle */
+    ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
+
+    service_registered = true;
+
+    for (i = 0; i < ARRAY_SIZE(clients); i++) {
+        if (clients[i].cli) {
+            clients[i].filter_type = ACCEPT;
+        }
+    }
+    return 0;
+}
+
+void
+bt_mesh_proxy_gatt_disconnect(void)
+{
+    int rc;
+    int i;
+
+    BT_DBG("");
+
+    for (i = 0; i < ARRAY_SIZE(clients); i++) {
+        struct bt_mesh_proxy_client *client = &clients[i];
+
+        if ((client->cli) &&
+            (client->filter_type == ACCEPT ||
+             client->filter_type == REJECT)) {
+            client->filter_type = NONE;
+            rc = ble_gap_terminate(client->cli->conn_handle,
+                                   BLE_ERR_REM_USER_CONN_TERM);
+            assert(rc == 0);
+        }
+    }
+}
+
+int
+bt_mesh_proxy_gatt_disable(void)
+{
+    uint16_t handle;
+    int rc;
+    BT_DBG("");
+
+    if (!service_registered) {
+        return -EALREADY;
+    }
+
+    bt_mesh_proxy_gatt_disconnect();
+
+    rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
+    assert(rc == 0);
+    ble_gatts_svc_set_visibility(handle, 0);
+    /* FIXME: figure out end handle */
+    ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
+    service_registered = false;
+
+    return 0;
+}
+
+void
+bt_mesh_proxy_addr_add(struct os_mbuf **buf, uint16_t addr)
+{
+    struct bt_mesh_proxy_client *client;
+    struct bt_mesh_proxy_role *cli =
+        CONTAINER_OF(buf, struct bt_mesh_proxy_role, buf);
+
+    client = find_client(cli->conn_handle);
+
+    BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
+
+    if (client->filter_type == ACCEPT) {
+        filter_add(client, addr);
+    } else if (client->filter_type == REJECT) {
+        filter_remove(client, addr);
+    }
+}
+
+static bool
+client_filter_match(struct bt_mesh_proxy_client *client,
+                    uint16_t addr)
+{
+    int i;
+
+    BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
+
+    if (client->filter_type == REJECT) {
+        for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+            if (client->filter[i] == addr) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    if (addr == BT_MESH_ADDR_ALL_NODES) {
+        return true;
+    }
+
+    if (client->filter_type == ACCEPT) {
+        for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+            if (client->filter[i] == addr) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+bool
+bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst)
+{
+    const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
+    void *cb_data = BT_MESH_ADV(buf)->cb_data;
+    bool relayed = false;
+    int i, err;
+
+    BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst);
+
+    for (i = 0; i < ARRAY_SIZE(clients); i++) {
+        struct bt_mesh_proxy_client *client = &clients[i];
+        struct os_mbuf *msg;
+
+        if (!client->cli) {
+            continue;
+        }
+
+        if (!client_filter_match(client, dst)) {
+            continue;
+        }
+
+        /* Proxy PDU sending modifies the original buffer,
+         * so we need to make a copy.
+         */
+        msg = NET_BUF_SIMPLE(32);
+        net_buf_simple_init(msg, 1);
+        net_buf_simple_add_mem(msg, buf->om_data, buf->om_len);
+
+        err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_NET_PDU,
+                         msg);
+
+        adv_send_start(0, err, cb, cb_data);
+        if (err) {
+            BT_ERR("Failed to send proxy message (err %d)", err);
+
+            /* If segment_and_send() fails the buf_send_end() callback will
+             * not be called, so we need to clear the user data (net_buf,
+             * which is just opaque data to segment_and send) reference given
+             * to segment_and_send() here.
+             */
+            net_buf_unref(buf);
+            continue;
+        }
+        os_mbuf_free_chain(msg);
+        relayed = true;
+    }
+
+    return relayed;
+}
+
+static void
+gatt_connected(uint16_t conn_handle)
+{
+    struct bt_mesh_proxy_client *client;
+    struct ble_gap_conn_desc info;
+    struct ble_hs_conn *conn;
+
+    conn = ble_hs_conn_find(conn_handle);
+    bt_conn_get_info(conn, &info);
+    if (info.role != BLE_GAP_ROLE_SLAVE ||
+        !service_registered) {
+        return;
+    }
+    BT_DBG("conn %d", conn_handle);
+
+    conn_count++;
+
+    client = get_client(conn_handle);
+    assert(client);
+
+    client->filter_type = NONE;
+    (void)memset(client->filter, 0, sizeof(client->filter));
+
+    client->cli = bt_mesh_proxy_role_setup(conn_handle, proxy_send,
+                           proxy_msg_recv);
+
+    /* Try to re-enable advertising in case it's possible */
+    if (conn_count < CONFIG_BT_MAX_CONN) {
+        bt_mesh_adv_update();
+    }
+}
+
+static void
+gatt_disconnected(struct ble_gap_conn_desc conn, uint8_t reason)
+{
+    struct bt_mesh_proxy_client *client;
+
+    if (conn.role != BLE_GAP_ROLE_SLAVE) {
+        return;
+    }
+
+    if (!service_registered && bt_mesh_is_provisioned()) {
+        (void)bt_mesh_proxy_gatt_enable();
+        return;
+    }
+
+    conn_count--;
+    client = find_client(conn.conn_handle);
+    if (client->cli) {
+        bt_mesh_proxy_role_cleanup(client->cli);
+        client->cli = NULL;
+    }
+
+    client->conn_handle = 0xffff;
+}
+
+void
+notify_complete(void)
+{
+    sys_snode_t *n;
+
+    if (atomic_dec(&pending_notifications) > 1) {
+        return;
+    }
+
+    BT_DBG("");
+
+    while ((n = sys_slist_get(&idle_waiters))) {
+        CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb();
+    }
+}
+
+static int
+proxy_send(uint16_t conn_handle,
+           const void *data, uint16_t len)
+{
+    struct os_mbuf *om;
+    int err = 0;
+
+    BT_DBG("%u bytes: %s", len, bt_hex(data, len));
+
+    om = ble_hs_mbuf_from_flat(data, len);
+    assert(om);
+    err = ble_gatts_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om);
+    notify_complete();
+
+    if (!err) {
+        atomic_inc(&pending_notifications);
+    }
+
+    return err;
+}
+
+int
+bt_mesh_proxy_adv_start(void)
+{
+    BT_DBG("");
+
+    if (!service_registered || !bt_mesh_is_provisioned()) {
+        return -ENOTSUP;
+    }
+
+    return gatt_proxy_advertise(next_sub());
+}
+
+
+static void
+ble_mesh_handle_connect(struct ble_gap_event *event, void *arg)
 {
 #if MYNEWT_VAL(BLE_EXT_ADV)
-	/* When EXT ADV is enabled then mesh proxy is connected
-	 * when proxy advertising instance is completed.
-	 * Therefore no need to handle BLE_GAP_EVENT_CONNECT
-	 */
-	if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
-		/* Reason 0 means advertising has been completed because
-		 * connection has been established
-		 */
-		if (event->adv_complete.reason != 0) {
-			return;
-		}
-
-		if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) {
-			return;
-		}
-
-		gatt_connected(event->adv_complete.conn_handle);
+    /* When EXT ADV is enabled then mesh proxy is connected
+     * when proxy advertising instance is completed.
+     * Therefore no need to handle BLE_GAP_EVENT_CONNECT
+     */
+    if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
+        /* Reason 0 means advertising has been completed because
+         * connection has been established
+         */
+        if (event->adv_complete.reason != 0) {
+            return;
+        }
+
+        if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) {
+            return;
+        }
+
+        gatt_connected(event->adv_complete.conn_handle);
 #if MYNEWT_VAL(BLE_MESH_PB_GATT)
-		gatt_connected_pb_gatt(event->adv_complete.conn_handle,
-				       event->adv_complete.reason);
+        gatt_connected_pb_gatt(event->adv_complete.conn_handle,
+                       event->adv_complete.reason);
 #endif
-	}
+    }
 #else
-	if (event->type == BLE_GAP_EVENT_CONNECT) {
-		gatt_connected(event->connect.conn_handle);
+    if (event->type == BLE_GAP_EVENT_CONNECT) {
+        gatt_connected(event->connect.conn_handle);
 #if MYNEWT_VAL(BLE_MESH_PB_GATT)
-		gatt_connected_pb_gatt(event->connect.conn_handle, event->connect.status);
+        gatt_connected_pb_gatt(event->connect.conn_handle, event->connect.status);
 #endif
-	}
+    }
 #endif
 }
 
-int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg)
-{
-	if ((event->type == BLE_GAP_EVENT_CONNECT) ||
-	    (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) {
-		ble_mesh_handle_connect(event, arg);
-	} else if (event->type == BLE_GAP_EVENT_DISCONNECT) {
-		gatt_disconnected(event->disconnect.conn,
-				   event->disconnect.reason);
+int
+ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg)
+{
+    if ((event->type == BLE_GAP_EVENT_CONNECT) ||
+        (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) {
+        ble_mesh_handle_connect(event, arg);
+    } else if (event->type == BLE_GAP_EVENT_DISCONNECT) {
+        gatt_disconnected(event->disconnect.conn,
+                   event->disconnect.reason);
 #if MYNEWT_VAL(BLE_MESH_PB_GATT)
-		gatt_disconnected_pb_gatt(event->disconnect.conn,
-				  event->disconnect.reason);
+        gatt_disconnected_pb_gatt(event->disconnect.conn,
+                  event->disconnect.reason);
 #endif
-	} else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) {
-		if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) {
+    } else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) {
+        if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) {
 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
-			proxy_ccc_write(event->subscribe.conn_handle);
+            proxy_ccc_write(event->subscribe.conn_handle);
 #endif
-		} else if (event->subscribe.attr_handle ==
-			   svc_handles.prov_data_out_h) {
+        } else if (event->subscribe.attr_handle ==
+                   svc_handles.prov_data_out_h) {
 #if (MYNEWT_VAL(BLE_MESH_PB_GATT))
-			prov_ccc_write(event->subscribe.conn_handle, event->type);
+            prov_ccc_write(event->subscribe.conn_handle, event->type);
 #endif
-		}
-	}
-
-	return 0;
-}
-
-int bt_mesh_proxy_init(void)
-{
-	int i;
+        }
+    }
+
+    return 0;
+}
+
+int
+bt_mesh_proxy_init(void)
+{
+    int i;
 
 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
-	if (!bt_mesh_subnet_cb_list[4]) {
-		bt_mesh_subnet_cb_list[4] = subnet_evt;
-	}
+    if (!bt_mesh_subnet_cb_list[4]) {
+        bt_mesh_subnet_cb_list[4] = subnet_evt;
+    }
 #endif
 
-	for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) {
+    for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) {
 #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
-		k_work_init(&clients[i].send_beacons, proxy_send_beacons);
+        k_work_init(&clients[i].send_beacons, proxy_send_beacons);
 #endif
-		clients[i].conn_handle = 0xffff;
-	}
-
-	resolve_svc_handles();
-
-	ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0);
-	ble_gatts_svc_set_visibility(svc_handles.prov_h, 0);
-
-	return 0;
-}
+        clients[i].conn_handle = 0xffff;
+    }
+
+    resolve_svc_handles();
+
+    ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0);
+    ble_gatts_svc_set_visibility(svc_handles.prov_h, 0);
+
+    return 0;
+}

apache-mynewt-bot avatar Jul 11 '22 13:07 apache-mynewt-bot