跳到主要内容

14.8 IEEE 802.15.4 和 6LoWPAN

上一节我们还在享受蓝牙带来的「个人区域网」便利,这一节我们要去一个更抠门、更严苛的世界。

那里没有带宽可以挥霍,每一个比特都要精打细算;那里的设备大部分时间都在睡觉,只有醒来那一瞬间才允许说话。这就是物联网的世界,主角是 IEEE 802.15.4 和跑在上面的 6LoWPAN

在这个世界里,标准的互联网协议(IPv6)遇到了巨大的麻烦。MTU 对不上地址太大塞不下组播不支持——每一个都是致命伤。但工程师们不仅解决了这些问题,还把 IPv6 成功塞进了这些只有几美元的微控制器里。

这节就是在讲「怎么把大象塞进冰箱」,而且还得塞得优雅。


8.1 什么是 IEEE 802.15.4?

先把标准摆出来:IEEE 802.15.4 定义了低速无线个人区域网(LR-WPANs)的 MAC 层物理层(PHY)

它的设计目标只有两个词:低成本低功耗

为了实现这两个目标,它做了很多妥协:

  • 速率低:最高 250 kb/s(2.4GHz 频段下),还有更慢的。
  • 距离短:通常就在 10 米左右转悠。
  • 帧小:物理层最大传输单元(MTU)只有 127 字节IEEE802154_MTU)。

这些设备通常是哪里来的?无线传感器网络(WSN)、安防传感器、工业自动化开关。标准由 IEEE 802.15 工作组维护。

在这层协议之上,通常坐着两个大佬:一个是 ZigBee(私有协议,虽然也有 ZigBee IP 这种开放标准),另一个就是我们今天的主角——6LoWPAN


8.2 为什么非要用 IPv6?

有人可能会问:这种破网速,用私有的协议不是更省事吗?

确实省事,但不自由。如果你想让你的传感器直接接入互联网,不想搞一大堆网关做协议转换,那就得用 IP。

IPv6 是这里唯一的选择,原因有三:

  1. 地址够多:IPv6 的地址空间是天文数字,能给世界上每一粒沙子都分配一个公网地址。这对于动辄成百上千个节点的传感器网络来说,是刚需。
  2. 包头更简单:IPv4 的头部长度可变,处理起来麻烦;IPv6 的头部固定,扩展头处理起来也比 IPv4 的 Option 简单。
  3. 自动配置:IPv6 的无状态地址自动配置(SLAAC)非常适合这种没人管的低端设备。

但问题是,IPv6 这种「贵族协议」,天生就不是为 IEEE 802.15.4 这种「贫民窟」设计的。为了让它跑起来,我们需要一个适配层,这就是 6LoWPAN

相关的 RFC 有一堆,这里列出来只是让你感受一下这个领域的活跃度,不用全背:

  • RFC 4944: 定义了怎么在 802.15.4 上传 IPv6 包(老标准)。
  • RFC 4919: 6LoWPAN 的总纲。
  • RFC 6282: 核心。引入了 LOWPAN_IPHC 这种更高效的编码格式,取代了旧时代的 HC1 和 HC2。
  • RFC 6775: 邻居发现优化。
  • RFC 6550: RPL 路由协议(针对低功耗有损网络)。

8.3 适配层的挑战:三个不匹配

现在我们来看看适配层到底要解决什么痛点。这三个问题如果解决不好,网络根本跑不起来。

挑战一:巨大的 MTU 鸿沟

  • IPv6 要求:链路 MTU 至少是 1280 字节。这是 IPv6 的底线,低于这个值,标准规定你得自己在网络层分片。
  • IEEE 802.15.4 提供:MTU 只有 127 字节

这是什么概念? 就像你要用一个小号信封(127字节)去寄一本厚书(1280字节)。适配层必须把这本厚书撕成 10 多个小碎片,发过去,再让对方拼起来。

这就是 6LoWPAN 适配层 的第一个核心任务:透明的分片与重组

挑战二:地址太长,塞不下

  • IPv6 地址:128 位。
  • IEEE 802.15.4 地址:要么是 64 位的扩展地址(IEEE802154_ADDR_LONG),要么是入网后分配的 16 位短地址(IEEE802154_ADDR_SHORT,只在 PAN 内唯一)。

如果我们不做压缩,光两个 IPv6 地址(源+目的)就要占掉 32 个字节,再加上包头,这包里还能装什么数据?

解决方案:利用 802.15.4 的短地址和链路本地前缀进行极致压缩。6LoWPAN 有一套复杂的压缩机制(IPHC),能将 40 字节的 IPv6 头部压缩成几个字节。

挑战三:组播失踪了

IPv6 特别依赖组播,尤其是 ICMPv6 和邻居发现协议(ND),全是靠组播活着的。

但 IEEE 802.15.4 不支持组播。它只支持广播(用 0xFFFF 短地址)。

