Linux Wireless之WiFi Beacon Hint 流程分析
Linux Wireless之WiFi Beacon Hint 流程分析
背景及概述
最近遇到了个问题,机器在使用无线的时候,wpa_supplicant 报了如下日志:
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Event message available
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Drv Event 42 (NL80211_CMD_REG_BEACON_HINT) received for wlo4
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Regulatory beacon hint
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Channel (before): freq=5180 max_tx_power=2000 no-IR
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Channel (after): freq=5180 max_tx_power=2000
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: wlo4: Event CHANNEL_LIST_CHANGED (27) received
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: wlo4: CTRL-EVENT-REGDOM-CHANGE init=BEACON_HINT type=UNKNOWN
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: wlo4: Updating hw mode
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Regulatory information - country=00
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 2402-2472 @ 40 MHz 20 mBm
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 2457-2482 @ 20 MHz 20 mBm (no IR)
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 2474-2494 @ 20 MHz 20 mBm (no OFDM) (no IR)
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 5170-5250 @ 80 MHz 20 mBm (no IR)
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 5250-5330 @ 80 MHz 20 mBm (DFS) (no IR)
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 5490-5730 @ 160 MHz 20 mBm (DFS) (no IR)
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 5735-5835 @ 80 MHz 20 mBm (no IR)
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: 57240-63720 @ 2160 MHz 0 mBm
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Added 802.11b mode based on 802.11g information
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Mode IEEE 802.11g: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467[NO_IR] 2472[NO_IR] 2484[NO_IR]
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Mode IEEE 802.11a: 5180 5200[NO_IR] 5220[NO_IR] 5240[NO_IR] 5260[NO_IR][RADAR] 5280[NO_IR][RADAR] 5300[NO_IR][RADAR] 5320[NO_IR][RADAR] 5500[NO_IR][RADAR] 5520[NO_IR][RADAR] 5540[NO_IR][RADAR] 5560[NO_IR][RADAR]
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: nl80211: Mode IEEE 802.11b: 2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467[NO_IR] 2472[NO_IR] 2484[NO_IR]
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: wlo4: Determining shared radio frequencies (max len 1)
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: wlo4: Shared frequencies (len=0): completed iteration
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: Add operating class 81
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: Channels - hexdump(len=11): 01 02 03 04 05 06 07 08 09 0a 0b
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: Add operating class 115
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: Channels - hexdump(len=1): 24
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: Add operating class 130
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: Channels - hexdump(len=1): 24
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: Update channel list
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: channels: 81:1,2,3,4,5,6,7,8,9,10,11 115:36 130:36
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: P2P: cli_channels:
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: wlo4: Already scanning - Reschedule the incoming scan req
Jun 4 15:25:29 3-5-pc wpa_supplicant[26279]: wlo4: Setting scan request: 1.000000 sec
触发了 Beacon Hint 机制,今天就来看看 Beacon Hint 机制及其流程。
Beacon Hint 是 Linux 内核无线子系统 (cfg80211) 的一种机制,用于在 World Roaming 模式下,通过扫描发现 AP 的 Beacon 帧,自动解锁受限信道 (如 2.4GHz ch12-13 或 5GHz 非 DFS 信道)。
它其实属于无线监管域( Regulatory Domain )处理的一部分,在前面分析监管域处理流程的时候也有提到:
- https://mp.weixin.qq.com/s/pycGds6vCYfKgHWmQkliYg
- https://notes.z-dd.online/2026/06/08/Linux%20Wireless%E4%B9%8BWIFI%E7%9B%91%E7%AE%A1%E5%9F%9F%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B/
Beacon Hint 完整流程
┌─────────────────────────────────────────────────────────────────────────────┐
│ Beacon Hint 完整流程 │
└─────────────────────────────────────────────────────────────────────────────┘
[扫描阶段]
│
├─ WiFi 驱动执行扫描
│
├─ 发现 BSS (Beacon 帧)
│ │
│ └─ 调用 regulatory_hint_found_beacon()
│ │
│ ├─ 过滤: 已发现/雷达/2.4G ch1-11
│ │
│ └─ 加入 reg_pending_beacons 列表
│
└─ 调度 reg_work 工作队列
[处理阶段]
│
├─ reg_todo() 工作函数
│ │
│ └─ reg_process_pending_beacon_hints()
│ │
│ └─ 遍历所有 wiphy
│ │
│ └─ handle_reg_beacon()
│ │
│ ├─ 检查 World Roaming
│ │
│ ├─ 移除 NO_IR 标志
│ │
│ └─ 发送 Netlink 事件
│
└─ Realtek 驱动处理(驱动私有处理)
│
├─ rtw_process_beacon_hint()
│ │
│ └─ 移除 RTW_CHF_NO_IR
│
└─ rtw_beacon_hint_ch_change_notifier()
│
└─ 更新 regulatory 并通知
[过期阶段](驱动私有处理)
│
└─ rtw_beacon_hint_expire()
│
└─ 恢复 NO_IR 标志
flowchart TD
A[扫描发现 BSS] --> B{是否已发现 beacon?}
B -->|是| C[跳过]
B -->|否| D{是雷达信道?}
D -->|是| C
D -->|否| E{2.4G ch1-11?}
E -->|是| C
E -->|否| F[regulatory_hint_found_beacon]
F --> G{已在 pending 列表?}
G -->|是| C
G -->|否| H[分配 reg_beacon]
H --> I[加入 reg_pending_beacons]
I --> J[调度 reg_work 工作队列]
J --> K[reg_todo]
K --> L[reg_process_pending_beacon_hints]
L --> M[遍历所有 wiphy]
M --> N[wiphy_update_new_beacon]
N --> O[handle_reg_beacon]
O --> P{信道匹配?}
P -->|否| C
P -->|是| Q{beacon_found?}
Q -->|是| C
Q -->|否| R[设置 beacon_found = true]
R --> S{World Roaming?}
S -->|否| C
S -->|是| T{DISABLE_BEACON_HINTS?}
T -->|是| C
T -->|否| U{有 NO_IR 标志?}
U -->|否| C
U -->|是| V[移除 NO_IR 标志]
V --> W[nl80211_send_beacon_hint_event]
W --> X[通知用户空间]
关键函数说明
内核 cfg80211 层
| 函数 | 文件 | 说明 |
|---|---|---|
regulatory_hint_found_beacon() |
reg.c:3666 | 入口函数,扫描发现 beacon 时调用 |
reg_process_pending_beacon_hints() |
reg.c:3138 | 处理待处理的 beacon hints |
handle_reg_beacon() |
reg.c:2187 | 处理单个 beacon,移除 NO_IR |
wiphy_update_new_beacon() |
reg.c:2231 | 更新 wiphy 的 beacon 信息 |
reg_is_world_roaming() |
reg.c:2164 | 判断是否 world roaming 模式 |
is_world_regdom() |
reg.c:369 | 判断 alpha2 是否为 “00” |
nl80211_send_beacon_hint_event() |
nl80211.c:18663 | 发送 netlink 事件 |
World Roaming 判断条件
判断流程
flowchart TD
A[reg_is_world_roaming] --> B{cr->alpha2是否为00?}
B -->|是| C[返回 true]
B -->|否| D{wr->alpha2是否为00?}
D -->|是| C
D -->|否| E{last_request 存在?}
E -->|否| F[返回 false]
E -->|是| G{initiator != COUNTRY_IE?}
G -->|否| F
G -->|是| H{wiphy 有 CUSTOM_REG?}
H -->|是| C
H -->|否| F
判断函数
static bool reg_is_world_roaming(struct wiphy *wiphy)
{
const struct ieee80211_regdomain *cr = get_cfg80211_regdom();
const struct ieee80211_regdomain *wr = get_wiphy_regdom(wiphy);
struct regulatory_request *lr = get_last_request();
// 条件1: alpha2 为 "00" (world regdom)
if (is_world_regdom(cr->alpha2) || (wr && is_world_regdom(wr->alpha2)))
return true;
// 条件2: 驱动自定义 regdom 且非 country IE 触发
if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)
return true;
return false;
}
触发场景
| 场景 | alpha2 | 说明 |
|---|---|---|
| 初始启动 | “00” | regulatory_hint_core("00") |
| 用户设置 | “00” | iw reg set 00 |
| CRDA 失败 | “00” | 查询失败回退到 world regdom |
| 驱动自定义 | 任意 | 设置 REGULATORY_CUSTOM_REG |
查看当前状态
# 查看当前 regulatory domain
iw reg get
# World Roaming 模式输出:
country 00: DFS-UNSET
(2402 - 2472 @ 40), (N/A, 20), (N/A)
(2457 - 2482 @ 20), (N/A, 20), (N/A), NO-IR
...
# 已确定国家输出:
country CN: DFS-FCC
(2402 - 2482 @ 40), (N/A, 20), (N/A)
...
Netlink 事件格式
NL80211_CMD_REG_BEACON_HINT
┌─────────────────────────────────────────────────────────────┐
│ Netlink Message │
├─────────────────────────────────────────────────────────────┤
│ NL80211_CMD_REG_BEACON_HINT │
├─────────────────────────────────────────────────────────────┤
│ NL80211_ATTR_WIPHY (wiphy index) │
├─────────────────────────────────────────────────────────────┤
│ NL80211_ATTR_FREQ_BEFORE (变化前信道) │
│ ├─ frequency │
│ ├─ channel │
│ └─ flags (NO_IR, DFS, etc.) │
├─────────────────────────────────────────────────────────────┤
│ NL80211_ATTR_FREQ_AFTER (变化后信道) │
│ ├─ frequency │
│ ├─ channel │
│ └─ flags (NO_IR removed) │
└─────────────────────────────────────────────────────────────┘
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DD'Notes!
评论





