Linux Wireless之WIFI监管域处理流程
Linux Wireless之WIFI监管域处理流程
1. 概述
Linux无线监管域(Regulatory Domain)是cfg80211无线子系统中的核心组件,负责管理无线设备的频段、功率、信道使用规则等参数。
前面有简单介绍了Linux下的WIFI无线监管域:
- https://mp.weixin.qq.com/s/MWMEiofdlPP4UD7vwaGiKA
- https://notes.z-dd.online/2025/10/27/WIFI%E6%97%A0%E7%BA%BF%E7%BD%91%E7%BB%9C%E4%B9%8B%E6%97%A0%E7%BA%BF%E7%9B%91%E7%AE%A1%E5%9F%9F/
今天来看看整个监管域处理流程(基于内核v7.1.0-rc6)。
2. 机制演进
Linux无线监管域机制经历了三个主要阶段演进:
- CRDA用户空间方案 (早期)
- 内核通过udev事件通知用户空间需要监管域
- CRDA守护进程响应请求,通过nl80211发送监管规则
- 需要udev规则:
KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda"
- 内置数据库方案 (中期)
- 引入
regulatory.db固件文件,编译时可链接到内核 - 通过
request_firmware_nowait()异步加载 - 支持签名验证(
load_builtin_regdb_keys()) - 保留CRDA作为后备方案(
CONFIG_CFG80211_CRDA_SUPPORT)
- 引入
- 自监管设备方案 (现代)
- 引入
REGULATORY_WIPHY_SELF_MANAGED标志 - 设备固件/驱动自行管理监管域,忽略外部提示
- 通过
regulatory_set_wiphy_regd()接口设置 - 不共享监管信息,独立于系统其他设备
- 引入
3. 整体架构图
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Linux无线监管域架构 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 用户空间 │ │ CRDA/ │ │ regulatory │ │ 内置数据库 │ │
│ │ iw/ip │ │ regdb │ │ .db文件 │ │ │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ nl80211 接口层 │ │
│ │ NL80211_CMD_SET_REG / NL80211_CMD_REQ_SET_REG / NL80211_CMD_GET_REG │ │
│ └────────────────────────────────┬────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 监管域核心 (reg.c) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 请求队列 │ │ 提示处理 │ │ 域交集算法 │ │ 数据库查询 │ │ │
│ │ │ reg_requests│ │ reg_process │ │ intersect │ │ query_regdb │ │ │
│ │ │ _list │ │ _hint │ │ │ │ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └────────────────────────────────┬────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 监管域应用层 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ wiphy更新 │ │ 信道处理 │ │ 规则应用 │ │ 通知机制 │ │ │
│ │ │ update_all │ │ handle_ │ │ map_regdom │ │ nl80211_ │ │ │
│ │ │ _wiphy │ │ channel │ │ _flags │ │ send_event │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └────────────────────────────────┬────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 无线驱动层 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 驱动提示 │ │ 自监管设备 │ │ 信标发现 │ │ DFS处理 │ │ │
│ │ │ regulatory │ │ wiphy_self │ │ found_ │ │ radar_ │ │ │
│ │ │ _hint │ │ _managed │ │ beacon │ │ detected │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
4. 监管域初始化流程
4.1 初始化流程图
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 监管域初始化流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ cfg80211_init() │
│ │ │
│ ▼ │
│ ┌────────────────────┐ │
│ │ regulatory_init() │ reg.c:4328 │
│ └─────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 1. 创建虚拟设备 reg_fdev │ │
│ │ faux_device_create("regulatory", NULL, NULL) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 2. 设置初始世界监管域 │ │
│ │ rcu_assign_pointer(cfg80211_regdomain, │ │
│ │ cfg80211_world_regdom) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 3. 初始化用户alpha2为 '97' (未配置) │ │
│ │ user_alpha2[0] = '9'; user_alpha2[1] = '7' │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 4. regulatory_init_db() │ │
│ │ late_initcall (内核模块) 或直接调用 (可加载模块) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 4.1 load_builtin_regdb_keys() │ │
│ │ 加载内置签名密钥 │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 4.2 regulatory_hint_core("00") │ │
│ │ 发送核心监管提示 (世界监管域) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 4.3 检查模块参数 ieee80211_regdom │ │
│ │ 如果非"00",调用 regulatory_hint_user() │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
4.2 世界监管域定义
// reg.c:233
static const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 8,
.alpha2 = "00",
.reg_rules = {
/* 2.4GHz: 信道 1-11 */
REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
/* 2.4GHz: 信道 12-13 */
REG_RULE(2467-10, 2472+10, 20, 6, 20, NL80211_RRF_NO_IR | NL80211_RRF_AUTO_BW),
/* 2.4GHz: 信道 14 (仅日本) */
REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM),
/* 5GHz: 信道 36-48 */
REG_RULE(5180-10, 5240+10, 80, 6, 20, NL80211_RRF_NO_IR | NL80211_RRF_AUTO_BW),
/* 5GHz: 信道 52-64 (DFS) */
REG_RULE(5260-10, 5320+10, 80, 6, 20, NL80211_RRF_NO_IR | NL80211_RRF_AUTO_BW | NL80211_RRF_DFS),
/* 5GHz: 信道 100-144 (DFS) */
REG_RULE(5500-10, 5720+10, 160, 6, 20, NL80211_RRF_NO_IR | NL80211_RRF_DFS),
/* 5GHz: 信道 149-165 */
REG_RULE(5745-10, 5825+10, 80, 6, 20, NL80211_RRF_NO_IR),
/* 60GHz: 信道 1-3 */
REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),
}
};
5. 监管域请求处理流程
5.1 请求来源与处理流程图
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 监管请求处理流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 用户空间 │ │ 驱动 │ │ AP国家IE │ │ 核心 │ │
│ │ iw set │ │ regulatory│ │ country │ │ regulatory│ │
│ │ reg │ │ _hint() │ │ _ie │ │ _hint_ │ │
│ │ country │ │ │ │ │ │ core() │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ regulatory_hint_*() 函数族 │ │
│ │ - regulatory_hint_user() reg.c:3244 │ │
│ │ - regulatory_hint() reg.c:3316 │ │
│ │ - regulatory_hint_country_ie() reg.c:3344 │ │
│ │ - regulatory_hint_core() reg.c:3225 │ │
│ └────────────────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ queue_regulatory_request() reg.c:3209 │ │
│ │ 1. 转换alpha2为大写 │ │
│ │ 2. 加入 reg_requests_list 链表 │ │
│ │ 3. 调度 reg_work 工作队列 │ │
│ └────────────────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ reg_todo() 工作队列处理 reg.c:3200 │ │
│ └────────────────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ reg_process_pending_hints() reg.c:3084 │ │
│ │ 1. 检查 last_request->processed 状态 │ │
│ │ 2. 从 reg_requests_list 取出第一个请求 │ │
│ │ 3. 调用 reg_process_hint() 处理 │ │
│ └────────────────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ reg_process_hint() reg.c:3013 │ │
│ │ │ │
│ │ switch(initiator) { │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ BY_CORE ──► reg_process_hint_core() reg.c:2675 │ │ │
│ │ │ BY_USER ──► reg_process_hint_user() reg.c:2734 │ │ │
│ │ │ BY_DRIVER ► reg_process_hint_driver() reg.c:2790 │ │ │
│ │ │ BY_COUNTRY ►reg_process_hint_country_ie() reg.c:2894 │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ reg_query_database() reg.c:1111 │ │
│ │ 1. query_regdb_file() - 查询内置数据库 │ │
│ │ 2. call_crda() - 调用CRDA用户空间守护进程 │ │
│ └────────────────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ set_regdom() reg.c:3942 │ │
│ │ 设置监管域并应用到所有wiphy │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
5.2 请求处理结果枚举
// reg.c:73
enum reg_request_treatment {
REG_REQ_OK, // 继续处理请求
REG_REQ_IGNORE, // 忽略请求
REG_REQ_INTERSECT, // 需要与当前域交集
REG_REQ_ALREADY_SET, // 已设置相同域,无需处理
};
6. 监管域设置流程
6.1 set_regdom() 主流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ set_regdom() 流程 reg.c:3942 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ set_regdom(rd, regd_src) │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 1. 验证请求有效性 │ │
│ │ - IS_ERR_OR_NULL(rd) │ │
│ │ - reg_is_valid_request(rd->alpha2) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 2. 重置CRDA超时 (如果是CRDA来源) │ │
│ │ if (regd_src == REGD_SOURCE_CRDA) │ │
│ │ reset_crda_timeouts() │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 3. 根据发起者类型调用对应设置函数 │ │
│ │ │ │
│ │ switch(lr->initiator) { │ │
│ │ ┌──────────────────────────────────────────────────────────────┐ │ │
│ │ │ BY_CORE ──────────► reg_set_rd_core() reg.c:3802 │ │ │
│ │ │ BY_USER ──────────► reg_set_rd_user() reg.c:3810 │ │ │
│ │ │ BY_DRIVER ────────► reg_set_rd_driver() reg.c:3841 │ │ │
│ │ │ BY_COUNTRY_IE ────► reg_set_rd_country_ie() reg.c:3904 │ │ │
│ │ └──────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 4. 处理错误 │ │
│ │ -EALREADY: 标记请求已处理 │ │
│ │ 其他错误: restore_regulatory_settings() 恢复 │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 5. 更新所有wiphy │ │
│ │ update_all_wiphy_regulatory(lr->initiator) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 6. 后续处理 │ │
│ │ - print_regdomain() 打印监管域信息 │ │
│ │ - nl80211_send_reg_change_event() 发送事件 │ │
│ │ - reg_set_request_processed() 标记已处理 │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
6.2 各类型设置函数对比
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 各类型设置函数对比 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ reg_set_rd_core() reg.c:3802 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 条件: 必须是世界监管域 (alpha2 == "00") │ │
│ │ 操作: update_world_regdomain(rd) │ │
│ │ 结果: 更新世界监管域指针 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ reg_set_rd_user() reg.c:3810 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 条件: 监管域必须有效 │ │
│ │ 操作: │ │
│ │ if (user_request->intersect) { │ │
│ │ intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()) │ │
│ │ reset_regdomains(false, intersected_rd) │ │
│ │ } else { │ │
│ │ reset_regdomains(false, rd) │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ reg_set_rd_driver() reg.c:3841 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 条件: 不能是世界监管域,监管域必须有效 │ │
│ │ 操作: │ │
│ │ if (!driver_request->intersect) { │ │
│ │ // 直接设置到wiphy和全局 │ │
│ │ rcu_assign_pointer(request_wiphy->regd, regd) │ │
│ │ reset_regdomains(false, rd) │ │
│ │ } else { │ │
│ │ // 交集处理 │ │
│ │ intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()) │ │
│ │ rcu_assign_pointer(request_wiphy->regd, rd) // 保存原始域 │ │
│ │ reset_regdomains(false, intersected_rd) │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ reg_set_rd_country_ie() reg.c:3904 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 条件: alpha2有效,监管域有效,不支持交集 │ │
│ │ 操作: reset_regdomains(false, rd) │ │
│ │ 结果: 直接设置监管域 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
7. 监管域应用流程
7.1 应用到wiphy的流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 监管域应用流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ update_all_wiphy_regulatory(initiator) reg.c:2515 │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 遍历所有注册的wiphy │ │
│ │ for_each_rdev(rdev) { │ │
│ │ wiphy = &rdev->wiphy; │ │
│ │ wiphy_update_regulatory(wiphy, initiator); │ │
│ │ } │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ wiphy_update_regulatory() reg.c:2485 │ │
│ │ │ │
│ │ 1. ignore_reg_update() 检查是否需要忽略 │ │
│ │ 2. 遍历所有频段: for (band = 0; band < NUM_NL80211_BANDS; band++) │ │
│ │ 3. handle_band(wiphy, initiator, wiphy->bands[band]) │ │
│ │ 4. reg_process_beacons() 处理信标提示 │ │
│ │ 5. reg_process_ht_flags() 处理HT标志 │ │
│ │ 6. reg_call_notifier() 调用驱动通知函数 │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ handle_band() reg.c:2018 │ │
│ │ │ │
│ │ for (i = 0; i < sband->n_channels; i++) │ │
│ │ handle_channel(wiphy, initiator, &sband->channels[i]); │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ handle_channel() reg.c:1934 │ │
│ │ │ │
│ │ 1. 获取信道频率 orig_chan_freq = ieee80211_channel_to_khz(chan) │ │
│ │ 2. 查询规则: rrule = freq_reg_info(wiphy, orig_chan_freq) │ │
│ │ │ │
│ │ if (IS_ERR(rrule)) { │ │
│ │ // 检查相邻规则 (±20MHz) │ │
│ │ rrule1 = freq_reg_info(wiphy, orig_chan_freq - 20MHz) │ │
│ │ rrule2 = freq_reg_info(wiphy, orig_chan_freq + 20MHz) │ │
│ │ if (找到相邻规则) │ │
│ │ handle_channel_adjacent_rules() │ │
│ │ else │ │
│ │ 禁用信道 │ │
│ │ } else { │ │
│ │ handle_channel_single_rule() │ │
│ │ } │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
7.2 信道处理详细流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ handle_channel_single_rule() 流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ handle_channel_single_rule(wiphy, initiator, chan, flags, │
│ lr, request_wiphy, reg_rule) │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 1. 计算带宽标志 │ │
│ │ bw_flags = reg_rule_to_chan_bw_flags(regd, │ │
│ │ reg_rule, │ │
│ │ chan) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 2. 判断是否为严格监管设备 (REGULATORY_STRICT_REG) │ │
│ │ │ │
│ │ if (lr->initiator == BY_DRIVER && │ │
│ │ request_wiphy == wiphy && │ │
│ │ request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { │ │
│ │ // 设置原始值 (不会被后续请求覆盖) │ │
│ │ chan->orig_flags = map_regdom_flags(reg_rule->flags) | bw_flags │ │
│ │ chan->orig_mag = MBI_TO_DBI(power_rule->max_antenna_gain) │ │
│ │ chan->orig_mpwr = MBM_TO_DBM(power_rule->max_eirp) │ │
│ │ } │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 3. 设置信道属性 │ │
│ │ │ │
│ │ chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags) │ │
│ │ chan->max_antenna_gain = min(chan->orig_mag, │ │
│ │ MBI_TO_DBI(power_rule->max_antenna_gain))│ │
│ │ chan->max_reg_power = MBM_TO_DBM(power_rule->max_eirp) │ │
│ │ │ │
│ │ // 设置最大功率 │ │
│ │ if (chan->orig_mpwr) │ │
│ │ chan->max_power = min(chan->orig_mpwr, chan->max_reg_power) │ │
│ │ else │ │
│ │ chan->max_power = chan->max_reg_power │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 4. DFS处理 │ │
│ │ │ │
│ │ if (chan->flags & IEEE80211_CHAN_RADAR) { │ │
│ │ chan->dfs_cac_ms = reg_rule->dfs_cac_ms ? │ │
│ │ reg_rule->dfs_cac_ms : │ │
│ │ IEEE80211_DFS_MIN_CAC_TIME_MS │ │
│ │ } │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
7.3 监管规则查询流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ freq_reg_info() 查询流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ freq_reg_info(wiphy, center_freq) reg.c:1656 │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 1. 确定最小带宽 │ │
│ │ min_bw = (center_freq < 1GHz) ? 1kHz : 20kHz │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 2. 调用 __freq_reg_info() │ │
│ │ reg.c:1638 │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 3. 获取监管域 │ │
│ │ regd = reg_get_regdomain(wiphy) │ │
│ │ │ │
│ │ // 优先级: │ │
│ │ // 1. 国家IE或用户请求 -> 全局监管域 │ │
│ │ // 2. 其他 -> wiphy->regd (驱动设置) │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 4. 尝试不同带宽 │ │
│ │ static const u32 bws[] = {0,1,2,4,5,8,10,16,20} │ │
│ │ │ │
│ │ for (i = 8; i >= 0; i--) { │ │
│ │ bw = MHZ_TO_KHZ(bws[i]) │ │
│ │ if (bw < min_bw) break │ │
│ │ reg_rule = freq_reg_info_regd(center_freq, │ │
│ │ regd, bw) │ │
│ │ if (!IS_ERR(reg_rule)) return reg_rule │ │
│ │ } │ │
│ └─────────┬──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 5. freq_reg_info_regd() 匹配逻辑 │ │
│ │ reg.c:1600 │ │
│ │ │ │
│ │ for (i = 0; i < regd->n_reg_rules; i++) { │ │
│ │ rr = ®d->reg_rules[i] │ │
│ │ fr = &rr->freq_range │ │
│ │ if (freq_in_rule_band(fr, center_freq) && │ │
│ │ cfg80211_does_bw_fit_range(fr, center, │ │
│ │ bw)) │ │
│ │ return rr │ │
│ │ } │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
8. 监管域交集算法
监管域交集(Regulatory Domain Intersection) 是一个极其核心的安全机制。用一句话概括:当系统同时收到多个不同来源的监管域规则时,最终生效的规则是这些规则中“最严格”的那一个。 这在逻辑上等同于取所有允许发射的信道、功率和带宽的数学交集。
8.1 交集计算流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 监管域交集算法 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ regdom_intersect(rd1, rd2) reg.c:1487 │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 1. 计算交集规则数量 │ │
│ │ │ │
│ │ for (x = 0; x < rd1->n_reg_rules; x++) { │ │
│ │ for (y = 0; y < rd2->n_reg_rules; y++) { │ │
│ │ if (!reg_rules_intersect(rd1, rd2, rule1, rule2, &tmp)) │ │
│ │ num_rules++ │ │
│ │ } │ │
│ │ } │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 2. 分配结果监管域 │ │
│ │ rd = kzalloc_flex(*rd, reg_rules, num_rules) │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 3. 计算并添加交集规则 │ │
│ │ │ │
│ │ for (x = 0; x < rd1->n_reg_rules; x++) { │ │
│ │ for (y = 0; y < rd2->n_reg_rules; y++) { │ │
│ │ r = reg_rules_intersect(rd1, rd2, rule1, rule2, &tmp) │ │
│ │ if (!r) │ │
│ │ add_rule(&tmp, rd->reg_rules, &rd->n_reg_rules) │ │
│ │ } │ │
│ │ } │ │
│ └────────────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 4. 设置结果属性 │ │
│ │ rd->alpha2 = "98" // 交集标识 │ │
│ │ rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region, │ │
│ │ rd2->dfs_region) │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
8.2 规则交集计算
┌─────────────────────────────────────────────────────────────────────────────────┐
│ reg_rules_intersect() 计算逻辑 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ reg_rules_intersect(rd1, rd2, rule1, rule2, intersected_rule) │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 频率范围交集 │ │
│ │ ───────────────────────────────────────────────────────────────────── │ │
│ │ intersected_rule->freq_range.start_freq_khz = │ │
│ │ max(rule1->freq_range.start_freq_khz, │ │
│ │ rule2->freq_range.start_freq_khz) │ │
│ │ │ │
│ │ intersected_rule->freq_range.end_freq_khz = │ │
│ │ min(rule1->freq_range.end_freq_khz, │ │
│ │ rule2->freq_range.end_freq_khz) │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 带宽限制 │ │
│ │ ───────────────────────────────────────────────────────────────────── │ │
│ │ // 如果有AUTO_BW标志,计算最大带宽 │ │
│ │ if (rule1->flags & NL80211_RRF_AUTO_BW) │ │
│ │ max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1) │ │
│ │ │ │
│ │ intersected_rule->freq_range.max_bandwidth_khz = │ │
│ │ min(max_bandwidth1, max_bandwidth2) │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 标志位处理 │ │
│ │ ───────────────────────────────────────────────────────────────────── │ │
│ │ // 取并集 │ │
│ │ intersected_rule->flags = rule1->flags | rule2->flags │ │
│ │ │ │
│ │ // AUTO_BW特殊处理 │ │
│ │ if (both have AUTO_BW) │ │
│ │ keep AUTO_BW │ │
│ │ else │ │
│ │ remove AUTO_BW │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ 功率规则 │ │
│ │ ───────────────────────────────────────────────────────────────────── │ │
│ │ // 取较小值 (更严格) │ │
│ │ intersected_rule->power_rule.max_eirp = │ │
│ │ min(rule1->power_rule.max_eirp, rule2->power_rule.max_eirp) │ │
│ │ │ │
│ │ intersected_rule->power_rule.max_antenna_gain = │ │
│ │ min(rule1->power_rule.max_antenna_gain, │ │
│ │ rule2->power_rule.max_antenna_gain) │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ DFS CAC时间 │ │
│ │ ───────────────────────────────────────────────────────────────────── │ │
│ │ // 取较大值 (更保守) │ │
│ │ intersected_rule->dfs_cac_ms = │ │
│ │ max(rule1->dfs_cac_ms, rule2->dfs_cac_ms) │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
9. 用户空间接口
9.1 nl80211命令接口
┌─────────────────────────────────────────────────────────────────────────────────┐
│ nl80211 监管域相关命令 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ NL80211_CMD_GET_REG │ │
│ │ 处理函数: nl80211_get_reg_do / nl80211_get_reg_dump │ │
│ │ 功能: 获取当前监管域信息 │ │
│ │ 权限: 普通用户可访问 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ NL80211_CMD_SET_REG (需要 CONFIG_CFG80211_CRDA_SUPPORT) │ │
│ │ 处理函数: nl80211_set_reg() nl80211.c:10452 │ │
│ │ 功能: CRDA设置监管域 │ │
│ │ 权限: GENL_ADMIN_PERM (需要CAP_NET_ADMIN) │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 流程: │ │
│ │ 1. 解析 NL80211_ATTR_REG_ALPHA2 (国家代码) │ │
│ │ 2. 解析 NL80211_ATTR_REG_RULES (监管规则) │ │
│ │ 3. 可选: 解析 NL80211_ATTR_DFS_REGION (DFS区域) │ │
│ │ 4. 构建 ieee80211_regdomain 结构 │ │
│ │ 5. 调用 set_regdom(rd, REGD_SOURCE_CRDA) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ NL80211_CMD_REQ_SET_REG │ │
│ │ 处理函数: nl80211_req_set_reg() nl80211.c:9725 │ │
│ │ 功能: 用户请求设置监管域 │ │
│ │ 权限: GENL_ADMIN_PERM (需要CAP_NET_ADMIN) │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 支持的提示类型: │ │
│ │ ┌───────────────────────────────────────────────────────────────────┐ │ │
│ │ │ NL80211_USER_REG_HINT_USER │ │ │
│ │ │ - 需要 NL80211_ATTR_REG_ALPHA2 属性 │ │ │
│ │ │ - 调用 regulatory_hint_user(alpha2, HINT_USER) │ │ │
│ │ ├───────────────────────────────────────────────────────────────────┤ │ │
│ │ │ NL80211_USER_REG_HINT_CELL_BASE │ │ │
│ │ │ - 需要 NL80211_ATTR_REG_ALPHA2 属性 │ │ │
│ │ │ - 调用 regulatory_hint_user(alpha2, HINT_CELL_BASE) │ │ │
│ │ ├───────────────────────────────────────────────────────────────────┤ │ │
│ │ │ NL80211_USER_REG_HINT_INDOOR │ │ │
│ │ │ - 可选 NL80211_ATTR_REG_INDOOR 属性 │ │ │
│ │ │ - 可选 NL80211_ATTR_SOCKET_OWNER 属性 │ │ │
│ │ │ - 调用 regulatory_hint_indoor(is_indoor, portid) │ │ │
│ │ └───────────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ NL80211_CMD_RELOAD_REGDB │ │
│ │ 处理函数: nl80211_reload_regdb() nl80211.c:9769 │ │
│ │ 功能: 重新加载监管数据库 │ │
│ │ 权限: GENL_ADMIN_PERM (需要CAP_NET_ADMIN) │ │
│ │ 调用: reg_reload_regdb() reg.c:1059 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
9.2 用户空间工具使用示例
# 1. 获取当前监管域
iw reg get
# 2. 设置国家代码 (用户提示)
iw reg set US
# 3. 设置室内环境
iw reg set indoor
# 4. 查看监管规则
iw reg get | grep -A 5 "country"
# 5. 使用CRDA (传统方式)
crda
10. 工作队列机制
10.1 工作队列架构
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 工作队列机制 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 主工作队列: reg_work │ │
│ │ 声明: static DECLARE_WORK(reg_work, reg_todo); reg.c:230 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 处理函数: reg_todo() reg.c:3200 │ │
│ │ │ │
│ │ static void reg_todo(struct work_struct *work) │ │
│ │ { │ │
│ │ rtnl_lock(); │ │
│ │ reg_process_pending_hints(); // 处理待处理提示 │ │
│ │ reg_process_pending_beacon_hints(); // 处理待处理信标 │ │
│ │ reg_process_self_managed_hints(); // 处理自监管提示 │ │
│ │ rtnl_unlock(); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 通道检查工作: reg_check_chans │ │
│ │ 声明: static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);│ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 处理函数: reg_check_chans_work() reg.c:2461 │ │
│ │ │ │
│ │ // 验证活动接口是否在合法信道上 │ │
│ │ static void reg_check_chans_work(struct work_struct *work) │ │
│ │ { │ │
│ │ rtnl_lock(); │ │
│ │ for_each_rdev(rdev) │ │
│ │ reg_leave_invalid_chans(&rdev->wiphy); │ │
│ │ rtnl_unlock(); │ │
│ │ } │ │
│ │ │ │
│ │ // 调度延迟 (60秒宽限期) │ │
│ │ void reg_check_channels(void) │ │
│ │ { │ │
│ │ mod_delayed_work(system_power_efficient_wq, ®_check_chans, │ │
│ │ msecs_to_jiffies(REG_ENFORCE_GRACE_MS)); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 数据库应用工作: reg_regdb_work │ │
│ │ 声明: static DECLARE_WORK(reg_regdb_work, reg_regdb_apply); reg.c:495 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 处理函数: reg_regdb_apply() reg.c:474 │ │
│ │ │ │
│ │ // 从队列中取出监管域并应用 │ │
│ │ static void reg_regdb_apply(struct work_struct *work) │ │
│ │ { │ │
│ │ rtnl_lock(); │ │
│ │ while (!list_empty(®_regdb_apply_list)) { │ │
│ │ request = list_first_entry(...); │ │
│ │ list_del(&request->list); │ │
│ │ set_regdom(request->regdom, REGD_SOURCE_INTERNAL_DB); │ │
│ │ kfree(request); │ │
│ │ } │ │
│ │ rtnl_unlock(); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ CRDA超时工作: crda_timeout (需要 CONFIG_CFG80211_CRDA_SUPPORT) │ │
│ │ 声明: static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work); │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ 处理函数: crda_timeout_work() reg.c:526 │ │
│ │ │ │
│ │ // CRDA响应超时处理 │ │
│ │ static void crda_timeout_work(struct work_struct *work) │ │
│ │ { │ │
│ │ rtnl_lock(); │ │
│ │ reg_crda_timeouts++; │ │
│ │ restore_regulatory_settings(true, false); │ │
│ │ rtnl_unlock(); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
11. 自监管设备支持
普通无线设备的射频合规由 Linux 内核“中央集权”管理,而自监管设备则自带“法务部”,由硬件或固件自己管理射频合规,Linux 内核放弃干预,只负责被动记录。
11.1 自监管设备流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 自监管设备 (WIPHY_SELF_MANAGED) 流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 特点: │ │
│ │ - 忽略所有非本设备的监管提示 │ │
│ │ - 不使用信标提示和国家IE │ │
│ │ - 不与其他设备共享监管信息 │ │
│ │ - 自动设置 REGULATORY_DISABLE_BEACON_HINTS | REGULATORY_COUNTRY_IE_IGNORE │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 设置接口: regulatory_set_wiphy_regd() reg.c:4050 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ int regulatory_set_wiphy_regd(struct wiphy *wiphy, │ │
│ │ struct ieee80211_regdomain *rd) │ │
│ │ { │ │
│ │ // 1. 验证自监管标志 │ │
│ │ if (!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)) │ │
│ │ return -EPERM; │ │
│ │ │ │
│ │ // 2. 验证监管域有效性 │ │
│ │ if (!is_valid_rd(rd)) return -EINVAL; │ │
│ │ │ │
│ │ // 3. 复制监管域 │ │
│ │ regd = reg_copy_regd(rd); │ │
│ │ │ │
│ │ // 4. 保存到rdev->requested_regd │ │
│ │ spin_lock(®_requests_lock); │ │
│ │ prev_regd = rdev->requested_regd; │ │
│ │ rdev->requested_regd = regd; │ │
│ │ spin_unlock(®_requests_lock); │ │
│ │ │ │
│ │ // 5. 调度处理 │ │
│ │ schedule_work(®_work); │ │
│ │ return 0; │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 同步设置接口: regulatory_set_wiphy_regd_sync() reg.c:4063 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ int regulatory_set_wiphy_regd_sync(struct wiphy *wiphy, │ │
│ │ struct ieee80211_regdomain *rd) │ │
│ │ { │ │
│ │ ASSERT_RTNL(); │ │
│ │ │ │
│ │ // 1. 保存请求 │ │
│ │ ret = __regulatory_set_wiphy_regd(wiphy, rd); │ │
│ │ │ │
│ │ // 2. 立即处理 (不通过工作队列) │ │
│ │ reg_process_self_managed_hint(wiphy); │ │
│ │ reg_check_channels(); │ │
│ │ return 0; │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 处理函数: reg_process_self_managed_hint() reg.c:3146 │ │
│ ├─────────────────────────────────────────────────────────────────────────┤ │
│ │ static void reg_process_self_managed_hint(struct wiphy *wiphy) │ │
│ │ { │ │
│ │ // 1. 获取请求的监管域 │ │
│ │ spin_lock(®_requests_lock); │ │
│ │ regd = rdev->requested_regd; │ │
│ │ rdev->requested_regd = NULL; │ │
│ │ spin_unlock(®_requests_lock); │ │
│ │ │ │
│ │ if (!regd) return; │ │
│ │ │ │
│ │ // 2. 设置到wiphy->regd │ │
│ │ tmp = get_wiphy_regdom(wiphy); │ │
│ │ rcu_assign_pointer(wiphy->regd, regd); │ │
│ │ rcu_free_regdom(tmp); │ │
│ │ │ │
│ │ // 3. 应用到所有频段 │ │
│ │ for (band = 0; band < NUM_NL80211_BANDS; band++) │ │
│ │ handle_band_custom(wiphy, wiphy->bands[band], regd); │ │
│ │ │ │
│ │ // 4. 处理HT标志 │ │
│ │ reg_process_ht_flags(wiphy); │ │
│ │ │ │
│ │ // 5. 发送通知 │ │
│ │ nl80211_send_wiphy_reg_change_event(&request); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
12. DFS区域处理
12.1 DFS状态传播流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ DFS状态传播流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ regulatory_propagate_dfs_state(wiphy, chandef, dfs_state, event) │
│ reg.c:4243 │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 1. 验证chandef有效性 │ │
│ │ if (WARN_ON(!cfg80211_chandef_valid(chandef))) │ │
│ │ return; │ │
│ └────────────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 2. 遍历所有wiphy │ │
│ │ │ │
│ │ for_each_rdev(rdev) { │ │
│ │ if (wiphy == &rdev->wiphy) continue; // 跳过源wiphy │ │
│ │ │ │
│ │ // 检查DFS区域是否相同 │ │
│ │ if (!reg_dfs_domain_same(wiphy, &rdev->wiphy)) │ │
│ │ continue; │ │
│ │ │ │
│ │ // 检查目标wiphy是否有相同频率的信道 │ │
│ │ if (!ieee80211_get_channel(&rdev->wiphy, │ │
│ │ chandef->chan->center_freq)) │ │
│ │ continue; │ │
│ │ │ │
│ │ // ... 处理 │ │
│ │ } │ │
│ └────────────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 3. 更新DFS状态 │ │
│ │ cfg80211_set_dfs_state(&rdev->wiphy, chandef, dfs_state) │ │
│ └────────────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 4. 根据事件类型处理 │ │
│ │ │ │
│ │ if (event == NL80211_RADAR_DETECTED || │ │
│ │ event == NL80211_RADAR_CAC_FINISHED) { │ │
│ │ // 调度DFS通道更新 │ │
│ │ cfg80211_sched_dfs_chan_update(rdev); │ │
│ │ // 结束相关CAC │ │
│ │ cfg80211_check_and_end_cac(rdev); │ │
│ │ } │ │
│ │ │ │
│ │ // 发送radar通知 │ │
│ │ nl80211_radar_notify(rdev, chandef, event, NULL, GFP_KERNEL); │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
13. 监管数据库
13.1 数据库加载流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 监管数据库加载流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ query_regdb_file(alpha2) reg.c:1037 │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 1. 检查数据库是否已加载 │ │
│ │ if (regdb) │ │
│ │ return query_regdb(alpha2); // 直接查询 │ │
│ └────────────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 2. 异步加载数据库 │ │
│ │ request_firmware_nowait(THIS_MODULE, true, "regulatory.db", │ │
│ │ ®_fdev->dev, GFP_KERNEL, │ │
│ │ (void *)alpha2, regdb_fw_cb) │ │
│ └────────────────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 3. 回调函数: regdb_fw_cb() reg.c:991 │ │
│ │ │ │
│ │ static void regdb_fw_cb(const struct firmware *fw, void *context) │ │
│ │ { │ │
│ │ // 验证数据库 │ │
│ │ if (!fw) { │ │
│ │ pr_info("failed to load regulatory.db\n"); │ │
│ │ set_error = -ENODATA; │ │
│ │ } else if (!valid_regdb(fw->data, fw->size)) { │ │
│ │ pr_info("loaded regulatory.db is malformed..."); │ │
│ │ set_error = -EINVAL; │ │
│ │ } │ │
│ │ │ │
│ │ rtnl_lock(); │ │
│ │ if (set_error) { │ │
│ │ regdb = ERR_PTR(set_error); │ │
│ │ } else if (fw) { │ │
│ │ // 复制到内核内存 │ │
│ │ db = kmemdup(fw->data, fw->size, GFP_KERNEL); │ │
│ │ if (db) { │ │
│ │ regdb = db; │ │
│ │ // 查询并应用 │ │
│ │ restore = context && query_regdb(context); │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ │ if (restore) │ │
│ │ restore_regulatory_settings(true, false); │ │
│ │ rtnl_unlock(); │ │
│ │ } │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
13.2 数据库格式
┌─────────────────────────────────────────────────────────────────────────────────┐
│ regulatory.db 文件格式 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 文件头 (fwdb_header) │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ magic: 0x52474442 ("RGDB") │ │ │
│ │ │ version: 20 │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 国家列表 (fwdb_country[]) │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ alpha2: "US" │ │ │
│ │ │ coll_ptr: 指向集合的指针 │ │ │
│ │ ├─────────────────────────────────────────────────────────────────────┤ │ │
│ │ │ alpha2: "JP" │ │ │
│ │ │ coll_ptr: 指向集合的指针 │ │ │
│ │ ├─────────────────────────────────────────────────────────────────────┤ │ │
│ │ │ ... │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 集合 (fwdb_collection) │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ len: 结构长度 │ │ │
│ │ │ n_rules: 规则数量 │ │ │
│ │ │ dfs_region: DFS区域 (FCC/ETSI/JP) │ │ │
│ │ │ rules_ptr[]: 规则指针数组 │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ 规则 (fwdb_rule) │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ len: 结构长度 │ │ │
│ │ │ flags: 标志位 (NO_OFDM, NO_OUTDOOR, DFS, NO_IR, AUTO_BW) │ │ │
│ │ │ max_eirp: 最大EIRP (dBm) │ │ │
│ │ │ start: 起始频率 (kHz) │ │ │
│ │ │ end: 结束频率 (kHz) │ │ │
│ │ │ max_bw: 最大带宽 (kHz) │ │ │
│ │ │ [可选] cac_timeout: CAC超时 (秒) │ │ │
│ │ │ [可选] wmm_ptr: WMM规则指针 │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
14. 完整流程总结
14.1 从用户空间到驱动的完整流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 监管域处理完整流程 (从用户空间到驱动) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户空间 │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ iw reg set US │ │
│ └────────────────────────────────────┬────────────────────────────────────┘ │
│ │ Netlink │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ nl80211_req_set_reg() │ │
│ │ regulatory_hint_user("US", NL80211_USER_REG_HINT_USER) │ │
│ └────────────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ queue_regulatory_request() │ │
│ │ 加入 reg_requests_list 链表 │ │
│ └────────────────────────────────────┬────────────────────────────────────┘ │
│ │ schedule_work │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ reg_todo() 工作队列 │ │
│ │ reg_process_pending_hints() │ │
│ └────────────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ reg_process_hint_user() │ │
│ │ reg_query_database() ──► query_regdb_file("US") │ │
│ │ ──► call_crda("US") │ │
│ └────────────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ set_regdom(us_regdom, REGD_SOURCE_INTERNAL_DB) │ │
│ │ reg_set_rd_user() ──► reset_regdomains(false, rd) │ │
│ └────────────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ update_all_wiphy_regulatory(NL80211_REGDOM_SET_BY_USER) │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ for_each_rdev(rdev) { │ │ │
│ │ │ wiphy_update_regulatory(wiphy, BY_USER) │ │ │
│ │ │ handle_band(wiphy, BY_USER, sband) │ │ │
│ │ │ handle_channel(wiphy, BY_USER, chan) │ │ │
│ │ │ freq_reg_info(wiphy, freq) ──► 查找匹配规则 │ │ │
│ │ │ handle_channel_single_rule() ──► 应用规则到信道 │ │ │
│ │ │ reg_call_notifier(wiphy, lr) ──► 通知驱动 │ │ │
│ │ │ } │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 驱动层 │ │
│ │ wiphy->reg_notifier(wiphy, request) ──► 驱动回调函数 │ │
│ │ 信道属性已更新: │ │
│ │ chan->flags, chan->max_power, chan->dfs_state 等 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
15. 总结
Linux无线监管域处理流程是一个复杂但设计良好的系统,具有以下特点:
- 多层架构: 核心层、驱动层、用户空间层协同工作
- 优先级管理: 不同来源的提示有不同的处理优先级
- 交集算法: 确保遵守最严格的监管限制
- 异步处理: 通过工作队列实现非阻塞处理
- RCU保护: 高效的读取并发支持
- 灵活接口: 支持多种设备类型和使用场景
该系统确保了无线设备在不同国家和地区都能遵守当地的无线电监管要求,同时提供了足够的灵活性供驱动和用户空间进行定制。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DD'Notes!
评论