这就像是大家都习惯喊「喂,所有人(组播)」,但底层硬件只懂「喂,大家(广播)」。适配层必须想办法把 IPv6 的组播请求「翻译」成硬件能理解的广播,或者干脆改写邻居发现协议(这就是 RFC 6775 干的事)。


8.4 帧类型与设备分类

IEEE 802.15.4 定义了四种帧类型,我们在内核代码里会经常看到它们的宏定义:

  • IEEE802154_FC_TYPE_BEACON:信标帧(用来同步网络)。
  • IEEE802154_FC_TYPE_MAC_CMD:MAC 命令帧。
  • IEEE802154_FC_TYPE_ACK:确认帧。
  • IEEE802154_FC_TYPE_DATA数据帧

IPv6 包只能坐在第四种车(数据帧)上。虽然 ACK 不是强制的,但谁用谁知道,开着更稳。

这里也有 HardMACSoftMAC 的区别(跟 Wi-Fi 一样):

  • HardMAC:硬件自己把协议干完了,驱动只管收数据。
  • SoftMAC:内核(MAC 层)干大部分活,硬件只负责撸信号。Linux 的 mac802154 就是干这个的。

网络里的三种角色

在 6LoWPAN 网络里,不是所有节点都生而平等。RFC 把它们分成了三六九等:

  1. 6LoWPAN Node (6LN)

    • 定义:可以是主机,也可以是路由器。
    • 特点:比较傻,能力有限,大部分时间在睡觉(省电)。
  2. 6LoWPAN Router (6LR)

    • 定义:能收发路由通告(RA/RS),还能转发数据包。
    • 特点:比 6LN 聪明点,内存和 CPU 稍微多点,负责在网内搬运数据。
  3. 6LoWPAN Border Router (6LBR)

    • 定义:网关节点。站在 6LoWPAN 网络和普通 IP 网络(比如以太网)的交界处。
    • 职责
      • 负责两个世界的数据转发。
      • 负责 6LoWPAN 节点的 IPv6 配置。
      • 维护上下文信息。
      • 几乎必须一直在线(不能睡觉)。

你可以把 6LBR 理解为一个辛苦的翻译官,一边是讲方言的传感器网络,一边是讲标准语的互联网,它得 24 小时盯着,不能睡。


8.5 邻居发现协议的「魔改」

普通的 IPv6 邻居发现(ND)协议在物联网里有两个大坑:

  1. 组播依赖:前面说了,硬件不支持。
  2. 功耗焦虑:ND 协议假设设备一直醒着,随时收听路由器的组播通告。但 802.15.4 设备大部分时间都在打瞌睡,为了收一个包醒来一次太费电。

于是,RFC 6775 对 ND 协议进行了针对性优化。

优化一:别再定期喊话了

标准 IPv6 里,路由器会定期发组播通告。 RFC 6775 说:。 改为 主机主动发起。主机想问路由器在不在,就发单播消息过去。路由器不用没事就喊。

优化二:地址唯一性检查(DAD)的简化

如果 IPv6 地址是基于 EUI-64 生成的(全球唯一),理论上不需要做重复地址检测(DAD)。省一步是一步。

新增的三个选项(Option)

为了支持上述优化,RFC 6775 给 ICMPv6 加了三个新选项:

  • Address Registration Option (ARO, Type 33)
    • 主机给路由器发单播 NS 消息时,带上这个选项,意思是「老大,我注册这个地址」。
    • 如果想注销,发个 lifetime 为 0 的 ARO 就行。
  • 6LoWPAN Context Option (6CO, Type 34)
    • 携带用于包头压缩的前缀信息。跟 IPv6 标准的 PIO 类似,但是给压缩层用的。
  • Authoritative Border Router Option (ABRO, Type 35)
    • 权威边界路由器选项。用来在网络里传播「谁才是老大(6LBR)」的信息,以及网络上下文。

新增的两个 ICMPv6 消息类型

为了处理地址冲突,还加了两个新消息:

  • Duplicate Address Request (DAR, Type 157)
  • Duplicate Address Confirmation (DAC, Type 158)

8.6 Linux 内核的实现:三层结构

Linux 内核从 v3.2 开始就把 6LoWPAN 纳进主线了(Siemens 团队贡献的)。代码结构分得很清楚,也是典型的三层:

  1. Network Layer (网络层)net/ieee802154
    • 包含 6lowpan 模块、Raw Socket、Netlink 接口等。
  2. MAC Layer (MAC 层)net/mac802154
    • 这是一个软 MAC 实现,负责处理 802.15.4 的 MAC 层逻辑,给 SoftMAC 驱动用。
  3. PHY Layer (驱动层)drivers/net/ieee802154
    • 各种具体的芯片驱动。

支持的硬件

虽然协议标准很宏大,但 Linux 内核实际支持的硬件并不多(相比于 Wi-Fi):

  • AT86RF230/231:Atmel(现 Microchip)的收发器。
  • MRF24J40:Microchip 的。
  • Fakelb:一个虚拟的回环驱动,用来在没有硬件时测试协议栈。
  • atusb:基于 AT86RF231 的 USB 棍子(有些在主线,有些还在折腾)。

