脚本概述
mac80211.sh 是 OpenWrt 中用于配置和管理基于 mac80211 驱动程序的无线接口的脚本。它位于 package/network/config/wifi-scripts/files/lib/wifi/
目录下,负责刷写固件后首次启动时处理无线网络接口的初始化、配置和启动。
脚本功能
该脚本的主要功能是刷写固件后首次启动时初始化无线网络接口、配置无线网络参数
关键函数解析
脚本中一些关键函数的作用和实现方式,如 check_mac80211_device
、get_band_defaults
、check_devidx
等。这些函数负责具体的无线网络接口管理任务。
部分函数详解
- check_mac80211_device函数
#该函数是 OpenWrt 无线设备自动配置的核心校验逻辑,通过 双重匹配机制(路径+MAC) 确保:
#避免重复配置已存在的设备
#兼容不同硬件识别方式(内核命名 vs 板级 JSON 定义)
#处理多 PHY 设备的复杂场景
check_mac80211_device() {
local device="$1" # UCI 配置中的设备节点名(如 "radio0")
local path="$2" # 待检查的物理设备路径(来自 /sys/class/ieee80211)
local macaddr="$3" # 待检查的 MAC 地址(来自硬件)
[ -n "$found" ] && return 0 # 已找到设备时直接退出,快速终止已匹配成功的后续检查
phy_path= # 清空物理路径变量
config_get phy "$device" phy # 从 UCI 读取设备的 phy 字段,若 device=radio0,可能读取到 phy=phy0
json_select wlan # 进入 /etc/board.json 的 wlan 配置段
[ -n "$phy" ] && case "$phy" in
phy*) # PHY 是内核命名(如 phy0)
[ -d /sys/class/ieee80211/$phy ] && \
phy_path="$(iwinfo nl80211 path "$dev")" # 通过工具获取路径
;;
*) # PHY 是 JSON 对象
if json_is_a "$phy" object; then # 完整对象(如 "phy0")
json_select "$phy"
json_get_var phy_path path # 提取 path 字段
json_select ..
elif json_is_a "${phy%.*}" object; then # 子对象(如 "phy0.1")
json_select "${phy%.*}" # 提取父对象(phy0)
json_get_var phy_path path # 获取父路径
json_select ..
phy_path="$phy_path+${phy##*.}" # 拼接子路径(phy0+1)
fi
;;
esac
json_select .. # 退出 JSON 的 wlan 段
[ -n "$phy_path" ] || config_get phy_path "$device" path # 后备读取 path
[ -n "$path" -a "$phy_path" = "$path" ] && { # 路径比对
found=1 # 标记已找到
return 0 # 优先通过路径匹配退出
}
config_get dev_macaddr "$device" macaddr # 从 UCI 读取 MAC
[ -n "$macaddr" -a "$dev_macaddr" = "$macaddr" ] && found=1
# MAC比对:上面的路径匹配失败时,通过 MAC 地址二次验证
return 0
}
- get_band_defaults函数
# 这个函数的主要功能是 为指定的无线设备(phy)确定默认的频段、信道和工作模式
get_band_defaults() {
# 定义函数,接收一个参数phy(物理无线设备)
local phy="$1"
# 遍历调用__get_band_defaults函数获取的列表,每个元素用c表示
for c in $(__get_band_defaults "$phy"); do
# 分割c的值,格式为 band:channel:mode
local band="${c%%:*}" # 提取第一个字段(频段编号)
c="${c#*:}" # 剩余部分(移除第一个字段)
local chan="${c%%:*}" # 提取第二个字段(信道)
c="${c#*:}" # 剩余部分(移除第二个字段)
local mode="${c%%:*}" # 提取第三个字段(模式,如HT40)
# 将频段编号转换为可读名称
case "$band" in
1) band=2g;; # 1对应2.4GHz
2) band=5g;; # 2对应5GHz
3) band=60g;; # 3对应60GHz(较少见)
4) band=6g;; # 4对应6GHz(Wi-Fi 6E)
*) band="";; # 其他值视为无效
esac
# 跳过无效频段
[ -n "$band" ] || continue
# 若已存在mode_band且当前是6GHz频段,则直接返回,优先处理6GHZ
[ -n "$mode_band" -a "$band" = "6g" ] && return
# 设置当前频段的默认参数
mode_band="$band" # 频段名称(如6g)
channel="$chan" # 默认信道
htmode="$mode" # 带宽模式
done
}
使用例子
- 设置默认的无线名称,信道以及工作模式
detect_mac80211() {
devidx=0
config_load wireless
config_foreach check_devidx wifi-device
json_load_file /etc/board.json
for _dev in /sys/class/ieee80211/*; do
[ -e "$_dev" ] || continue
dev="${_dev##*/}"
mode_band=""
channel=""
htmode=""
ht_capab=""
get_band_defaults "$dev"
path="$(iwinfo nl80211 path "$dev")"
macaddr="$(cat /sys/class/ieee80211/${dev}/macaddress)"
# work around phy rename related race condition
[ -n "$path" -o -n "$macaddr" ] || continue
board_dev=
fallback_board_dev=
json_for_each_item check_board_phy wlan
[ -n "$board_dev" ] || board_dev="$fallback_board_dev"
[ -n "$board_dev" ] && dev="$board_dev"
found=
config_foreach check_mac80211_device wifi-device "$path" "$macaddr"
[ -n "$found" ] && continue
name="radio${devidx}"
devidx=$(($devidx + 1))
case "$dev" in
phy*)
if [ -n "$path" ]; then
dev_id="set wireless.${name}.path='$path'"
else
dev_id="set wireless.${name}.macaddr='$macaddr'"
fi
;;
*)
dev_id="set wireless.${name}.phy='$dev'"
;;
esac
# set wireless.default_${name}.ssid=$(echo $mode_band | grep -q '2g' && echo 'ceshi' || echo 'ceshi-5G')
# 这行代码设置了无线2.4G和5G的默认ssid
# set wireless.default_${name}.encryption=psk+ccmp
# 这行代码设置了默认工作模式为psk+ccmp
# set wireless.default_${name}.key='12345678'
# 这行代码设置了无线的默认密码为12345678
uci -q batch <<-EOF
set wireless.${name}=wifi-device
set wireless.${name}.type=mac80211
${dev_id}
set wireless.${name}.channel=${channel:-auto}
set wireless.${name}.band=${mode_band}
set wireless.${name}.htmode=$htmode
set wireless.${name}.cell_density=0
set wireless.${name}.legacy_rates=1
set wireless.default_${name}=wifi-iface
set wireless.default_${name}.device=${name}
set wireless.default_${name}.network=lan
set wireless.default_${name}.mode=ap
set wireless.default_${name}.ssid=$(echo $mode_band | grep -q '2g' && echo 'ceshi' || echo 'ceshi-5G')
set wireless.default_${name}.encryption=psk+ccmp
set wireless.default_${name}.key='12345678'
EOF
uci -q commit wireless
done
}
ps:有注释的那几行就是修改了的代码,其他代码未修改。