说明
本文档介绍如何在 Buildroot 系统中配置 AP6256 WiFi 模块为 AP 模式(热点),实现开机自动启动 WiFi 热点、DHCP 分配 IP,并可选开启 NAT 上网转发。
环境说明
- 板卡:TaishanPi-3M(RK3576)
- WiFi 模块:AP6256(Broadcom BCM43456,SDIO 接口)
- 系统:Buildroot
- 依赖:SDK 已预装 hostapd、dnsmasq、iw 和 bcmdhd 驱动,内核已支持 NAT
工作原理
AP6256 基于 Broadcom BCM43456 芯片,走 SDIO 接口,Linux 下使用 bcmdhd 驱动。和 Realtek 系列模块不一样的地方在于,AMPAK 封装的 Broadcom 模块没有现成的 p2p0 接口,需要用 iw 命令在物理无线接口上创建一个虚拟接口来承载 AP 功能:
iw phy0 interface add wlan1 type managedhostapd 启动时会自动把这个 managed 类型的虚拟接口切换到 AP 模式。整个开机启动链路是这样的:
开机 → S36wifibt-init(加载 bcmdhd.ko,出现 wlan0)
→ S45wifi-ap(创建 wlan1 → 配置 IP → hostapd → dnsmasq → NAT)
→ 热点就绪2
3
涉及三个用户态组件:
| 组件 | 作用 |
|---|---|
| hostapd | 管理热点(广播 SSID、处理关联和认证) |
| dnsmasq | 给连接设备分配 IP(DHCP)和解析 DNS |
| iptables | NAT 转发,让连接的设备通过 eth0 上网(可选) |
SDK 里已经预装好了 hostapd、dnsmasq、iw 和 bcmdhd 驱动(含 AP 特性编译选项),内核也支持 NAT。大家需要做的就是:把 WiFi 模块切换到 AP6256、补充配置文件和启动脚本,再顺手修复一个 overlay 安装脚本的小问题。
需要修改的文件清单
先整体过一遍要做的事情,心里有个数:
| 文件 | 操作 | 说明 |
|---|---|---|
device/rockchip/.chips/rk3576/tspi_3m_rk3576_buildroot_defconfig | 修改 | 指定 WiFi 模块为 AP6256 |
buildroot/configs/rockchip/wifibt/wireless.config | 修改(可选) | 添加 iptables(NAT 上网用) |
device/rockchip/common/scripts/post-overlay.sh | 修改 | 修复 overlay 安装脚本(必做) |
device/rockchip/common/overlays/rootfs/wifi-ap/etc/init.d/S45wifi-ap | 新建 | 开机自启服务 |
device/rockchip/common/overlays/rootfs/wifi-ap/usr/bin/wifi-ap | 新建 | AP 启停控制脚本 |
device/rockchip/common/overlays/rootfs/wifi-ap/etc/hostapd.conf | 新建 | hostapd 配置 |
device/rockchip/common/overlays/rootfs/wifi-ap/etc/dnsmasq.ap.conf | 新建 | DHCP 配置 |
注意
post-overlay.sh 的修改必须做,否则即使 overlay 文件创建得完全正确,构建出来的 rootfs 里也不会包含它们。具体原因见本文档最后一节的「附录A:overlay 安装脚本问题说明」。
操作步骤
下面所有路径都是相对于 SDK 根目录的。
指定 WiFi 模块为 AP6256
打开 device/rockchip/.chips/rk3576/tspi_3m_rk3576_buildroot_defconfig,找到 WiFi/BT 模块配置部分,替换为:
############################################################
# WiFi/BT Module (AP6256, SDIO)
############################################################
RK_WIFIBT_CHIP="AP6256"
RK_WIFIBT_ON_BOARD=y2
3
4
5
SDK 的配置系统通过 RK_WIFIBT_CHIP 和 RK_WIFIBT_ON_BOARD 来选定板载模块,构建脚本检测到 "AP6" 时会自动编译 bcmdhd SDIO 驱动,并把 AP6256 的固件(fw_bcm43456c5_ag.bin、nvram_ap6256.txt)打包进 rootfs。设备树默认已经包含了 SDIO WiFi 节点,不需要改动。
添加 iptables(可选)
如果需要让连接热点的设备通过板子的 eth0 口上网,打开 buildroot/configs/rockchip/wifibt/wireless.config,在末尾加一行:
BR2_PACKAGE_IPTABLES=y提示
如果只是纯局域网使用(设备之间互通即可),这一步可以跳过。
修复 overlay 安装脚本
打开 device/rockchip/common/scripts/post-overlay.sh,找到文件开头附近的这两行:
RK_RSYNC="rsync -av --chmod=u=rwX,go=rX --copy-unsafe-links --exclude .empty --exclude .git"
RK_OVERLAY_ALLOWED="$@"2
把第二行替换成下面这段:
RK_RSYNC="rsync -av --chmod=u=rwX,go=rX --copy-unsafe-links --exclude .empty --exclude .git"
RK_OVERLAY_ALLOWED=""
for arg in "$@"; do
for d in "$RK_COMMON_DIR" "$RK_CHIP_DIR"; do
[ -d "$d/overlays/rootfs/$arg" ] && \
RK_OVERLAY_ALLOWED="$RK_OVERLAY_ALLOWED $arg"
done
done2
3
4
5
6
7
8
9
创建 overlay 文件
先建好目录结构:
mkdir -p device/rockchip/common/overlays/rootfs/wifi-ap/etc/init.d
mkdir -p device/rockchip/common/overlays/rootfs/wifi-ap/usr/bin2
然后依次创建下面 4 个文件,创建完之后记得给两个脚本加上可执行权限:
chmod +x device/rockchip/common/overlays/rootfs/wifi-ap/etc/init.d/S45wifi-ap
chmod +x device/rockchip/common/overlays/rootfs/wifi-ap/usr/bin/wifi-ap2
etc/init.d/S45wifi-ap
开机自启服务脚本,负责在驱动加载后调用 wifi-ap start:
#!/bin/sh
### BEGIN INIT INFO
# Provides: wifi-ap
# Required-Start: wifibt-init
# Required-Stop:
# Default-Start: S
# Default-Stop:
# Description: Start WiFi AP mode (AP6256)
### END INIT INFO
WIFI_AP_AUTOSTART="${WIFI_AP_AUTOSTART:-yes}"
WIFI_AP_SSID="${WIFI_AP_SSID:-TaishanPi-3M}"
WIFI_AP_PASSWORD="${WIFI_AP_PASSWORD:-12345678}"
case "$1" in
start)
if [ "$WIFI_AP_AUTOSTART" = "yes" ]; then
echo "Starting WiFi AP (autostart)..."
/usr/bin/wifi-ap start "$WIFI_AP_SSID" "$WIFI_AP_PASSWORD"
else
echo "WiFi AP autostart disabled."
fi
;;
stop)
/usr/bin/wifi-ap stop
;;
restart)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
exit 02
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
脚本编号 S45 是为了排在 S36wifibt-init(加载 WiFi 驱动)之后,保证 wlan0 就绪后再启动 AP。
usr/bin/wifi-ap
AP 启停控制脚本,这是整个 AP 功能的核心:
#!/bin/sh -e
#
# WiFi AP mode control script for AP6256
#
# Usage:
# wifi-ap start [SSID] [PASSWORD]
# wifi-ap stop
# wifi-ap status
#
AP_CONF="/etc/hostapd.conf"
AP_DNSMASQ_CONF="/etc/dnsmasq.ap.conf"
AP_IFACE="wlan1"
AP_IP="192.168.88.1"
AP_NETMASK="255.255.255.0"
AP_DHCP_RANGE_START="192.168.88.100"
AP_DHCP_RANGE_END="192.168.88.200"
UPLINK_IFACE="eth0"
wait_for_wifi()
{
# WiFi 驱动由 S36wifibt-init 异步加载,等待 wlan0 就绪且能 up
for i in $(seq 1 100); do
ip link show wlan0 >/dev/null 2>&1 && \
ip link set wlan0 up >/dev/null 2>&1 && return 0
sleep 0.2
done
echo "ERROR: wlan0 not ready, WiFi driver not loaded?"
return 1
}
ap_start()
{
SSID="${1:-TaishanPi-3M}"
PASSWORD="$2"
wait_for_wifi || return 1
# SDK 自带的 S80dnsmasq 会在开机时读取 /etc/dnsmasq.conf 启动一个
# STA 模式的 dnsmasq 实例,和 AP 模式的 DHCP 冲突,把它重命名掉
if [ -f /etc/dnsmasq.conf ] && [ ! -f /etc/dnsmasq.conf.bak ]; then
mv /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
fi
killall dnsmasq 2>/dev/null || true
echo "Setting up AP interface $AP_IFACE ..."
# bcmdhd 驱动加载时可能已自动创建 wlan1,存在则直接用,不存在才创建
if ! ip link show "$AP_IFACE" >/dev/null 2>&1; then
iw phy0 interface add "$AP_IFACE" type managed
fi
sleep 1
ifconfig "$AP_IFACE" "$AP_IP" netmask "$AP_NETMASK"
ip link set "$AP_IFACE" up
generate_hostapd_conf "$SSID" "$PASSWORD"
echo "Starting hostapd ..."
hostapd -B "$AP_CONF"
for i in $(seq 1 30); do
[ -d /var/run/hostapd ] && break
sleep 0.3
done
echo "Starting dnsmasq ..."
dnsmasq --conf-file="$AP_DNSMASQ_CONF" --interface="$AP_IFACE"
setup_nat
echo ""
echo "============================================"
echo " WiFi AP started successfully!"
echo " SSID : $SSID"
[ -n "$PASSWORD" ] && echo " Password : $PASSWORD"
echo " AP IP : $AP_IP"
echo " DHCP range: $AP_DHCP_RANGE_START - $AP_DHCP_RANGE_END"
echo " Interface : $AP_IFACE"
echo "============================================"
}
ap_stop()
{
echo "Stopping WiFi AP ..."
killall hostapd 2>/dev/null || true
killall dnsmasq 2>/dev/null || true
sleep 1
# 只 down 接口不删除(bcmdhd 驱动自动创建的接口删了下次起不来)
ip link set "$AP_IFACE" down 2>/dev/null || true
iptables -t nat -D POSTROUTING -o "$UPLINK_IFACE" \
-s "${AP_IP%.*}.0/24" -j MASQUERADE 2>/dev/null || true
iptables -D FORWARD -i "$AP_IFACE" -o "$UPLINK_IFACE" \
-j ACCEPT 2>/dev/null || true
iptables -D FORWARD -i "$UPLINK_IFACE" -o "$AP_IFACE" \
-m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
sysctl -w net.ipv4.ip_forward=0 >/dev/null 2>&1 || true
}
setup_nat()
{
which iptables >/dev/null 2>&1 || {
echo "INFO: iptables not found, skipping NAT (LAN-only mode)"
return 0
}
sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1 || true
iptables -t nat -A POSTROUTING -o "$UPLINK_IFACE" \
-s "${AP_IP%.*}.0/24" -j MASQUERADE 2>/dev/null || true
iptables -A FORWARD -i "$AP_IFACE" -o "$UPLINK_IFACE" \
-j ACCEPT 2>/dev/null || true
iptables -A FORWARD -i "$UPLINK_IFACE" -o "$AP_IFACE" \
-m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
}
generate_hostapd_conf()
{
SSID="$1"
PASSWORD="$2"
cat > "$AP_CONF" <<EOF
interface=$AP_IFACE
ctrl_interface=/var/run/hostapd
driver=nl80211
ssid=$SSID
channel=6
hw_mode=g
ieee80211n=1
ignore_broadcast_ssid=0
wmm_enabled=1
EOF
if [ -n "$PASSWORD" ]; then
if [ ${#PASSWORD} -lt 8 ]; then
echo "WARNING: WPA password < 8 chars, AP will be OPEN"
return 0
fi
cat >> "$AP_CONF" <<EOF
auth_algs=1
wpa=2
wpa_passphrase=$PASSWORD
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
EOF
fi
}
ap_status()
{
echo "=== WiFi AP Status ==="
if pgrep -x hostapd >/dev/null 2>&1; then
echo " hostapd : RUNNING"
else
echo " hostapd : STOPPED"
fi
if ip link show "$AP_IFACE" >/dev/null 2>&1; then
echo " $AP_IFACE : UP"
ip addr show "$AP_IFACE" 2>/dev/null | grep inet || true
else
echo " $AP_IFACE : NOT FOUND"
fi
echo " Connected stations:"
iw dev "$AP_IFACE" station dump 2>/dev/null || echo " (none)"
}
case "$1" in
start)
ap_start "$2" "$3"
;;
stop)
ap_stop
;;
restart)
ap_stop
sleep 1
ap_start "$2" "$3"
;;
status)
ap_status
;;
*)
echo "Usage: $0 {start [ssid] [password] | stop | restart | status}"
echo ""
echo "Examples:"
echo " $0 start # 开放热点,SSID=TaishanPi-3M"
echo " $0 start MyAP mypassword123 # WPA2 加密热点"
echo " $0 stop"
echo " $0 status"
exit 1
;;
esac
exit 02
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
etc/hostapd.conf
hostapd 的配置文件,定义热点参数:
interface=wlan1
ctrl_interface=/var/run/hostapd
driver=nl80211
ssid=TaishanPi-3M
channel=6
hw_mode=g
ieee80211n=1
ignore_broadcast_ssid=0
wmm_enabled=1
# WPA2 加密,注释以下各行则为开放热点
auth_algs=1
wpa=2
wpa_passphrase=12345678
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
etc/dnsmasq.ap.conf
dnsmasq 的 DHCP 配置,负责给连接设备分配 IP:
user=root
interface=wlan1
listen-address=192.168.88.1
bind-interfaces
dhcp-range=192.168.88.100,192.168.88.200,255.255.255.0,12h
dhcp-option=option:router,192.168.88.1
dhcp-option=option:dns-server,192.168.88.1,8.8.8.8
no-hosts
no-resolv2
3
4
5
6
7
8
9
10
11
12
构建与烧录
编译镜像
- 编译方式参考:Buildroot镜像编译🚀 章节。
注意
如果之前已经构建过其他系统(比如 Ubuntu),或者改了 Buildroot 的包配置,记得先清理再编译:
rm -rf buildroot/output/构建完成后验证
烧录之前先检查 overlay 文件有没有正确打进 rootfs:
ls buildroot/output/rockchip_rk3576/target/etc/init.d/S45wifi-ap
ls buildroot/output/rockchip_rk3576/target/usr/bin/wifi-ap
ls buildroot/output/rockchip_rk3576/target/etc/hostapd.conf
ls buildroot/output/rockchip_rk3576/target/etc/dnsmasq.ap.conf2
3
4
四个文件都在就没问题。如果不存在,回头检查 修复 overlay 安装脚本 那一步是否到位。
烧录镜像
- 烧录方式参考:成品镜像烧录🚀 章节。
验证
板上检查
串口或 SSH 登录板子后,依次确认:
# WiFi 驱动是否加载
ip link show wlan0
# AP6256 固件是否正常
dmesg | grep -i bcmdhd
# 虚拟 AP 接口是否创建
ip link show wlan1
# hostapd 和 dnsmasq 是否在运行
pgrep -a hostapd
pgrep -a dnsmasq
# 查看 AP 状态
wifi-ap status2
3
4
5
6
7
8
9
10
11
12
13
14
15
手机连接测试
- 打开手机 WiFi,找到名为
TaishanPi-3M的热点 - 输入密码
12345678连接 - 手机会拿到
192.168.88.100~192.168.88.200之间的 IP - 如果板子
eth0接了网且编译时启用了 iptables,手机就能上网
手动控制命令
日常使用中可以用 wifi-ap 命令手动控制热点:
wifi-ap stop # 关闭热点
wifi-ap start # 用默认参数启动
wifi-ap start MyHotspot MyPass123 # 自定义名称和密码
wifi-ap status # 查看状态和已连接设备2
3
4
自定义配置
改热点名称和密码
编辑板子上的 /etc/init.d/S45wifi-ap,修改这两个变量:
WIFI_AP_SSID="你的热点名"
WIFI_AP_PASSWORD="你的密码"2
也可以直接用命令行参数启动:wifi-ap start 热点名 密码。
改 IP 网段
需要同时修改两个文件保持一致。
/usr/bin/wifi-ap 顶部的变量:
AP_IP="192.168.1.1"
AP_NETMASK="255.255.255.0"
AP_DHCP_RANGE_START="192.168.1.100"
AP_DHCP_RANGE_END="192.168.1.200"2
3
4
/etc/dnsmasq.ap.conf:
listen-address=192.168.1.1
dhcp-range=192.168.1.100,192.168.1.200,255.255.255.0,12h
dhcp-option=option:router,192.168.1.1
dhcp-option=option:dns-server,192.168.1.1,8.8.8.82
3
4
关闭开机自启
把 /etc/init.d/S45wifi-ap 里的 WIFI_AP_AUTOSTART 改成 no,之后用 wifi-ap start 手动启动即可。
切换回 STA 模式
如果需要让板子去连路由器(STA 模式),先关掉热点再连接:
wifi-ap stop
wifi-connect.sh "WiFi名" "WiFi密码"2
提示
STA 模式的详细使用方法参考:Buildroot AP6256 WiFi和蓝牙使用🚀 章节。
常见问题
构建后 rootfs 里没有 wifi-ap 相关文件
检查构建日志:
grep -A5 "90-overlay" output/log/latest/post-rootfs.log如果只看到 Running 90-overlay.sh 但没有 Installing overlay 字样,说明 修复 overlay 安装脚本 那一步的 post-overlay.sh 修改没生效。
看不到 wlan0 接口
dmesg | grep -i "bcmdhd\|wifi\|wlan"确认 /lib/modules/bcmdhd.ko、/lib/firmware/fw_bcm43456c5_ag.bin、/lib/firmware/nvram_ap6256.txt 都在。如果固件不在,检查 defconfig 里 WiFi 模块是不是设成了 AP6256。
iw phy0 interface add wlan1 报错
iw phy # 确认 phy0 存在
ip link set wlan0 up # 确保 wlan0 已经 up2
驱动刚加载时接口可能还没完全就绪,等几秒再试。
hostapd 启动失败
前台运行看详细报错:
hostapd -dd /etc/hostapd.conf
dmesg | tail -302
手机连上了但拿不到 IP
pgrep -a dnsmasq # dnsmasq 在不在
ip addr show wlan1 # IP 是不是 192.168.88.1
dnsmasq --test --conf-file=/etc/dnsmasq.ap.conf # 配置文件语法对不对2
3
如果有两个 dnsmasq 在跑(SDK 自带的 S80dnsmasq 没被禁掉):
killall dnsmasq
mv /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
wifi-ap restart2
3
拿到 IP 了但上不了网
cat /proc/sys/net/ipv4/ip_forward # 应该是 1
iptables -t nat -L POSTROUTING -n # 应该有 MASQUERADE 规则
ping -c 3 8.8.8.8 # eth0 本身能不能上网2
3
如果编译时没加 iptables 包,NAT 功能不可用,但局域网内部通信不受影响。
附录A:overlay 安装脚本问题说明
SDK 的 post-overlay.sh 负责把 device/rockchip/common/overlays/rootfs/ 下的各个目录安装到 rootfs。原脚本里有一行:
RK_OVERLAY_ALLOWED="$@"这个变量原本是给手动调试用的——比如只想安装某一个 overlay 时,可以通过参数指定。但在正常编译流程中,构建系统调用这个脚本时传入的参数里除了目标目录,还带有 defconfig 名称(比如 rockchip_rk3576_defconfig)。脚本把 shift 之后剩下的参数原样赋给了 RK_OVERLAY_ALLOWED,导致后续的安装逻辑拿着 rockchip_rk3576_defconfig 去做过滤——没有任何 overlay 目录叫这个名字,于是所有 overlay(包括 wifi-ap、irqbalance、fstrim 等)都被跳过了。
修复思路就是只把确实存在于 overlays/rootfs/ 下的目录名加入过滤列表,其余参数忽略掉。
附录B:开机启动顺序
上电
│
├─ S36wifibt-init 加载 bcmdhd.ko,wlan0 出现
├─ S40network ifup -a
├─ S45wifi-ap wifi-ap start
│ ├─ 创建 wlan1 虚拟接口
│ ├─ 配置 wlan1 的静态 IP
│ ├─ 启动 hostapd(AP 守护进程)
│ ├─ 启动 dnsmasq(DHCP)
│ └─ 配置 iptables NAT(如果可用)
├─ S80dnsmasq /etc/dnsmasq.conf 已被改名 → 直接退出
│
└─ 热点就绪,等待设备连接2
3
4
5
6
7
8
9
10
11
12
13
附录C:文件对照表
| 功能 | SDK 源码位置 | 板上路径 |
|---|---|---|
| WiFi 驱动 | external/rkwifibt/drivers/bcmdhd/bcmdhd.ko | /lib/modules/bcmdhd.ko |
| WiFi 固件 | external/rkwifibt/firmware/broadcom/AP6256/wifi/ | /lib/firmware/ |
| AP 控制脚本 | overlays/rootfs/wifi-ap/usr/bin/wifi-ap | /usr/bin/wifi-ap |
| AP 自启服务 | overlays/rootfs/wifi-ap/etc/init.d/S45wifi-ap | /etc/init.d/S45wifi-ap |
| hostapd 配置 | overlays/rootfs/wifi-ap/etc/hostapd.conf | /etc/hostapd.conf |
| dnsmasq 配置 | overlays/rootfs/wifi-ap/etc/dnsmasq.ap.conf | /etc/dnsmasq.ap.conf |