目录
一、什么是BLE Mesh Network Layer网络层?
二、网络层介绍
2.1 节点地址
2.2 Network PDU
2.2.1 IVI
2.2.2 NID
2.2.3 CTL
2.2.4 TTL
2.2.5 SEQ
2.2.6 SRC
2.2.7 DST
2.2.8 TransportPDU
2.2.9 NetMIC
三、网络层收发数据流程
四、资料获取
BLE mesh使用了四种类型的地址,地址长度为16位,分别是:
未分配的地址(Unassigned Address):一种特殊的地址类型,值为 0x0000。它的使用表明未经配置的元素或未被指定地址的元素。未分配的地址不能用于网络数据的发送。
单播地址(Unicast Address):单播地址的范围是从0x0001到0x7FFF,也就是说最多可以有32767个单播地址。用于标识网络中的单个元素,由provisioner分配,不能重复。在“启动配置”(provisioning)期间,启动配置设备(provisioner)会在网络节点的生命周期内为节点中的每个节点元素 (一个节点Node可以有多个节点元素Element, 例如一个多孔插座作为一个节点,插座上的每一个插孔都是一个独立的节点元素)分配一个单播地址。
组播地址(Group Address):用于标识网络中的一组元素,可以由任何节点创建,必须唯一。组播地址的范围是从0xC000到0xFFFB,其中0xFF00到0xFFFB是保留地址,不能使用。0xFFFC到0xFFFF是特殊地址,用于表示不同类型的节点。
0xFFFC 代指所有的代理节点(Proxy Node)
0xFFFD 代指所有的朋友节点(Friend Node)
0xFFFE 代指所有的转发节点(Relay Node)
0xFFFF 代指所有的节点(All Nodes)
虚拟地址(Virtual Address):用于标识网络中的一组元素,由128位的标签(Label UUID)生成,可以创建更多的地址,但需要更多的存储空间和处理时间。
Filed |
Size(bits) |
Notes |
IVI |
1 |
包含了IV Index的最低有效位 |
NID |
7 |
一个7位的网络标识符,用于查找验证和加密此网络层PDU的密钥 |
CTL |
1 |
用于确定消息是控制消息的一部分还是访问消息的一部分 |
TTL |
7 |
指定消息的传输生存时间 |
SEQ |
24 |
一个24位的整数,与IV Index结合使用,应该是唯一的值 |
SRC |
16 |
标识发起这个网络层PDU的元素地址 |
DST |
16 |
标识网络层PDU所指向的一个或多个元素地址 |
TransportPDU |
8-128 |
数据的字节序列 |
NetMIC |
32或64 |
用于验证DST和TransportPDU是否被更改 |
IVI(Initialization Vector Index)是一个32位的值,用于保证网络层的数据加密和混淆的安全性和随机性。
IVI与序列号(SEQ)一起组成了nonce,nonce是用于AES-CCM算法的输入参数,用于对网络层PDU进行加密和认证。
IVI可以防止nonce的重复使用,从而提高网络层的安全性。
IVI是一个共享的网络资源,网络中的所有节点必须保持IVI的一致性,否则会导致通信失败。IVI通过安全网络信标(Secure Network Beacon)进行共享和更新。当节点的序列号接近耗尽时,或者检测到其他节点的IVI更新时,节点会启动IV更新过程,将IVI递增1,并通知网络中的其他节点。IV更新过程有一定的时间限制和规则,以保证网络的稳定性和兼容性。
IVI更新时间和规则是指ivi更新过程中的时间要求和状态转换条件,具体如下:
节点需支持IV索引恢复,因长时间离线节点可能错过IV更新,导致无法通信。为恢复IV index,节点需监听含网络ID和当前IV的安全信标。当接收到验证后其IV高于当前的主子网信标时,节点应设置其当前IV及其更新状态。此过程不考虑96小时限制。
/*BLE Mesh网络层更新IVI子函数*/
/*源自开源协议栈NimBLE*/
static void ivu_refresh(struct ble_npl_event *work)
{
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)) {
bt_mesh_store_iv(true);
}
k_delayed_work_submit(&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)) {
bt_mesh_store_iv(true);
}
}
NID(Network Identifier)是一个7位的值,用于标识用于保护网络层PDU的加密密钥和隐私密钥。
NID是从NetKey派生出来的,每个NetKey对应一个唯一的NID。
当节点收到网络层PDU时,会根据NID字段查找是否有匹配的NetKey,如果没有,则忽略该PDU。如果有,则使用NetKey派生的EncryptionKey和PrivacyKey对PDU进行解密和去混淆,得到消息的内容和元数据。
NID可以防止节点接收和处理不属于同一个网络的PDU,从而提高网络的安全性和效率。
/*BLE Mesh网络层生成NID字段*/
/*源自开源协议栈NimBLE*/
err = bt_mesh_k2(key, p, sizeof(p), &nid, keys->enc, keys->privacy);
if (err) {
BT_ERR("Unable to generate NID, EncKey & PrivacyKey");
return err;
}
为什么不直接用netkey去匹配,而要加个NID字段?
因为netkey是一个128位的密钥,直接用它来匹配会占用太多的空间和时间,影响网络的效率和性能。NID(Network Identifier)是一个7位的值,是从netkey派生出来的,每个netkey对应一个唯一的NID。NID可以提供一种快速的方法来确定使用哪个netkey对消息加密和解密,同时也保证了消息的安全性和隐私性。NID只占用很少的空间,可以节省网络的带宽和资源,提高网络的速度和稳定性。
CTL(Control)是一个1位的值,用于区分网络层PDU(Protocol Data Unit)是访问消息(Access Message)还是控制消息(Control Message)。访问消息是用于传输应用层数据的,控制消息是用于实现网络层的管理功能的,比如创建和维护友谊(Friendship)和心跳(Heartbeat)。CTL的值也会影响网络层PDU的大小和NetMIC(Network Message Integrity Check)的长度。具体来说:
TTL(Time To Live)是一个7位的值,用于限制网络层PDU(Protocol Data Unit)的最大中继次数。
TTL的作用是防止消息在网络中无限循环,同时也可以控制消息的传播范围和效率。TTL的值由消息的发布者设定,每个消息都有一个初始的TTL值,范围是0-127。当消息被中继节点转发时,TTL的值会减1,当TTL的值为0时,消息不会再被转发。
TTL的值也会影响消息的优先级,TTL越高的消息越优先被转发。
SEQ(Sequence Number)是一个24位的值,用于防止重放攻击。
重放攻击是一种网络安全威胁,攻击者拦截并重复发送消息,以欺骗接收者或执行未授权的操作。
SEQ的作用是保证每个消息的唯一性和时效性,避免消息被重复处理或滥用。
每个元素在发送消息时都会增加SEQ的值,从0开始到0xFFFFFF为止。每个节点在接收消息时都会检查SEQ的值,如果小于或等于之前收到的同一元素的消息的SEQ值,就会丢弃该消息,认为它是过期或重复的。当SEQ的值接近最大值时,元素应该更新IVI(Initialization Vector Index),以防止SEQ的值溢出或重复。
/*BLE Mesh网络层生成SEQ字段*/
/*源自开源协议栈NimBLE*/
u32_t bt_mesh_next_seq(void)
{
u32_t seq = bt_mesh.seq++;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_seq();
}
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) &&
bt_mesh.seq > IV_UPDATE_SEQ_LIMIT &&
bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY)) {
bt_mesh_beacon_ivu_initiator(true);
bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true);
bt_mesh_net_sec_update(NULL);
}
return seq;
}
SRC(Source Address)是一个16位的值,用于标识网络层PDU(Protocol Data Unit)的发送者。
SRC的作用是让接收者知道消息的来源,以便进行回复或处理。
SRC的值必须是一个单播地址或一个虚拟地址,不能是一个组播地址或一个未分配的地址。
SRC的值也会影响消息的安全性和隐私性,因为它会与IVI(Initialization Vector Index)和SEQ(Sequence Number)一起组成nonce,nonce是用于AES-CCM算法的输入参数,用于对网络层PDU进行加密和认证。
DST(Destination Address)是一个16位的值,用于标识网络层PDU(Protocol Data Unit)的接收者。DST的作用是让发送者指定消息的目的地,以便进行广播或单播。DST的值可以是一个单播地址、一个组播地址或一个虚拟地址,不能是一个未分配的地址。
DST的值也会影响消息的安全性和隐私性,因为它会与IVI(Initialization Vector Index)和SEQ(Sequence Number)一起组成nonce,nonce是用于AES-CCM算法的输入参数,用于对网络层PDU进行加密和认证。
TransportPDU(Transport Protocol Data Unit)是网络层PDU(Protocol Data Unit)的一部分,用于承载上层传输层的数据或控制信息。TransportPDU的作用是实现网络层和上层传输层之间的数据交换,以及对数据进行分段和重组。
TransportPDU的长度和内容取决于CTL(Control)字段的值,CTL字段是网络层PDU的一部分,用于区分网络层PDU是访问消息(Access Message)还是控制消息(Control Message)。具体来说:
NetMIC(Network Message Integrity Check)是网络层PDU(Protocol Data Unit)的一部分,用于保证网络层数据的完整性和认证性。NetMIC的作用是防止消息被篡改或伪造,从而提高网络的安全性和可靠性。
NetMIC是使用NetKey派生的EncryptionKey和nonce(由IVI,SEQ,SRC,DST组成)对网络层PDU进行AES-CCM算法的输出结果。NetMIC的长度取决于CTL(Control)字段的值,如果CTL为0,表示网络层PDU是访问消息,NetMIC是32位的;如果CTL为1,表示网络层PDU是控制消息,NetMIC是64位的。
BLE Mesh 网络层发送数据的流程大致如下:
/*BLE Mesh网络层发送数据子函数*/
/*源自开源协议栈NimBLE*/
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)
{
int err;
BT_DBG("src 0x%04x dst 0x%04x len %u headroom %zu tailroom %zu",
tx->src, tx->ctx->addr, buf->om_len, net_buf_headroom(buf),
net_buf_tailroom(buf));
BT_DBG("Payload len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
BT_DBG("Seq 0x%06x", bt_mesh.seq);
if (tx->ctx->send_ttl == BT_MESH_TTL_DEFAULT) {
tx->ctx->send_ttl = bt_mesh_default_ttl_get();
}
err = bt_mesh_net_encode(tx, buf, false);
if (err) {
goto done;
}
BT_DBG("encoded %u bytes: %s", buf->om_len,
bt_hex(buf->om_data, buf->om_len));
/* Deliver to GATT Proxy Clients if necessary. Mesh spec 3.4.5.2:
* "The output filter of the interface connected to advertising or
* GATT bearers shall drop all messages with TTL value set to 1."
*/
if (MYNEWT_VAL(BLE_MESH_GATT_PROXY) &&
tx->ctx->send_ttl != 1) {
if (bt_mesh_proxy_relay(buf, tx->ctx->addr) &&
BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) {
/* Notify completion if this only went
* through the Mesh Proxy.
*/
send_cb_finalize(cb, cb_data);
err = 0;
goto done;
}
}
/* Deliver to local network interface if necessary */
if (bt_mesh_fixed_group_match(tx->ctx->addr) ||
bt_mesh_elem_find(tx->ctx->addr)) {
if (cb && cb->start) {
cb->start(0, 0, cb_data);
}
net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf));
if (cb && cb->end) {
cb->end(0, cb_data);
}
k_work_submit(&bt_mesh.local_work);
} else if (tx->ctx->send_ttl != 1) {
/* Deliver to to the advertising network interface. Mesh spec
* 3.4.5.2: "The output filter of the interface connected to
* advertising or GATT bearers shall drop all messages with
* TTL value set to 1."
*/
bt_mesh_adv_send(buf, cb, cb_data);
}
done:
net_buf_unref(buf);
return err;
}
BLE Mesh 网络层接收数据的流程大致如下:
输入过滤器的功能:
1、防止不必要的消息传递:输入过滤器可以排除不关心的消息,减少网络层的处理负担。
2、提高网络效率:只有符合特定条件的消息才会被传递到上层,从而提高网络的效率。
3、增强网络安全性:输入过滤器可以阻止不合法或恶意的消息进入网络。
具体的流程:
/*BLE Mesh网络层接收数据子函数*/
/*源自开源协议栈NimBLE*/
void bt_mesh_net_recv(struct os_mbuf *data, s8_t rssi,
enum bt_mesh_net_if net_if)
{
struct os_mbuf *buf = NET_BUF_SIMPLE(29);
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_elem_find(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] = 0ULL;
/* 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);
}
通过点击以下链接,您可以获取BLE Mesh模块原理图、源代码以及开发资料。链接地址将为您提供详细的文件资料,以供您进行参考和使用。
如果您在使用过程中遇到任何问题或疑虑,欢迎加我QQ ,一起探讨技术问题,我的QQ号是986571840,加的时候请注明CSDN。
BLE Mesh蓝牙组网模块 - 硬创社 (jlc.com)https://x.jlc.com/platform/detail/001d23cba7b64b0d9df5b9b69720fadb
感谢各位用户点赞、分享、在看,这些行为让知识得以更加广泛地传播,从而让更多人受益。
请在转载作品时注明出处,严禁抄袭行为。