这些设备大多通过 SPI 挂在主控板上,也有通过串口的(实验性)。


8.7 初始化与数据接收:代码视角

来看看代码是怎么跑起来的。

注册协议处理器

初始化函数 lowpan_init_module() 主要做两件事:

  1. 初始化 Netlink socket。
  2. 注册协议处理器

它定义了一个 packet_type 结构体 lowpan_packet_type,告诉内核:「凡是看到 ETH_P_IEEE802154 (0x00F6) 类型的包,都交给我处理」。

static struct packet_type lowpan_packet_type = {
.type = __constant_htons(ETH_P_IEEE802154),
.func = lowpan_rcv,
};

static int __init lowpan_init_module(void)
{
. . .
dev_add_pack(&lowpan_packet_type); // 把这个 handler 挂到内核协议栈上
. . .
}

这个 lowpan_rcv 就是 6LoWPAN 的 Rx 主入口函数。当数据包从物理层上来,经过 MAC 层处理后,最终会调用这个函数。

虚拟链路与解包

Linux 里面实现了一个很巧妙的「虚拟链路」机制来适配 MTU:

  • 一头(6LoWPAN Interface):MTU = 1280,说标准的 IPv6。
  • 另一头(WPAN Interface):MTU = 127,说 6LoWPAN 方言。

数据包进来的流程(lowpan_rcv):

  1. 判断:这是压缩包还是没压缩的包(Dispatch Type)?
  2. 解压:如果是压缩包,调用 lowpan_process_data()
    • 里面会调用 lowpan_uncompress_addr() 解压地址。
    • 调用 lowpan_uncompress_udp_header() 解压 UDP 头(如果是 UDP 的话)。
  3. 交付:解压完成后,还原成了一个标准的 IPv6 skb。
  4. 传递:调用 lowpan_skb_deliver(),把这个包交给那个 MTU 为 1280 的虚拟 6LoWPAN 接口。

到了这个接口上,内核的 IPv6 协议栈就会认领它,就像处理一个普通的以太网包一样。这就实现了「底层方言」到「上层标准语」的无缝翻译。


8.8 关于 Contiki 和其他资源

值得一提的是,Linux 的 6LoWPAN 实现里有一部分代码(比如 UDP 头压缩)其实是移植自 Contiki OS 的。

Contiki 是一个专门为物联网设计的开源操作系统,由 Adam Dunkels 开发。它在嵌入式圈子里地位很高,不仅实现了 6LoWPAN,还有 RPL 协议栈。Linux 社区站在巨人的肩膀上,把这层技术搬进了内核。

如果你想继续深挖,可以看:

  • 6LoWPAN: The Wireless Embedded Internet (Shelby & Bormann)
  • Interconnecting Smart Objects with IP (Vasseur & Dunkels)

管理工具方面,有一个 lowpan-tools 包,可以用来管理 Linux 的 LoWPAN 栈。


本章回响

从蓝牙到 6LoWPAN,我们看到了无线网络的两个极端。

上一节的蓝牙,像是在现代化的办公大楼里搭建会议室,带宽充裕,设备虽然小但能力不弱;而这一节的 6LoWPAN,像是在荒野里搭建对讲机网络,资源极度匮乏,每一个比特的传输都要计算成本。

但 Linux 内核的伟大之处在于,它用统一的网络栈抽象,把这些截然不同的物理层都统一到了 struct net_deviceTCP/IP 协议族之下。无论是软绵绵的蓝牙,还是硬核的工业无线,最终在 /dev 里的样子,都是一个网络接口。

不过,IEEE 802.15.4 和 6LoWPAN 毕竟是「短距离」无线。下一节,我们要去见识一个真正的「超短距离」技术——近到两台设备必须贴在一起才能通信。那就是 NFC(近场通信)

鼠标连不上,跑一下 btmon,一目了然。


本章回响

我们完成了从底层硬件驱动到上层 IP 协议的完整穿越。

表面上看,这一节是在讲「蓝牙怎么连上网」,实际上我们在看一个完整的网络子系统是如何分层协作的

  • HCI 层屏蔽了硬件差异(USB, UART, SDIO)。
  • L2CAP 层提供了多路复用和基础传输服务。
  • BNEP 层把异构的蓝牙链路伪装成了标准的以太网设备,让现有的 TCP/IP 协议栈无需修改即可运行。

还记得开头那个「办公大楼」的类比吗?现在你应该明白,Linux 蓝牙子系统之所以复杂,是因为它不仅要管理大楼的前台(HCI),还要管理收发室(L2CAP),甚至还要在大楼之间架设货运专线(BNEP)。每一层都有自己独立的状态机和协议,但又紧密咬合。

下一节,我们将从个人区域网(PAN)跳到更广阔、但也更底层的无线领域——IEEE 802.15.46LoWPAN。那是物联网的世界,那里的协议更精简,对资源更抠门,但设计哲学与蓝牙有着异曲同工之妙。