in nimble/host/mesh/src/net.c [657:738]
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);
}