板子上插一块 WiFi 模组,用户态敲 iw / wpa_supplicant,内核里却常常分不清:nl80211、cfg80211、mac80211、厂商驱动、固件各自干啥。排障时「扫不到 AP」「连上没 IP」「吞吐只有几 Mbps」,也说不清卡在哪一层。
本文按嵌入式常见路径,把 Linux WiFi 软件栈 从用户态到硬件串成一条完整链路,覆盖 FullMAC / SoftMAC、扫描关联、数据收发、rfkill、设备树与调试手段,读完应对照源码与 iw 自己验证。
源码锚点
| 路径 | 作用 |
|---|---|
include/net/cfg80211.h |
struct cfg80211_ops、wiphy_new、cfg80211_connect_* |
net/wireless/ |
cfg80211 核心、nl80211 |
include/net/mac80211.h |
SoftMAC:struct ieee80211_ops、ieee80211_register_hw |
net/mac80211/ |
SoftMAC:MLME、聚合、速率控制协作 |
include/uapi/linux/nl80211.h |
用户态 ↔ 内核 Netlink 属性 |
include/linux/ieee80211.h |
802.11 帧头、能力位 |
include/linux/rfkill.h |
射频开关统一框架 |
Documentation/networking/mac80211* / wireless |
内核文档 |
注册 SoftMAC 网卡(概念):
c
/* include/net/mac80211.h */
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops);
int ieee80211_register_hw(struct ieee80211_hw *hw);
FullMAC / cfg80211 直连(概念):
c
/* include/net/cfg80211.h */
struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
int wiphy_register(struct wiphy *wiphy);
先建立分层:谁管配置,谁管收发包
#mermaid-svg-XS5kOwFsrhOU7tXo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XS5kOwFsrhOU7tXo .error-icon{fill:#552222;}#mermaid-svg-XS5kOwFsrhOU7tXo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XS5kOwFsrhOU7tXo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XS5kOwFsrhOU7tXo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XS5kOwFsrhOU7tXo .marker.cross{stroke:#333333;}#mermaid-svg-XS5kOwFsrhOU7tXo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XS5kOwFsrhOU7tXo p{margin:0;}#mermaid-svg-XS5kOwFsrhOU7tXo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XS5kOwFsrhOU7tXo .cluster-label text{fill:#333;}#mermaid-svg-XS5kOwFsrhOU7tXo .cluster-label span{color:#333;}#mermaid-svg-XS5kOwFsrhOU7tXo .cluster-label span p{background-color:transparent;}#mermaid-svg-XS5kOwFsrhOU7tXo .label text,#mermaid-svg-XS5kOwFsrhOU7tXo span{fill:#333;color:#333;}#mermaid-svg-XS5kOwFsrhOU7tXo .node rect,#mermaid-svg-XS5kOwFsrhOU7tXo .node circle,#mermaid-svg-XS5kOwFsrhOU7tXo .node ellipse,#mermaid-svg-XS5kOwFsrhOU7tXo .node polygon,#mermaid-svg-XS5kOwFsrhOU7tXo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XS5kOwFsrhOU7tXo .rough-node .label text,#mermaid-svg-XS5kOwFsrhOU7tXo .node .label text,#mermaid-svg-XS5kOwFsrhOU7tXo .image-shape .label,#mermaid-svg-XS5kOwFsrhOU7tXo .icon-shape .label{text-anchor:middle;}#mermaid-svg-XS5kOwFsrhOU7tXo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XS5kOwFsrhOU7tXo .rough-node .label,#mermaid-svg-XS5kOwFsrhOU7tXo .node .label,#mermaid-svg-XS5kOwFsrhOU7tXo .image-shape .label,#mermaid-svg-XS5kOwFsrhOU7tXo .icon-shape .label{text-align:center;}#mermaid-svg-XS5kOwFsrhOU7tXo .node.clickable{cursor:pointer;}#mermaid-svg-XS5kOwFsrhOU7tXo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XS5kOwFsrhOU7tXo .arrowheadPath{fill:#333333;}#mermaid-svg-XS5kOwFsrhOU7tXo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XS5kOwFsrhOU7tXo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XS5kOwFsrhOU7tXo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XS5kOwFsrhOU7tXo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XS5kOwFsrhOU7tXo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XS5kOwFsrhOU7tXo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XS5kOwFsrhOU7tXo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XS5kOwFsrhOU7tXo .cluster text{fill:#333;}#mermaid-svg-XS5kOwFsrhOU7tXo .cluster span{color:#333;}#mermaid-svg-XS5kOwFsrhOU7tXo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XS5kOwFsrhOU7tXo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XS5kOwFsrhOU7tXo rect.text{fill:none;stroke-width:0;}#mermaid-svg-XS5kOwFsrhOU7tXo .icon-shape,#mermaid-svg-XS5kOwFsrhOU7tXo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XS5kOwFsrhOU7tXo .icon-shape p,#mermaid-svg-XS5kOwFsrhOU7tXo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XS5kOwFsrhOU7tXo .icon-shape .label rect,#mermaid-svg-XS5kOwFsrhOU7tXo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XS5kOwFsrhOU7tXo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XS5kOwFsrhOU7tXo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XS5kOwFsrhOU7tXo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 内核数据面与驱动
内核配置面
用户态
SoftMAC
FullMAC
netif 收发
netif 收发
wpa_supplicant / hostapd / NetworkManager
iw / iwconfig
DHCP / 路由 / nftables
nl80211 Netlink
cfg80211
驱动类型?
mac80211 SoftMAC
FullMAC 厂商驱动
固件 Firmware
WiFi 硬件 / SDIO/USB/PCIe
一句话:
- cfg80211 + nl80211:统一「配置面」------扫描、关联、密钥、AP 模式、监管域。
- mac80211 :SoftMAC 芯片由内核做大部分 802.11 MAC;驱动实现
ieee80211_ops(收发、队列、密钥等)。 - FullMAC :MAC 多在固件;驱动主要实现
cfg80211_ops,把配置下到固件,并把网卡挂到网络栈。
嵌入式模组(如多数 SDIO WiFi)FullMAC 居多 ;部分 USB/PCIe 芯片走 SoftMAC。看驱动是否调用 ieee80211_register_hw 还是只 wiphy_register 即可判断。
调用链:从「连热点」到硬件
配置面:关联 AP
#mermaid-svg-Mhk8QrnCjuYAk0D4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .error-icon{fill:#552222;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .marker.cross{stroke:#333333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 p{margin:0;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .cluster-label text{fill:#333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .cluster-label span{color:#333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .cluster-label span p{background-color:transparent;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .label text,#mermaid-svg-Mhk8QrnCjuYAk0D4 span{fill:#333;color:#333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .node rect,#mermaid-svg-Mhk8QrnCjuYAk0D4 .node circle,#mermaid-svg-Mhk8QrnCjuYAk0D4 .node ellipse,#mermaid-svg-Mhk8QrnCjuYAk0D4 .node polygon,#mermaid-svg-Mhk8QrnCjuYAk0D4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .rough-node .label text,#mermaid-svg-Mhk8QrnCjuYAk0D4 .node .label text,#mermaid-svg-Mhk8QrnCjuYAk0D4 .image-shape .label,#mermaid-svg-Mhk8QrnCjuYAk0D4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .rough-node .label,#mermaid-svg-Mhk8QrnCjuYAk0D4 .node .label,#mermaid-svg-Mhk8QrnCjuYAk0D4 .image-shape .label,#mermaid-svg-Mhk8QrnCjuYAk0D4 .icon-shape .label{text-align:center;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .node.clickable{cursor:pointer;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .arrowheadPath{fill:#333333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Mhk8QrnCjuYAk0D4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Mhk8QrnCjuYAk0D4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Mhk8QrnCjuYAk0D4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .cluster text{fill:#333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .cluster span{color:#333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Mhk8QrnCjuYAk0D4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .icon-shape,#mermaid-svg-Mhk8QrnCjuYAk0D4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .icon-shape p,#mermaid-svg-Mhk8QrnCjuYAk0D4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .icon-shape .label rect,#mermaid-svg-Mhk8QrnCjuYAk0D4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Mhk8QrnCjuYAk0D4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Mhk8QrnCjuYAk0D4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Mhk8QrnCjuYAk0D4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} wpa_supplicant: ADD_NETWORK / ENABLE
nl80211 CONNECT
cfg80211
cfg80211_ops.connect 或 auth/assoc
驱动下发固件 / SoftMAC MLME
cfg80211_connect_result / connect_bss
用户态得知已关联
DHCP 拿 IP
成功/失败必须回调:cfg80211_connect_result() / cfg80211_connect_bss() / cfg80211_connect_timeout()(见 cfg80211.h 注释约定)。驱动只「发出去不回报」会导致用户态一直卡住。
SoftMAC 数据面(示意)
text
上层 IP 包 → netdev → mac80211 封装 802.11
→ ieee80211_ops.tx → 驱动 DMA/总线 → 射频
接收:硬件中断/NAPI → 驱动上报 → ieee80211_rx*
→ mac80211 解密/重组 → netif_receive_skb
FullMAC 数据面(示意)
text
netdev.ndo_start_xmit → 驱动封装厂商协议 → SDIO/USB 写固件队列
固件完成 802.11;RX 路径反向,驱动把以太网帧交给协议栈
重点知识
1. cfg80211_ops:配置面契约
struct cfg80211_ops(include/net/cfg80211.h)是驱动向 cfg80211 注册的后端。嵌入式最常碰到:
| 回调(概念) | 作用 |
|---|---|
scan |
扫描;完成后 cfg80211_scan_done |
connect / disconnect |
SME 连接(FullMAC 常见) |
auth / assoc |
拆分认证关联(部分驱动) |
add_key / del_key / set_default_key |
WPA/WPA2/WPA3 密钥 |
start_ap / stop_ap |
AP / SoftAP |
set_wiphy_params |
RTS、分片等 |
set_power_mgmt |
省电 |
驱动必须先 wiphy_new → 填能力(频段、cipher、interface modes)→ wiphy_register,再创建 wireless_dev / netdev。
2. mac80211 与 ieee80211_ops
SoftMAC 驱动实现 ieee80211_ops:start/stop、tx、add_interface、config、bss_info_changed、set_key、ampdu_action 等。
mac80211 负责:beacon 处理、关联状态机、聚合、速率控制协作、与 cfg80211 对接。
注册:ieee80211_alloc_hw → 填 hw->wiphy 能力 → ieee80211_register_hw。
3. nl80211 与用户态工具
| 工具 | 角色 |
|---|---|
iw |
直接 nl80211:scan、link、reg、info |
wpa_supplicant |
STA:扫描、WPA、漫游、与 DHCP 协作 |
hostapd |
AP |
| NetworkManager / connman | 桌面/发行版集成 |
调试先确认内核侧:iw dev、iw phy,再查用户态配置,避免「驱动没起来却调 wpa」。
4. Interface 模式与并发
NL80211_IFTYPE_STATION / AP / MONITOR / P2P_* 等。嵌入式常要 STA+AP 并发 (手机热点同理),取决于固件/驱动是否声明组合能力(interface_combinations)。能力不够会出现「开 SoftAP 后 STA 掉线」。
5. 监管域 Regulatory
频段、功率受国家码约束。iw reg get / iw reg set CN;设备树或驱动也可带默认 regdomain。错误监管会导致「扫不到 5G」或非法信道。
6. rfkill
rfkill 统一软/硬射频开关。rfkill list;硬开关(机身拨码)会 block WiFi。现象:驱动加载了但 iw 扫描失败、日志有 rfkill。
7. 总线与固件(嵌入式痛点)
| 总线 | 关注点 |
|---|---|
| SDIO | 时钟、电源时序、MMC 控制器、mmc 报错 |
| USB | 电流、hub、固件加载超时 |
| PCIe | ASPM、BAR、MSI |
固件路径通常 /lib/firmware/...;缺失则 probe 失败。看 dmesg 中 Direct firmware load ... failed。
设备树示例要素(概念):兼容字符串、interrupt、vmmc/vqmmc 电源、pinctrl、校准数据分区。
8. 安全与加密
WPA2-PSK / WPA3-SAE 密钥下发走 add_key;PMF、SAE 依赖驱动/固件能力位。嵌入式旧模组常「能连 WPA2、不能 WPA3」。
9. 性能与省电
- 吞吐 :聚合 AMPDU、总线带宽、CPU 软中断、
txqueue。 - 延迟:省电 PS / uAPSD 会换延迟;产线测吞吐时常关省电。
- 天线 / 校准:校准数据错误 → RSSI 差、易掉线。
10. 排障路径
| 现象 | 先查 |
|---|---|
| 无 wlan0 | probe、固件、设备树、rfkill |
| 扫不到 AP | 监管域、天线、区域、驱动 scan 回调 |
| 关联失败 | 密钥、超时回调、固件崩溃 |
| 有 link 无 IP | 上层 DHCP/网络命名空间,非 WiFi MAC |
| 吞吐差 | 总线、省电、干扰、信道宽 |
常用命令:
bash
dmesg | grep -iE 'wlan|firmware|cfg80211|brcm|nl80211'
ip link; iw dev; iw phy
rfkill list
iw dev wlan0 scan | head
iw dev wlan0 link
cat /sys/kernel/debug/ieee80211/*/stations/*/rc_stats 2>/dev/null # SoftMAC 示例
Checklist
- 能画出:用户态 → nl80211 → cfg80211 → FullMAC/mac80211 → 固件 → 硬件
- 能判断本板驱动是 FullMAC 还是 SoftMAC
- 关联路径上知道必须有
cfg80211_connect_*类结果回调 - 会用
iw/rfkill/dmesg区分「没模组」与「上层配置错」 - 清楚 STA/AP 并发依赖
interface_combinations - 查过固件路径与设备树电源/中断
- 吞吐问题先排除省电与总线,再查 802.11 层
成稿:
articles/csdn-merged/嵌入式Linux-WiFi框架完整篇.md