はじめに
OpenWrt搭載Wi-Fi7デバイス比較
Wi-Fi7デバイス
-
SinoVoip Banana Pi BPI-R4
価格: 4~6万円程度
用途: オープンソースルーター開発向け
CPU: MediaTek MT7988A (Filogic 880)
メモリ: 4GB or 8GB DDR4
ストレージ: MicroSD(TF) card or 8GB eMMC
WAN: 1G ×1
LAN: 1G ×3
SFP: 10G ×2
USB: USB 3.2 Type-A
OS: OpenWrt -
Linksys Velop WRT Pro 7
価格: 5万5千~6万円程度
用途: ホーム&ビジネス向け
CPU: Qualcomm IPQ9554
メモリ: 1GB DDR4
ストレージ: 8GB eMMC
WAN: 2.5G ×1
LAN: 1G ×4
OS: QSDK 19.07/カーネル 5.4.213(公式OpenWrtインストール不可)
MLO: サポート -
GL.iNet Flint 3 GL-BE9300
https://www.gl-inet.com/campaign/gl-be9300-jp/
価格: 1万5千~3万円程度
用途: 家庭や小規模オフィス向け
CPU: Qualcomm IPQ9554?
メモリ: 1GB DDR4
ストレージ: 8GB eMMC
WAN: 2.5G ×1
WAN/LAN: 2.5G ×1
LAN: 2.5G ×4
USB: USB 3.0 Type-A
OS: QSDK 23.05/カーネル 5.4.213 (公式OpenWrtインストール可?)
MLO: サポート
OpenWrt
デバイス情報
インストール
ファームウェア
カスタムファームウェア
-
デバイス用のOpenWrtカスタムファームウェアをダウンロード
イメージのダウンロード
SDカードの場合:SDCARD.IMG.GZ
-
インストールされたパッケージ、初回起動時のスクリプトのカスタマイズ
リリースビルド
※含む: モデム、SFP、モデムパッケージなど
base-files ca-bundle dnsmasq dropbear firewall4 fitblk fstools kmod-crypto-hw-safexcel kmod-gpio-button-hotplug kmod-leds-gpio kmod-nft-offload kmod-phy-aquantia libc libgcc libustream-mbedtls logd mtd netifd nftables odhcp6c odhcpd-ipv6only opkg ppp ppp-mod-pppoe procd-ujail uboot-envtools uci uclient-fetch urandom-seed urngd wpad-basic-mbedtls kmod-hwmon-pwmfan kmod-i2c-mux-pca954x kmod-eeprom-at24 kmod-mt7996-firmware kmod-mt7996-233-firmware kmod-rtc-pcf8563 kmod-sfp kmod-usb3 e2fsprogs f2fsck mkf2fs mt7988-wo-firmware luci
snapshotビルド
※含む: モデム、SFP、モデムパッケージなど
apk-mbedtls base-files ca-bundle dnsmasq dropbear firewall4 fitblk fstools kmod-crypto-hw-safexcel kmod-gpio-button-hotplug kmod-leds-gpio kmod-nft-offload libc libgcc libustream-mbedtls logd mtd netifd nftables odhcp6c odhcpd-ipv6only ppp ppp-mod-pppoe procd-ujail uboot-envtools uci uclient-fetch urandom-seed urngd wpad-basic-mbedtls kmod-hwmon-pwmfan kmod-i2c-mux-pca954x kmod-eeprom-at24 kmod-mt7996-firmware kmod-mt7996-233-firmware kmod-rtc-pcf8563 kmod-sfp kmod-usb3 e2fsprogs f2fsck mkf2fs mt7988-wo-firmware luci
初回起動時に実行されるスクリプト (uci-defaults)
※高速ローミング構成 (usteer + 802.11r/k/v)
# Beware! This script will be in /rom/etc/uci-defaults/ as part of the image.
# Uncomment lines to apply:
#
root_password="12345678"
lan_ip_address="192.168.1.1"
#
# pppoe_username=""
# pppoe_password=""
#
enable_led="1"
#
enable_ttyd="1"
#
wlan_name="ばなな"
wlan_password="12345678"
usteer_country="JP"
usteer_mobility_domain="1234"
usteer_bands="2g 5g 6g"
usteer_htmodes="HE20 HE80 HE160"
usteer_txpowers="10 15 ''"
usteer_channels="1 auto auto"
usteer_nasids="ap1-2g ap1-5g ap1-6g"
usteer_snr="30 20 15"
# log potential errors
exec >/tmp/setup.log 2>&1
if [ -n "$root_password" ]; then
(echo "$root_password"; sleep 1; echo "$root_password") | passwd > /dev/null
fi
# Configure LAN
# More options: https://openwrt.org/docs/guide-user/base-system/basic-networking
if [ -n "$lan_ip_address" ]; then
uci set network.lan.ipaddr="$lan_ip_address"
uci commit network
fi
# Configure PPPoE
# More options: https://openwrt.org/docs/guide-user/network/wan/wan_interface_protocols#protocol_pppoe_ppp_over_ethernet
if [ -n "$pppoe_username" -a "$pppoe_password" ]; then
uci set network.wan.proto=pppoe
uci set network.wan.username="$pppoe_username"
uci set network.wan.password="$pppoe_password"
uci commit network
fi
# Configure LED indicators
if [ -n "$enable_led" ]; then
# Configure WAN LED
uci add system led
uci set system.@led[-1].name='wan'
uci set system.@led[-1].sysfs='green
:status'
uci set system.@led[-1].trigger='netdev'
uci set system.@led[-1].dev='wan'
uci set system.@led[-1].mode='link tx rx'
# Configure LAN LED
uci add system led
uci set system.@led[-1].name='br-lan'
uci set system.@led[-1].sysfs='blue:wps'
uci set system.@led[-1].trigger='netdev'
uci set system.@led[-1].dev='br-lan'
uci set system.@led[-1].mode='link tx rx'
uci commit system
fi
# Configure ttyd
if [ -n "$enable_ttyd" ]; then
if ! uci -q get ttyd.@ttyd[0]; then
uci add ttyd ttyd
fi
uci set ttyd.@ttyd[0].interface='@lan'
uci set ttyd.@ttyd[0].command='/bin/login -f root'
uci set ttyd.@ttyd[0].ipv6='1'
uci commit ttyd
fi
# Configure usteer with multi-band WiFi
if [ -n "$wlan_name" -a -n "$wlan_password" -a ${#wlan_password} -ge 8 ]; then
cp /etc/config/wireless /etc/config/wireless.usteer.bak
NUM_IFACES=$(grep -c "^config wifi-device" /etc/config/wireless)
i=0
while [ $i -lt $NUM_IFACES ]; do
iface="default_radio${i}"
radio="radio${i}"
band=$(echo $usteer_bands | awk -v n=$((i+1)) '{print $n}')
htmode=$(echo $usteer_htmodes | awk -v n=$((i+1)) '{print $n}')
txpower=$(echo $usteer_txpowers | awk -v n=$((i+1)) '{print $n}')
nasid=$(echo $usteer_nasids | awk -v n=$((i+1)) '{print $n}')
min_snr=$(echo $usteer_snr | awk -v n=$((i+1)) '{print $n}')
channel=$(echo $usteer_channels | awk -v n=$((i+1)) '{print $n}')
uci set wireless.$radio.band="$band"
uci set wireless.$radio.channel="$channel"
uci set wireless.$radio.htmode="$htmode"
uci set wireless.$radio.country="$usteer_country"
[ -n "$txpower" ] && uci set wireless.$radio.txpower="$txpower"
uci set wireless.$radio.disabled='0'
uci set wireless.$iface.device="$radio"
uci set wireless.$iface.network='lan'
uci set wireless.$iface.mode='ap'
uci set wireless.$iface.ssid="$wlan_name"
uci set wireless.$iface.encryption='sae'
uci set wireless.$iface.key="$wlan_password"
uci set wireless.$iface.isolate='1'
uci set wireless.$iface.ocv='1'
uci set wireless.$iface.ieee80211r='1'
uci set wireless.$iface.mobility_domain="$usteer_mobility_domain"
uci set wireless.$iface.ft_over_ds='1'
uci set wireless.$iface.nasid="$nasid"
uci set wireless.$iface.usteer_min_snr="$min_snr"
uci set wireless.$iface.ieee80211k='1'
uci set wireless.$iface.ieee80211v='1'
uci set wireless.$iface.disabled='0'
[ "$band" = "5g" ] && uci set wireless.$iface.background_radar='1' && uci set wireless.$iface.ft_psk_generate_local='1'
i=$((i+1))
done
uci set usteer.@usteer[0].band_steering='1'
uci set usteer.@usteer[0].load_balancing='1'
uci set usteer.@usteer[0].sta_block_timeout='300'
uci set usteer.@usteer[0].min_snr='20'
uci set usteer.@usteer[0].max_snr='80'
uci set usteer.@usteer[0].signal_diff_threshold='10'
uci commit wireless
uci commit usteer
/etc/init.d/usteer enable
wifi reload
fi
# Configure LED indicators
if [ -n "$enable_led_config" ]; then
# Configure WAN LED
if [ -n "$wan_led_name" -a -n "$wan_led_sysfs" ]; then
uci add system led
uci set system.@led[-1].name="$wan_led_name"
uci set system.@led[-1].sysfs="$wan_led_sysfs"
uci set system.@led[-1].trigger='netdev'
uci set system.@led[-1].dev='wan'
uci set system.@led[-1].mode='link tx rx'
fi
echo "All done!"
SDカードサイズの拡張
SDカード初期化
※管理者として実行
diskpart
list disk
select disk
clean
SDカード拡張
- 用意するもの:
SDカード ×2枚 ※サイズが異なっても可
SDカードリーダー - 作業工程
両方のSDカードに同じイメージを書き込み
サブのSDカードでデバイス起動
メインのSDカードをリーダーに差してUSB接続
fdiskでパーティション7を容量拡張
SDカードを入れ替え (完了)
Type UUID: CAE9BE83-B15F-49CC-863F-081B744A2D93
Partition UUID: 5452574F-2211-4433-5566-778899AABB07
- 手順
PKGS="f2fs-tools fdisk gdisk kmod-usb-storage kmod-usb-storage-uas parted"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
partprobe /dev/sda
fdisk /dev/sda
d
7
n
7
未入力
未入力
t
7
CAE9BE83-B15F-49CC-863F-081B744A2D93
x
u
7
5452574F-2211-4433-5566-778899AABB07
n
7
production
r
w
- 断電しメインのSDカードをデバイスに入替挿入 ※USBカードリーダーを抜く
ビルド
Linuxライブディストリビューション (設定永続化仕様)
Live Linux
Ubuntu
- Ubuntu Desktop 24.04.2 LTS
-
Ubuntu Desktop 日本語 Remix
Ubuntu 22.04 LTS: ubuntu-ja-22.04-desktop-amd64.iso
RAMディスク作成
- クライアント確認
free -h
df -h
- RAMディスク自動マウント設定
/etc/fstab 自動追記(要8GB以上: 動的サイズ)
※推奨メモリ: 16GB以上
#!/bin/bash
sudo cp /etc/fstab /etc/fstab.bak.$(date +%Y%m%d%H%M%S)
free -m | awk '
/^Mem:/ {
total_mb = $2
if (total_mb <= 8000) exit 0
size_gb = int(total_mb / 2 / 1024)
if (size_gb > 32) size_gb = 32
if (size_gb < 1) size_gb = 1
print "tmpfs /mnt/ramdisk tmpfs defaults,size=" size_gb "G 0 0"
}
' > /tmp/ramdisk_fstab
sudo sed -i '/^tmpfs \/mnt\/ramdisk tmpfs /d' /etc/fstab
if [ -s /tmp/ramdisk_fstab ]; then
sudo tee -a /etc/fstab < /tmp/ramdisk_fstab
fi
rm -f /tmp/ramdisk_fstab
sudo mkdir -p /mnt/ramdisk
sudo umount /mnt/ramdisk 2>/dev/null
sudo mount -a
df -h /mnt/ramdisk
grep '/mnt/ramdisk' /etc/fstab
echo "RAMディスク設定完了"
- Windowsの時刻がUTCになる問題対応
sudo timedatectl set-local-rtc 1
timedatectl
# RTC in local TZ: yes
カスタムイメージ
bpi-r4-openwrt-builder
Ubuntu
- ビルド用パッケージインストール
sudo apt update && sudo apt install -y build-essential libncurses-dev zlib1g-dev gawk git gettext libssl-dev xsltproc rsync python3 python3-setuptools python3-pip unzip file wget qemu-utils device-tree-compiler swig libzstd-dev libtool flex bison patch subversion mercurial libfuse-dev libglib2.0-dev libelf-dev libmpc-dev libmpfr-dev libgmp-dev autoconf automake pkg-config libpython3-dev libusb-dev libusb-1.0-0-dev libffi-dev liblzma-dev perl
- GitHubリポジトリクローン及びビルド実行
cd /mnt/ramdisk # RAMディスク利用
git clone https://github.com/fatal1101/bpi-r4-openwrt-builder.git
cd bpi-r4-openwrt-builder
# 最新のタグ名を取得し、そのタグにチェックアウトする
LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
git checkout ${LATEST_TAG}
# ビルドスクリプトの実行
./bpi-r4-openwrt-builder.sh
- トラブル対応
# Disable crypto-eip package due to build issues
sed -i 's/CONFIG_PACKAGE_crypto-eip=y/# CONFIG_PACKAGE_crypto-eip is not set/' mtk-openwrt-feeds/autobuild/unified/filogic/24.10/defconfig
# Disable pce package if it causes issues
sed -i 's/CONFIG_PACKAGE_pce=y/# CONFIG_PACKAGE_pce is not set/' mtk-openwrt-feeds/autobuild/unified/filogic/24.10/defconfig
cd /mnt/ramdisk/bpi-r4-openwrt-builder
./bpi-r4-openwrt-builder.sh
チューニング
ネットワークパフォーマンス
ツール
-
メモリ・バッファ設定
net.core.rmem_max/wmem_max: ソケット受信/送信バッファの最大サイズ
tcp_rmem/tcp_wmem: TCP受信/送信バッファサイズ(最小/デフォルト/最大)
初期値: rmem_max/wmem_max = 212KB (212,992 bytes)
推奨値: 12MB以上(4GBメモリなら16MB推奨)
設定値: 16MB (16,777,216 bytes) -
TCP最適化
tcp_fastopen: TCP Fast Open(接続高速化)
tcp_keepalive_probes: 接続維持のプローブ回数
初期値: tcp_wmem最大値 = 4MB (4,194,304), tcp_rmem最大値 = 6MB (6,291,456)
推奨値: 16MB以上
設定値: 16MB (16,777,216) -
TCP設定
tcp_congestion_control: 輻輳制御アルゴリズム
初期値: cubic, fastopen=1, keepalive_probes=9
推奨値: westwood, fastopen=3, keepalive_probes=3
設定値: cubic, fastopen=3, keepalive_probes=3(westwoodは利用不可) -
コネクション追跡
nf_conntrack_max: 同時接続数の上限
netdev_max_backlog: ネットワークデバイスのキューサイズ
somaxconn: リスニングキューの最大サイズ
初期値: nf_conntrack_max=65,536, netdev_max_backlog=1,000, somaxconn=4,096
推奨値: 131,072接続以上
設定値: nf_conntrack_max=262,144, netdev_max_backlog=5,000, somaxconn=16,384 -
設定
#!/bin/sh
TMP=/tmp/aios
mkdir -p "$TMP"
cat > "$TMP/dynamic-network-optimizer.sh" << 'SCRIPT_END'
#!/bin/sh
set -e
CONFIG_FILE="/etc/sysctl.d/99-network-optimization-auto.conf"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'
log_info() { printf "${BLUE}[INFO]${NC} %s\n" "$1"; }
log_success() { printf "${GREEN}[OK]${NC} %s\n" "$1"; }
log_warning() { printf "${YELLOW}[WARN]${NC} %s\n" "$1"; }
log_error() { printf "${RED}[ERROR]${NC} %s\n" "$1"; }
log_highlight() { printf "${CYAN}[HIGHLIGHT]${NC} %s\n" "$1"; }
detect_memory() {
local mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
printf '%s\n' "$((mem_kb / 1024))"
}
detect_cpu_cores() {
grep -c ^processor /proc/cpuinfo
}
get_current_connections() {
if [ -f /proc/sys/net/netfilter/nf_conntrack_count ]; then
cat /proc/sys/net/netfilter/nf_conntrack_count
else
printf '%s\n' "0"
fi
}
get_best_congestion_control() {
local available
available=$(cat /proc/sys/net/ipv4/tcp_available_congestion_control)
for algo in bbr cubic reno; do
if printf '%s\n' "$available" | grep -q "$algo"; then
printf '%s\n' "$algo"
return
fi
done
printf '%s\n' "$(printf '%s\n' "$available" | awk '{print $1}')"
}
# Get current value dynamically - this is the key fix
get_current_value() {
local setting="$1"
case "$setting" in
"rmem_max")
cat /proc/sys/net/core/rmem_max 2>/dev/null || printf "%s" "unknown"
;;
"wmem_max")
cat /proc/sys/net/core/wmem_max 2>/dev/null || printf "%s" "unknown"
;;
"tcp_rmem")
cat /proc/sys/net/ipv4/tcp_rmem 2>/dev/null | tr -s '\t' ' ' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//' || printf "%s" "unknown"
;;
"tcp_wmem")
cat /proc/sys/net/ipv4/tcp_wmem 2>/dev/null | tr -s '\t' ' ' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//' || printf "%s" "unknown"
;;
"tcp_congestion_control")
cat /proc/sys/net/ipv4/tcp_congestion_control 2>/dev/null || printf "%s" "unknown"
;;
"nf_conntrack_max")
cat /proc/sys/net/netfilter/nf_conntrack_max 2>/dev/null || printf "%s" "unknown"
;;
"netdev_max_backlog")
cat /proc/sys/net/core/netdev_max_backlog 2>/dev/null || printf "%s" "unknown"
;;
"somaxconn")
cat /proc/sys/net/core/somaxconn 2>/dev/null || printf "%s" "unknown"
;;
"active_connections")
get_current_connections
;;
*)
printf "%s" "unknown"
;;
esac
}
calculate_buffer_sizes() {
local mem_mb=$1
local cores=$2
if [ "$mem_mb" -ge 3072 ]; then
rmem_max=16777216; wmem_max=16777216
tcp_rmem="4096 262144 16777216"; tcp_wmem="4096 262144 16777216"
conntrack_max=262144; netdev_backlog=5000; somaxconn=16384
elif [ "$mem_mb" -ge 1536 ]; then
rmem_max=8388608; wmem_max=8388608
tcp_rmem="4096 131072 8388608"; tcp_wmem="4096 131072 8388608"
conntrack_max=131072; netdev_backlog=2500; somaxconn=8192
elif [ "$mem_mb" -ge 512 ]; then
rmem_max=4194304; wmem_max=4194304
tcp_rmem="4096 65536 4194304"; tcp_wmem="4096 65536 4194304"
conntrack_max=65536; netdev_backlog=1000; somaxconn=4096
else
rmem_max=1048576; wmem_max=1048576
tcp_rmem="4096 32768 1048576"; tcp_wmem="4096 32768 1048576"
conntrack_max=32768; netdev_backlog=500; somaxconn=2048
fi
if [ "$cores" -gt 4 ]; then
netdev_backlog=$((netdev_backlog * 2))
somaxconn=$((somaxconn * 2))
elif [ "$cores" -gt 2 ]; then
netdev_backlog=$((netdev_backlog + netdev_backlog / 2))
somaxconn=$((somaxconn + somaxconn / 2))
fi
}
format_bytes() {
local bytes=$1
if [ "$bytes" = "unknown" ]; then
printf '%s' "unknown"
return
fi
if [ "$bytes" -ge 1048576 ]; then
printf '%s' "$((bytes / 1048576))MB"
elif [ "$bytes" -ge 1024 ]; then
printf '%s' "$((bytes / 1024))KB"
else
printf '%s' "${bytes}B"
fi
}
values_equal() {
local current="$1"
local new="$2"
if [ "$current" = "unknown" ] || [ "$new" = "unknown" ]; then
return 1
fi
local norm_current=$(printf '%s\n' "$current" | tr -s ' \t' ' ' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
local norm_new=$(printf '%s\n' "$new" | tr -s ' \t' ' ' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
[ "$norm_current" = "$norm_new" ]
}
show_comparison() {
printf '\n'
printf "BEFORE vs AFTER COMPARISON\n"
printf '\n'
local max_setting=7
local max_value=6
local status_width=11
local single_settings="rmem_max wmem_max tcp_congestion_control nf_conntrack_max netdev_max_backlog somaxconn"
for setting in $single_settings; do
[ ${#setting} -gt $max_setting ] && max_setting=${#setting}
done
local tcp_items="tcp_rmem (min) tcp_rmem (default) tcp_rmem (max) tcp_wmem (min) tcp_wmem (default) tcp_wmem (max)"
for item in $tcp_items; do
[ ${#item} -gt $max_setting ] && max_setting=${#item}
done
for setting in $single_settings; do
local current_value=$(get_current_value "$setting")
local new_value
case "$setting" in
"rmem_max") new_value="$rmem_max" ;;
"wmem_max") new_value="$wmem_max" ;;
"tcp_congestion_control") new_value="$best_congestion" ;;
"nf_conntrack_max") new_value="$conntrack_max" ;;
"netdev_max_backlog") new_value="$netdev_backlog" ;;
"somaxconn") new_value="$somaxconn" ;;
esac
local display_current display_new
case "$setting" in
"rmem_max"|"wmem_max")
display_current="$(format_bytes "$current_value")"
display_new="$(format_bytes "$new_value")"
;;
*)
display_current="$current_value"
display_new="$new_value"
;;
esac
[ ${#display_current} -gt $max_value ] && max_value=${#display_current}
[ ${#display_new} -gt $max_value ] && max_value=${#display_new}
done
for proto in rmem tcp_wmem; do
local cur=$(get_current_value "${proto/tcp_/tcp_}")
local new=$(eval echo "\$tcp_${proto/tcp_}")
if [ "$cur" != "unknown" ]; then
for val in $(echo "$cur") $(echo "$new"); do
[ ${#val} -gt $max_value ] && max_value=${#val}
done
fi
done
max_setting=$((max_setting + 1))
max_value=$((max_value + 1))
local sep_setting sep_value sep_status
sep_setting=$(printf '%*s' "$max_setting" '' | tr ' ' '-')
sep_value=$(printf '%*s' "$max_value" '' | tr ' ' '-')
sep_status=$(printf '%*s' "$status_width" '' | tr ' ' '-')
printf "%-${max_setting}s| %-${max_value}s| %-${max_value}s| %-${status_width}s\n" "Setting" "Before" "After" "Status"
printf "%s+-%s+-%s+-%s\n" "$sep_setting" "$sep_value" "$sep_value" "$sep_status"
print_row() {
local setting="$1" current_val="$2" new_val="$3" status="$4"
printf "%-${max_setting}s| %-${max_value}s| %-${max_value}s| %s\n" "$setting" "$current_val" "$new_val" "$status"
}
for setting in $single_settings; do
local current_value=$(get_current_value "$setting")
local new_value status
case "$setting" in
"rmem_max") new_value="$rmem_max" ;;
"wmem_max") new_value="$wmem_max" ;;
"tcp_congestion_control") new_value="$best_congestion" ;;
"nf_conntrack_max") new_value="$conntrack_max" ;;
"netdev_max_backlog") new_value="$netdev_backlog" ;;
"somaxconn") new_value="$somaxconn" ;;
esac
local display_current display_new
case "$setting" in
"rmem_max"|"wmem_max")
display_current="$(format_bytes "$current_value")"
display_new="$(format_bytes "$new_value")"
;;
*)
display_current="$current_value"
display_new="$new_value"
;;
esac
if values_equal "$current_value" "$new_value"; then
status="Same"
else
status="Changed"
if [ "$current_value" != "unknown" ] && [ "$new_value" != "unknown" ]; then
case "$setting" in
"rmem_max"|"wmem_max"|"netdev_max_backlog"|"somaxconn"|"nf_conntrack_max")
if [ "$new_value" -gt "$current_value" ] 2>/dev/null; then
status="↑ Increased"
elif [ "$new_value" -lt "$current_value" ] 2>/dev/null; then
status="↓ Optimized"
fi
;;
esac
fi
fi
print_row "$setting" "$display_current" "$display_new" "$status"
done
print_tcp_rows() {
local name="$1" cur="$2" new="$3"
if [ "$cur" = "unknown" ]; then
print_row "${name} (min)" "unknown" "$(echo "$new" | awk '{print $1}')" "Unknown"
print_row "${name} (default)" "unknown" "$(echo "$new" | awk '{print $2}')" "Unknown"
print_row "${name} (max)" "unknown" "$(echo "$new" | awk '{print $3}')" "Unknown"
return
fi
local c1 c2 c3 n1 n2 n3 s1 s2 s3
c1=$(echo "$cur" | awk '{print $1}'); n1=$(echo "$new" | awk '{print $1}')
c2=$(echo "$cur" | awk '{print $2}'); n2=$(echo "$new" | awk '{print $2}')
c3=$(echo "$cur" | awk '{print $3}'); n3=$(echo "$new" | awk '{print $3}')
s1="Same"; s2="Same"; s3="Same"
[ "$c1" != "$n1" ] && s1="Changed"
[ "$c2" != "$n2" ] && s2="Changed"
[ "$c3" != "$n3" ] && s3="Changed"
[ "$n1" -gt "$c1" ] 2>/dev/null && s1="↑ Increased"
[ "$n1" -lt "$c1" ] 2>/dev/null && s1="↓ Decreased"
[ "$n2" -gt "$c2" ] 2>/dev/null && s2="↑ Increased"
[ "$n2" -lt "$c2" ] 2>/dev/null && s2="↓ Decreased"
[ "$n3" -gt "$c3" ] 2>/dev/null && s3="↑ Increased"
[ "$n3" -lt "$c3" ] 2>/dev/null && s3="↓ Decreased"
print_row "${name} (min)" "$c1" "$n1" "$s1"
print_row "${name} (default)" "$c2" "$n2" "$s2"
print_row "${name} (max)" "$c3" "$n3" "$s3"
}
print_tcp_rows "tcp_rmem" "$(get_current_value tcp_rmem)" "$tcp_rmem"
print_tcp_rows "tcp_wmem" "$(get_current_value tcp_wmem)" "$tcp_wmem"
printf "%s+-%s+-%s+-%s\n" "$sep_setting" "$sep_value" "$sep_value" "$sep_status"
print_row "active_connections" "$(get_current_connections)" "$(get_current_connections)" "Same"
printf '\n'
printf "Legend:\n"
printf " Same - No change needed\n"
printf " ↑ Increased - Value will be increased for better performance\n"
printf " ↓ Optimized - Value will be reduced for memory optimization\n"
printf " Changed - Value will be modified\n"
printf '\n'
}
verify_applied_settings() {
printf '\n'
log_info "=== Post-Application Verification ==="
local verification_failed=0
verify_setting() {
local setting_name="$1"
local expected_value="$2"
local actual_value="$3"
local display_name="$4"
if values_equal "$actual_value" "$expected_value"; then
log_success "$display_name: $(format_bytes "$actual_value" 2>/dev/null || printf "%s" "$actual_value")"
else
log_warning "$display_name: $actual_value (expected: $expected_value)"
verification_failed=1
fi
}
# Verify each setting using the same dynamic fetch method
verify_setting "rmem_max" "$rmem_max" "$(get_current_value "rmem_max")" "rmem_max"
verify_setting "wmem_max" "$wmem_max" "$(get_current_value "wmem_max")" "wmem_max"
verify_setting "netdev_max_backlog" "$netdev_backlog" "$(get_current_value "netdev_max_backlog")" "netdev_max_backlog"
verify_setting "somaxconn" "$somaxconn" "$(get_current_value "somaxconn")" "somaxconn"
verify_setting "tcp_rmem" "$tcp_rmem" "$(get_current_value "tcp_rmem")" "tcp_rmem"
verify_setting "tcp_wmem" "$tcp_wmem" "$(get_current_value "tcp_wmem")" "tcp_wmem"
# Overall result
if [ "$verification_failed" -eq 0 ]; then
log_success "All settings verified successfully!"
else
log_warning "Some settings may not have been applied correctly"
printf '\n'
log_info "This may be due to:"
printf " - Kernel module not loaded (e.g., nf_conntrack)\n"
printf " - Insufficient permissions\n"
printf " - Kernel version compatibility\n"
printf " - Hardware limitations\n"
printf '\n'
log_info "Running 'dmesg | tail' might provide more information"
fi
}
show_performance_impact() {
printf "Performance Impact Summary\n"
printf '\n'
mem_mb=$(detect_memory)
cores=$(detect_cpu_cores)
printf "System Profile: %dMB RAM, %d CPU cores\n" "$mem_mb" "$cores"
printf '\n'
changes_found=0
improvements=""
# Check for actual improvements by comparing current vs new values
current_rmem=$(get_current_value rmem_max)
current_wmem=$(get_current_value wmem_max)
current_backlog=$(get_current_value netdev_max_backlog)
current_somaxconn=$(get_current_value somaxconn)
if ! values_equal "$current_rmem" "$rmem_max" && [ "$current_rmem" != unknown ] && [ "$current_rmem" -gt 0 ] 2>/dev/null; then
rmem_impr=$(( (rmem_max - current_rmem) * 100 / current_rmem ))
if [ "$rmem_impr" -gt 0 ]; then
improvements="${improvements}Receive buffer: +${rmem_impr}% increase -> Better download performance\n"
changes_found=1
elif [ "$rmem_impr" -lt 0 ]; then
improvements="${improvements}Receive buffer: ${rmem_impr}% decrease -> Memory optimized\n"
changes_found=1
fi
fi
if ! values_equal "$current_wmem" "$wmem_max" && [ "$current_wmem" != unknown ] && [ "$current_wmem" -gt 0 ] 2>/dev/null; then
wmem_impr=$(( (wmem_max - current_wmem) * 100 / current_wmem ))
if [ "$wmem_impr" -gt 0 ]; then
improvements="${improvements}Send buffer: +${wmem_impr}% increase -> Better upload performance\n"
changes_found=1
elif [ "$wmem_impr" -lt 0 ]; then
improvements="${improvements}Send buffer: ${wmem_impr}% decrease -> Memory optimized\n"
changes_found=1
fi
fi
if ! values_equal "$current_backlog" "$netdev_backlog" && [ "$current_backlog" != unknown ] && [ "$current_backlog" -gt 0 ] 2>/dev/null; then
backlog_impr=$(( (netdev_backlog - current_backlog) * 100 / current_backlog ))
if [ "$backlog_impr" -gt 0 ]; then
improvements="${improvements}Network backlog: +${backlog_impr}% increase -> Better packet processing\n"
changes_found=1
fi
fi
if ! values_equal "$current_somaxconn" "$somaxconn" && [ "$current_somaxconn" != unknown ] && [ "$current_somaxconn" -gt 0 ] 2>/dev/null; then
connq_impr=$(( (somaxconn - current_somaxconn) * 100 / current_somaxconn ))
if [ "$connq_impr" -gt 0 ]; then
improvements="${improvements}Connection queue: +${connq_impr}% increase -> More concurrent connections\n"
changes_found=1
fi
fi
if [ "$changes_found" -eq 1 ]; then
printf "Performance Improvements:\n"
printf "%b" "$improvements"
else
printf "System is already optimally configured for your hardware\n"
printf "No significant changes needed\n"
fi
printf '\n'
printf "Expected Benefits:\n"
printf " - Reduced packet drops under high load\n"
printf " - Better throughput for large file transfers\n"
printf " - Improved responsiveness for multiple connections\n"
printf " - Optimized memory usage for your hardware\n"
printf '\n'
}
remove_optimizer() {
printf "Network Optimizer Removal Tool\n"
printf "==============================\n"
if [ ! -f "$CONFIG_FILE" ]; then
log_info "No optimization config found"
return 0
fi
printf "Do you want to remove the existing optimization config? (y/N): "
read -r confirm_remove
if [ "$confirm_remove" != "y" ] && [ "$confirm_remove" != "Y" ]; then
log_info "Removal cancelled by user"
return 0
fi
local backup_file=""
for backup in "${CONFIG_FILE}.backup."*; do
[ -f "$backup" ] && { backup_file="$backup"; break; }
done
if [ -n "$backup_file" ]; then
log_info "Restoring from backup: $backup_file"
cp "$backup_file" "$CONFIG_FILE"
sysctl -p "$CONFIG_FILE" >/dev/null 2>&1
log_success "Original settings restored"
else
log_info "No backup found – removing config file"
rm "$CONFIG_FILE"
log_success "Config file removed"
log_highlight "Reboot required to return to system defaults"
fi
}
optimizer_main() {
printf "Dynamic Network Performance Optimizer\n"
printf "=====================================\n"
if [ -f "$CONFIG_FILE" ]; then
log_warning "Existing config detected: $CONFIG_FILE"
remove_optimizer
exit 0
fi
printf '\n'
log_info "=== System Analysis ==="
local mem_mb=$(detect_memory)
local cores=$(detect_cpu_cores)
local best_congestion=$(get_best_congestion_control)
log_info "Detected RAM: ${mem_mb}MB"
log_info "Detected CPU cores: $cores"
log_info "Best congestion control: $best_congestion"
calculate_buffer_sizes "$mem_mb" "$cores"
show_comparison
show_performance_impact
printf "Do you want to apply these changes? (y/N): "
read -r confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
log_info "Operation cancelled by user"
exit 0
fi
if [ -f "$CONFIG_FILE" ]; then
local backup_file="${CONFIG_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
cp "$CONFIG_FILE" "$backup_file"
log_info "Backed up existing config to: $backup_file"
fi
log_info "Creating configuration: $CONFIG_FILE"
cat > "$CONFIG_FILE" << CONFIG_EOF
net.core.rmem_max = $rmem_max
net.core.wmem_max = $wmem_max
net.ipv4.tcp_rmem = $tcp_rmem
net.ipv4.tcp_wmem = $tcp_wmem
net.ipv4.tcp_congestion_control = $best_congestion
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_keepalive_probes = 3
net.netfilter.nf_conntrack_max = $conntrack_max
net.core.netdev_max_backlog = $netdev_backlog
net.core.somaxconn = $somaxconn
CONFIG_EOF
printf '\n'
log_info "Applying configuration"
if sysctl -p "$CONFIG_FILE" >/dev/null 2>&1; then
log_success "Configuration applied successfully"
else
log_warning "Some settings may have failed (check kernel support)"
fi
verify_applied_settings
printf '\n'
log_success "Network optimization completed!"
log_highlight "Reboot recommended for full effect and persistent changes"
printf '\n'
log_info "Current memory usage:"
free -h
}
if [ "$0" = "${0#*/}" ] || [ "${0##*/}" = "$(basename "$0")" ]; then
optimizer_main "$@"
fi
SCRIPT_END
chmod +x "$TMP/dynamic-network-optimizer.sh"
sh "$TMP/dynamic-network-optimizer.sh"
Wi-Fi
ドライバー
- ドライバー
firmware/mt7996
-
mt7996_eeprom_233_2i5i6i.bin
/lib/firmware/mediatek/mt7996
OpenWrt24.10ファームウェアでの無線周波数のパフォーマンスを向上
wget -O /tmp/mt7996_eeprom_233_2i5i6i.bin 'https://github.com/openwrt/mt76/raw/refs/heads/master/firmware/mt7996/mt7996_eeprom_233_2i5i6i.bin'
FW_DIR="/lib/firmware/mediatek/mt7996"
if [ -f "$FW_DIR/mt7996_eeprom_233_2i5i6i.bin" ]; then
mv "$FW_DIR/mt7996_eeprom_233_2i5i6i.bin" "$FW_DIR/mt7996_eeprom_233_2i5i6i.bin.bak"
fi
mv /tmp/mt7996_eeprom_233_2i5i6i.bin "$FW_DIR/"
-
mt7996_eeprom_233.bin
/lib/firmware/mediatek/mt7996
wget -O /tmp/mt7996_eeprom_233.bin 'https://github.com/openwrt/mt76/raw/refs/heads/master/firmware/mt7996/mt7996_eeprom_233.bin'
FW_DIR="/lib/firmware/mediatek/mt7996"
if [ -f "$FW_DIR/mt7996_eeprom_233.bin" ]; then
mv "$FW_DIR/mt7996_eeprom_233.bin" "$FW_DIR/mt7996_eeprom_233.bin.bak"
fi
mv /tmp/mt7996_eeprom_233.bin "$FW_DIR/"
バックグラウンドレーダー
uci set wireless.default_radio1.background_radar=1
# uci set wireless.default_radio2.background_radar=1
uci commit wireless
wifi reload
ワイヤレスオフロード有効化 (スナップショット)
- SDカード用設定(RAMを2GB以下に制限)
if ! fw_printenv -n bootargs | grep -q 'mem=2048M'; then
new_bootargs="$(fw_printenv -n bootargs) mem=2048M"
fw_setenv bootargs "$new_bootargs"
fi
grep -q '^options mt7996e wed_enable=Y sr_scene_detect=Y' /etc/modules.conf || echo 'options mt7996e wed_enable=Y sr_scene_detect=Y' >> /etc/modules.conf
echo "再起動してください"
# reboot
- 復元
new_bootargs=$(fw_printenv -n bootargs | sed 's/mem=2048M//g')
fw_setenv bootargs $new_bootargs
sed -i '/^options mt7915e wed_enable=Y$/d' /etc/modules.conf
sed -i '/^options mt7996e wed_enable=Y sr_scene_detect=Y$/d' /etc/modules.conf
echo "再起動してください"
# reboot
Wi-Fi 7
MLO (スナップショット)
MAC80211_MT76_Programming_Guide_V4.10.pdf
- MLO設定
#!/bin/sh
SSID='ばなな'
WPA_KEY='password'
COUNTRY='JP'
MLD_ID='42'
BANDS="2g 5g 6g"
CHANNELS="11 auto auto"
HTMODES="EHT40 EHT160 EHT320"
cp /etc/config/wireless /etc/config/wireless.mlo.bak
rm /etc/config/wireless
wifi config
NUM_RADIOS=$(echo $BANDS | wc -w)
i=0
while [ $i -lt $NUM_RADIOS ]; do
radio="radio${i}"
iface="default_radio${i}"
band=$(echo $BANDS | awk -v n=$((i+1)) '{print $n}')
channel=$(echo $CHANNELS | awk -v n=$((i+1)) '{print $n}')
htmode=$(echo $HTMODES | awk -v n=$((i+1)) '{print $n}')
mlo_link_id="$i"
uci set wireless.$radio.disabled='0'
uci set wireless.$radio.band="$band"
uci set wireless.$radio.channel="$channel"
uci set wireless.$radio.htmode="$htmode"
uci set wireless.$radio.country="$COUNTRY"
uci set wireless.$radio.mlo='1'
uci set wireless.$radio.mld_id="$MLD_ID"
([ "$band" = "5g" ] || [ "$band" = "6g" ]) && uci set wireless.$radio.background_radar='1'
uci set wireless.$iface.disabled='0'
uci set wireless.$iface.device="$radio"
uci set wireless.$iface.network='lan'
uci set wireless.$iface.mode='ap'
uci set wireless.$iface.ssid="$SSID"
uci set wireless.$iface.encryption='sae'
uci set wireless.$iface.key="$WPA_KEY"
uci set wireless.$iface.mlo_link_id="$mlo_link_id"
i=$((i+1))
done
uci set wireless.default_radio1.background_radar=1
uci commit wireless
wifi reload
- 復元
cp /etc/config/wireless.mlo.bak /etc/config/wireless
uci commit wireless
wifi reload
Wi-Fi 6
高速ローミング構成 (usteer + 802.11r/k/v)
#!/bin/sh
SSID='ばなな'
WIFI_KEY='password'
COUNTRY='JP'
MOBILITY_DOMAIN='1234'
BANDS="2g 5g 6g"
HTMODES="HE20 HE80 HE160"
TXPOWERS="10 15 ''"
CHANNELS="1 auto auto"
NASIDS="ap1-2g ap1-5g ap1-6g"
SNR="30 20 15"
opkg list-installed | grep -q "luci-app-usteer" || { opkg update && opkg install luci-app-usteer; }
cp /etc/config/wireless /etc/config/wireless.usteer.bak
rm /etc/config/wireless
wifi config
NUM_IFACES=$(grep -c "^config wifi-device" /etc/config/wireless)
i=0
while [ $i -lt $NUM_IFACES ]; do
iface="default_radio${i}"
radio="radio${i}"
band=$(echo $BANDS | awk -v n=$((i+1)) '{print $n}')
htmode=$(echo $HTMODES | awk -v n=$((i+1)) '{print $n}')
txpower=$(echo $TXPOWERS | awk -v n=$((i+1)) '{print $n}')
nasid=$(echo $NASIDS | awk -v n=$((i+1)) '{print $n}')
min_snr=$(echo $SNR | awk -v n=$((i+1)) '{print $n}')
channel=$(echo $CHANNELS | awk -v n=$((i+1)) '{print $n}')
uci set wireless.$radio.band="$band"
uci set wireless.$radio.channel="$channel"
uci set wireless.$radio.htmode="$htmode"
uci set wireless.$radio.country="$COUNTRY"
[ -n "$txpower" ] && uci set wireless.$radio.txpower="$txpower"
uci set wireless.$radio.disabled='0'
uci set wireless.$iface.device="$radio"
uci set wireless.$iface.network='lan'
uci set wireless.$iface.mode='ap'
uci set wireless.$iface.ssid="$SSID"
uci set wireless.$iface.encryption='sae'
uci set wireless.$iface.key="$WIFI_KEY"
uci set wireless.$iface.isolate='1'
uci set wireless.$iface.ocv='1'
uci set wireless.$iface.ieee80211r='1'
uci set wireless.$iface.mobility_domain="$MOBILITY_DOMAIN"
uci set wireless.$iface.ft_over_ds='1'
uci set wireless.$iface.nasid="$nasid"
uci set wireless.$iface.usteer_min_snr="$min_snr"
uci set wireless.$iface.ieee80211k='1'
uci set wireless.$iface.ieee80211v='1'
uci set wireless.$iface.disabled='0'
# DFS (BPI-R4固有設定)
[ "$band" = "5g" ] && uci set wireless.$iface.background_radar='1' && uci set wireless.$iface.ft_psk_generate_local='1'
i=$((i+1))
done
uci set usteer.@usteer[0].band_steering='1'
uci set usteer.@usteer[0].load_balancing='1'
uci set usteer.@usteer[0].sta_block_timeout='300'
uci set usteer.@usteer[0].min_snr='20'
uci set usteer.@usteer[0].max_snr='80'
uci set usteer.@usteer[0].signal_diff_threshold='10'
uci set wireless.default_radio1.background_radar=1
uci commit
/etc/init.d/usteer enable
/etc/init.d/usteer start
wifi reload
- 復元
#!/bin/sh
/etc/init.d/usteer stop
/etc/init.d/usteer disable
cp /etc/config/wireless.usteer.bak /etc/config/wireless
rm -f /etc/config/usteer
opkg remove luci-app-usteer usteer
uci commit wireless
wifi reload
パーツ
ACアダプター
UCB Type-C PD 20V
-
純正ACアダプター:
12V/5.2A or 19V 3.2A
-
PD 20V: 65Wアダプター
PC-VP-BP143:20V/3.25A,15V/3A,9V/3A,5V/3A
EC-AC8565BK:20V/3.25A,15V/3A,12V/3A,9V/3A,5V/3A
ファン
BPI-R4用ファン確認
- ハードウェアモニタ(hwmon)デバイス一覧
ls -l /sys/class/hwmon/
- ファンPWM値の現在値確認
cat /sys/class/hwmon/hwmon1/pwm1
- ファンPWM制御の状態確認
cat /sys/class/hwmon/hwmon1/pwm1_enable
- サーマルゾーン(温度トリップポイント)の種類確認
cat /sys/class/thermal/thermal_zone0/trip_point_0_type # クリティカル: 100%
cat /sys/class/thermal/thermal_zone0/trip_point_1_type # ホット
cat /sys/class/thermal/thermal_zone0/trip_point_2_type # アクティブ: 50%
cat /sys/class/thermal/thermal_zone0/trip_point_3_type # アクティブ: 30%
cat /sys/class/thermal/thermal_zone0/trip_point_4_type # アクティブ: 0%
- サーマルゾーン(温度トリップポイント)の温度設定確認
cat /sys/class/thermal/thermal_zone0/trip_point_0_temp # 臨界: 125℃
cat /sys/class/thermal/thermal_zone0/trip_point_1_temp # 高: 120℃
cat /sys/class/thermal/thermal_zone0/trip_point_2_temp # 高: 115℃
cat /sys/class/thermal/thermal_zone0/trip_point_3_temp # 中: 85℃
cat /sys/class/thermal/thermal_zone0/trip_point_4_temp # 低: 40℃
BPI-R4用ファンスクリプト
- pwmfan
# /etc/init.d/pwmfan
cat <<'EOF' > /etc/init.d/pwmfan
#!/bin/sh /etc/rc.common
START=99
PIDFILE=/var/run/pwmfan.pid
start() {
if [ -f $PIDFILE ]; then
PID=$(cat $PIDFILE 2>/dev/null)
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
echo "Already running"
return 1
else
rm -f $PIDFILE
fi
fi
/usr/bin/pwmfan-loop &
echo $! > $PIDFILE
}
stop() {
if [ -f $PIDFILE ]; then
PID=$(cat $PIDFILE 2>/dev/null)
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
kill $PID
fi
rm -f $PIDFILE
fi
}
restart() {
stop
sleep 1
start
}
EOF
chmod 755 /etc/init.d/pwmfan
# /usr/bin/pwmfan-loop
cat <<'EOF' > /usr/bin/pwmfan-loop
#!/bin/sh
CONFIG=pwmfan
SECTION="pwmfan"
get_temp() {
local temp
temp=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null)
[ -z "$temp" ] && temp=0
echo $((temp / 1000))
}
set_pwm() {
local pwm="$1"
echo 1 > /sys/class/hwmon/hwmon1/pwm1_enable
echo $pwm > /sys/class/hwmon/hwmon1/pwm1
}
read_config() {
INTERVAL=$(uci get ${CONFIG}.@${SECTION}[0].interval 2>/dev/null)
[ -z "$INTERVAL" ] && INTERVAL=30
TRIP_TEMP=$(uci get ${CONFIG}.@${SECTION}[0].trip_temp 2>/dev/null)
TRIP_PWM=$(uci get ${CONFIG}.@${SECTION}[0].trip_pwm 2>/dev/null)
MINPWM=$(uci get ${CONFIG}.@${SECTION}[0].minpwm 2>/dev/null)
[ -z "$MINPWM" ] && MINPWM=100
MAXPWM=$(uci get ${CONFIG}.@${SECTION}[0].maxpwm 2>/dev/null)
[ -z "$MAXPWM" ] && MAXPWM=255
if [ -z "$TRIP_TEMP" ] || [ -z "$TRIP_PWM" ]; then
exit 1
fi
case "$INTERVAL" in
''|*[!0-9]*) INTERVAL=30 ;;
esac
}
main_loop() {
read_config
local temp pwm i t p last_pwm=0
set -- $TRIP_TEMP
local trip_count=$#
while true; do
temp=$(get_temp)
pwm=$MINPWM
set -- $TRIP_TEMP
local j=1
for t in $@; do
set -- $TRIP_PWM
p=$(eval "echo \$$j")
[ -z "$p" ] && p=$MINPWM
[ "$temp" -ge "$t" ] && pwm=$p
j=$((j+1))
done
[ "$pwm" -lt "$MINPWM" ] && pwm=$MINPWM
[ "$pwm" -gt "$MAXPWM" ] && pwm=$MAXPWM
if [ "$pwm" != "$last_pwm" ]; then
set_pwm "$pwm"
last_pwm=$pwm
fi
sleep "$INTERVAL"
done
}
main_loop
EOF
chmod 755 /usr/bin/pwmfan-loop
touch /etc/config/pwmfan
uci -q delete pwmfan.@pwmfan[0]
uci -q commit pwmfan
uci -q add pwmfan pwmfan
uci -q set pwmfan.@pwmfan[-1].interval='20'
uci -q set pwmfan.@pwmfan[-1].minpwm='80'
uci -q set pwmfan.@pwmfan[-1].maxpwm='255'
uci -q set pwmfan.@pwmfan[-1].trip_temp='60 70'
uci -q set pwmfan.@pwmfan[-1].trip_pwm='128 255'
uci -q commit pwmfan
/etc/init.d/pwmfan enable
/etc/init.d/pwmfan restart
# /usr/bin/fan-status
cat <<'EOF' > /usr/bin/fan-status
#!/bin/sh
TEMP_RAW=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null)
TEMP_C=$(awk "BEGIN {printf \"%.1f\", $TEMP_RAW/1000}")
PWM=$(cat /sys/class/hwmon/hwmon1/pwm1 2>/dev/null)
PWM_PERCENT=$((PWM * 100 / 255))
echo "========================="
echo " Fan & Temperature Status"
echo "-------------------------"
echo " Temperature : ${TEMP_C} °C"
echo " Fan PWM : ${PWM} (${PWM_PERCENT} %)"
echo "========================="
EOF
chmod 755 /usr/bin/fan-status
fan-status
- 監視
while true; do
fan-status
sleep 20
done
- リムーブ
/etc/init.d/pwmfan stop
/etc/init.d/pwmfan disable
rm -f /etc/init.d/pwmfan
rm -f /usr/bin/pwmfan-loop
rm -f /usr/bin/fan-status
uci -q delete pwmfan.@pwmfan[0]
uci -q commit pwmfan
[ ! -s /etc/config/pwmfan ] && rm -f /etc/config/pwmfan
モデム
Fibocom FM350-GL (14c3:4d75)
-
動作環境
Revision: 1.1
OpenWrt: 24.10.2
ModemManager: 1.22.0
kmod-mtk-t7xx: 6.6.93-r1
14C3:4D75: 81600.0000.00.29.18.16_DO
モード: PCIe
SIMスロット: SIM1
キャリア: docomo -
MHF4コネクタ (アンテナ端子)
M: プライマリ/送信 (全利用)
M1: 4×4 MIMO
M2: 4×4 MIMO
D/G: ダイバーシティ/受信 (全利用) -
既知の問題
モデムデバイスは、完全に断電してから通電させないと、認識しない
※M.2スロットの3.3 V電源ラインはカーネルから制御できず、PCIeリセットピンも露出していない
PCIeモードでは、ATコマンドは送信出来ない
SIM1の青色LEDは、通信が確立しないと点灯しない
SIMトレイがスムースに挿入出来ない場合、SIMが認識しない事がある (ケースネジを緩め要調整) -
モデム設定
#!/bin/sh
WWAN="wwan"
APN="spmode.ne.jp"
ALLOWEDAUTH="chap"
ALLOWEDMODE="5G" # SPモードの場合必須
METRIC="100"
IPTYPE="ipv4v6"
LOGLEVEL="ERR"
IP6ASSIGN="64"
MTU="1500"
SIGNALRATE="120"
INIT_EPSBEARER="default" # SPモードの場合必須
AUTO="0"
cp /etc/config/network /etc/config/network.wwan.bak
cp /etc/config/firewall /etc/config/firewall.wwan.bak
PKGS="kmod-mtk-t7xx modemmanager-rpcd luci-proto-modemmanager pciutils mbim-utils ubus"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
WWAN_IDX=$(uci show network | grep "name='wwan0'" | sed -n "s/network.@device
\[\([0-9]\+\)\]
.*/\1/p")
if [ -n "$WWAN_IDX" ]; then
uci set network.@device[$WWAN_IDX].ipv6='1'
[ -n "$MTU" ] && uci set network.@device[$WWAN_IDX].mtu="${MTU}"
[ -n "$MTU" ] && uci set network.@device[$WWAN_IDX].mtu6="${MTU}"
else
uci add network device
uci set network.@device[-1].name='wwan0'
uci set network.@device[-1].ipv6='1'
[ -n "$MTU" ] && uci set network.@device[-1].mtu="${MTU}"
[ -n "$MTU" ] && uci set network.@device[-1].mtu6="${MTU}"
fi
uci set network.${WWAN}=interface
uci set network.${WWAN}.proto='modemmanager'
uci set network.${WWAN}.apn="${APN}"
uci set network.${WWAN}.allowedauth="${ALLOWEDAUTH}"
uci set network.${WWAN}.allowedmode="${ALLOWEDMODE}"
uci set network.${WWAN}.iptype="${IPTYPE}"
uci set network.${WWAN}.loglevel="${LOGLEVEL}"
uci set network.${WWAN}.metric="${METRIC}"
uci set network.${WWAN}.force_link='1'
uci set network.${WWAN}.ip6assign="${IP6ASSIGN}"
[ -n "$MTU" ] && uci set network.${WWAN}.mtu="${MTU}"
[ -n "$SIGNALRATE" ] && uci set network.${WWAN}.signalrate="${SIGNALRATE}"
uci set network.${WWAN}.auto="${AUTO}"
uci set network.${WWAN}.init_epsbearer="${INIT_EPSBEARER}"
[ -z "$(uci get firewall.@zone[1].network 2>/dev/null | grep -w 'wwan')" ] && uci add_list firewall.@zone[1].network='wwan'
uci commit network
uci commit firewall
/etc/init.d/modemmanager stop
sleep 2
/etc/init.d/modemmanager start
sleep 3
ubus call network reload
sleep 2
ifup wwan
- モデムリセット
※テスト中 (動作不安定: セーフモードに入るリスク有)
cat > /etc/modem_power.sh << 'EOF'
#!/bin/sh
pci_reset() {
local pci_path="/sys/bus/pci/devices/0003:01:00.0"
if [ -f "$pci_path/reset" ]; then
echo 1 > "$pci_path/reset"
return 0
else
return 1
fi
}
driver_reset() {
echo "0003:01:00.0" > /sys/bus/pci/drivers/mtk_t7xx/unbind 2>/dev/null
sleep 2
echo "0003:01:00.0" > /sys/bus/pci/drivers/mtk_t7xx/bind 2>/dev/null
sleep 3
}
modem_reset() {
/etc/init.d/modemmanager stop
sleep 2
if ! pci_reset; then
driver_reset
fi
sleep 3
/etc/init.d/modemmanager start
sleep 5
}
check_status() {
lspci | grep -i mediatek | grep 4d75
ls -la /dev/wwan0* 2>/dev/null || echo "なし"
mmcli -L 2>/dev/null || echo "モデムなし"
if mmcli -L 2>/dev/null | grep -q "Modem"; then
mmcli -m 0 2>/dev/null | grep -E "(状態|State|オペレータ|Operator|信号|Signal)" || true
fi
dmesg | grep -i -E "(t7xx|mtk|modem)" | tail -5
}
case "$1" in
reset)
modem_reset
;;
status)
check_status
;;
*)
echo "使用法: $0 {reset|status}"
;;
esac
EOF
chmod +x /etc/modem_power.sh
- モデムリセット
sh /etc/modem_power.sh reset
- 復元
cp /etc/config/network.wwan.bak /etc/config/network
cp /etc/config/firewall.wwan.bak /etc/config/firewall
uci commit network
uci commit firewall
# reboot
- デバイス確認
lspci
ls -la /dev/ | grep -E "(cdc|wwan)"
- ネットワークインターフェース確認
ip link show
- ベンダーID、プロダクトID確認
ls /sys/class/net/wwan0/device/
cat /sys/class/net/wwan0/device/../../../modalias
cat /sys/class/net/wwan0/device/../../../uevent
- モデム確認
ubus call modemmanager info
ubus call modemmanager dump
mmcli -L
mmcli -m 0
- 使用可能なすべてのオプション
mbimcli --help-all
- バージョン確認
mbimcli --version
- FCCロック確認
mbimcli -d /dev/wwan0mbim0 --intel-query-fcc-lock
mbimcli -d /dev/wwan0mbim0 --set-radio-state=on
- FCCロック解除(必要な場合)
mbimcli -d /dev/wwan0mbim0 --intel-set-fcc-unlock
/etc/ModemManager/fcc.unlock/
dispatcher-fcc-unlock
MODEM="14c3" # 例
mkdir -p /etc/ModemManager/fcc.unlock/
chmod 644 /etc/ModemManager/fcc.unlock/$MODEM
cat <<'EOF' > /etc/ModemManager/fcc.unlock/$MODEM
# <ここにdispatcher-fcc-unlockの該当ソースを貼る>
EOF
/etc/init.d/modemmanager restart
- モデム有効化(enable)
mmcli -m 0 -e
- ラジオ有効化
mbimcli -d /dev/wwan0mbim0 --set-radio-state=on
- ラジオ状態確認
mbimcli -d /dev/wwan0mbim0 --query-radio-state
- デバイス機能確認
mbimcli -d /dev/wwan0mbim0 --query-device-caps
- SIM状態確認
mbimcli -d /dev/wwan0mbim0 --query-subscriber-ready-status
- ネットワーク登録状態確認
mbimcli -d /dev/wwan0mbim0 --query-registration-state
- 信号強度確認
mmcli -m 0 --signal-get
mbimcli -d /dev/wwan0mbim0 --query-signal-state
- APN設定確認
mbimcli -d /dev/wwan0mbim0 --query-provisioned-contexts
- 接続IP情報
mbimcli -d /dev/wwan0mbim0 -p --query-ip-configuration=0
- モデムの詳細状態確認
mmcli -m 0 --output-keyvalue
- モデムの詳細情報
root@bpi-r4:~# mmcli -m 0
-----------------------------------
General | path: /org/freedesktop/ModemManager1/Modem/0
| device id: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----------------------------------
Hardware | manufacturer: generic
| model: MBIM [14C3:4D75]
| firmware revision: 81600.0000.00.29.18.16_DO
| C43
| h/w revision: V1.0.6
| supported: gsm-umts, lte, 5gnr
| current: gsm-umts, lte, 5gnr
| equipment id: XXXXXXXXXXXXXXXX
-----------------------------------
System | device: /sys/devices/platform/soc/11280000.pcie/pci0003:00/0003:00:00.0/0003:01:00.0
| physdev: /sys/devices/platform/soc/11280000.pcie/pci0003:00/0003:00:00.0/0003:01:00.0
| drivers: mtk_t7xx
| plugin: generic
| primary port: wwan0mbim0
| ports: wwan0 (net), wwan0at0 (at), wwan0mbim0 (mbim)
-----------------------------------
Numbers | own: XXXXXXXXXXXX
-----------------------------------
Status | lock: sim-pin2
| unlock retries: sim-pin2 (3)
| state: connected
| power state: on
| access tech: lte, 5gnr
| signal quality: 48% (cached)
-----------------------------------
Modes | supported: allowed: 3g; preferred: none
| allowed: 4g; preferred: none
| allowed: 3g, 4g; preferred: none
| allowed: 5g; preferred: none
| allowed: 3g, 5g; preferred: none
| allowed: 4g, 5g; preferred: none
| allowed: 3g, 4g, 5g; preferred: none
| current: allowed: 5g; preferred: none
-----------------------------------
IP | supported: ipv4, ipv6, ipv4v6
-----------------------------------
3GPP | imei: XXXXXXXXXXXXXXXX
| enabled locks: fixed-dialing
| operator id: 44010
| operator name: NTT DOCOMO
| registration: home
| packet service state: attached
-----------------------------------
3GPP EPS | ue mode of operation: csps-2
| initial bearer path: /org/freedesktop/ModemManager1/Bearer/4
| initial bearer apn: spmode.ne.jp
| initial bearer ip type: ipv4v6
-----------------------------------
3GPP 5GNR | mico mode: disabled
-----------------------------------
SIM | primary sim path: /org/freedesktop/ModemManager1/SIM/0
| sim slot paths: slot 1: /org/freedesktop/ModemManager1/SIM/0 (active)
| slot 2: /org/freedesktop/ModemManager1/SIM/1
-----------------------------------
Bearer | paths: /org/freedesktop/ModemManager1/Bearer/5
root@bpi-r4:~#
Telit LN940 よりは速いが、5Gの速度にしては遅すぎる
RTC
RTC有効化
-
バナナパイR4 RTCが動作しない#15766
LIR2032 (充電式電池)
RTCバッテリーボックス (1.25mm: JST)
PKGS="i2c-tools"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
fw_setenv bootconf_extra mt7988a-bananapi-bpi-r4-rtc
デバイス用のOpenWrtカスタムファームウェアをダウンロード
デバイスアクセス
デバイスアクセス(UCI)
パワーシェルでアクセス
PowerShellの開始
- キー入力:
Win
+x
>a
>はい
UCI(SSH)アクセス
ssh -o StrictHostKeyChecking=no -oHostKeyAlgorithms=+ssh-rsa root@192.168.1.1
- root@192.168.1.1's password:
初期値:パスワード無し
SSHログイン出来ない場合
-
%USERPROFILE%\.ssh\known_hosts
※Windows隠しファイル
Clear-Content .ssh\known_hosts -Force
OpenSSHのインストールが無い場合
- 機能の確認
※Windows 10 Fall Creators Update(1709)以降標準搭載
```powershell:powershell
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
```
- 機能のインストール
```powershell:powershell
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
```
---
初期設定
パスワード
初期値から変更
passwd
Changing password for root
New password:
任意のパスワード
Retype password:
再入力
passwd: password for root changed by root
exit
ホストネーム
ホストネーム(openwrt)を変更
#!/bin/sh
HOSTNAME='openwrt' # デバイス名
uci set system.@system[0].hostname=${HOSTNAME}
uci commit system
/etc/init.d/system reload
NTP
NTPサーバーを変更
#!/bin/sh
POOL='jp'
uci delete system.ntp.server
uci add_list system.ntp.server=0.${POOL}.pool.ntp.org
uci add_list system.ntp.server=1.${POOL}.ppl.ntp.org
uci add_list system.ntp.server=2.${POOL}.pool.ntp.org
uci add_list system.ntp.server=3.${POOL}.pool.ntp.org
uci set system.ntp.enable_server='1'
uci set system.ntp.use_dhcp='0'
uci set system.ntp.interface='lan'
uci commit system
/etc/init.d/sysntpd restart
SSH
WANからのアクセスを遮断
uci set dropbear.@dropbear[0].Interface='lan'
uci commit dropbear
LED
ネットワークアクセスで点灯点滅
#! /bin/sh
uci add system led
uci set system.@led[-1].name='wan'
uci set system.@led[-1].sysfs='green:status'
uci set system.@led[-1].trigger='netdev'
uci set system.@led[-1].dev='wan'
uci set system.@led[-1].mode='link tx rx'
uci add system led
uci set system.@led[-1].name='br-lan'
uci set system.@led[-1].sysfs='blue:wps'
uci set system.@led[-1].trigger='netdev'
uci set system.@led[-1].dev='br-lan'
uci set system.@led[-1].mode='link tx rx'
uci commit system
/etc/init.d/led reload
パッケージ
母国語サポート
LuCiの言語パッケージをインストール
- 対応言語検索
#! /bin/sh
PATTERN="luci-i18n-base*"
command -v opkg && opkg update && opkg list $PATTERN
command -v apk && apk update && apk search $PATTERN
- 設定
#! /bin/sh
I18N="ja"
PKGS="luci-i18n-base-${I18N} luci-i18n-firewall-${I18N}"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
UCI(TTYD)
ブラウザーでUCIにアクセス
#! /bin/sh
I18N="ja"
PKGS="luci-i18n-ttyd-${I18N}"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
uci set ttyd.@ttyd[0].ipv6='1'
uci set ttyd.@ttyd[0].command='/bin/login -f root' #自動ログイン
uci commit ttyd
/etc/init.d/rpcd restart
ファイラー
ブラウザでファイルにアクセス
mkdir -p /tmp/aios && wget -q -O /tmp/aios/install-filebrowser.sh https://raw.githubusercontent.com/site-u2023/aios/main/install-filebrowser.sh && sh /tmp/aios/install-filebrowser.sh
-
管理画面
192.168.1.1:8080 -
設定
# ポート変更
uci set filebrowser.config.port=9090
# ルートディレクトリ変更
uci set filebrowser.config.root=/mnt/storage
# ユーザーネーム及びパスワード変更
uci set filebrowser.config.username='root'
uci set filebrowser.config.password='password'
uci commit filebrowser
# 設定確認
uci show filebrowser
# サービス再起動
service filebrowser restart
# 既存DBをリセットしてUCI値で上書きしたいとき
rm /etc/filebrowser/filebrowser.db
service filebrowser restart
- 使用方法
filebrowser_main.sh: 自動判定 (インストールまたはリムーブ)
filebrowser_main.sh install: インストール
filebrowser_main.sh remove: リムーブ
filebrowser_main.sh status: 状態確認
WinSCPでファイルにアクセス
#! /bin/sh
PKGS="openssh-sftp-server"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
クライアント設定(Windows)
- 手動インストール
- ダウンロード:WinSCP
- 自動インストール
- キー入力:
Win
+x
>a
>はい
- 最新版ソフトウェアのインストール
- キー入力:
$psVersion = $PSVersionTable.PSVersion.Major
$LINKS = Invoke-WebRequest "https://winscp.net/eng/download.php"
$LINKS_VERSION = $LINKS.Links | Where-Object {$_.href -like "*WinSCP-*-Setup.exe*"} | Select-Object -ExpandProperty href
$VERSION = ($LINKS_VERSION -split '/')[-2] -replace "WinSCP-([0-9]+\.[0-9]+\.[0-9]+).*", '$1'
Write-Host "Version to install: $VERSION"
$downloadUrl = "https://jaist.dl.sourceforge.net/project/winscp/WinSCP/$VERSION/WinSCP-$VERSION-Setup.exe?viasf=1"
Write-Host "Downloading from: $downloadUrl"
$ONAMAE = (whoami).Split('\')[1]
$destinationPath = "C:\Users\$ONAMAE\Downloads\WinSCP-$VERSION-Setup.exe"
Invoke-WebRequest -Uri $downloadUrl -OutFile $destinationPath
Write-Host "Installing WinSCP..."
Start-Process -FilePath $destinationPath -ArgumentList "/VERYSILENT /NORESTART" -Wait
Invoke-Expression "C:\Users\$ONAMAE\AppData\Local\Programs\WinSCP\WinSCP.exe"
-
警告
>強制的に貼り付け
-
WinSCP設定
- セッション
- ホスト名:
192.168.1.1
- ユーザー名:
root
- パスワード:
設定したパスワード
-
ログイン
をクリック
- ホスト名:
- セッション
CPU負荷分散
インストール
#! /bin/sh
PKGS="irqbalance"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
uci set irqbalance.irqbalance=irqbalance
uci set irqbalance.irqbalance.enabled='1'
uci commit irqbalance
/etc/init.d/irqbalance start
ネットワーク統計インターフェイス
インストール
#! /bin/sh
I18N="ja"
PKGS="luci-i18n-statistics-${I18N}"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
/etc/init.d/collectd enable
/etc/init.d/rpcd restart
- プラグイン検索
#! /bin/sh
PATTERN="collectd-mod\*"
command -v opkg && opkg update && opkg list $PATTERN
command -v apk && apk update && apk search $PATTERN
追加テーマ
インストール
#! /bin/sh
PKGS="luci-theme-openwrt luci-theme-material"
command -v opkg && opkg update && opkg install $PKGS
command -v apk && apk update && apk add $PKGS
AdGuard Home
インストール
- インストール及びリムーブ
#!/bin/sh
TMP=/tmp/aios
mkdir -p "$TMP"
cat <<'EOF' > "$TMP"/standalone-blocker-adguardhome.sh
#!/bin/sh
# OpenWrt 19.07+ configuration
# Reference: https://openwrt.org/docs/guide-user/services/dns/adguard-home
# https://github.com/AdguardTeam/AdGuardHome
# This script file can be used standalone.
SCRIPT_VERSION="2025.08.26-00-00"
# set -ex
REQUIRED_MEM="50" # unit: MB
REQUIRED_FLASH="100" # unit: MB
LAN="${LAN:-br-lan}"
DNS_PORT="${DNS_PORT:-53}"
DNS_BACKUP_PORT="${DNS_BACKUP_PORT:-54}"
NET_ADDR=""
NET_ADDR6_LIST=""
SERVICE_NAME=""
INSTALL_MODE=""
ARCH=""
AGH=""
PACKAGE_MANAGER=""
FAMILY_TYPE=""
check_system() {
if /etc/AdGuardHome/AdGuardHome --version >/dev/null 2>&1 || /usr/bin/AdGuardHome --version >/dev/null 2>&1; then
printf "\033[1;33mAdGuard Home is already installed. Exiting.\033[0m\n"
remove_adguardhome
exit 0
fi
printf "\033[1;34mChecking system requirements\033[0m\n"
LAN="$(ubus call network.interface.lan status 2>/dev/null | jsonfilter -e '@.l3_device')"
if [ -z "$LAN" ]; then
printf "\033[1;31mLAN interface not found. Aborting.\033[0m\n"
exit 1
fi
if command -v opkg >/dev/null 2>&1; then
PACKAGE_MANAGER="opkg"
elif command -v apk >/dev/null 2>&1; then
PACKAGE_MANAGER="apk"
else
printf "\033[1;31mNo supported package manager (apk or opkg) found.\033[0m\n"
printf "\033[1;31mThis script is designed for OpenWrt systems only.\033[0m\n"
exit 1
fi
MEM_TOTAL_KB=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)
MEM_FREE_KB=$(awk '/^MemAvailable:/ {print $2}' /proc/meminfo)
BUFFERS_KB=$(awk '/^Buffers:/ {print $2}' /proc/meminfo)
CACHED_KB=$(awk '/^Cached:/ {print $2}' /proc/meminfo)
if [ -n "$MEM_FREE_KB" ]; then
MEM_FREE_MB=$((MEM_FREE_KB / 1024))
else
MEM_FREE_MB=$(((BUFFERS_KB + CACHED_KB) / 1024))
fi
MEM_TOTAL_MB=$((MEM_TOTAL_KB / 1024))
DF_OUT=$(df -k / | awk 'NR==2 {print $2, $4}')
FLASH_TOTAL_KB=$(printf '%s\n' "$DF_OUT" | awk '{print $1}')
FLASH_FREE_KB=$(printf '%s\n' "$DF_OUT" | awk '{print $2}')
FLASH_FREE_MB=$((FLASH_FREE_KB / 1024))
FLASH_TOTAL_MB=$((FLASH_TOTAL_KB / 1024))
if [ "$MEM_FREE_MB" -lt "$REQUIRED_MEM" ]; then
mem_col="1;31"
else
mem_col="1;32"
fi
if [ "$FLASH_FREE_MB" -lt "$REQUIRED_FLASH" ]; then
flash_col="1;31"
else
flash_col="1;32"
fi
printf "Memory: Free \033[%sm%s MB\033[0m / Total %s MB\n" \
"$mem_col" "$MEM_FREE_MB" "$MEM_TOTAL_MB"
printf "Flash: Free \033[%sm%s MB\033[0m / Total %s MB\n" \
"$flash_col" "$FLASH_FREE_MB" "$FLASH_TOTAL_MB"
printf "LAN interface: %s\n" "$LAN"
printf "Package manager: %s\n" "$PACKAGE_MANAGER"
if [ "$MEM_FREE_MB" -lt "$REQUIRED_MEM" ]; then
printf "\033[1;31mError: Insufficient memory. At least %sMB RAM is required.\033[0m\n" \
"$REQUIRED_MEM"
exit 1
fi
if [ "$FLASH_FREE_MB" -lt "$REQUIRED_FLASH" ]; then
printf "\033[1;31mError: Insufficient flash storage. At least %sMB free space is required.\033[0m\n" \
"$REQUIRED_FLASH"
exit 1
fi
}
install_prompt() {
printf "\033[1;34mSystem resources are sufficient for AdGuard Home installation. Proceeding with setup.\033[0m\n"
if [ -n "$1" ]; then
case "$1" in
official) INSTALL_MODE="official"; return ;;
openwrt) INSTALL_MODE="openwrt"; return ;;
remove) remove_adguardhome ;;
exit) exit 0 ;;
*) printf "\033[1;31mWarning: Unrecognized argument '$1'. Proceeding with interactive prompt.\033[0m\n" ;;
esac
fi
while true; do
printf "[1] Install OpenWrt package\n"
printf "[2] Install Official binary\n"
printf "[0] Exit\n"
printf "Please select (1, 2 or 0): "
read -r choice
case "$choice" in
1|openwrt) INSTALL_MODE="openwrt"; break ;;
2|official) INSTALL_MODE="official"; break ;;
0|exit)
printf "\033[1;33mInstallation cancelled.\033[0m\n"
exit 0
;;
*) printf "\033[1;31mInvalid choice '$choice'. Please enter 1, 2, or 0.\033[0m\n" ;;
esac
done
}
install_cacertificates() {
case "$PACKAGE_MANAGER" in
apk)
apk update >/dev/null 2>&1
apk add ca-certificates >/dev/null 2>&1
;;
opkg)
opkg update --verbosity=0 >/dev/null 2>&1
opkg install --verbosity=0 ca-bundle >/dev/null 2>&1
;;
esac
}
install_openwrt() {
printf "Installing adguardhome (OpenWrt package)\n"
case "$PACKAGE_MANAGER" in
apk)
PKG_VER=$(apk search adguardhome | grep "^adguardhome-" | sed 's/^adguardhome-//' | sed 's/-r[0-9]*$//')
if [ -n "$PKG_VER" ]; then
apk add adguardhome || {
printf "\033[1;31mNetwork error during apk add. Aborting.\033[0m\n"
exit 1
}
printf "\033[1;32madguardhome %s has been installed\033[0m\n" "$PKG_VER"
else
printf "\033[1;31mPackage 'adguardhome' not found in apk repository, falling back to official\033[0m\n"
install_official
fi
;;
opkg)
PKG_VER=$(opkg list | grep "^adguardhome " | awk '{print $3}')
if [ -n "$PKG_VER" ]; then
opkg install --verbosity=0 adguardhome || {
printf "\033[1;31mNetwork error during opkg install. Aborting.\033[0m\n"
exit 1
}
printf "\033[1;32madguardhome %s has been installed\033[0m\n" "$PKG_VER"
else
printf "\033[1;31mPackage 'adguardhome' not found in opkg repository, falling back to official\033[0m\n"
install_official
fi
;;
esac
SERVICE_NAME="adguardhome"
}
install_official() {
CA="--no-check-certificate"
URL="https://api.github.com/repos/AdguardTeam/AdGuardHome/releases/latest"
VER=$( { wget -q -O - "$URL" || wget -q "$CA" -O - "$URL"; } | jsonfilter -e '@.tag_name' )
[ -n "$VER" ] || { printf "\033[1;31mError: Failed to get AdGuardHome version from GitHub API.\033[0m\n"; exit 1; }
mkdir -p /etc/AdGuardHome
case "$(uname -m)" in
aarch64|arm64) ARCH=arm64 ;;
armv7l) ARCH=armv7 ;;
armv6l) ARCH=armv6 ;;
armv5l) ARCH=armv5 ;;
x86_64|amd64) ARCH=amd64 ;;
i386|i686) ARCH=386 ;;
mips) ARCH=mipsle ;;
mips64) ARCH=mips64le ;;
*) printf "Unsupported arch: %s\n" "$(uname -m)"; exit 1 ;;
esac
TAR="AdGuardHome_linux_${ARCH}.tar.gz"
URL2="https://github.com/AdguardTeam/AdGuardHome/releases/download/${VER}/${TAR}"
DEST="/etc/AdGuardHome/${TAR}"
printf "Downloading AdGuardHome (official binary)\n"
if ! { wget -q -O "$DEST" "$URL2" || wget -q "$CA" -O "$DEST" "$URL2"; }; then
printf '\033[1;31mDownload failed. Please check network connection.\033[0m\n'
exit 1
fi
printf "\033[1;32mAdGuardHome %s has been downloaded\033[0m\n" "$VER"
tar -C /etc/ -xzf "/etc/AdGuardHome/${TAR}"
rm "/etc/AdGuardHome/${TAR}"
chmod +x /etc/AdGuardHome/AdGuardHome
SERVICE_NAME="AdGuardHome"
/etc/AdGuardHome/AdGuardHome -s install >/dev/null 2>&1 || {
printf "\033[1;31mInitialization failed. Check AdGuardHome.yaml and port availability.\033[0m\n"
exit 1
}
chmod 700 /etc/"$SERVICE_NAME"
}
get_iface_addrs() {
local flag=0
if ip -4 -o addr show dev "$LAN" scope global | grep -q 'inet '; then
NET_ADDR=$(ip -4 -o addr show dev "$LAN" scope global | awk 'NR==1{sub(/\/.*/,"",$4); print $4}')
flag=$((flag | 1))
else
printf "\033[1;33mWarning: No IPv4 address on %s\033[0m\n" "$LAN"
fi
if ip -6 -o addr show dev "$LAN" scope global | grep -q 'inet6 '; then
NET_ADDR6_LIST=$(ip -6 -o addr show dev "$LAN" scope global | grep -v temporary | awk 'match($4,/^(2|fd|fc)/){sub(/\/.*/,"",$4); print $4;}')
flag=$((flag | 2))
else
printf "\033[1;33mWarning: No IPv6 address on %s\033[0m\n" "$LAN"
fi
case $flag in
3) FAMILY_TYPE=any ;;
1) FAMILY_TYPE=ipv4 ;;
2) FAMILY_TYPE=ipv6 ;;
*) FAMILY_TYPE="" ;;
esac
}
common_config() {
cp /etc/config/network /etc/config/network.adguard.bak
cp /etc/config/dhcp /etc/config/dhcp.adguard.bak
cp /etc/config/firewall /etc/config/firewall.adguard.bak
uci set dhcp.@dnsmasq[0].noresolv="1"
uci set dhcp.@dnsmasq[0].cachesize="0"
uci set dhcp.@dnsmasq[0].rebind_protection='0'
# uci set dhcp.@dnsmasq[0].rebind_protection='1' # keep enabled
# uci set dhcp.@dnsmasq[0].rebind_localhost='1' # protect localhost
# uci add_list dhcp.@dnsmasq[0].rebind_domain='lan' # allow internal domain
uci set dhcp.@dnsmasq[0].port="${DNS_BACKUP_PORT}"
uci set dhcp.@dnsmasq[0].domain="lan"
uci set dhcp.@dnsmasq[0].local="/lan/"
uci set dhcp.@dnsmasq[0].expandhosts="1"
uci -q del dhcp.@dnsmasq[0].server || true
uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#${DNS_PORT}"
uci add_list dhcp.@dnsmasq[0].server="::1#${DNS_PORT}"
uci -q del dhcp.lan.dhcp_option || true
uci add_list dhcp.lan.dhcp_option="6,${NET_ADDR}"
uci -q del dhcp.lan.dhcp_option6 || true
if [ -n "$NET_ADDR6_LIST" ]; then
for ip in $NET_ADDR6_LIST; do
uci add_list dhcp.lan.dhcp_option6="option6:dns=[${ip}]"
done
fi
uci commit dhcp
/etc/init.d/dnsmasq restart || {
printf "\033[1;31mFailed to restart dnsmasq\033[0m\n"
printf "\033[1;31mTo remove AdGuard Home, run:\033[0m\n"
printf "\033[1;31msh %s/standalone-blocker-adguardhome.sh remove_adguardhome auto\033[0m\n" "$TMP"
exit 1
}
/etc/init.d/odhcpd restart || {
printf "\033[1;31mFailed to restart odhcpd\033[0m\n"
printf "\033[1;31mTo remove AdGuard Home, run:\033[0m\n"
printf "\033[1;31msh %s/standalone-blocker-adguardhome.sh remove_adguardhome auto\033[0m\n" "$TMP"
exit 1
}
/etc/init.d/"$SERVICE_NAME" enable
/etc/init.d/"$SERVICE_NAME" start
printf "Router IPv4: %s\n" "$NET_ADDR"
if [ -z "$NET_ADDR6_LIST" ]; then
printf "\033[1;33mRouter IPv6: none found\033[0m\n"
else
printf "Router IPv6: %s\n" "$(echo "$NET_ADDR6_LIST" | tr '\n' ' ')"
fi
printf "\033[1;32mSystem configuration completed\033[0m\n"
}
common_config_firewall() {
uci -q delete firewall.@include[0].reload
uci commit firewall
rule_name="adguardhome_dns_${DNS_PORT}"
uci -q delete firewall."$rule_name" || true
if [ -z "$FAMILY_TYPE" ]; then
printf "\033[1;31mNo valid IP address family detected. Skipping firewall rule setup.\033[0m\n"
return
fi
uci set firewall."$rule_name"=redirect
uci set firewall."$rule_name".name="AdGuardHome DNS Redirect (${FAMILY_TYPE})"
uci set firewall."$rule_name".family="$FAMILY_TYPE"
uci set firewall."$rule_name".src="lan"
uci set firewall."$rule_name".dest="lan"
uci add_list firewall."$rule_name".proto="tcp"
uci add_list firewall."$rule_name".proto="udp"
uci set firewall."$rule_name".src_dport="$DNS_PORT"
uci set firewall."$rule_name".dest_port="$DNS_PORT"
uci set firewall."$rule_name".target="DNAT"
uci commit firewall
/etc/init.d/firewall restart || {
printf "\033[1;31mFailed to restart firewall\033[0m\n"
printf "\033[1;31mTo remove AdGuard Home, run:\033[0m\n"
printf "\033[1;31msh %s/standalone-blocker-adguardhome.sh remove_adguardhome auto\033[0m\n" "$TMP"
exit 1
}
printf "\033[1;32mFirewall configuration completed\033[0m\n"
}
remove_adguardhome() {
local auto_confirm="$1"
printf "\033[1;34mRemoving AdGuard Home\033[0m\n"
if /etc/AdGuardHome/AdGuardHome --version >/dev/null 2>&1; then
INSTALL_TYPE="official"; AGH="AdGuardHome"
elif /usr/bin/AdGuardHome --version >/dev/null 2>&1; then
INSTALL_TYPE="openwrt"; AGH="adguardhome"
else
printf "\033[1;31mAdGuard Home not found\033[0m\n"
return 1
fi
printf "Found AdGuard Home (%s version)\n" "$INSTALL_TYPE"
if [ "$auto_confirm" != "auto" ]; then
printf "Do you want to remove it? (y/N): "
read -r confirm
case "$confirm" in
[yY]*) ;;
*) printf "\033[1;33mCancelled\033[0m\n"; return 0 ;;
esac
else
printf "\033[1;33mAuto-removing due to installation error\033[0m\n"
fi
/etc/init.d/"${AGH}" stop 2>/dev/null || true
/etc/init.d/"${AGH}" disable 2>/dev/null || true
if [ "$INSTALL_TYPE" = "official" ]; then
"/etc/${AGH}/${AGH}" -s uninstall 2>/dev/null || true
else
if command -v apk >/dev/null 2>&1; then
apk del "$AGH" 2>/dev/null || true
else
opkg remove --verbosity=0 "$AGH" 2>/dev/null || true
fi
fi
if [ -d "/etc/${AGH}" ] || [ -f "/etc/adguardhome.yaml" ]; then
if [ "$auto_confirm" != "auto" ]; then
printf "Do you want to delete the AdGuard Home configuration file(s)? (y/N): "
read -r cfg
case "$cfg" in
[yY]*) rm -rf "/etc/${AGH}" /etc/adguardhome.yaml ;;
esac
else
rm -rf "/etc/${AGH}" /etc/adguardhome.yaml
fi
fi
for cfg in network dhcp firewall; do
bak="/etc/config/${cfg}.adguard.bak"
if [ -f "$bak" ]; then
printf "\033[1;34mRestoring %s configuration\033[0m\n" "$cfg"
cp "$bak" "/etc/config/${cfg}"
rm -f "$bak"
fi
done
uci commit network
uci commit dhcp
uci commit firewall
/etc/init.d/dnsmasq restart || { printf "\033[1;31mFailed to restart dnsmasq\033[0m\n"; exit 1; }
/etc/init.d/odhcpd restart || { printf "\033[1;31mFailed to restart odhcpd\033[0m\n"; exit 1; }
/etc/init.d/firewall restart || { printf "\033[1;31mFailed to restart firewall\033[0m\n"; exit 1; }
printf "\033[1;32mAdGuard Home has been removed successfully.\033[0m\n"
if [ "$auto_confirm" != "auto" ]; then
printf "\033[33mPress any key to reboot.\033[0m\n"
read -r -n1 -s
reboot
else
printf "\033[1;33mAuto-rebooting\033[0m\n"
reboot
fi
exit 0
}
get_access() {
local cfg port addr
if [ -f "/etc/AdGuardHome/AdGuardHome.yaml" ]; then
cfg="/etc/AdGuardHome/AdGuardHome.yaml"
elif [ -f "/etc/adguardhome.yaml" ]; then
cfg="/etc/adguardhome.yaml"
fi
if [ -n "$cfg" ]; then
addr=$(awk '
$1=="http:" {flag=1; next}
flag && /^[[:space:]]*address:/ {print $2; exit}
' "$cfg" 2>/dev/null)
port="${addr##*:}"
[ -z "$port" ] && port=
fi
[ -z "$port" ] && port=3000
if command -v qrencode >/dev/null 2>&1; then
printf "\033[1;32mWeb interface IPv4: http://${NET_ADDR}:${port}/\033[0m\n"
printf "http://${NET_ADDR}:${port}/\n" | qrencode -t UTF8 -v 3
if [ -n "$NET_ADDR6_LIST" ]; then
set -- $NET_ADDR6_LIST
printf "\033[1;32mWeb interface IPv6: http://[%s]:%s/\033[0m\n" "$1" "$port"
printf "http://[%s]:%s/\n" "$1" "$port" | qrencode -t UTF8 -v 3
fi
else
printf "\033[1;32mWeb interface IPv4: http://${NET_ADDR}:${port}/\033[0m\n"
if [ -n "$NET_ADDR6_LIST" ]; then
set -- $NET_ADDR6_LIST
printf "\033[1;32mWeb interface IPv6: http://[%s]:%s/\033[0m\n" "$1" "$port"
fi
fi
}
adguardhome_main() {
check_system
install_prompt "$@"
install_cacertificates
install_"$INSTALL_MODE"
get_iface_addrs
common_config
common_config_firewall
printf "\n\033[1;32mAdGuard Home installation and configuration completed successfully.\033[0m\n\n"
get_access
}
adguardhome_main "$@"
EOF
chmod +x "$TMP"/standalone-blocker-adguardhome.sh
sh "$TMP"/standalone-blocker-adguardhome.sh
- 管理画面ログイン
http://192.168.1.1:3000/
- DNS BIND MODE
# Set default bind mode: "loopback" or "gua"
DNS_BIND_MODE="${DNS_BIND_MODE:-loopback}"
common_config() {
# Option | DNS_BIND_MODE
#
# By setting DNS_BIND_MODE, you can switch dnsmasq’s upstream DNS between
# “loopback” mode (127.0.0.1#53 / ::1#53) and
# “gua” mode (router’s global IP#53).
#
# ・loopback (default)
# – dnsmasq → always resolves via local loopback to AdGuard Home
# – Ideal for environments where AdGuard Home is bound to localhost only
#
# ・gua
# – dnsmasq → resolves via the router’s global IPv4/IPv6 addresses
# – Useful for MAP-E/DS-Lite/WireGuard tunnels or
# direct DNS access from external clients
#
# Usage:
# export DNS_BIND_MODE="${DNS_BIND_MODE:-loopback}"
printf "\033[1;34mBacking up configuration files\033[0m\n"
cp /etc/config/network /etc/config/network.adguard.bak
cp /etc/config/dhcp /etc/config/dhcp.adguard.bak
cp /etc/config/firewall /etc/config/firewall.adguard.bak
[ "$INSTALL_MODE" = "official" ] && {
/etc/AdGuardHome/AdGuardHome -s install >/dev/null 2>&1 || {
printf "\033[1;31mInitialization failed. Check AdGuardHome.yaml and port availability.\033[0m\n"
exit 1
}
}
chmod 700 /etc/"$SERVICE_NAME"
/etc/init.d/"$SERVICE_NAME" enable
/etc/init.d/"$SERVICE_NAME" start
uci set dhcp.@dnsmasq[0].noresolv="1"
uci set dhcp.@dnsmasq[0].cachesize="0"
uci set dhcp.@dnsmasq[0].rebind_protection='0'
# uci set dhcp.@dnsmasq[0].rebind_protection='1' # keep enabled
# uci set dhcp.@dnsmasq[0].rebind_localhost='1' # protect localhost
# uci add_list dhcp.@dnsmasq[0].rebind_domain='lan' # allow internal domain
uci set dhcp.@dnsmasq[0].port="54"
uci set dhcp.@dnsmasq[0].domain="lan"
uci set dhcp.@dnsmasq[0].local="/lan/"
uci set dhcp.@dnsmasq[0].expandhosts="1"
uci -q del dhcp.@dnsmasq[0].server || true
if [ "$DNS_BIND_MODE" = "gua" ]; then
uci add_list dhcp.@dnsmasq[0].server="${NET_ADDR}#53"
for ip6 in $NET_ADDR6_LIST; do
uci add_list dhcp.@dnsmasq[0].server="${ip6}#53"
done
else
uci add_list dhcp.@dnsmasq[0].server='127.0.0.1#53'
uci add_list dhcp.@dnsmasq[0].server='::1#53'
fi
uci -q del dhcp.lan.dhcp_option || true
uci add_list dhcp.lan.dhcp_option="6,${NET_ADDR}"
uci set dhcp.@dnsmasq[0].dns="::"
uci -q del dhcp.lan.dhcp_option6 || true
if [ -n "$NET_ADDR6_LIST" ]; then
for ip6 in $NET_ADDR6_LIST; do
uci add_list dhcp.lan.dhcp_option6="option6:dns=[${ip6}]"
done
fi
uci commit dhcp
/etc/init.d/dnsmasq restart || {
printf "\033[1;31mFailed to restart dnsmasq\033[0m\n"
printf "\033[1;31mCritical error: Auto-removing AdGuard Home and rebooting in 10 seconds (Ctrl+C to cancel)\033[0m\n"
sleep 10
remove_adguardhome "auto"
reboot
exit 1
}
/etc/init.d/odhcpd restart || {
printf "\033[1;31mFailed to restart odhcpd\033[0m\n"
printf "\033[1;31mCritical error: Auto-removing AdGuard Home and rebooting in 10 seconds (Ctrl+C to cancel)\033[0m\n"
sleep 10
remove_adguardhome "auto"
reboot
exit 1
}
printf "\033[1;32mRouter IPv4: %s\033[0m\n" "$NET_ADDR"
if [ -z "$NET_ADDR6_LIST" ]; then
printf "\033[1;33mRouter IPv6: none found\033[0m\n"
else
printf "Router IPv6: %s\n" "$NET_ADDR6_LIST"
fi
}
Webmin
インストール
- webminインストール
#!/bin/sh
set -e
## 1. 変数定義
INSTALL_DIR=/usr/libexec/webmin # Webmin 本体設置先
CONFIG_DIR=/etc/webmin # 設定ディレクトリ
LOG_DIR=/lib/webmin # ログ出力先
PID_DIR=/var/run/webmin # pid 保存先
USER=admin # 管理ユーザー名
PASS=$(tr -dc A-Za-z0-9 </dev/urandom | head -c12) # ランダムパスワード
PORT=10000 # リッスンポート
## 2. 依存パッケージのインストール(SSL 有効化に perl-net-ssleay)
opkg update
BASE_PKGS="
tar gzip unzip shared-mime-info openssl-util
coreutils coreutils-install coreutils-stty coreutils-df
make gawk fdisk patch diffutils binutils-objdump
perl perlbase perlbase-bignum perlbase-commons perlbase-time
perl-test-warn perl-test-harness
"
PERLBASE_PKGS="$(opkg list | awk '/^perlbase-/{print $1}')"
opkg install $BASE_PKGS $PERLBASE_PKGS --force-overwrite
echo "依存パッケージのインストールが完了しました。"
## 3. グループ「bin」の確認/追加
grep -q '^bin:' /etc/group || echo 'bin:x:2:' >> /etc/group
## 4. ディレクトリ作成
mkdir -p ${INSTALL_DIR} ${CONFIG_DIR} ${LOG_DIR} ${PID_DIR}
## 5. Webmin ダウンロード&展開
wget --no-check-certificate -O /tmp/webmin.tar.gz https://www.webmin.com/download/webmin-current.tar.gz
tar xzf /tmp/webmin.tar.gz -C ${INSTALL_DIR} --strip-components=1
## 6. setup.sh の無人化パッチ
# atboot=1 → 0(xinetd 非依存化)
# makeboot=1 行削除
sed -i -e 's/^atboot=1/atboot=0/' -e '/^makeboot=1/d' ${INSTALL_DIR}/setup.sh
## 7. setup.sh を非対話で実行
perl_bin=$(which perl || echo /usr/bin/perl)
os_name="Generic Linux"
os_ver=$(uname -r)
/usr/bin/env bash <<EOF | ${INSTALL_DIR}/setup.sh ${INSTALL_DIR}
${LOG_DIR}
${perl_bin}
${os_name}
${os_ver}
${PORT}
${USER}
${PASS}
${PASS}
n
EOF
## 8. SSL 無効化(SSLeay ライブラリなしでも動くように)
sed -i -e 's/^ssl=1/ssl=0/' ${CONFIG_DIR}/miniserv.conf
## 9. procd/rc.common ベースの init スクリプト作成
cat << 'EOI' > /etc/init.d/webmin
#!/bin/sh /etc/rc.common
START=90
STOP=10
USE_PROCD=1
PIDFILE=/var/run/webmin/miniserv.pid
COMMAND=/etc/webmin/.start-init
start_service() {
procd_open_instance
procd_set_param command ${COMMAND}
procd_set_param pidfile ${PIDFILE}
procd_set_param respawn
procd_close_instance
}
stop_service() {
/etc/webmin/.stop-init
}
reload_service() {
/etc/webmin/.reload-init
}
EOI
chmod +x /etc/init.d/webmin
## 10. サービス有効化&起動
/etc/init.d/webmin enable
/etc/init.d/webmin start
## 完了メッセージ
echo "-------------------------------------------------"
echo "Webmin Installed!"
echo "URL: http://$(ip addr show dev br-lan | grep -Po 'inet \K[\d.]+'):${PORT}/"
echo "User: ${USER}"
echo "Pass: ${PASS}"
echo "Log: ${LOG_DIR}/miniserv.log"
echo "-------------------------------------------------"
- 管理画面ログイン
http://192.168.1.1:10000/
- リムーブ
service webmin stop
rm -rf /etc/init.d/webmin
rm -rf /etc/init.d/webmin.old
sed -i "/bin:x:2:/d" /etc/group
sed -i "/webmin/d" /etc/services
/etc/webmin/uninstall.sh
テスト
iperf3
インストール
#!/bin/sh
TMP=/tmp/aios
mkdir -p "$TMP"
cat > "$TMP"/iperf3_setup.sh << 'SCRIPT_END'
#!/bin/sh
# Usage: ./iperf3_setup.sh [start|stop|restart|enable|disable|status|interactive]
SERVICE_FILE="/etc/init.d/iperf3"
PIDFILE="/var/run/iperf3.pid"
LAN="br-lan"
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
CYAN='\033[1;36m'
NC='\033[0m'
print_msg() { printf "${1}${2}${NC}\n"; }
get_iface_addrs() {
local flag=0
if ip -4 -o addr show dev "$LAN" scope global 2>/dev/null | grep -q 'inet '; then
NET_ADDR=$(ip -4 -o addr show dev "$LAN" scope global | awk 'NR==1{sub(/\/.*/,"",$4); print $4}')
flag=$((flag | 1))
else
printf "\033[1;33mWarning: No IPv4 address on %s\033[0m\n" "$LAN"
fi
if ip -6 -o addr show dev "$LAN" scope global 2>/dev/null | grep -q 'inet6 '; then
NET_ADDR6_LIST=$(ip -6 -o addr show dev "$LAN" scope global | grep -v temporary | awk 'match($4,/^(2|fd|fc)/){sub(/\/.*/,"",$4); print $4;}')
flag=$((flag | 2))
else
printf "\033[1;33mWarning: No IPv6 address on %s\033[0m\n" "$LAN"
fi
case $flag in
3) FAMILY_TYPE=any ;;
1) FAMILY_TYPE=ipv4 ;;
2) FAMILY_TYPE=ipv6 ;;
*) FAMILY_TYPE="" ;;
esac
}
get_lan_ip() {
get_iface_addrs
if [ -n "$NET_ADDR" ]; then
printf "${NET_ADDR}"
else
printf "192.168.1.1"
fi
}
check_package() {
command -v iperf3 >/dev/null 2>&1 || {
command -v apk >/dev/null 2>&1 && apk info iperf3 >/dev/null 2>&1
} || {
command -v opkg >/dev/null 2>&1 && opkg list-installed | grep -q "^iperf3 "
}
}
check_service() { [ -f "$SERVICE_FILE" ]; }
install_package(){
PKGS="iperf3"
print_msg "$BLUE" "Installing $PKGS package"
command -v opkg >/dev/null 2>&1 && opkg update >/dev/null 2>&1 && opkg install $PKGS && return 0
command -v apk >/dev/null 2>&1 && apk update >/dev/null 2>&1 && apk add $PKGS && return 0
print_msg "$RED" "No supported package manager found (opkg/apk)"
return 1
}
create_service() {
local ip
ip=$(get_lan_ip)
print_msg "$BLUE" "Creating iperf3 service for $ip:5201"
cat > "$SERVICE_FILE" << 'SERVICEEOF'
#!/bin/sh /etc/rc.common
START=95
STOP=01
USE_PROCD=1
PROG=/usr/bin/iperf3
pidfile=/var/run/iperf3.pid
start_service() {
local ip
ip=$(ip -4 -o addr show dev br-lan scope global 2>/dev/null | awk 'NR==1{sub(/\/.*/,"",$4); print $4}')
[ -z "$ip" ] && ip="192.168.1.1"
printf "Starting iperf3 server on %s:5201\n" "$ip"
procd_open_instance
procd_set_param command "$PROG" --server --daemon --pidfile "$pidfile" --bind "$ip"
procd_set_param pidfile "$pidfile"
procd_set_param respawn
procd_close_instance
}
stop_service() {
printf "Stopping iperf3 server\n"
[ -f "$pidfile" ] && {
pid=$(cat "$pidfile" 2>/dev/null)
[ -n "$pid" ] && kill -0 "$pid" 2>/dev/null && {
kill "$pid" 2>/dev/null && printf "iperf3 server stopped\n" || {
printf "Failed to stop iperf3 server (PID: %s)\n" "$pid"; return 1
}
}
rm -f "$pidfile"
}
}
status() {
local ip pid
ip=$(ip -4 -o addr show dev br-lan scope global 2>/dev/null | awk 'NR==1{sub(/\/.*/,"",$4); print $4}')
[ -z "$ip" ] && ip="192.168.1.1"
[ -f "$pidfile" ] && {
pid=$(cat "$pidfile" 2>/dev/null)
[ -n "$pid" ] && kill -0 "$pid" 2>/dev/null && {
printf "iperf3 server is running (PID: %s) on %s:5201\n" "$pid" "$ip"; return 0
}
printf "iperf3 server is not running (stale pidfile)\n"; rm -f "$pidfile"; return 1
} || { printf "iperf3 server is not running\n"; return 1; }
}
SERVICEEOF
chmod +x "$SERVICE_FILE"
print_msg "$GREEN" "Service configured for $ip:5201"
}
install_iperf3() {
print_msg "$BLUE" "Installing iperf3"
command -v iperf3 >/dev/null 2>&1 || install_package iperf3 || { print_msg "$RED" "Package installation failed"; return 1; }
[ -f "$SERVICE_FILE" ] || create_service || { print_msg "$RED" "Service creation failed"; return 1; }
print_msg "$GREEN" "Installation completed"
printf "${CYAN}service iperf3 [enable|start|stop|status]${NC}\n"
printf "${CYAN}Test: iperf3 -c $(get_lan_ip) -t 10${NC}\n"
}
remove_iperf3() {
local auto="$1"
print_msg "$BLUE" "Removing iperf3"
local pkg=false svc=false
check_package && pkg=true
check_service && svc=true
[ "$pkg" = "false" ] && [ "$svc" = "false" ] && { print_msg "$RED" "iperf3 not found"; return 1; }
[ "$auto" != "auto" ] && {
printf "Remove iperf3? (y/N): "
read -r confirm
case "$confirm" in
[yY]*) ;;
*) print_msg "$YELLOW" "Cancelled"; return 0;;
esac
}
[ "$svc" = "true" ] && {
print_msg "$BLUE" "Removing service"
service iperf3 stop 2>/dev/null || true
service iperf3 disable 2>/dev/null || true
rm -f "$SERVICE_FILE" "$PIDFILE"
print_msg "$GREEN" "Service removed"
}
[ "$pkg" = "true" ] && {
print_msg "$BLUE" "Removing package"
if command -v apk >/dev/null 2>&1; then
apk del iperf3 && print_msg "$GREEN" "Package removed" || { print_msg "$RED" "Remove failed"; return 1; }
elif command -v opkg >/dev/null 2>&1; then
opkg remove iperf3 && print_msg "$GREEN" "Package removed" || { print_msg "$RED" "Remove failed"; return 1; }
else
print_msg "$YELLOW" "Cannot remove package - no package manager"
fi
}
print_msg "$GREEN" "Removal completed"
}
show_usage() {
printf "Usage: %s [command]\n\n" "$0"
printf "Commands:\n"
printf " start - Start iperf3 service\n"
printf " stop - Stop iperf3 service\n"
printf " restart - Restart iperf3 service\n"
printf " enable - Enable service at boot\n"
printf " disable - Disable service at boot\n"
printf " status - Show service status\n"
printf " interactive - Interactive mode (default)\n"
printf " help - Show this help\n\n"
printf "Note: Install/Uninstall is determined automatically\n"
}
interactive_mode() {
while true; do
printf "\n${BLUE}iperf3 Management${NC}\n"
check_package && pkg=true || pkg=false
check_service && svc=true || svc=false
if [ "$svc" = "true" ]; then
service iperf3 status >/dev/null 2>&1 && running=true || running=false
else
running=false
fi
if [ "$pkg" = "false" ] || [ "$svc" = "false" ]; then
printf "[1] Install iperf3\n"
printf "[2] Exit\n"
printf "Please select (1-2): "
read -r choice
case "$choice" in
1)
install_iperf3
;;
2)
print_msg "$GREEN" "Goodbye"
break
;;
*)
printf "${RED}Invalid selection: %s${NC}\n" "$choice"
;;
esac
else
printf "[1] Start service [5] Disable service\n"
printf "[2] Stop service [6] Show status\n"
printf "[3] Restart service [7] Remove iperf3\n"
printf "[4] Enable service [8] Exit\n"
printf "Please select (1-8): "
read -r choice
case "$choice" in
1) service iperf3 start;;
2) service iperf3 stop;;
3) service iperf3 restart;;
4)
service iperf3 enable
print_msg "$GREEN" "Enabled at boot"
;;
5)
service iperf3 disable
print_msg "$GREEN" "Disabled at boot"
;;
6)
service iperf3 status
;;
7)
remove_iperf3
;;
8)
print_msg "$GREEN" "Goodbye"
break
;;
*)
printf "${RED}Invalid selection: %s${NC}\n" "$choice"
;;
esac
fi
if [ "$choice" != "2" ] && [ "$choice" != "8" ]; then
printf "\n${CYAN}Press Enter to continue${NC}"
read -r dummy 2>/dev/null || true
fi
done
}
iperf3_main() {
case "${1:-interactive}" in
start|stop|restart)
check_service || {
print_msg "$RED" "Service not configured. Run script to install."
exit 1
}
service iperf3 "$1"
;;
enable|disable)
check_service || {
print_msg "$RED" "Service not configured. Run script to install."
exit 1
}
service iperf3 "$1"
print_msg "$GREEN" "Service ${1}d at boot"
;;
status)
check_service || {
print_msg "$RED" "Service not configured"
exit 1
}
service iperf3 status
printf "\n${CYAN}Server: $(get_lan_ip):5201${NC}\n"
printf "${CYAN}Test: iperf3 -c $(get_lan_ip) -t 10${NC}\n"
;;
interactive)
interactive_mode
;;
auto-toggle)
if check_package || check_service; then
remove_iperf3
else
install_iperf3
fi
;;
help|-h|--help)
show_usage
;;
*)
print_msg "$RED" "Unknown command: $1"
show_usage
exit 1
;;
esac
}
[ "${0##*/}" = "iperf3_setup.sh" ] && iperf3_main "$@"
SCRIPT_END
chmod +x "$TMP"/iperf3_setup.sh
printf "\n${GREEN}=== iperf3 Setup Script Created ===${NC}\n"
printf "${CYAN}Location: $TMP/iperf3_setup.sh${NC}\n"
printf "${YELLOW}Usage: $TMP/iperf3_setup.sh [start|stop|status|help]${NC}\n"
printf "${YELLOW}Interactive: $TMP/iperf3_setup.sh${NC}\n"
printf "\n${BLUE}Running script in interactive mode${NC}\n"
sh "$TMP"/iperf3_setup.sh
- サーバー起動 (2回目以降)
/etc/init.d/iperf3 start
- クライアントで実行
$iperf3 = Get-Command iperf3.exe -ErrorAction SilentlyContinue
if (-not $iperf3) {
$iperf3 = Get-ChildItem -Path $PWD -Filter iperf3.exe -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
if ($iperf3) { $iperf3 = $iperf3.FullName }
else {
Write-Host "iperf3.exe が見つかりません。" -ForegroundColor Red
exit 1
}
} else {
$iperf3 = $iperf3.Source
}
$server = (Get-DnsClientServerAddress -AddressFamily IPv4 | Select-Object -ExpandProperty ServerAddresses)[0]
& "$iperf3" -c $server -t 10
- 追加テスト
& "$iperf3" -c $server -t 60 -P 16 -w 2M
- リムーブ
sh /tmp/aios/iperf3_setup.sh auto-toggle
トラブル
初期化
ファクトリーリセット(初期化)
リセット
# 要注意
firstboot && reboot now
This will erase all settings and remove any installed packages. Are you sure? [N/y]
y
デバイスリセットボタン
デバイスのリセットボタンを10秒押し続ける