Replace tarball with un-tarred ImmortalWrt patch tree (package/feeds/files overrides)
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# v33 完美固件源码包
|
||||
|
||||
对应 sysupgrade-v33.bin(md5 57d43f1a56c66fafd5c62e8846641232)。
|
||||
|
||||
## 包含文件(相对 ImmortalWrt 源码树根)
|
||||
|
||||
### package/mtk/ — MTK 闭源驱动层补丁
|
||||
- `applications/mtwifi-cfg/files/mtwifi-cfg/mtwifi_cfg` — 5G/HE160 双分支写 VHT_Sec80_Channel=155
|
||||
- `applications/mtwifi-cfg/files/mtwifi.sh` — detect_mtwifi 诚实 UCI(idx=1=5g/HE160, idx=2=2g/HE40)
|
||||
- `applications/mtwifi-cfg/files/netifd/mtwifi.sh` — v33 关键补丁:setup 完成后 deferred 后台检测 dat MacAddress 与物理 netdev MAC,重发 wireless_add_vif 上报物理 ifname
|
||||
- `applications/luci-app-mtk/luasrc/controller/mtkwifi.lua` — 顶部空 index() 禁用 MTK 私有面板
|
||||
|
||||
### package/mtk/drivers/wifi-profile/
|
||||
- `files/mt7981/l1profile.dat` — 主次顺序 b0;b1(出厂值,未改动)
|
||||
|
||||
### feeds/luci/
|
||||
- `modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js` — Overview/Modal SSID 读 iwinfo、reload-block 补丁、freqlist/txpowerlist 改传物理 ifname
|
||||
|
||||
### files/ — 烤入 squashfs 的配置与脚本
|
||||
- `etc/uci-defaults/99-custom-config` — 首启 UCI 默认值(诚实标签 + turboacc tcpcca=bbr)
|
||||
- `etc/wifi-band-verify.sh` — log-only 验证脚本
|
||||
- `etc/rc.local` — 开机兜底(检测 vxlan0,缺失重触发)
|
||||
- `etc/hotplug.d/iface/30-mss-clamp` — MSS clamp 持久化
|
||||
- `etc/hotplug.d/iface/40-wg-track` — WG 隧道状态跟踪
|
||||
- `etc/sysctl.d/99-bridge-nf.conf` — bridge-nf-call-{ip,ip6,ar}tables=1
|
||||
- `etc/config/{wireless,firewall,dhcp,turboacc,dropbear,network}` — 7 个核心 UCI 配置全部烤入(**network 已脱敏:private_key 与 preshared_key 替换为占位符,使用前必须重新生成 WG 密钥对**)
|
||||
|
||||
### 顶层
|
||||
- `netifd-wireless.sh` — `/lib/netifd/netifd-wireless.sh` (wifi-scripts 包)
|
||||
|
||||
## 刷入流程
|
||||
1. 克隆 padavanonly fork 的 ImmortalWrt-Actions 源码树到 build server
|
||||
2. 用本包覆盖对应路径
|
||||
3. `make -j4` → `bin/targets/mediatek/filogic/immortalwrt-mediatek-filogic-cudy_tr3000-v1-ubootmod-squashfs-sysupgrade.bin`
|
||||
4. FIT 镜像雕刻验证:`OFF=$(grep -abo "hsqs" image.bin | head -1 | cut -d: -f1); dd if=image.bin of=root.sqfs bs=1 skip=$OFF; unsquashfs -d sq root.sqfs`
|
||||
5. U-Boot TFTP/网页刷入(**绝不用 sysupgrade**)
|
||||
+2468
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
config dnsmasq
|
||||
option domainneeded '1'
|
||||
option boguspriv '1'
|
||||
option filterwin2k '0'
|
||||
option localise_queries '1'
|
||||
option rebind_protection '1'
|
||||
option rebind_localhost '1'
|
||||
option local '/lan/'
|
||||
option domain 'lan'
|
||||
option expandhosts '1'
|
||||
option nonegcache '0'
|
||||
option cachesize '1000'
|
||||
option authoritative '1'
|
||||
option readethers '1'
|
||||
option leasefile '/tmp/dhcp.leases'
|
||||
option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
|
||||
option nonwildcard '1'
|
||||
option localservice '1'
|
||||
option ednspacket_max '1232'
|
||||
option filter_aaaa '0'
|
||||
option filter_a '0'
|
||||
|
||||
config dhcp 'lan'
|
||||
option interface 'lan'
|
||||
option ignore '1'
|
||||
|
||||
config dhcp 'wan'
|
||||
option interface 'wan'
|
||||
option ignore '1'
|
||||
|
||||
config odhcpd 'odhcpd'
|
||||
option maindhcp '0'
|
||||
option leasefile '/tmp/hosts/odhcpd'
|
||||
option leasetrigger '/usr/sbin/odhcpd-update'
|
||||
option loglevel '4'
|
||||
@@ -0,0 +1,4 @@
|
||||
config dropbear
|
||||
option PasswordAuth 'on'
|
||||
option RootPasswordAuth 'on'
|
||||
option Port '22'
|
||||
@@ -0,0 +1,122 @@
|
||||
config defaults
|
||||
option input 'REJECT'
|
||||
option output 'ACCEPT'
|
||||
option forward 'REJECT'
|
||||
option synflood_protect '1'
|
||||
option fullcone '1'
|
||||
option flow_offloading '0'
|
||||
|
||||
config zone
|
||||
option name 'lan'
|
||||
option input 'ACCEPT'
|
||||
option output 'ACCEPT'
|
||||
option forward 'ACCEPT'
|
||||
list network 'lan'
|
||||
list network 'wg0'
|
||||
|
||||
config zone
|
||||
option name 'wan'
|
||||
option input 'REJECT'
|
||||
option output 'ACCEPT'
|
||||
option forward 'REJECT'
|
||||
option masq '1'
|
||||
option mtu_fix '1'
|
||||
list network 'wan'
|
||||
list network 'wan6'
|
||||
|
||||
config forwarding
|
||||
option src 'lan'
|
||||
option dest 'wan'
|
||||
|
||||
config rule
|
||||
option name 'Allow-DHCP-Renew'
|
||||
option src 'wan'
|
||||
option proto 'udp'
|
||||
option dest_port '68'
|
||||
option target 'ACCEPT'
|
||||
option family 'ipv4'
|
||||
|
||||
config rule
|
||||
option name 'Allow-Ping'
|
||||
option src 'wan'
|
||||
option proto 'icmp'
|
||||
option icmp_type 'echo-request'
|
||||
option family 'ipv4'
|
||||
option target 'ACCEPT'
|
||||
|
||||
config rule
|
||||
option name 'Allow-IGMP'
|
||||
option src 'wan'
|
||||
option proto 'igmp'
|
||||
option family 'ipv4'
|
||||
option target 'ACCEPT'
|
||||
|
||||
config rule
|
||||
option name 'Allow-DHCPv6'
|
||||
option src 'wan'
|
||||
option proto 'udp'
|
||||
option dest_port '546'
|
||||
option family 'ipv6'
|
||||
option target 'ACCEPT'
|
||||
|
||||
config rule
|
||||
option name 'Allow-MLD'
|
||||
option src 'wan'
|
||||
option proto 'icmp'
|
||||
option src_ip 'fe80::/10'
|
||||
list icmp_type '130/0'
|
||||
list icmp_type '131/0'
|
||||
list icmp_type '132/0'
|
||||
list icmp_type '143/0'
|
||||
option family 'ipv6'
|
||||
option target 'ACCEPT'
|
||||
|
||||
config rule
|
||||
option name 'Allow-ICMPv6-Input'
|
||||
option src 'wan'
|
||||
option proto 'icmp'
|
||||
list icmp_type 'echo-request'
|
||||
list icmp_type 'echo-reply'
|
||||
list icmp_type 'destination-unreachable'
|
||||
list icmp_type 'packet-too-big'
|
||||
list icmp_type 'time-exceeded'
|
||||
list icmp_type 'bad-header'
|
||||
list icmp_type 'unknown-header-type'
|
||||
list icmp_type 'router-solicitation'
|
||||
list icmp_type 'neighbour-solicitation'
|
||||
list icmp_type 'router-advertisement'
|
||||
list icmp_type 'neighbour-advertisement'
|
||||
option limit '1000/sec'
|
||||
option family 'ipv6'
|
||||
option target 'ACCEPT'
|
||||
|
||||
config rule
|
||||
option name 'Allow-ICMPv6-Forward'
|
||||
option src 'wan'
|
||||
option dest '*'
|
||||
option proto 'icmp'
|
||||
list icmp_type 'echo-request'
|
||||
list icmp_type 'echo-reply'
|
||||
list icmp_type 'destination-unreachable'
|
||||
list icmp_type 'packet-too-big'
|
||||
list icmp_type 'time-exceeded'
|
||||
list icmp_type 'bad-header'
|
||||
list icmp_type 'unknown-header-type'
|
||||
option limit '1000/sec'
|
||||
option family 'ipv6'
|
||||
option target 'ACCEPT'
|
||||
|
||||
config rule
|
||||
option name 'Allow-IPSec-ESP'
|
||||
option src 'wan'
|
||||
option dest 'lan'
|
||||
option proto 'esp'
|
||||
option target 'ACCEPT'
|
||||
|
||||
config rule
|
||||
option name 'Allow-ISAKMP'
|
||||
option src 'wan'
|
||||
option dest 'lan'
|
||||
option dest_port '500'
|
||||
option proto 'udp'
|
||||
option target 'ACCEPT'
|
||||
@@ -0,0 +1,49 @@
|
||||
config interface 'loopback'
|
||||
option device 'lo'
|
||||
option proto 'static'
|
||||
option ipaddr '127.0.0.1'
|
||||
option netmask '255.0.0.0'
|
||||
|
||||
config globals 'globals'
|
||||
option ula_prefix 'fdab:c3fc:a55d::/48'
|
||||
|
||||
config device
|
||||
option name 'br-lan'
|
||||
option type 'bridge'
|
||||
list ports 'eth1'
|
||||
|
||||
config interface 'lan'
|
||||
option device 'br-lan'
|
||||
option proto 'static'
|
||||
option ipaddr '192.168.1.2'
|
||||
option netmask '255.255.255.0'
|
||||
option ip6assign '60'
|
||||
|
||||
config interface 'wan'
|
||||
option device 'eth0'
|
||||
option proto 'dhcp'
|
||||
|
||||
config interface 'wan6'
|
||||
option device 'eth0'
|
||||
option proto 'dhcpv6'
|
||||
|
||||
config interface 'wg0'
|
||||
option proto 'wireguard'
|
||||
option private_key '<REDACTED-YOUR-WG-PRIVATE-KEY'
|
||||
option listen_port '51820'
|
||||
list addresses '10.99.0.2/32'
|
||||
option mtu '1420'
|
||||
option route_allowed_ips '1'
|
||||
|
||||
config wireguard_wg0 'wgpeer'
|
||||
option public_key 'GPrZqc8t7F3DG/D0ks+GcZQeUYy+3ClFnbSftSqiygQ='
|
||||
option preshared_key '<REDACTED-YOUR-WG-PSK'
|
||||
option endpoint_host '10.200.80.93'
|
||||
option endpoint_port '51820'
|
||||
option persistent_keepalive '25'
|
||||
list allowed_ips '10.99.0.1/32'
|
||||
|
||||
config route
|
||||
option interface 'wg0'
|
||||
option target '10.99.0.1'
|
||||
option netmask '255.255.255.255'
|
||||
@@ -0,0 +1,14 @@
|
||||
config turboacc 'config'
|
||||
option fastpath 'mediatek_hnat'
|
||||
option fastpath_mh_eth_hnat '1'
|
||||
option fastpath_mh_eth_hnat_v6 '1'
|
||||
option fastpath_mh_eth_hnat_bind_rate '30'
|
||||
option fastpath_mh_eth_hnat_bind_trap '0'
|
||||
option fullcone_nat '2'
|
||||
option hal 'none'
|
||||
option sw_flow '0'
|
||||
option hw_flow '0'
|
||||
option sfe_bridge '0'
|
||||
option bbr_cca '1'
|
||||
option dns_caching '0'
|
||||
option dns_caching_dns '223.5.5.5,223.6.6.6'
|
||||
@@ -0,0 +1,43 @@
|
||||
config wifi-device 'MT7981_1_1'
|
||||
option type 'mtwifi'
|
||||
option phy 'ra0'
|
||||
option hwmode '11a'
|
||||
option band '5g'
|
||||
option dbdc_main '1'
|
||||
option channel '36'
|
||||
option txpower '100'
|
||||
option htmode 'HE160'
|
||||
option country 'CN'
|
||||
option mu_beamformer '1'
|
||||
option noscan '0'
|
||||
option serialize '1'
|
||||
|
||||
config wifi-iface 'default_MT7981_1_1'
|
||||
option device 'MT7981_1_1'
|
||||
option network 'lan'
|
||||
option mode 'ap'
|
||||
option ssid 'ImmortalWrt-5G'
|
||||
option encryption 'none'
|
||||
option uapsd '0'
|
||||
|
||||
config wifi-device 'MT7981_1_2'
|
||||
option type 'mtwifi'
|
||||
option phy 'rax0'
|
||||
option hwmode '11g'
|
||||
option band '2g'
|
||||
option dbdc_main '0'
|
||||
option channel 'auto'
|
||||
option txpower '100'
|
||||
option htmode 'HE40'
|
||||
option country 'CN'
|
||||
option mu_beamformer '1'
|
||||
option noscan '1'
|
||||
option serialize '1'
|
||||
|
||||
config wifi-iface 'default_MT7981_1_2'
|
||||
option device 'MT7981_1_2'
|
||||
option network 'lan'
|
||||
option mode 'ap'
|
||||
option ssid 'ImmortalWrt-2.4G'
|
||||
option encryption 'none'
|
||||
option uapsd '0'
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
# === MSS clamp persistence (坑 #12 part 3) ===
|
||||
# fw4 reload (triggered by any ifup) wipes the nft rule added by 20-vxlan hotplug.
|
||||
# This iface hotplug re-adds the rule after every interface ifup event,
|
||||
# but only if the rule is missing (idempotent).
|
||||
# Idempotency: grep for the unique "set 1360" string before adding.
|
||||
[ "$ACTION" = "ifup" ] || exit 0
|
||||
sleep 2 # wait for fw4 reload to complete
|
||||
nft list chain inet fw4 mangle_forward 2>/dev/null | grep -q 'set 1360' || \
|
||||
nft add rule inet fw4 mangle_forward 'iifname "br-lan" tcp flags syn tcp option maxseg size set 1360' 2>/dev/null
|
||||
exit 0
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# /etc/hotplug.d/iface/40-wg-track
|
||||
# 触发: 小路由 WAN iface 起来时 (boot / DHCP renew / link bounce)
|
||||
# 目的: 跟踪 WG 隧道自动恢复状态,验证坑 #15 是否真根除
|
||||
# 安装: scp 到 /etc/hotplug.d/iface/40-wg-track + chmod +x
|
||||
|
||||
[ "$ACTION" = "ifup" ] || exit 0
|
||||
case "$INTERFACE" in
|
||||
wan) ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
|
||||
WAN_IP=$(ip -4 addr show eth0 2>/dev/null | awk '/inet / {print $2; exit}' | cut -d/ -f1)
|
||||
[ -z "$WAN_IP" ] && exit 0
|
||||
|
||||
LOGFILE=/tmp/wg-tunnel-track.log
|
||||
|
||||
# 等 30s 让 tunnel 稳定 (handshake init + keepalive 至少跑两轮)
|
||||
sleep 30
|
||||
|
||||
TS=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
ENDPOINT=$(wg show wg0 2>/dev/null | awk '/endpoint:/ {print $2; exit}')
|
||||
HANDSHAKE=$(wg show wg0 2>/dev/null | awk -F': ' '/latest handshake/ {print $2}')
|
||||
TRANSFER=$(wg show wg0 2>/dev/null | awk '/transfer:/ {print $2, $3, $4, $5}')
|
||||
PING_LOSS=$(ping -c 3 -W 2 10.99.0.1 2>&1 | awk '/packets transmitted/ {print $6}')
|
||||
|
||||
STATUS="OK"
|
||||
[ "$PING_LOSS" != "0%" ] && STATUS="FAIL"
|
||||
|
||||
echo "$TS | status=$STATUS | WAN=$WAN_IP | endpoint=$ENDPOINT | handshake=$HANDSHAKE | loss=$PING_LOSS | xfer=$TRANSFER" >> "$LOGFILE"
|
||||
|
||||
# Rotate: 只保留最后 200 行
|
||||
tail -200 "$LOGFILE" > "$LOGFILE.tmp" 2>/dev/null && mv "$LOGFILE.tmp" "$LOGFILE"
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
# RPS/RFS tuning for single-RX-queue devices (mtk_soc_eth)
|
||||
# Distributes softirq across all CPUs; without this, all eth RX runs on CPU0 only.
|
||||
# Pairs with sysctl tuning in /etc/sysctl.conf (BBR + buffer sizes).
|
||||
|
||||
[ -d /sys/class/net/eth1/queues ] && echo 3 > /sys/class/net/eth1/queues/rx-0/rps_cpus
|
||||
[ -d /sys/class/net/eth0/queues ] && echo 3 > /sys/class/net/eth0/queues/rx-0/rps_cpus
|
||||
[ -d /sys/class/net/br-lan/queues ] && echo 3 > /sys/class/net/br-lan/queues/rx-0/rps_cpus
|
||||
[ -d /sys/class/net/ra0/queues ] && echo 3 > /sys/class/net/ra0/queues/rx-0/rps_cpus
|
||||
[ -d /sys/class/net/rax0/queues ] && echo 3 > /sys/class/net/rax0/queues/rx-0/rps_cpus
|
||||
|
||||
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries 2>/dev/null
|
||||
[ -f /sys/class/net/eth1/queues/rx-0/rps_flow_cnt ] && echo 32768 > /sys/class/net/eth1/queues/rx-0/rps_flow_cnt
|
||||
[ -f /sys/class/net/br-lan/queues/rx-0/rps_flow_cnt ] && echo 32768 > /sys/class/net/br-lan/queues/rx-0/rps_flow_cnt
|
||||
|
||||
# === VXLAN boot fallback (keng #12 part 2) ===
|
||||
# Hotplug 20-vxlan sometimes misses wg0 ifup at boot (no 10.99 route, no log entry).
|
||||
# If we got here without vxlan0, manually re-trigger the same script.
|
||||
[ -e /sys/class/net/vxlan0 ] || ACTION=ifup INTERFACE=wg0 /etc/hotplug.d/net/20-vxlan
|
||||
|
||||
# === WiFi band label verifier (v28, log-only) ===
|
||||
# Aligns UCI wifi labels with physical broadcast once driver is stable.
|
||||
# Log-only (no uci mutation); see /etc/wifi-band-verify.sh for rationale.
|
||||
( /etc/wifi-band-verify.sh >/dev/null 2>&1 & )
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,3 @@
|
||||
net.bridge.bridge-nf-call-ip6tables=1
|
||||
net.bridge.bridge-nf-call-iptables=1
|
||||
net.bridge.bridge-nf-call-arptables=1
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
# 99-custom-config - Apply TR3000-specific defaults on first boot
|
||||
# Sets LAN IP, WiFi SSID/htmode/uapsd, dnsmasq, IPv6 RA, turboacc BBR
|
||||
# Runs once (uci-defaults scripts auto-delete after running)
|
||||
#
|
||||
# v29 2026-07-22: HONEST labels. UCI idx=1=5g config (driver maps
|
||||
# band=5g content to the 5G PHY whatever netdev it is this boot).
|
||||
# idx=2=2g config (maps to 2.4G PHY). ra0/rax0 netdev binding is
|
||||
# random per boot but physical broadcast always correct (band-content
|
||||
# invariant). LuCI Overview shows iwinfo truth. Edit forms show UCI
|
||||
# config. Do NOT use LuCI Save and Apply (triggers wifi reload);
|
||||
# reboot to apply wireless changes.
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
# ===== LAN IP =====
|
||||
uci set network.lan.ipaddr="192.168.1.2"
|
||||
uci set network.lan.netmask="255.255.255.0"
|
||||
uci commit network
|
||||
|
||||
# ===== WiFi SSID + htmode + uapsd (honest labels) =====
|
||||
uci set wireless.MT7981_1_1.phy="ra0"
|
||||
uci set wireless.MT7981_1_1.band="5g"
|
||||
uci set wireless.MT7981_1_1.hwmode="11a"
|
||||
uci set wireless.MT7981_1_1.htmode="HE160"
|
||||
uci set wireless.MT7981_1_1.country="CN"
|
||||
uci set wireless.MT7981_1_1.channel="36"
|
||||
uci set wireless.MT7981_1_1.dbdc_main="1"
|
||||
uci set wireless.default_MT7981_1_1.ssid="ImmortalWrt-5G"
|
||||
uci set wireless.default_MT7981_1_1.uapsd="0"
|
||||
uci set wireless.default_MT7981_1_1.encryption="none"
|
||||
|
||||
uci set wireless.MT7981_1_2.phy="rax0"
|
||||
uci set wireless.MT7981_1_2.band="2g"
|
||||
uci set wireless.MT7981_1_2.hwmode="11g"
|
||||
uci set wireless.MT7981_1_2.htmode="HE40"
|
||||
uci set wireless.MT7981_1_2.country="CN"
|
||||
uci set wireless.MT7981_1_2.channel="auto"
|
||||
uci set wireless.MT7981_1_2.dbdc_main="0"
|
||||
uci set wireless.default_MT7981_1_2.ssid="ImmortalWrt-2.4G"
|
||||
uci set wireless.default_MT7981_1_2.uapsd="0"
|
||||
uci set wireless.default_MT7981_1_2.encryption="none"
|
||||
|
||||
uci commit wireless
|
||||
|
||||
# ===== dnsmasq enable =====
|
||||
/etc/init.d/dnsmasq enable
|
||||
|
||||
# ===== IPv6 RA disabled =====
|
||||
uci set dhcp.lan.ra="disabled"
|
||||
uci set dhcp.lan.dhcpv6="disabled"
|
||||
uci commit dhcp
|
||||
|
||||
# ===== turboacc: BBR as default TCP CCA =====
|
||||
# /etc/init.d/turboacc force-sets tcp_congestion_control from
|
||||
# turboacc.config.tcpcca at every boot (S90, after sysctl.d), defaulting
|
||||
# to cubic and clobbering sysctl.d/12-tcp-bbr.conf. Pin bbr here so the
|
||||
# 网络加速 page shows BBR active out of the box.
|
||||
uci set turboacc.config.tcpcca="bbr"
|
||||
uci commit turboacc
|
||||
|
||||
# ===== Firewall: prepare for MSS clamp via hotplug =====
|
||||
# fw4 reload wipes hotplug MSS clamp rules; the 30-mss-clamp hotplug
|
||||
# re-adds them on every iface ifup. No static config needed here.
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/bin/sh
|
||||
# wifi-band-verify.sh — LOG-ONLY diagnostic. Compares UCI labels against the
|
||||
# PHYSICAL band each netdev is on and records the verdict to logread.
|
||||
# NEVER writes UCI: with ra0/rax0 ↔ dat binding random per boot (and band-content
|
||||
# invariant keeping physical always correct), mutating UCI oscillates across
|
||||
# wifi reloads. Logging the mismatch is enough — LuCI display patch (wireless.js
|
||||
# getActiveSSID) makes the UI match iwinfo truth regardless of UCI labels.
|
||||
# Triggered by rc.local at boot and mtwifi_cfg dispatcher tail.
|
||||
# Commit-only would still be loop-safe, but useless: detection is non-deterministic
|
||||
# across reloads, so any commit causes oscillation. Log-only is structurally stable.
|
||||
|
||||
LOCK=/tmp/wifi-band-verify.lock
|
||||
NOW=$(date +%s)
|
||||
if [ -f "$LOCK" ]; then
|
||||
LAST=$(cat "$LOCK" 2>/dev/null)
|
||||
[ -n "$LAST" ] && [ $((NOW - LAST)) -lt 120 ] && exit 0
|
||||
fi
|
||||
echo "$NOW" > "$LOCK"
|
||||
|
||||
log() { logger -t wifi-band-verify -- "$*"; }
|
||||
|
||||
get_ch() { iwinfo "$1" info 2>/dev/null | awk '/Channel:/ {print $4}'; }
|
||||
get_essid(){ iwinfo "$1" info 2>/dev/null | awk -F"\x22" '/ESSID:/ {print $2}'; }
|
||||
|
||||
# Phase 1: wait until both radios report identical channels on two consecutive
|
||||
# 10s probes (guards against mid-init transient reads; max 18 rounds = 3min).
|
||||
ra0ch=""; rax0ch=""; stable=0; i=0
|
||||
while [ $i -lt 18 ]; do
|
||||
c1=$(get_ch ra0); c2=$(get_ch rax0)
|
||||
case "$c1" in ""|*[!0-9]*) c1="" ;; esac
|
||||
case "$c2" in ""|*[!0-9]*) c2="" ;; esac
|
||||
if [ -n "$c1" ] && [ -n "$c2" ] && [ "$c1" = "$ra0ch" ] && [ "$c2" = "$rax0ch" ]; then
|
||||
stable=1; break
|
||||
fi
|
||||
ra0ch=$c1; rax0ch=$c2
|
||||
i=$((i+1)); sleep 10
|
||||
done
|
||||
[ $stable -eq 1 ] || { log "radios not stable after 3min; skipped"; exit 0; }
|
||||
|
||||
# Phase 2: physical band from channel (2g ≤14, 5g ≥36)
|
||||
band_of() { [ "$1" -le 14 ] && echo 2g || echo 5g; }
|
||||
ra0band=$(band_of "$ra0ch"); rax0band=$(band_of "$rax0ch")
|
||||
[ "$ra0band" = "$rax0band" ] && { log "both radios on $ra0band ch$ra0ch/$rax0ch; abnormal"; exit 0; }
|
||||
|
||||
# Phase 3: read UCI labels and live ESSIDs, log verdict — NO mutation.
|
||||
uci -q get wireless.MT7981_1_1 >/dev/null || exit 0
|
||||
uci -q get wireless.MT7981_1_2 >/dev/null || exit 0
|
||||
u1=$(uci -q get wireless.MT7981_1_1.band)
|
||||
u2=$(uci -q get wireless.MT7981_1_2.band)
|
||||
s1=$(uci -q get wireless.default_MT7981_1_1.ssid)
|
||||
s2=$(uci -q get wireless.default_MT7981_1_2.ssid)
|
||||
e1=$(get_essid ra0); e2=$(get_essid rax0)
|
||||
|
||||
if [ "$u1" = "$ra0band" ] && [ "$u2" = "$rax0band" ] && [ "$s1" = "$e1" ] && [ "$s2" = "$e2" ]; then
|
||||
log "consistent: ra0=$ra0band ch$ra0ch [$e1], rax0=$rax0band ch$rax0ch [$e2]; uci=$u1/$u2"
|
||||
else
|
||||
log "MISMATCH (no-op): ra0=$ra0band ch$ra0ch [$e1], rax0=$rax0band ch$rax0ch [$e2]; uci=$u1/$u2 ssid=$s1/$s2"
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,440 @@
|
||||
NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. $NETIFD_MAIN_DIR/utils.sh
|
||||
|
||||
CMD_UP=0
|
||||
CMD_SET_DATA=1
|
||||
CMD_PROCESS_ADD=2
|
||||
CMD_PROCESS_KILL_ALL=3
|
||||
CMD_SET_RETRY=4
|
||||
|
||||
add_driver() {
|
||||
return
|
||||
}
|
||||
|
||||
wireless_setup_vif_failed() {
|
||||
local error="$1"
|
||||
echo "Interface $_w_iface setup failed: $error"
|
||||
}
|
||||
|
||||
wireless_setup_failed() {
|
||||
local error="$1"
|
||||
|
||||
echo "Device setup failed: $error"
|
||||
wireless_set_retry 0
|
||||
}
|
||||
|
||||
prepare_key_wep() {
|
||||
local key="$1"
|
||||
local hex=1
|
||||
|
||||
echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
|
||||
[ "${#key}" -eq 10 -a $hex -eq 1 ] || \
|
||||
[ "${#key}" -eq 26 -a $hex -eq 1 ] || {
|
||||
[ "${key:0:2}" = "s:" ] && key="${key#s:}"
|
||||
key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
|
||||
}
|
||||
echo "$key"
|
||||
}
|
||||
|
||||
_wdev_prepare_channel() {
|
||||
json_get_vars channel band hwmode
|
||||
|
||||
auto_channel=0
|
||||
enable_ht=0
|
||||
htmode=
|
||||
hwmode="${hwmode##11}"
|
||||
|
||||
case "$channel" in
|
||||
""|0|auto)
|
||||
channel=0
|
||||
auto_channel=1
|
||||
;;
|
||||
[0-9]*) ;;
|
||||
*)
|
||||
wireless_setup_failed "INVALID_CHANNEL"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$hwmode" in
|
||||
a|b|g|ad) ;;
|
||||
*)
|
||||
if [ "$channel" -gt 14 ]; then
|
||||
hwmode=a
|
||||
else
|
||||
hwmode=g
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$band" in
|
||||
2g) hwmode=g;;
|
||||
5g|6g) hwmode=a;;
|
||||
60g) hwmode=ad;;
|
||||
*)
|
||||
case "$hwmode" in
|
||||
*a) band=5g;;
|
||||
*ad) band=60g;;
|
||||
*b|*g) band=2g;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_wdev_handler() {
|
||||
json_load "$data"
|
||||
|
||||
json_select config
|
||||
_wdev_prepare_channel
|
||||
json_select ..
|
||||
|
||||
eval "drv_$1_$2 \"$interface\""
|
||||
}
|
||||
|
||||
_wdev_msg_call() {
|
||||
local old_cb
|
||||
|
||||
json_set_namespace wdev old_cb
|
||||
"$@"
|
||||
json_set_namespace $old_cb
|
||||
}
|
||||
|
||||
_wdev_wrapper() {
|
||||
while [ -n "$1" ]; do
|
||||
eval "$1() { _wdev_msg_call _$1 \"\$@\"; }"
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
_wdev_notify_init() {
|
||||
local command="$1"; shift;
|
||||
|
||||
json_init
|
||||
json_add_int "command" "$command"
|
||||
json_add_string "device" "$__netifd_device"
|
||||
while [ -n "$1" ]; do
|
||||
local name="$1"; shift
|
||||
local value="$1"; shift
|
||||
json_add_string "$name" "$value"
|
||||
done
|
||||
json_add_object "data"
|
||||
}
|
||||
|
||||
_wdev_notify() {
|
||||
local options="$1"
|
||||
|
||||
json_close_object
|
||||
ubus $options call network.wireless notify "$(json_dump)"
|
||||
}
|
||||
|
||||
_wdev_add_variables() {
|
||||
while [ -n "$1" ]; do
|
||||
local var="${1%%=*}"
|
||||
local val="$1"
|
||||
shift
|
||||
[[ "$var" = "$val" ]] && continue
|
||||
val="${val#*=}"
|
||||
json_add_string "$var" "$val"
|
||||
done
|
||||
}
|
||||
|
||||
_wireless_add_vif() {
|
||||
local name="$1"; shift
|
||||
local ifname="$1"; shift
|
||||
|
||||
_wdev_notify_init $CMD_SET_DATA "interface" "$name"
|
||||
json_add_string "ifname" "$ifname"
|
||||
_wdev_add_variables "$@"
|
||||
_wdev_notify
|
||||
}
|
||||
|
||||
_wireless_add_vlan() {
|
||||
local name="$1"; shift
|
||||
local ifname="$1"; shift
|
||||
|
||||
_wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name"
|
||||
json_add_string "ifname" "$ifname"
|
||||
_wdev_add_variables "$@"
|
||||
_wdev_notify
|
||||
}
|
||||
|
||||
_wireless_set_up() {
|
||||
_wdev_notify_init $CMD_UP
|
||||
_wdev_notify
|
||||
}
|
||||
|
||||
_wireless_set_data() {
|
||||
_wdev_notify_init $CMD_SET_DATA
|
||||
_wdev_add_variables "$@"
|
||||
_wdev_notify
|
||||
}
|
||||
|
||||
_wireless_add_process() {
|
||||
_wdev_notify_init $CMD_PROCESS_ADD
|
||||
local exe="$2"
|
||||
[ -L "$exe" ] && exe="$(readlink -f "$exe")"
|
||||
json_add_int pid "$1"
|
||||
json_add_string exe "$exe"
|
||||
[ -n "$3" ] && json_add_boolean required 1
|
||||
[ -n "$4" ] && json_add_boolean keep 1
|
||||
exe2="$(readlink -f /proc/$1/exe)"
|
||||
[ "$exe" != "$exe2" ] && echo "WARNING (wireless_add_process): executable path $exe does not match process $1 path ($exe2)"
|
||||
_wdev_notify
|
||||
}
|
||||
|
||||
_wireless_process_kill_all() {
|
||||
_wdev_notify_init $CMD_PROCESS_KILL_ALL
|
||||
[ -n "$1" ] && json_add_int signal "$1"
|
||||
_wdev_notify
|
||||
}
|
||||
|
||||
_wireless_set_retry() {
|
||||
_wdev_notify_init $CMD_SET_RETRY
|
||||
json_add_int retry "$1"
|
||||
_wdev_notify
|
||||
}
|
||||
|
||||
_wdev_wrapper \
|
||||
wireless_add_vif \
|
||||
wireless_add_vlan \
|
||||
wireless_set_up \
|
||||
wireless_set_data \
|
||||
wireless_add_process \
|
||||
wireless_process_kill_all \
|
||||
wireless_set_retry \
|
||||
|
||||
wireless_vif_parse_encryption() {
|
||||
json_get_vars encryption
|
||||
set_default encryption none
|
||||
|
||||
auth_mode_open=1
|
||||
auth_mode_shared=0
|
||||
auth_type=none
|
||||
|
||||
if [ "$hwmode" = "ad" ]; then
|
||||
wpa_cipher="GCMP"
|
||||
else
|
||||
wpa_cipher="CCMP"
|
||||
fi
|
||||
|
||||
case "$encryption" in
|
||||
*tkip+aes|*tkip+ccmp|*aes+tkip|*ccmp+tkip) wpa_cipher="CCMP TKIP";;
|
||||
*ccmp256) wpa_cipher="CCMP-256";;
|
||||
*aes|*ccmp) wpa_cipher="CCMP";;
|
||||
*tkip) wpa_cipher="TKIP";;
|
||||
*gcmp256) wpa_cipher="GCMP-256";;
|
||||
*gcmp) wpa_cipher="GCMP";;
|
||||
wpa3-192*) wpa_cipher="GCMP-256";;
|
||||
esac
|
||||
|
||||
# 802.11n requires CCMP for WPA
|
||||
[ "$enable_ht:$wpa_cipher" = "1:TKIP" ] && wpa_cipher="CCMP TKIP"
|
||||
|
||||
# Examples:
|
||||
# psk-mixed/tkip => WPA1+2 PSK, TKIP
|
||||
# wpa-psk2/tkip+aes => WPA2 PSK, CCMP+TKIP
|
||||
# wpa2/tkip+aes => WPA2 RADIUS, CCMP+TKIP
|
||||
|
||||
case "$encryption" in
|
||||
wpa2*|wpa3*|*psk2*|psk3*|sae*|owe*)
|
||||
wpa=2
|
||||
;;
|
||||
wpa*mixed*|*psk*mixed*)
|
||||
wpa=3
|
||||
;;
|
||||
wpa*|*psk*)
|
||||
wpa=1
|
||||
;;
|
||||
*)
|
||||
wpa=0
|
||||
wpa_cipher=
|
||||
;;
|
||||
esac
|
||||
wpa_pairwise="$wpa_cipher"
|
||||
|
||||
case "$encryption" in
|
||||
owe*)
|
||||
auth_type=owe
|
||||
;;
|
||||
wpa3-192*)
|
||||
auth_type=eap192
|
||||
;;
|
||||
wpa3-mixed*)
|
||||
auth_type=eap-eap2
|
||||
;;
|
||||
wpa3*)
|
||||
auth_type=eap2
|
||||
;;
|
||||
psk3-mixed*|sae-mixed*)
|
||||
auth_type=psk-sae
|
||||
;;
|
||||
psk3*|sae*)
|
||||
auth_type=sae
|
||||
;;
|
||||
*psk*)
|
||||
auth_type=psk
|
||||
;;
|
||||
*wpa*|*8021x*)
|
||||
auth_type=eap
|
||||
;;
|
||||
*wep*)
|
||||
auth_type=wep
|
||||
case "$encryption" in
|
||||
*shared*)
|
||||
auth_mode_open=0
|
||||
auth_mode_shared=1
|
||||
;;
|
||||
*mixed*)
|
||||
auth_mode_shared=1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$encryption" in
|
||||
*osen*)
|
||||
auth_osen=1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_wireless_set_brsnoop_isolation() {
|
||||
local multicast_to_unicast="$1"
|
||||
local isolate
|
||||
|
||||
json_get_vars isolate proxy_arp
|
||||
|
||||
[ ${isolate:-0} -gt 0 -o -z "$network_bridge" ] && return
|
||||
[ ${multicast_to_unicast:-1} -gt 0 -o ${proxy_arp:-0} -gt 0 ] && json_add_boolean isolate 1
|
||||
}
|
||||
|
||||
for_each_interface() {
|
||||
local _w_types="$1"; shift
|
||||
local _w_ifaces _w_iface
|
||||
local _w_type
|
||||
local _w_found
|
||||
|
||||
local multicast_to_unicast
|
||||
|
||||
json_get_keys _w_ifaces interfaces
|
||||
json_select interfaces
|
||||
for _w_iface in $_w_ifaces; do
|
||||
json_select "$_w_iface"
|
||||
if [ -n "$_w_types" ]; then
|
||||
json_get_var network_bridge bridge
|
||||
json_get_var network_ifname bridge-ifname
|
||||
json_get_var multicast_to_unicast multicast_to_unicast
|
||||
json_select config
|
||||
_wireless_set_brsnoop_isolation "$multicast_to_unicast"
|
||||
json_get_var _w_type mode
|
||||
json_select ..
|
||||
_w_types=" $_w_types "
|
||||
[[ "${_w_types%$_w_type*}" = "$_w_types" ]] && {
|
||||
json_select ..
|
||||
continue
|
||||
}
|
||||
fi
|
||||
__cur_interface="$_w_iface"
|
||||
"$@" "$_w_iface"
|
||||
json_select ..
|
||||
done
|
||||
json_select ..
|
||||
}
|
||||
|
||||
for_each_vlan() {
|
||||
local _w_vlans _w_vlan
|
||||
|
||||
json_get_keys _w_vlans vlans
|
||||
json_select vlans
|
||||
for _w_vlan in $_w_vlans; do
|
||||
json_select "$_w_vlan"
|
||||
json_select config
|
||||
"$@" "$_w_vlan"
|
||||
json_select ..
|
||||
json_select ..
|
||||
done
|
||||
json_select ..
|
||||
}
|
||||
|
||||
for_each_station() {
|
||||
local _w_stas _w_sta
|
||||
|
||||
json_get_keys _w_stas stas
|
||||
json_select stas
|
||||
for _w_sta in $_w_stas; do
|
||||
json_select "$_w_sta"
|
||||
json_select config
|
||||
"$@" "$_w_sta"
|
||||
json_select ..
|
||||
json_select ..
|
||||
done
|
||||
json_select ..
|
||||
}
|
||||
|
||||
_wdev_common_device_config() {
|
||||
config_add_string channel hwmode band htmode noscan
|
||||
}
|
||||
|
||||
_wdev_common_iface_config() {
|
||||
config_add_string mode ssid encryption 'key:wpakey'
|
||||
config_add_boolean bridge_isolate
|
||||
config_add_array tags
|
||||
}
|
||||
|
||||
_wdev_common_vlan_config() {
|
||||
config_add_string name vid iface
|
||||
config_add_boolean bridge_isolate
|
||||
}
|
||||
|
||||
_wdev_common_station_config() {
|
||||
config_add_string mac key vid iface
|
||||
}
|
||||
|
||||
init_wireless_driver() {
|
||||
name="$1"; shift
|
||||
cmd="$1"; shift
|
||||
|
||||
case "$cmd" in
|
||||
dump)
|
||||
add_driver() {
|
||||
eval "drv_$1_cleanup"
|
||||
|
||||
json_init
|
||||
json_add_string name "$1"
|
||||
|
||||
json_add_array device
|
||||
_wdev_common_device_config
|
||||
eval "drv_$1_init_device_config"
|
||||
json_close_array
|
||||
|
||||
json_add_array iface
|
||||
_wdev_common_iface_config
|
||||
eval "drv_$1_init_iface_config"
|
||||
json_close_array
|
||||
|
||||
json_add_array vlan
|
||||
_wdev_common_vlan_config
|
||||
eval "drv_$1_init_vlan_config"
|
||||
json_close_array
|
||||
|
||||
json_add_array station
|
||||
_wdev_common_station_config
|
||||
eval "drv_$1_init_station_config"
|
||||
json_close_array
|
||||
|
||||
json_dump
|
||||
}
|
||||
;;
|
||||
setup|teardown)
|
||||
interface="$1"; shift
|
||||
data="$1"; shift
|
||||
export __netifd_device="$interface"
|
||||
|
||||
add_driver() {
|
||||
[[ "$name" == "$1" ]] || return 0
|
||||
_wdev_handler "$1" "$cmd"
|
||||
}
|
||||
;;
|
||||
esac
|
||||
}
|
||||
+1380
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,698 @@
|
||||
#!/usr/bin/lua
|
||||
--[[
|
||||
*
|
||||
* Copyright (C) 2023 hanwckf <hanwckf@vip.qq.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* The Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
]]
|
||||
|
||||
local cjson = require "cjson"
|
||||
local inspect = require "inspect"
|
||||
local nixio = require "nixio"
|
||||
local l1parser = require "l1dat_parser"
|
||||
local datconf = require "datconf"
|
||||
local utils = require "mtwifi_utils"
|
||||
local defs = require "mtwifi_defs"
|
||||
|
||||
local l1dat = l1parser.load_l1_profile(l1parser.L1_DAT_PATH)
|
||||
|
||||
function string:split(sep)
|
||||
local sep, fields = sep or ":", {}
|
||||
local pattern = string.format("([^%s]+)", sep)
|
||||
self:gsub(pattern, function(c) fields[#fields+1] = c end)
|
||||
return fields
|
||||
end
|
||||
|
||||
function load_profile(path)
|
||||
local cfgs = {}
|
||||
|
||||
cfgobj = datconf.openfile(path)
|
||||
if cfgobj then
|
||||
cfgs = cfgobj:getall()
|
||||
cfgobj:close()
|
||||
end
|
||||
|
||||
return cfgs
|
||||
end
|
||||
|
||||
function save_profile(cfgs, path)
|
||||
if not cfgs then
|
||||
return
|
||||
end
|
||||
|
||||
local datobj = datconf.openfile(path)
|
||||
datobj:merge(cfgs)
|
||||
datobj:close(true)
|
||||
|
||||
os.execute("sync")
|
||||
end
|
||||
|
||||
function diff_cfg(cfg1, cfg2)
|
||||
local diff = {}
|
||||
|
||||
for k,v in pairs(cfg1) do
|
||||
if tostring(cfg2[k]) ~= tostring(cfg1[k]) then
|
||||
diff[k] = {cfg1[k] or "", cfg2[k] or ""}
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs(cfg2) do
|
||||
if tostring(cfg2[k]) ~= tostring(cfg1[k]) then
|
||||
diff[k] = {cfg1[k] or "", cfg2[k] or ""}
|
||||
end
|
||||
end
|
||||
|
||||
return diff
|
||||
end
|
||||
|
||||
function vif_status(ifname)
|
||||
local flags = tonumber(utils.read_pipe("cat /sys/class/net/"..ifname.."/flags 2>/dev/null")) or 0
|
||||
if flags%2 == 1 then
|
||||
return "up"
|
||||
end
|
||||
return "down"
|
||||
end
|
||||
|
||||
function is_dbdc_inited(ifname)
|
||||
local mac = utils.trim(utils.read_pipe("cat /sys/class/net/"..ifname.."/address 2>/dev/null"))
|
||||
if mac and mac ~= "00:00:00:00:00:00" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ifup(ifname)
|
||||
if ifname and #ifname > 0 then
|
||||
os.execute("ifconfig "..ifname.." up")
|
||||
end
|
||||
end
|
||||
|
||||
function ifdown(ifname)
|
||||
if ifname and #ifname > 0 then
|
||||
os.execute("ifconfig "..ifname.." down")
|
||||
end
|
||||
end
|
||||
|
||||
function cfg2dat(cfg)
|
||||
if type(cfg) == type(true) then
|
||||
if cfg then return 1 else return 0 end
|
||||
elseif type(cfg) == type(0) or type(cfg) == type("") then
|
||||
return cfg
|
||||
end
|
||||
end
|
||||
|
||||
function set_dev_dat(dats, dat, cfg)
|
||||
if cfg ~= nil then
|
||||
dats[dat] = cfg2dat(cfg)
|
||||
end
|
||||
end
|
||||
|
||||
function set_dat(dats, apidx, dat, cfg)
|
||||
if cfg ~= nil then
|
||||
dats[dat] = utils.token_set(dats[dat], apidx, cfg2dat(cfg))
|
||||
end
|
||||
end
|
||||
|
||||
function set_idx_dat(dats, apidx, dat, cfg)
|
||||
if cfg ~= nil then
|
||||
dats[dat..tostring(apidx)] = cfg
|
||||
end
|
||||
end
|
||||
|
||||
function vif_in_dev(vif, dev)
|
||||
if (vif == dev.main_ifname
|
||||
or string.match(vif, utils.esc(dev.ext_ifname).."[0-9]+")
|
||||
or string.match(vif, utils.esc(dev.apcli_ifname).."[0-9]+")
|
||||
or string.match(vif, utils.esc(dev.wds_ifname).."[0-9]+")
|
||||
or string.match(vif, utils.esc(dev.mesh_ifname).."[0-9]+")) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function vif_is_apcli(vif, dev)
|
||||
if (string.match(vif, utils.esc(dev.apcli_ifname).."[0-9]+")) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function vif_count(cfg)
|
||||
local vif_num = 0
|
||||
local ap_num = 0
|
||||
local apcli_num = 0
|
||||
|
||||
for k,v in pairs(cfg.interfaces) do
|
||||
vif_num = vif_num + 1
|
||||
if v.config.mode == "ap" then
|
||||
ap_num = ap_num + 1
|
||||
elseif v.config.mode == "sta" then
|
||||
apcli_num = apcli_num +1
|
||||
end
|
||||
end
|
||||
|
||||
return vif_num, ap_num, apcli_num
|
||||
end
|
||||
|
||||
function mtwifi_cfg_foreach_vif(cfg, mode, func)
|
||||
if cfg == nil or func == nil then return end
|
||||
|
||||
local vif_num,_,_ = vif_count(cfg)
|
||||
for idx=0,vif_num-1 do
|
||||
local v = cfg.interfaces[tostring(idx)]
|
||||
if v.config.mode and v.config.mode == mode then
|
||||
func(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function __apcli_auto_connect(ifname)
|
||||
__exec_iwpriv_cmd(ifname, "ApCliEnable", "1")
|
||||
__exec_iwpriv_cmd(ifname, "ApCliAutoConnect", "3")
|
||||
end
|
||||
|
||||
function mtwifi_up(devname, cfg, restore_vifs, is_dbdc)
|
||||
nixio.syslog("info", "mtwifi-cfg: start "..devname)
|
||||
local dev = l1dat.devname_ridx[devname]
|
||||
local dbdc_main_ifname = defs.dbdc_init_ifname
|
||||
|
||||
if not dev then return end
|
||||
|
||||
if is_dbdc then
|
||||
if not is_dbdc_inited(dbdc_main_ifname) then
|
||||
nixio.syslog("info", "mtwifi-cfg: dbdc card init...")
|
||||
ifup(dbdc_main_ifname)
|
||||
utils.sleep(1)
|
||||
ifdown(dbdc_main_ifname)
|
||||
end
|
||||
|
||||
if restore_vifs and devname ~= cfg.device then
|
||||
-- restart ap vif
|
||||
for _,vif in ipairs(restore_vifs) do
|
||||
if vif_in_dev(vif, dev) and (not vif_is_apcli(vif, dev)) then
|
||||
nixio.syslog("info", "mtwifi-cfg: restore ap vif: "..vif)
|
||||
ifup(vif)
|
||||
end
|
||||
end
|
||||
-- restart apcli vif
|
||||
for _,vif in ipairs(restore_vifs) do
|
||||
if vif_is_apcli(vif, dev) then
|
||||
nixio.syslog("info", "mtwifi-cfg: restore apcli vif: "..vif)
|
||||
ifup(vif)
|
||||
__apcli_auto_connect(vif)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local start_vif = function(v)
|
||||
if (not v.config.disabled) and v.mtwifi_ifname then
|
||||
local vif = v.mtwifi_ifname
|
||||
nixio.syslog("info", "mtwifi-cfg: up vif: "..vif)
|
||||
ifup(vif)
|
||||
end
|
||||
end
|
||||
|
||||
mtwifi_cfg_foreach_vif(cfg, "ap", start_vif)
|
||||
mtwifi_cfg_foreach_vif(cfg, "sta", start_vif)
|
||||
os.execute("startwapp.sh")
|
||||
end
|
||||
|
||||
function mtwifi_down(devname, cfg)
|
||||
nixio.syslog("info", "mtwifi-cfg: stop "..devname)
|
||||
local dev = l1dat.devname_ridx[devname]
|
||||
local reset_vifs = {}
|
||||
|
||||
if not dev then return end
|
||||
|
||||
for _,vif in ipairs(string.split(utils.read_pipe("ls /sys/class/net"), "\n")) do
|
||||
if (vif_status(vif) == "up" and vif_in_dev(vif, dev)) then
|
||||
nixio.syslog("info", "mtwifi-cfg: down vif: "..vif)
|
||||
ifdown(vif)
|
||||
if cfg and devname ~= cfg.device then
|
||||
reset_vifs[#reset_vifs+1] = vif
|
||||
end
|
||||
end
|
||||
end
|
||||
os.execute("startwapp.sh")
|
||||
return reset_vifs
|
||||
end
|
||||
|
||||
function mtwifi_reinstall()
|
||||
nixio.syslog("info", "mtwifi-cfg: unload mtwifi module...")
|
||||
|
||||
--os.execute("rmmod mt_whnat")
|
||||
--os.execute("rmmod mtfwd")
|
||||
os.execute("rmmod mtk_warp_proxy")
|
||||
os.execute("rmmod mtk_warp")
|
||||
--os.execute("rmmod mt7915_mt_wifi")
|
||||
os.execute("rmmod mt_wifi")
|
||||
|
||||
utils.sleep(2)
|
||||
|
||||
nixio.syslog("info", "mtwifi-cfg: reload mtwifi module...")
|
||||
|
||||
os.execute("modprobe mt_wifi")
|
||||
--os.execute("modprobe mt7915_mt_wifi")
|
||||
os.execute("modprobe mtk_warp")
|
||||
os.execute("modprobe mtk_warp_proxy")
|
||||
--os.execute("modprobe mtfwd")
|
||||
--os.execute("modprobe mt_whnat")
|
||||
end
|
||||
|
||||
function __exec_iwpriv_cmd(ifname, key, val)
|
||||
local cmd = string.format("iwpriv %s set %s=%s", ifname, key, tostring(val))
|
||||
nixio.syslog("info", "mtwifi-cfg: iwpriv cmd: "..cmd)
|
||||
os.execute(cmd)
|
||||
end
|
||||
|
||||
function mtwifi_cfg_iwpriv_hook(cfg)
|
||||
local ap_hook = function(v)
|
||||
if (not v.config.disabled) and v.mtwifi_ifname then
|
||||
local vif = v.mtwifi_ifname
|
||||
for k, j in pairs(defs.iwpriv_ap_cfgs) do
|
||||
__exec_iwpriv_cmd(vif, j[1], v.config[k] or j[2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local apcli_hook = function(v)
|
||||
if (not v.config.disabled) and v.mtwifi_ifname then
|
||||
local vif = v.mtwifi_ifname
|
||||
__apcli_auto_connect(vif)
|
||||
end
|
||||
end
|
||||
|
||||
mtwifi_cfg_foreach_vif(cfg, "ap", ap_hook)
|
||||
mtwifi_cfg_foreach_vif(cfg, "sta", apcli_hook)
|
||||
end
|
||||
|
||||
function set_chip_cfg(cfg, dats)
|
||||
local dev_dats
|
||||
local uci
|
||||
local dat_key
|
||||
|
||||
if not cfg.config.dbdc_main then return end
|
||||
|
||||
for k,v in pairs(defs.chip_cfgs) do
|
||||
uci = k
|
||||
dat_key = v[1]
|
||||
|
||||
-- reset chip cfgs to default
|
||||
dats[dat_key] = v[2]
|
||||
|
||||
-- setup current dev cfg
|
||||
set_dev_dat(dats, dat_key, cfg.config[uci])
|
||||
end
|
||||
|
||||
-- setup other dev cfg
|
||||
for k,v in pairs(l1dat.devname_ridx) do
|
||||
if k ~= cfg.device then
|
||||
dev_dats = load_profile(v.profile_path)
|
||||
if dev_dats then
|
||||
for _,j in pairs(defs.chip_cfgs) do
|
||||
dat_key = j[1]
|
||||
set_dev_dat(dev_dats, dat_key, dats[dat_key])
|
||||
end
|
||||
save_profile(dev_dats, v.profile_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mtwifi_cfg_setup(argv)
|
||||
local cfg = cjson.decode(argv)
|
||||
|
||||
utils.log2file("input = " .. inspect(cfg))
|
||||
|
||||
local devname = cfg.device
|
||||
local dev = l1dat.devname_ridx[devname]
|
||||
|
||||
if not dev then return end
|
||||
|
||||
local profile = dev.profile_path
|
||||
|
||||
local dats = load_profile(profile)
|
||||
if not dats then
|
||||
nixio.syslog("err", "mtwifi-cfg: profile ".. profile .. "open failed")
|
||||
return
|
||||
end
|
||||
local dats_orig = load_profile(profile)
|
||||
|
||||
local vif_num, bssid_num, apcli_num = vif_count(cfg)
|
||||
|
||||
if vif_num == 0 then
|
||||
nixio.syslog("err", "mtwifi-cfg: not valid vif found!")
|
||||
return
|
||||
end
|
||||
if bssid_num > defs.max_mbssid then
|
||||
nixio.syslog("err", "mtwifi-cfg: too many vifs!")
|
||||
return
|
||||
end
|
||||
if apcli_num > 1 then
|
||||
nixio.syslog("err", "mtwifi-cfg: only support one apcli vif!")
|
||||
end
|
||||
|
||||
if bssid_num > 0 then
|
||||
dats.BssidNum = bssid_num
|
||||
else
|
||||
dats.BssidNum = 1
|
||||
end
|
||||
|
||||
-- setup apcli
|
||||
dats.ApCliEnable = 0
|
||||
dats.ApCliSsid = ""
|
||||
dats.ApCliBssid = ""
|
||||
dats.ApCliAuthMode = ""
|
||||
dats.ApCliEncrypType = ""
|
||||
dats.ApCliWPAPSK = ""
|
||||
dats.ApCliPMFMFPC = 0
|
||||
dats.ApCliPMFMFPR = 0
|
||||
dats.ApCliPMFSHA256 = 0
|
||||
|
||||
for _,v in pairs(cfg.interfaces) do
|
||||
if v.config.mode == "sta" then
|
||||
if not v.config.disabled then
|
||||
dats.ApCliEnable = 1
|
||||
end
|
||||
dats.ApCliSsid = v.config.ssid or ""
|
||||
dats.ApCliBssid = v.config.bssid or ""
|
||||
dats.ApCliAuthMode = defs.enc2dat[v.config.encryption][1]
|
||||
dats.ApCliEncrypType = defs.enc2dat[v.config.encryption][2]
|
||||
dats.ApCliWPAPSK = v.config.key or ""
|
||||
|
||||
if dats.ApCliAuthMode == "OWE" or dats.ApCliAuthMode == "WPA3PSK" then
|
||||
dats.ApCliPMFMFPC = 1
|
||||
dats.ApCliPMFMFPR = 1
|
||||
dats.ApCliPMFSHA256 = 0
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- setup chip cfgs
|
||||
set_chip_cfg(cfg, dats)
|
||||
|
||||
-- setup dev cfgs
|
||||
if cfg.config.twt then
|
||||
dats.TWTSupport = cfg.config.twt
|
||||
else
|
||||
dats.TWTSupport = 0
|
||||
end
|
||||
|
||||
if type(cfg.config.country) == type("") and #cfg.config.country == 2 then
|
||||
dats.CountryCode = cfg.config.country
|
||||
if cfg.config.band == "2g" then
|
||||
dats.CountryRegion = defs.countryRegions[cfg.config.country][1]
|
||||
elseif cfg.config.band == "5g" then
|
||||
dats.CountryRegionABand = defs.countryRegions[cfg.config.country][2]
|
||||
end
|
||||
end
|
||||
|
||||
if cfg.config.channel == "auto" then
|
||||
dats.AutoChannelSelect = 3
|
||||
dats.Channel = 0
|
||||
else
|
||||
dats.AutoChannelSelect = 0
|
||||
dats.Channel = cfg.config.channel
|
||||
end
|
||||
|
||||
if cfg.config.htmode == "HT20" or cfg.config.htmode == "VHT20" or cfg.config.htmode == "HE20" then
|
||||
dats.HT_BW = 0
|
||||
dats.VHT_BW = 0
|
||||
elseif cfg.config.htmode == "HT40" or cfg.config.htmode == "VHT40" or cfg.config.htmode == "HE40" then
|
||||
dats.HT_BW = 1
|
||||
dats.VHT_BW = 0
|
||||
if cfg.config.noscan ~= nil and cfg.config.noscan == "1" then
|
||||
dats.HT_BSSCoexistence = 0
|
||||
else
|
||||
dats.HT_BSSCoexistence = 1
|
||||
end
|
||||
elseif cfg.config.htmode == "VHT80" or cfg.config.htmode == "HE80" then
|
||||
dats.HT_BW = 1
|
||||
dats.VHT_BW = 1
|
||||
elseif cfg.config.htmode == "VHT160" or cfg.config.htmode == "HE160" then
|
||||
dats.HT_BW = 1
|
||||
dats.VHT_BW = 2
|
||||
end
|
||||
-- DBDC merge quirk workaround (Cudy TR3000 / MT7981B):
|
||||
-- ra0/rax0 <-> dat binding is RANDOM per boot (dat.MacAddress
|
||||
-- writes flip across reboots). The driver applies PHY-correct
|
||||
-- band/channel/htmode/SSID per netdev regardless of which dat it
|
||||
-- bound (band-content invariant), so physical broadcast is always
|
||||
-- correct: ra0 broadcasts 2.4G HE40, rax0 broadcasts 5G HE160 ch36.
|
||||
-- Only UCI labels vs iwinfo can disagree. mtwifi_cfg writes
|
||||
-- VHT_Sec80_Channel based on cfg.config.band (not idx), so the 5g
|
||||
-- profile carries Sec80=155 whether it lands in b0.dat or b1.dat;
|
||||
-- the 2g profile harmlessly carries VHT_BW=2 + Sec80=155 (Sec80
|
||||
-- ignored on 2.4G).
|
||||
if cfg.config.band == "2g" then
|
||||
dats.HT_BW = 1
|
||||
dats.VHT_BW = 2
|
||||
dats.VHT_Sec80_Channel = 155
|
||||
elseif cfg.config.band == "5g" and (cfg.config.htmode == "HE160" or cfg.config.htmode == "VHT160") then
|
||||
dats.VHT_Sec80_Channel = 155
|
||||
end
|
||||
|
||||
if cfg.config.txpower and cfg.config.txpower < 100 then
|
||||
dats.PERCENTAGEenable = 1
|
||||
dats.TxPower = cfg.config.txpower
|
||||
else
|
||||
dats.PERCENTAGEenable = 0
|
||||
dats.TxPower = 100
|
||||
end
|
||||
|
||||
if cfg.config.mu_beamformer then
|
||||
dats.ETxBfEnCond = 1
|
||||
if dats.ApCliEnable == 1 then
|
||||
dats.MUTxRxEnable = 3
|
||||
else
|
||||
dats.MUTxRxEnable = 3
|
||||
end
|
||||
dats.ITxBfEn = 1
|
||||
else
|
||||
dats.ETxBfEnCond = 0
|
||||
dats.MUTxRxEnable = 0
|
||||
dats.ITxBfEn = 0
|
||||
end
|
||||
|
||||
local WirelessMode
|
||||
if cfg.config.band == "2g" then
|
||||
if string.sub(cfg.config.htmode,1,2) == "HE" then
|
||||
WirelessMode = 16 -- PHY_11AX_24G
|
||||
else
|
||||
WirelessMode = 9 -- PHY_11BGN_MIXED
|
||||
end
|
||||
elseif cfg.config.band == "5g" then
|
||||
if string.sub(cfg.config.htmode,1,2) == "HE" then
|
||||
WirelessMode = 17 -- PHY_11AX_5G
|
||||
else
|
||||
WirelessMode = 15 -- PHY_11VHT_N_MIXED
|
||||
end
|
||||
end
|
||||
|
||||
-- reset vif cfgs to default
|
||||
for k,v in pairs(defs.vif_cfgs) do
|
||||
dats[k] = ""
|
||||
for i = 1, bssid_num do
|
||||
dats[k] = utils.token_set(dats[k], i, v)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs(defs.vif_cfgs_idx) do
|
||||
for i = 1, defs.max_mbssid do
|
||||
dats[k..tostring(i)] = ""
|
||||
end
|
||||
for i = 1, bssid_num do
|
||||
dats[k..tostring(i)] = v
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs(defs.vif_acl) do
|
||||
for i = 0, defs.max_mbssid-1 do
|
||||
dats[k..tostring(i)] = ""
|
||||
end
|
||||
for i = 0, bssid_num-1 do
|
||||
dats[k..tostring(i)] = v
|
||||
end
|
||||
end
|
||||
|
||||
-- setup vif cfgs
|
||||
local apidx = 1
|
||||
for idx = 0,vif_num-1 do
|
||||
v = cfg.interfaces[tostring(idx)]
|
||||
if v.config.mode == "ap" then
|
||||
set_idx_dat(dats, apidx, "SSID", v.config.ssid)
|
||||
set_idx_dat(dats, apidx, "WPAPSK", v.config.key or "")
|
||||
set_dat(dats, apidx, "NoForwarding", 0)
|
||||
set_dat(dats, apidx, "HideSSID", v.config.hidden)
|
||||
set_dat(dats, apidx, "WmmCapable", v.config.wmm)
|
||||
set_dat(dats, apidx, "RRMEnable", v.config.ieee80211k)
|
||||
set_dat(dats, apidx, "FtSupport", v.config.ieee80211r)
|
||||
set_dat(dats, apidx, "RekeyInterval", v.config.wpa_group_rekey)
|
||||
set_dat(dats, apidx, "MuMimoDlEnable",0)
|
||||
set_dat(dats, apidx, "MuMimoUlEnable",0)
|
||||
set_dat(dats, apidx, "MuOfdmaDlEnable",v.config.ofdma_dl)
|
||||
set_dat(dats, apidx, "MuOfdmaUlEnable",v.config.ofdma_ul)
|
||||
set_dat(dats, apidx, "HT_AMSDU",v.config.amsdu)
|
||||
set_dat(dats, apidx, "HT_AutoBA",v.config.autoba)
|
||||
set_dat(dats, apidx, "APSDCapable",v.config.uapsd)
|
||||
set_dat(dats, apidx, "RTSThreshold", v.config.rts)
|
||||
set_dat(dats, apidx, "FragThreshold",v.config.frag)
|
||||
set_dat(dats, apidx, "WirelessMode", WirelessMode)
|
||||
|
||||
if v.config.macfilter then
|
||||
if v.config.macfilter == "allow" then
|
||||
set_idx_dat(dats, apidx-1, "AccessPolicy", 1)
|
||||
elseif v.config.macfilter == "deny" then
|
||||
set_idx_dat(dats, apidx-1, "AccessPolicy", 2)
|
||||
end
|
||||
end
|
||||
|
||||
if v.config.maclist then
|
||||
local maclist = ""
|
||||
for i, v in ipairs(v.config.maclist) do
|
||||
if i > defs.max_acl_entry then
|
||||
break
|
||||
end
|
||||
if #maclist > 0 then
|
||||
maclist = maclist .. ";" .. v
|
||||
else
|
||||
maclist = v
|
||||
end
|
||||
end
|
||||
set_idx_dat(dats, apidx-1, "AccessControlList", maclist)
|
||||
end
|
||||
|
||||
local authmode = defs.enc2dat[v.config.encryption][1]
|
||||
set_dat(dats, apidx, "AuthMode", authmode)
|
||||
set_dat(dats, apidx, "EncrypType", defs.enc2dat[v.config.encryption][2])
|
||||
|
||||
if authmode == "OWE" or authmode == "WPA3PSK" then
|
||||
set_dat(dats, apidx, "PMFMFPC", 1)
|
||||
set_dat(dats, apidx, "PMFMFPR", 1)
|
||||
set_dat(dats, apidx, "PMFSHA256", 0)
|
||||
elseif authmode == "WPA2PSKWPA3PSK" then
|
||||
set_dat(dats, apidx, "PMFMFPC", 1)
|
||||
set_dat(dats, apidx, "PMFMFPR", 0)
|
||||
set_dat(dats, apidx, "PMFSHA256", 0)
|
||||
end
|
||||
|
||||
if not (authmode == "OPEN" or authmode == "OWE") then
|
||||
set_dat(dats, apidx, "RekeyMethod", "TIME")
|
||||
end
|
||||
|
||||
apidx = apidx + 1
|
||||
end
|
||||
end
|
||||
|
||||
local reinstall_wifidrv = false
|
||||
local cfg_diff = diff_cfg(dats_orig, dats)
|
||||
utils.log2file("diff = " .. inspect(cfg_diff))
|
||||
|
||||
save_profile(dats, profile)
|
||||
|
||||
for _,v in pairs(defs.reinstall_cfgs) do
|
||||
if cfg_diff[v] ~= nil then
|
||||
if utils.exists("/sys/module/mt_wifi") == false then
|
||||
nixio.syslog("err", "mtwifi-cfg: mtwifi module is build-in, please reboot the device!")
|
||||
return
|
||||
end
|
||||
reinstall_wifidrv = true
|
||||
end
|
||||
end
|
||||
|
||||
if string.find(profile, "dbdc") then
|
||||
if reinstall_wifidrv then
|
||||
for k, _ in pairs(l1dat.devname_ridx) do
|
||||
mtwifi_down(k)
|
||||
end
|
||||
|
||||
mtwifi_reinstall()
|
||||
|
||||
for k, _ in pairs(l1dat.devname_ridx) do
|
||||
if k == devname then
|
||||
mtwifi_up(k, cfg, nil, true)
|
||||
else
|
||||
os.execute("/sbin/wifi up " .. k) -- TODO: may cause deadlock
|
||||
end
|
||||
end
|
||||
else
|
||||
local restore_vifs = {}
|
||||
local restart_other_dbdc_dev = false
|
||||
if next(cfg_diff) ~= nil then
|
||||
restart_other_dbdc_dev = true
|
||||
end
|
||||
|
||||
if restart_other_dbdc_dev then
|
||||
for k, _ in pairs(l1dat.devname_ridx) do
|
||||
local ret = mtwifi_down(k, cfg)
|
||||
for _, v in ipairs(ret) do
|
||||
table.insert(restore_vifs, v)
|
||||
end
|
||||
end
|
||||
if #restore_vifs > 0 then
|
||||
nixio.syslog("info", "mtwifi-cfg: dbdc restore_vifs: "..inspect.inspect(restore_vifs))
|
||||
end
|
||||
|
||||
for k, _ in pairs(l1dat.devname_ridx) do
|
||||
mtwifi_up(k, cfg, restore_vifs, true)
|
||||
end
|
||||
else
|
||||
mtwifi_down(devname)
|
||||
mtwifi_up(devname, cfg, nil, true)
|
||||
end
|
||||
end
|
||||
else
|
||||
mtwifi_down(devname)
|
||||
|
||||
if reinstall_wifidrv then
|
||||
mtwifi_reinstall()
|
||||
end
|
||||
|
||||
mtwifi_up(devname, cfg)
|
||||
end
|
||||
|
||||
mtwifi_cfg_iwpriv_hook(cfg)
|
||||
end
|
||||
|
||||
function mtwifi_cfg_down(devname)
|
||||
if devname then
|
||||
mtwifi_down(devname)
|
||||
else
|
||||
for k, _ in pairs(l1dat.devname_ridx) do
|
||||
mtwifi_down(k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local action = {
|
||||
["down"] = function(devname)
|
||||
mtwifi_cfg_down(devname)
|
||||
end,
|
||||
|
||||
["setup"] = function()
|
||||
local argv = io.read()
|
||||
if #argv > 0 then
|
||||
mtwifi_cfg_setup(argv)
|
||||
os.execute("( /etc/wifi-band-verify.sh >/dev/null 2>&1 & )")
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
if #arg == 1 then
|
||||
action[arg[1]]()
|
||||
elseif #arg == 2 then
|
||||
action[arg[1]](arg[2])
|
||||
end
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2023, hanwckf <hanwckf@vip.qq.com>
|
||||
#
|
||||
# v21 2026-07-21: HONEST labels (UCI now matches physical reality).
|
||||
# Driver binds profiles by MacAddress match, NOT by l1profile order:
|
||||
# b0.dat (MacAddress=2.4G eeprom MAC) -> rax0 netdev (2.4G HW)
|
||||
# b1.dat (MacAddress=5G eeprom MAC) -> ra0 netdev (5G HW)
|
||||
# v21 additionally swaps INDEX0_profile_path in l1profile.dat to
|
||||
# "b1.dat;b0.dat", so l1dat_parser maps: idx=1 (ra0) -> b1.dat,
|
||||
# idx=2 (rax0) -> b0.dat. Result: each UCI section writes the DAT that
|
||||
# the driver actually binds to its phy, so UCI band/ssid can be honest:
|
||||
# idx=1 (ra0, 5G HW): band=5g HE160 ch 36 ssid=ImmortalWrt-5G
|
||||
# idx=2 (rax0, 2.4G HW): band=2g HE40 ch auto ssid=ImmortalWrt-2.4G
|
||||
# Kernel DBDC merge quirk (unchanged): VHT_BW / VHT_Sec80_Channel for
|
||||
# ra0's slot are taken from b0.dat, so mtwifi_cfg still forces
|
||||
# VHT_BW=2 + VHT_Sec80_Channel=155 into the band==2g profile.
|
||||
# Validated live on v20 2026-07-21: ra0 2401Mbps HE160 ch36,
|
||||
# rax0 HE40, DBDC_card0.dat identical to v20 working state.
|
||||
|
||||
append DRIVERS "mtwifi"
|
||||
|
||||
detect_mtwifi() {
|
||||
local idx ifname
|
||||
local band hwmode htmode htbsscoex ssid dbdc_main channel
|
||||
if [ -d "/sys/module/mt_wifi" ]; then
|
||||
dev_list="$(l1util list)"
|
||||
for dev in $dev_list; do
|
||||
ifname="$(l1util get ${dev} main_ifname)"
|
||||
idx="$(l1util get ${dev} subidx)"
|
||||
if [ $idx -eq 1 ]; then
|
||||
# v29: UCI idx=1 is the 5G config. Driver maps band=5g content
|
||||
# to the 5G PHY (whichever netdev it is this boot).
|
||||
dbdc_main="1"
|
||||
band="5g"
|
||||
hwmode="11a"
|
||||
htmode="HE160"
|
||||
htbsscoex="0"
|
||||
ssid="ImmortalWrt-5G"
|
||||
txpower="100"
|
||||
channel="36"
|
||||
else
|
||||
# v29: UCI idx=2 is the 2.4G config.
|
||||
dbdc_main="0"
|
||||
band="2g"
|
||||
hwmode="11g"
|
||||
htmode="HE40"
|
||||
htbsscoex="1"
|
||||
ssid="ImmortalWrt-2.4G"
|
||||
txpower="100"
|
||||
channel="auto"
|
||||
fi
|
||||
config_get type ${dev//./_} type
|
||||
if [ "$type" != "mtwifi" ]; then
|
||||
uci -q batch <<-EOF
|
||||
set wireless.${dev//./_}=wifi-device
|
||||
set wireless.${dev//./_}.type=mtwifi
|
||||
set wireless.${dev//./_}.phy=${ifname}
|
||||
set wireless.${dev//./_}.hwmode=${hwmode}
|
||||
set wireless.${dev//./_}.band=${band}
|
||||
set wireless.${dev//./_}.dbdc_main=${dbdc_main}
|
||||
set wireless.${dev//./_}.channel=${channel}
|
||||
set wireless.${dev//./_}.txpower=${txpower}
|
||||
set wireless.${dev//./_}.htmode=${htmode}
|
||||
set wireless.${dev//./_}.country=CN
|
||||
set wireless.${dev//./_}.mu_beamformer=1
|
||||
set wireless.${dev//./_}.noscan=${htbsscoex}
|
||||
set wireless.${dev//./_}.serialize=1
|
||||
|
||||
set wireless.default_${dev//./_}=wifi-iface
|
||||
set wireless.default_${dev//./_}.device=${dev//./_}
|
||||
set wireless.default_${dev//./_}.network=lan
|
||||
set wireless.default_${dev//./_}.mode=ap
|
||||
set wireless.default_${dev//./_}.ssid=${ssid}
|
||||
set wireless.default_${dev//./_}.encryption=none
|
||||
set wireless.default_${dev//./_}.uapsd=0
|
||||
EOF
|
||||
else
|
||||
uci -q batch <<-EOF
|
||||
set wireless.${dev//./_}.phy=${ifname}
|
||||
set wireless.${dev//./_}.hwmode=${hwmode}
|
||||
set wireless.${dev//./_}.band=${band}
|
||||
set wireless.${dev//./_}.dbdc_main=${dbdc_main}
|
||||
set wireless.${dev//./_}.channel=${channel}
|
||||
set wireless.${dev//./_}.htmode=${htmode}
|
||||
set wireless.${dev//./_}.country=CN
|
||||
set wireless.${dev//./_}.mu_beamformer=1
|
||||
set wireless.${dev//./_}.noscan=${htbsscoex}
|
||||
set wireless.${dev//./_}.serialize=1
|
||||
set wireless.default_${dev//./_}.device=${dev//./_}
|
||||
set wireless.default_${dev//./_}.network=lan
|
||||
set wireless.default_${dev//./_}.mode=ap
|
||||
EOF
|
||||
fi
|
||||
uci -q commit wireless
|
||||
done
|
||||
fi
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2023, hanwckf <hanwckf@vip.qq.com>
|
||||
#
|
||||
|
||||
. /lib/netifd/netifd-wireless.sh
|
||||
|
||||
init_wireless_driver "$@"
|
||||
|
||||
LOCK_FILE="/tmp/mtwifi.lock"
|
||||
|
||||
MTWIFI_MAX_AP_IDX=15
|
||||
MTWIFI_MAX_APCLI_IDX=0
|
||||
MTWIFI_CFG_IFNAME_KEY="mtwifi_ifname"
|
||||
|
||||
drv_mtwifi_init_device_config() {
|
||||
config_add_int txpower beacon_int dtim_period
|
||||
config_add_boolean mu_beamformer dbdc_main whnat bandsteering
|
||||
config_add_string country twt
|
||||
}
|
||||
|
||||
drv_mtwifi_init_iface_config() {
|
||||
config_add_string 'ssid:string' macfilter bssid kicklow assocthres steeringthresold
|
||||
config_add_boolean wmm hidden isolate ieee80211k ieee80211r
|
||||
config_add_int wpa_group_rekey frag rts
|
||||
config_add_array 'maclist:list(macaddr)' 'steeringbssid:list(macaddr)'
|
||||
config_add_boolean mumimo_dl mumimo_ul ofdma_dl ofdma_ul amsdu autoba uapsd
|
||||
}
|
||||
|
||||
drv_mtwifi_cleanup() {
|
||||
return
|
||||
}
|
||||
|
||||
mtwifi_vif_ap_config() {
|
||||
local name="$1"
|
||||
local ifname=""
|
||||
local disabled=""
|
||||
|
||||
json_select config
|
||||
json_get_var disabled disabled
|
||||
json_select ..
|
||||
|
||||
[ "$disabled" = "1" ] && return
|
||||
|
||||
json_get_var ifname $MTWIFI_CFG_IFNAME_KEY
|
||||
[ -z "$ifname" ] && return
|
||||
|
||||
# v33: record vif for the deferred physical remap (see
|
||||
# mtwifi_deferred_phys_remap). The ra*/rax* <-> PHY binding is random
|
||||
# per boot and the second netdev may not exist yet at this point, so
|
||||
# the remap runs after setup completes.
|
||||
echo "$name $ifname" >> "/tmp/mtwifi_vifs.$MTWIFI_CUR_DEV"
|
||||
|
||||
logger -t "netifd-mtwifi" "add $ifname to vifidx $name"
|
||||
wireless_add_vif "$name" "$ifname"
|
||||
}
|
||||
|
||||
mtwifi_phys_ifname() {
|
||||
# Echo the netdev that PHYSICALLY carries the given device's content.
|
||||
# The section's dat (l1profile profile_path) always programs its own
|
||||
# PHY, and the dat's MacAddress equals the MAC of whichever netdev
|
||||
# physically carries it this boot.
|
||||
local dat mac n
|
||||
dat=$(l1util get "${1//_/.}" profile_path 2>/dev/null)
|
||||
[ -f "$dat" ] || return
|
||||
mac=$(sed -n 's/^MacAddress=//p' "$dat" | head -1)
|
||||
[ -n "$mac" ] || return
|
||||
for n in /sys/class/net/ra* /sys/class/net/rax*; do
|
||||
[ -f "$n/address" ] || continue
|
||||
if [ "$(cat "$n/address")" = "$mac" ]; then
|
||||
basename "$n"
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
mtwifi_deferred_phys_remap() {
|
||||
# Re-notify netifd with the physical ifname for each vif of device $1
|
||||
# once the netdev shows up, so ubus status (and everything derived
|
||||
# from it: LuCI title, freqlist, channel dropdown, bridge membership)
|
||||
# matches reality. UCI writes stay section-based and unaffected.
|
||||
local dev="$1" vifs="/tmp/mtwifi_vifs.$1"
|
||||
local name static_if phys tries=0
|
||||
[ -s "$vifs" ] || return
|
||||
while [ $tries -lt 45 ]; do
|
||||
phys=$(mtwifi_phys_ifname "$dev")
|
||||
[ -n "$phys" ] && break
|
||||
sleep 1
|
||||
tries=$((tries+1))
|
||||
done
|
||||
[ -n "$phys" ] || return
|
||||
while read -r name static_if; do
|
||||
[ -n "$name" ] || continue
|
||||
[ "$phys" = "$static_if" ] && continue
|
||||
logger -t "netifd-mtwifi" "deferred physical remap: $dev $static_if -> $phys"
|
||||
__netifd_device="$dev"
|
||||
wireless_add_vif "$name" "$phys"
|
||||
done < "$vifs"
|
||||
rm -f "$vifs"
|
||||
}
|
||||
|
||||
mtwifi_vif_sta_config() {
|
||||
local name="$1"
|
||||
local ifname=""
|
||||
local disabled=""
|
||||
|
||||
json_select config
|
||||
json_get_var disabled disabled
|
||||
json_select ..
|
||||
|
||||
[ "$disabled" = "1" ] && return
|
||||
|
||||
json_get_var ifname $MTWIFI_CFG_IFNAME_KEY
|
||||
|
||||
if [ -n "$ifname" ]; then
|
||||
logger -t "netifd-mtwifi" "add $ifname to vifidx $name"
|
||||
wireless_add_vif "$name" "$ifname"
|
||||
fi
|
||||
}
|
||||
|
||||
mtwifi_vif_ap_set_data() {
|
||||
local ifname=""
|
||||
|
||||
if [ ! $AP_IDX -gt $MTWIFI_MAX_AP_IDX ]; then
|
||||
ifname="${MTWIFI_AP_IF_PREFIX}${AP_IDX}"
|
||||
AP_IDX=$((AP_IDX+1))
|
||||
fi
|
||||
|
||||
json_add_string "$MTWIFI_CFG_IFNAME_KEY" "$ifname"
|
||||
}
|
||||
|
||||
mtwifi_vif_sta_set_data() {
|
||||
local ifname=""
|
||||
|
||||
if [ ! $APCLI_IDX -gt $MTWIFI_MAX_APCLI_IDX ]; then
|
||||
ifname="${MTWIFI_APCLI_IF_PREFIX}${APCLI_IDX}"
|
||||
APCLI_IDX=$((APCLI_IDX+1))
|
||||
fi
|
||||
|
||||
json_add_string "$MTWIFI_CFG_IFNAME_KEY" "$ifname"
|
||||
}
|
||||
|
||||
drv_mtwifi_setup() {
|
||||
ubus -t 120 wait_for network.interface.lan
|
||||
|
||||
local dev="$1"
|
||||
# UCI section names use underscores (e.g., MT7981_1_1) but l1util/l1dat
|
||||
# expect dotted names (e.g., MT7981.1.1). Convert before any lookup.
|
||||
local dev_dot="${dev//_/.}"
|
||||
|
||||
json_add_string device "$dev_dot"
|
||||
MTWIFI_CUR_DEV="$dev"
|
||||
rm -f "/tmp/mtwifi_vifs.$dev"
|
||||
|
||||
lock $LOCK_FILE
|
||||
|
||||
logger -t "netifd-mtwifi" "up: $dev ($dev_dot)"
|
||||
|
||||
MTWIFI_AP_IF_PREFIX="$(l1util get $dev_dot ext_ifname)"
|
||||
MTWIFI_APCLI_IF_PREFIX="$(l1util get $dev_dot apcli_ifname)"
|
||||
|
||||
AP_IDX=0
|
||||
for_each_interface ap mtwifi_vif_ap_set_data
|
||||
|
||||
APCLI_IDX=0
|
||||
for_each_interface sta mtwifi_vif_sta_set_data
|
||||
|
||||
json_dump | /sbin/mtwifi_cfg setup
|
||||
|
||||
for_each_interface ap mtwifi_vif_ap_config
|
||||
for_each_interface sta mtwifi_vif_sta_config
|
||||
|
||||
wireless_set_up
|
||||
|
||||
lock -u $LOCK_FILE
|
||||
|
||||
( mtwifi_deferred_phys_remap "$dev" ) >/dev/null 2>&1 </dev/null &
|
||||
}
|
||||
|
||||
drv_mtwifi_teardown() {
|
||||
local dev="$1"
|
||||
local dev_dot="${dev//_/.}"
|
||||
|
||||
lock $LOCK_FILE
|
||||
|
||||
logger -t "netifd-mtwifi" "down: $dev ($dev_dot)"
|
||||
|
||||
rm -f "/tmp/mtwifi_vifs.$dev"
|
||||
/sbin/mtwifi_cfg down "$dev_dot"
|
||||
|
||||
lock -u $LOCK_FILE
|
||||
}
|
||||
|
||||
add_driver mtwifi
|
||||
@@ -0,0 +1,16 @@
|
||||
Default
|
||||
INDEX0=MT7981
|
||||
INDEX0_profile_path=/etc/wireless/mediatek/mt7981.dbdc.b0.dat;/etc/wireless/mediatek/mt7981.dbdc.b1.dat
|
||||
INDEX0_init_script=/lib/wifi/mtwifi.lua;/lib/wifi/mtwifi.lua
|
||||
INDEX0_init_compatible=mtwifi;mtwifi
|
||||
INDEX0_EEPROM_offset=0x0
|
||||
INDEX0_EEPROM_size=0x5000
|
||||
INDEX0_EEPROM_name=e2p
|
||||
INDEX0_main_ifname=ra0;rax0
|
||||
INDEX0_ext_ifname=ra;rax
|
||||
INDEX0_wds_ifname=wds;wdsx
|
||||
INDEX0_apcli_ifname=apcli;apclix
|
||||
INDEX0_mesh_ifname=mesh;meshx
|
||||
INDEX0_nvram_zone=dev1;dev2
|
||||
INDEX0_single_sku_path=/etc/wireless/mediatek/mt7981-sku.dat
|
||||
INDEX0_bf_sku_path=/etc/wireless/mediatek/mt7981-sku-bf.dat
|
||||
Reference in New Issue
Block a user