Linux 无线网络驱动开发 之 子系统源码框架(nl80211、cfg80211、mac80211)
基础框架
基础概念
- nl80211
作用:用户空间与内核空间无线配置的接口(Netlink API)
功能:提供基于 netlink 的通信机制,允许用户空间工具配置和管理无线设备
代码位置:net/wireless/nl80211.c - cfg80211
作用:无线配置框架,管理所有无线设备和驱动
功能:
1)提供统一的无线配置接口(如设置频段、信道、功率等)
2)管理 mac80211 和直接支持 FullMAC 的硬件
3)处理 MLME(MAC Layer Management Entity)逻辑(如认证、关联)
代码位置:net/wireless/ - mac80211
作用:driver开发者可用于为SoftMAC无线设备写驱动的框架,处理大部分 802.11 MAC 层功能
功能:
1)实现 Beacon 处理、ACK 管理、速率控制、加密(WPA/WPA2) 等
2)依赖硬件驱动实现 PHY 层操作(如发送/接收数据包)
3)支持 AP、STA、Monitor、Mesh 等多种模式
代码位置:net/mac80211/
理解
- nl80211是介于用户空间与内核空间之间的 API ,可以算是 cfg80211 的前端
- cfg80211 是设备和用户空间之间的桥梁,工作则是跟踪 WLAN 设备所处的实际状态
- mac80211 的工作是给出硬件的所有功能和与硬件进行交互
- 如果某些功能无法由设备硬件实现,那么就可以以纯软的方式实现,其也被称为 “Soft MAC” 模块,与 “Hard MAC” (由设备固件完成所有工作)相对。实际项目中通常是这两种方案混合使用的
那我们怎么去代码理解这几个组件呢,下面我将用一个管理路径的方式,去分析理解
iw dev wlan1 scan命令是如何调用到wifi驱动的
基本调用框架图
逻辑图
-
首先是iw工具
iw 源码获取:git clone https://git.kernel.org/pub/scm/linux/kernel/git/jberg/iw.git
编译完成后进行源码跟踪,将iw工具编译后命名为iw-debug. -
添加打印
从如下调用就可看到iw最后调用的是libnl库函数 ---------> 理解iw到libnl的框架图
执行命令查看调用路径:
-
使用strace命令跟踪iw调用
sudo strace -e socket,sendmsg,recvmsg iw dev wlan1 scan
消息的构造发生在iw工具,从下面的棘突也能看出,并且对应的是scan指令
libnl我们就不跟踪了,我们知道是一个非常好用的库就行了 -
nl80211接收来自应用层的netlink消息
内核源码中,genl_init 是 Linux 内核中 Generic Netlink(通用 Netlink)框架的初始化函数,负责在系统启动时注册 Generic Netlink 的核心组件
nl80211通过genl_family_rcv_msg接收netlink信息,通过回调函数nl80211_pre_doit, 查找cfg80211注册时的设备信息dev
-
nl80211初始化
-
nl80211消息传递给cfg80211
rdev_scan 函数已经属于 cfg80211 组件的范畴
-
ops直接调用到mac80211
-
调用到驱动函数
驱动扫描函数实现
有管理路径针对管理帧,数据路径针对数据帧,所以还有数据路径,数据和管理路径在 mac80211 里面是分开实现的。
数据路径发送
- 内核协议栈 → mac80211
调用逻辑
→ neigh_resolve_output()→ dev_queue_xmit() → __dev_xmit_skb()→ sch_direct_xmit()→ dev_hard_start_xmit()→ netdev_start_xmit()
2. mac80211 → 驱动(ath9k/ath9k_htc)
调用路径:
ieee80211_subif_start_xmit()//mac802111入口函数-->__ieee80211_subif_start_xmit()-->ieee80211_xmit()-->ieee80211_tx()-->__ieee80211_tx()-->ieee80211_tx_frags()-->drv_tx()-->[local->ops->tx()]
调用drv_tx(),把帧传递给驱动
-
驱动(ath9k/ath9k_htc)
-
驱动 → 硬件
USB 设备(ath9k_htc):
通过 USB Bulk 传输发送 HTC 协议封装的数据包。
数据路径接收
- 硬件中断 → 驱动
中断处理:网卡收到数据后触发中断。
USB 设备:USB 回调函数 - 驱动 → mac80211
如下是ieee80211_rx的源码解释:
- mac80211 → 内核协议栈
解密和校验:处理 WPA/WPA2 解密、校验帧完整性。
协议栈上传:通过 netif_receive_skb() 将数据包传递给 TCP/IP 协议栈
如果收到的帧是数据,它将被转换成 802.3 数据帧(通过 __ieee80211_data_to_8023 实现),然后该数据帧将通过 netif_receive_skb 交付到网络协议栈。在协议栈中,各层网络协议将会对数据进行解析,识别协议首部。
- 协议栈 → 用户空间
Socket 接收:用户程序通过 recv() 或 read() 读取数据。
什么是MLME
即MAC(Media Access Control ) Layer Management Entity,它管理物理层MAC状态机,负责 认证、关联、扫描、省电模式 等
如何理解MLME
- MLME 功能(扫描、认证、关联、省电模式等)由 mac80211 在软件中实现
- mac80211 不参与管理,仅通过 cfg80211 去操作MLME功能
- 简单点理解可以为 cfg80211负责管理,mac80211负责实现MLME功能
疑问?
- 既然iw工具可以创建socket并连接netlink,为什么要需要调用libnl去发送消息给nl80211?
若直接使用原生 Socket,代码量可能增加 3-5 倍,且难以维护,安全性、稳定性也难以保证 - MLME跟wifi状态机有什么关系?
mlme是管理wifi 状态机的,wifi状态机是 MLME 的具体实现方式
这里是简单的框架梳理,希望能够抛砖引玉,谢谢