OpenWrt Wi-Fi Dynamic_frequency_selection (DFS) Guest_Wi-Fi (QR code) Target_Wake_Time (TWT)

:warning:Japanese notation
# はじめに

::: note
### 初心者対応構成
- スクリプトでの自動設定
- UCIとLuCi及びWinSCPにて比較しながら作業がおススメ
:::

::: note
### [PowerShell](https://learn.microsoft.com/ja-jp/powershell/scripting/what-is-windows-powershell?view=powershell-7.4)で[SSHアクセス](https://openwrt.org/docs/guide-quick-start/sshadministration)

- [PowerShellの開始](https://learn.microsoft.com/ja-jp/powershell/scripting/windows-powershell/starting-windows-powershell?view=powershell-7.4) (キー入力)：`Win`+`x` > `a` > `はい`
※Windows7以降標準搭載

```sh
ssh root@192.168.1.1
```

<details><summary>ssh root@192.168.1.1のショートカット作成（デスクトップ）</summary>

```powershell:powershell
$DESKTOP = ([Environment]::GetFolderPath("Desktop") + "\192.168.1.1.lnk")
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("$DESKTOP")
$Shortcut.TargetPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$Shortcut.Arguments = '-windowstyle hidden -ExecutionPolicy RemoteSigned "Start-Process ssh root@192.168.1.1"'
$Shortcut.IconLocation = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe,0"
$Shortcut.WorkingDirectory = "."
$Shortcut.Save()

```

- `強制的に貼り付け`
- `yes`

---

</details>

<details><summary>SSHログイン出来ない場合:exclamation:</summary>

known_hostsクリア
- `C:\Users\yourusername\.ssh\known_hosts` ※Windows隠しファイル
```powershell:powershell
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

```
---

</details>

:::


# Dynamic frequency selection (DFS)

::: note
### ZZDFS
DFSによるWi-Fi停波対策

![dfslog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/8ace999d-562e-cbb0-4399-8861926a764d.png)

 ### 仕様
iwinfoをトリガーにセット済みDFS用チャンネルへフォールバックし30分後元チャンネルに復旧する
※固定チャンネルかつ160MHz利用で特に有効

- サービス：１分15秒スリープ後起動
- システムログ：DFS感知時リセット
※`ver/log/syslog`に転送
- 復旧時チャンネル：初期設定時また再起動時のチャンネルでセット
- インターバル：更新間隔（初期値5分）
※最小インターバル：1分
  - 更新間隔変更：[zzdfsl](https://qiita.com/site_u/items/f42be7c0953187b9428a#%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%90%E3%83%AB%E6%99%82%E9%96%93%E8%A8%AD%E5%AE%9A%E5%A4%89%E6%9B%B4)利用
※CRONからの変更はスクリプト実行時初期値に復元

### DFS帯域確認
```sh
iw reg get

```

### デバイス確認
```sh
{
#! /bin/sh
RADIO=`uci show wireless | grep "band='5g'" | cut -d'.' -f2 | awk '{ print $1 }'`
CHS=`echo ${RADIO} | wc -w`
if [ ${CHS} = 2 ];then
    RADIO=`echo ${RADIO}| awk '{print $2}'`
fi
CH=`echo ${RADIO} | grep -o "[0-9]*"`
DEV=`iw dev | awk '/Interface/{print $2}' | grep ${CH}`
CHANNEL=$(uci get wireless.${RADIO}.channel)
echo -------------------
echo radio: ${RADIO}
echo device: ${DEV} 
echo channel: ${CHANNEL}
echo -------------------
}

```

### 動作確認
[BPI-R3](https://qiita.com/site_u/items/4c3363f7c1ce2b7b3bfa)/ [NCP-HG100](https://qiita.com/site_u/items/e07cd5b6326039e45fde)
### 構成
- サービス
`/etc/init.d/zzdfs`
- スクリプト
[`/etc/config-software/zzdfs-config.sh`](https://github.com/site-u2023/config-software/blob/main/zzdfs-config.sh)
`/usr/bin/zzdfsl`
`/usr/bin/zzdfst`

### 設定


```sh
#! /bin/sh

uci set system.@system[0].log_file='/var/log/syslog'
uci set 
uci commit system
service system restart
service log restart

cat << "EOF" > /etc/init.d/zzdfs
#!/bin/sh /etc/rc.common

INTERVAL=5    # check interval (min)
FB_BAND=40    # fallback band
FB_CHANNEL=36 # fallback channel

START=99
STOP=01
     
start() {
	sleep 1m 15s
	logger "ZZDFS: Start"
    mkdir -p /tmp/config-software/
    RADIO=`uci show wireless | grep "band='5g'" | cut -d'.' -f2 | awk '{ print $1 }'`
    CHS=`echo ${RADIO} | wc -w`
    if [ ${CHS} = 2 ];then
        RADIO=`echo ${RADIO}| awk '{print $2}'`
    fi
    CH=`echo ${RADIO} | grep -o "[0-9]*"`
    echo $(iw dev | awk '/Interface/{print $2}' | grep ${CH}) > /tmp/config-software/dev
    echo ${INTERVAL} > /tmp/config-software/interval
    echo ${RADIO} > /tmp/config-software/radio
	echo $(uci get wireless.${RADIO}.channel) > /tmp/config-software/channel
    echo $(uci get wireless.${RADIO}.htmode) > /tmp/config-software/htmode    
    echo ${FB_BAND} > /tmp/config-software/fb_band
    echo ${FB_CHANNEL} > /tmp/config-software/fb_channel
    sed -i "/zzdfs.sh/d" /etc/crontabs/root
    echo "*/${INTERVAL} * * * * sh /etc/config-software/zzdfs.sh # ZZDFS" >> /etc/crontabs/root
    service cron restart
    exit 0
}
restart() {
    exit 0
}
stop() {
    logger "ZZDFS: Stop"
    sed -i "/zzdfs.sh/d" /etc/crontabs/root
    service cron restart
    rm -rf /tmp/config-software
    exit 0
}
EOF
chmod +x /etc/init.d/zzdfs


mkdir -p /etc/config-software/
cat << "EOF" > /etc/config-software/zzdfs.sh
#! /bin/sh

function _DFS() {
	logger "ZZDFS: ZZDFS_ON"
	sed -i "/zzdfs.sh/d" /etc/crontabs/root
	service cron restart
	read RADIO < /tmp/config-software/radio
	read FB_CHANNEL < /tmp/config-software/fb_channel
	read FB_BAND < /tmp/config-software/fb_band
	echo $(uci get wireless.${RADIO}.channel) > /tmp/config-software/channel
	HTMODE=$(uci get wireless.${RADIO}.htmode | tee /tmp/config-software/htmode) 
	MODE=`echo ${HTMODE} | grep -o "[A-Z]*"`	
	uci set wireless.${RADIO}.channel=${FB_CHANNEL}
	uci set wireless.${RADIO}.htmode=${MODE}${FB_BAND}
	uci commit wireless
	wifi reload ${RADIO}
	sleep 30m
	logger "ZZDFS: ZZDFS_OFF"	
	read CHANNEL < /tmp/config-software/channel
	read HTMODE < /tmp/config-software/htmode
	uci set wireless.${RADIO}.channel=${CHANNEL}
	uci set wireless.${RADIO}.htmode=${HTMODE}
	uci commit wireless
	wifi reload ${RADIO}
    sleep 1m 10s
    service log restart
    read INTERVAL < /tmp/config-software/interval
    echo "*/${INTERVAL} * * * * sh /etc/config-software/zzdfs.sh # ZZDFS" >> /etc/crontabs/root
    service cron restart
	return 0
}


read DEV < /tmp/config-software/dev
iwinfo ${DEV} info 2>&1 | grep -q 'No such wireless device'
if [ $? = 0 ]; then
    read RADIO < /tmp/config-software/radio
    WIFI=`uci get wireless.${RADIO}.disabled`
    if [ 1 != "${WIFI}" ]; then 
        _DFS
	fi
fi
EOF


cat <<"EOF" > /usr/bin/zzdfst
#! /bin/sh

read INTERVAL < /tmp/config-software/interval

if [ -n "$1" ]; then
    logger "ZZDFS: Interval_Change"
	description_INTERVAL="$1"
	sed -i -e "s/INTERVAL=${INTERVAL}/INTERVAL=${description_INTERVAL}/g" /etc/init.d/zzdfs
    echo ${description_INTERVAL} > /tmp/config-software/interval
    sed -i "/zzdfs.sh/d" /etc/crontabs/root
    echo "*/${description_INTERVAL} * * * * sh /etc/config-software/zzdfs.sh # DFS ZZDFS" >> /etc/crontabs/root
    service cron restart
    echo " Set time: ${description_INTERVAL} min"
	exit 0
else
	while :
	do
        logger "ZZDFS: Interval_Change"
		echo -e " \033[1;37mInterval time setting\033[0;39m"
        echo -e " \033[1;37mNow Interval: ${INTERVAL} min\033[0;39m"
        read -p " Interval time change (y or q): " input_CHANGE
        if [ "${input_CHANGE}" = "q" ]; then
            exit 0
        fi
		read -p " Interval time (min): " input_INTERVAL
		read -p " Please select key [y or q]: " num
		case "${num}" in
		"y" ) sed -i -e "s/INTERVAL=${INTERVAL}/INTERVAL=${input_INTERVAL}/g" /etc/init.d/zzdfs
              echo ${input_INTERVAL} > /tmp/config-software/interval
              sed -i "/zzdfs.sh/d" /etc/crontabs/root
              echo "*/${input_INTERVAL} * * * * sh /etc/config-software/zzdfs.sh # ZZDFS" >> /etc/crontabs/root
              service cron restart
			  echo " Set time: ${input_INTERVAL} min"
		      exit 0 ;;
	    "q" ) exit 0 ;;
	    esac
    done
fi
EOF
chmod +x /usr/bin/zzdfst


cat <<"EOF" > /usr/bin/zzdfsl
#!/bin/sh
LOGDIR="/tmp/log/syslog"
echo -e "\033[1;36mZZDFS\033[0;39m"
echo -e "\033[1;36mLOG ------------------------------------\033[0;39m"
echo -e "\033[1;37mLOG:\033[0;39m"
grep "ZZDFS" ${LOGDIR} | awk '{ print $1,$2,$3,$4,$5,$9 }' | tail -n 10
echo -e "\033[1;37mDISABLED:\033[0;39m"
grep "DFS->DISABLED" ${LOGDIR} | awk '{ print $1,$2,$3,$4,$5,$11 }' | tail -n 1
echo -e "\033[1;37mENABLED:\033[0;39m"
grep "DFS->ENABLED" ${LOGDIR} | awk '{ print $1,$2,$3,$4,$5,$11 }' | tail -n 1
echo -e "\033[1;36mINFORMATION ----------------------------\033[0;39m"
read INTERVAL < /tmp/config-software/interval
echo -e "\033[1;37mInterval: ${INTERVAL}min\033[0;39m"
read FB_BAND < /tmp/config-software/fb_band
read FB_CHANNEL < /tmp/config-software/fb_channel
read RADIO < /tmp/config-software/radio
HTMODE=$(uci get wireless.${RADIO}.htmode)
MODE=`echo ${HTMODE} | grep -o "[A-Z]*"`
read RADIO < /tmp/config-software/radio
CHANNEL=$(uci get wireless.${RADIO}.channel)
HTMODE=$(uci get wireless.${RADIO}.htmode)
WIFI=`uci get wireless.${RADIO}.disabled` 2>/dev/null
if [ "${WIFI}" != 1 ]; then
    echo -e "\033[1;32mWi-Fi 5G ${RADIO} ENABLE\033[0;39m"   
else
    echo -e "\033[1;31mWi-Fi 5G ${RADIO} DISABLE\033[0;39m"
fi
echo -e "\033[1;37mFALLBACK Channel/ Htmode: ${FB_CHANNEL}Ch/ ${MODE}${FB_BAND}\033[0;39m"
echo -e "\033[1;33mWi-Fi 5G Channel/ Htmode: ${CHANNEL}Ch/ ${HTMODE}\033[0;39m"
echo -e "\033[1;36m----------------------------------------\033[0;39m"
EOF
chmod +x /usr/bin/zzdfsl


service zzdfs enable
service zzdfs start

zzdfsl

```

### サービス開始及び停止
```sh
# 有効
service zzdfs enable
# 開始
service zzdfs start
# 停止
service zzdfs stop
# 無効
service zzdfs disable

```

### 動作確認
```sh
zzdfsl

```

### インターバル時間設定変更
- コマンド実行
```sh
zzdfst
```

```sh:サンプル
zzdfst 2

```
- CRON実行
```sh:サンプル
echo "00 00 * * * zzdfst 30" >> /etc/crontabs/root
echo "00 08 * * * zzdfst 2" >> /etc/crontabs/root

```

### スクリプト速度測定
```sh
time sh /etc/config-software/zzdfs.sh

```

### ログ
```sh
cat /var/log/syslog
# /tmp/log/syslog

```

### 削除
- ファイル
```sh
service zzdfs stop
service zzdfs disable
rm -rf /etc/config-software/zzdfs.sh
rm -rf /etc/init.d/zzdfs
rm -rf /usr/bin/zzdfsl
rm -rf /usr/bin/zzdfst
rm -rf /tmp/config-software/

```

---

</details>

### 旧版

<details><summary>logread トリガー版</summary>

ワンポイント：update不要なら最初に#を入力
```sh
opkg update
opkg install coreutils-date
#! /bin/sh

cat << "EOF" > /etc/init.d/zzdfs
#!/bin/sh /etc/rc.common

INTERVAL=5    # check interval (min)
FB_BAND=40    # fallback band
FB_CHANNEL=36 # fallback channel

START=99
STOP=01
     
start() {
	sleep 1m 10s
	logger "ZZDFS: Start"
    mkdir -p /tmp/config-software/
    RADIO=`uci show wireless | grep "band='5g'" | cut -d'.' -f2 | awk '{ print $1 }'`
    CHS=`echo ${RADIO} | wc -w`
    if [ ${CHS} = 2 ];then
        RADIO=`echo ${RADIO}| awk '{print $2}'`
    fi
    CH=`echo ${RADIO} | grep -o "[0-9]*"`
    echo $(iw dev | awk '/Interface/{print $2}' | grep ${CH}) > /tmp/config-software/dev
    echo ${INTERVAL} > /tmp/config-software/interval
    expr $((${INTERVAL} * 60)) > /tmp/config-software/schedule
    echo ${RADIO} > /tmp/config-software/radio
	echo $(uci get wireless.${RADIO}.channel) > /tmp/config-software/channel
    echo $(uci get wireless.${RADIO}.htmode) > /tmp/config-software/htmode    
    echo ${FB_BAND} > /tmp/config-software/fb_band
    echo ${FB_CHANNEL} > /tmp/config-software/fb_channel
    sed -i "/zzdfs.sh/d" /etc/crontabs/root
    echo "*/${INTERVAL} * * * * sh /etc/config-software/zzdfs.sh # ZZDFS" >> /etc/crontabs/root
    service cron restart
    exit 0
}
restart() {
    exit 0
}
stop() {
    logger "ZZDFS: Stop"
    sed -i "/zzdfs.sh/d" /etc/crontabs/root
    service cron restart
    rm -rf /tmp/config-software
    exit 0
}
EOF
chmod +x /etc/init.d/zzdfs


mkdir -p /etc/config-software/
cat << "EOF" > /etc/config-software/zzdfs.sh
#! /bin/sh

function _DISABLE() {
	DATE=`date +%s`
	DATEDD=`date +%s -d "${DATED}"`
	TIME=`expr $((${DATE} - ${DATEDD}))`
	read SCHEDULE < /tmp/config-software/schedule
	if [ ${TIME} -lt ${SCHEDULE} ]; then
		logger "ZZDFS: ZZDFS_ON"
		echo $(uci get wireless.${RADIO}.channel) > /tmp/config-software/channel
		HTMODE=$(uci get wireless.${RADIO}.htmode | tee /tmp/config-software/htmode) 
		read RADIO < /tmp/config-software/radio
		read DFS_CHANNEL < /tmp/config-software/dfs_channel
		MODE=`echo ${HTMODE} | grep -o "[A-Z]*"`	
		read DFS_BAND < /tmp/config-software/dfs_band
		uci set wireless.${RADIO}.channel=${DFS_CHANNEL}
		uci set wireless.${RADIO}.htmode=${MODE}${DFS_BAND}
		uci commit wireless
		wifi reload ${RADIO}
		return 0
	else
		logger "ZZDFS: ZZDFS_ON_TIME_OVER"
		return 0
	fi
}

function _ENABLE() {
	DATE=`date +%s`
	DATEEE=`date +%s -d "${DATEE}"`
	TIME=`expr $((${DATE} - ${DATEEE}))`
	read SCHEDULE < /tmp/config-software/schedule
	if [ ${TIME} -lt ${SCHEDULE} ]; then
		logger "ZZDFS: ZZDFS_OFF"
		read RADIO < /tmp/config-software/radio
		read CHANNEL < /tmp/config-software/channel
		read HTMODE < /tmp/config-software/htmode
		uci set wireless.${RADIO}.channel=${CHANNEL}
		uci set wireless.${RADIO}.htmode=${HTMODE}
		uci commit wireless
		wifi reload ${RADIO}
		return 0
	else
		logger "ZZDFS: DZZDFS_OFF_TIME_OVER"
		return 0
	fi
}
	
DATED=`exec logread | grep "DFS->DISABLED" | awk '{ print $1,$2,$3,$4,$5 }' | tail -n 1`
DATEE=`exec logread | grep "DFS->ENABLED" | awk '{ print $1,$2,$3,$4,$5 }' | tail -n 1`
if [[ -n "${DATED}" && -z "${DATEE}" ]]; then
	logger "ZZDFS: DISABLE_ON_ENABLE_OFF"
    _DISABLE
elif [[ -n "${DATED}" && -n "${DATEE}" ]]; then
    if [ "${DATEE}" -lt "${DATED}" ]; then
		logger "ZZDFS: DISABLE_ON_ENABLE_ON"
        _DISABLE
    else
		if [ "${DATED}" -lt "${DATEE}" ]; then
			_ENABLE
			logger "ZZDFS: ENABLE_ON_DISABLE_ON"
		fi
    fi
elif [ -n "${DATEE}" ]; then
	logger "ZZDFS: ENABLE_ON"
    _ENABLE
fi
EOF



cat <<"EOF" > /usr/bin/zzdfst
#! /bin/sh

read INTERVAL < /tmp/config-software/interval

if [ -n "$1" ]; then
    logger "ZZDFS: Interval_Change"
	description_INTERVAL="$1"
	sed -i -e "s/INTERVAL=${INTERVAL}/INTERVAL=${description_INTERVAL}/g" /etc/init.d/zzdfs
    echo ${description_INTERVAL} > /tmp/config-software/interval
	expr $((${description_INTERVAL} * 60)) > /tmp/config-software/schedule
    sed -i "/zzdfs.sh/d" /etc/crontabs/root
    echo "*/${description_INTERVAL} * * * * sh /etc/config-software/zzdfs.sh # DFS ZZDFS" >> /etc/crontabs/root
    service cron restart
    echo " Set time: ${description_INTERVAL} min"
	exit 0
else
	while :
	do
        logger "ZZDFS: Interval_Change"
		echo -e " \033[1;37mInterval time setting\033[0;39m"
        echo -e " \033[1;37mNow Interval: ${INTERVAL} min\033[0;39m"
        read -p " Interval time change (y or q): " input_CHANGE
        if [ "${input_CHANGE}" = "q" ]; then
            exit 0
        fi
		read -p " Interval time (min): " input_INTERVAL
		read -p " Please select key [y or q]: " num
		case "${num}" in
		"y" ) sed -i -e "s/INTERVAL=${INTERVAL}/INTERVAL=${input_INTERVAL}/g" /etc/init.d/zzdfs
              echo ${input_INTERVAL} > /tmp/config-software/interval
			  expr $((${input_INTERVAL} * 60)) > /tmp/config-software/schedule
              sed -i "/zzdfs.sh/d" /etc/crontabs/root
              echo "*/${input_INTERVAL} * * * * sh /etc/config-software/zzdfs.sh # ZZDFS" >> /etc/crontabs/root
              service cron restart
			  echo " Set time: ${input_INTERVAL} min"
		      exit 0 ;;
	    "q" ) exit 0 ;;
	    esac
    done
fi
EOF
chmod +x /usr/bin/zzdfst


cat <<"EOF" > /usr/bin/zzdfsl
#!/bin/sh
echo -e "\033[1;36mZZDFS\033[0;39m"
echo -e "\033[1;36mLOG ------------------------------------\033[0;39m"
echo -e "\033[1;37mLOG:\033[0;39m"
exec logread | grep "ZZDFS" | awk '{ print $1,$2,$3,$4,$5,$9 }' | tail -n 10
echo -e "\033[1;37mDISABLED:\033[0;39m"
exec logread | grep "DFS->DISABLED" | awk '{ print $1,$2,$3,$4,$5,$11 }' | tail -n 1
echo -e "\033[1;37mENABLED:\033[0;39m"
exec logread | grep "DFS->ENABLED" | awk '{ print $1,$2,$3,$4,$5,$11 }' | tail -n 1
echo -e "\033[1;36mINFORMATION ----------------------------\033[0;39m"
read INTERVAL < /tmp/config-software/interval
echo -e "\033[1;37mInterval: ${INTERVAL}min\033[0;39m"
read FB_BAND < /tmp/config-software/fb_band
read FB_CHANNEL < /tmp/config-software/fb_channel
read RADIO < /tmp/config-software/radio
HTMODE=$(uci get wireless.${RADIO}.htmode)
MODE=`echo ${HTMODE} | grep -o "[A-Z]*"`
read RADIO < /tmp/config-software/radio
CHANNEL=$(uci get wireless.${RADIO}.channel)
HTMODE=$(uci get wireless.${RADIO}.htmode)
WIFI=`uci get wireless.${RADIO}.disabled` 2>/dev/null
if [ "${WIFI}" != 1 ]; then
    echo -e "\033[1;37mWi-Fi 5G ${RADIO} ENABLE\033[0;39m"   
else
    echo -e "\033[1;37mWi-Fi 5G ${RADIO} DISABLE\033[0;39m"
fi
echo -e "\033[1;37mWi-Fi 5G Channel/ Htmode: ${CHANNEL}Ch/ ${HTMODE}\033[0;39m"
echo -e "\033[1;37mFALLBACK Channel/ Htmode: ${FB_CHANNEL}Ch/ ${MODE}${FB_BAND}\033[0;39m"
echo -e "\033[1;36m----------------------------------------\033[0;39m"
EOF
chmod +x /usr/bin/zzdfsl


service zzdfs enable
service zzdfs start

zzdfs

```
---

</details>


<details><summary>iw dev トリガー版</summary>

### 設定

```sh
#! /bin/sh

cat << "EOF" > /etc/init.d/zzdfs
#!/bin/sh /etc/rc.common

START=99
STOP=01
    
start() {
	logger "zzdfs: Start"
    mkdir -p /tmp/config-software/
    RADIO=`uci show wireless | grep "band='5g'" | cut -d'.' -f2 | awk '{ print $1 }'`
    CHS=`echo ${RADIO} | wc -w`
    if [ ${CHS} = 2 ];then
        RADIO=`echo ${RADIO}| awk '{print $2}'`
    fi
    CH=`echo ${RADIO} | grep -o "[0-9]*"`
    echo $(iw dev | awk '/Interface/{print $2}' | grep ${CH}) > /tmp/config-software/dev
    echo ${RADIO} > /tmp/config-software/radio
    sed -i "/dfs_check.sh/d" /etc/crontabs/root
    /etc/init.d/cron restart
    echo "*/15 * * * * sh /etc/config-software/zzdfs.sh # ZZDFS ON" >> /etc/crontabs/root
    /etc/init.d/cron restart
    exit 0
}
restart() {
    exit 0
}
stop() {
    logger "zzdfs: Stop"
    sed -i "/zzdfs.sh/d" /etc/crontabs/root
    /etc/init.d/cron restart
    exit 0
}
EOF
chmod +x /etc/init.d/zzdfs


mkdir -p /etc/config-software
cat << "EOF" > /etc/config-software/zzdfs.sh
#! /bin/sh

read DEV < /tmp/config-software/dev
read RADIO < /tmp/config-software/radio
CHANNEL=`iw dev ${DEV} info 2>/dev/null | awk '/channel/{print $2}'`

if [ 1 = "$(uci get wireless.${RADIO}.disabled 2>/dev/null)" ]; then
    exit 0
elif [ -z "${CHANNEL}" ]; then
    wifi down ${RADIO}
    sleep 2
    wifi up ${RADIO}
	exit 0
else
    if [ "$(uci get wireless.${RADIO}.channel)" != "${CHANNEL}" ]; then
        wifi down ${RADIO}
        sleep 2
        wifi up ${RADIO}
	    exit 0
	fi
fi
EOF


service zzdfs enable
service zzdfs start

```
---

</details>

### 他参考

<details><summary>アイロス DFS リセット</summary>

- [アイロス DFS リセット](https://openwrt.org/packages/pkgdata/airos-dfs-reset)

```sh
opkg update
opkg install airos-dfs-reset
USERNAME='root'
PASSWORD='password'
DEVICE='radio1' # radio0 or radio1
DAYTIME_LIMIT='08:00-23:00'
NET_IF="lan"
. /lib/functions/network.sh
network_flush_cache
network_get_ipaddr NET_ADDR "${NET_IF}"
uci add airos-dfs-reset.general=airos-dfs-reset
uci set airos-dfs-reset.general.interval='600'
uci set airos-dfs-reset.general.reset_sleep='120'
uci set airos-dfs-reset.${DEVICE}=device
uci set airos-dfs-reset.${DEVICE}.target=${NET_ADDR}
uci set airos-dfs-reset.${DEVICE}.username=${USERNAME}
uci set airos-dfs-reset.${DEVICE}.password=${PASSWORD}
uci set airos-dfs-reset.${DEVICE}.daytime_limit=${DAYTIME_LIMIT}
uci commit airos-dfs-reset

```

---

</details>

<details><summary>iwchanによるWi-Fi自動チャンネル選択</summary>

- [iwchanによるWi-Fi自動チャンネル選択](https://openwrt.org/docs/guide-user/network/wifi/iwchan?rev=1694213842)
- これはドキュメントの古いリビジョンです

[iwchan.awk](https://gist.github.com/laoshaw/f5ce60dc01b2847c8b41ee5ff4797d2a)

[[解決済み] Iwchan.awk で Wi-Fi 情報を表示する](https://forum.openwrt.org/t/solved-iwchan-awk-to-show-wi-fi-info/179454)

```sh
URL="https://openwrt.org/_export/code/docs/guide-user/network/wifi/iwchan"
uclient-fetch -O /root/iwchan.awk "${URL}?codeblock=0"
uclient-fetch -O /root/iwchan.sh "${URL}?codeblock=1"
cat << EOF >> /etc/sysupgrade.conf
/root
EOF
cat << "EOF" >> /etc/crontabs/root
0 4 * * * . /root/iwchan.sh
EOF
/etc/init.d/cron restart

```

---

</details>

:::

# Guest Wi-Fi (QR code)
::: note
### Guest Wi-Fi
ゲストのサービス化 (QRコード発行とランダムパスワード)

service guest_wifi start
![start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/aed68402-592c-26af-a956-80dc08a70ef8.png)

service guest_wifi stop
![stop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3412833/993513c9-bbd7-d983-0968-2a61d0b2771d.png)

[The URI is defined by [7] and formatted by the WIFI-qr ABNF rule:
](https://www.wi-fi.org/system/files/WPA3%20Specification%20v3.2.pdf#page=25)
※つまるところWPA3は無い

<details><summary>qrencode</summary>

WIFI-qr = “WIFI:” [type “;”] [trdisable “;”] ssid “;” [hidden “;”] [id “;”] [password “;”] [publickey “;”] “;”
type = “T:” *(unreserved) ; security type
trdisable = “R:” *(HEXDIG) ; Transition Disable value
ssid = “S:” *(printable / pct-encoded) ; SSID of the network
hidden = “H:true” ; when present, indicates a hidden (stealth) SSID is used
id = “I:” *(printable / pct-encoded) ; UTF-8 encoded password identifier, present if the password
has an SAE password identifier
password = “P:” *(printable / pct-encoded) ; password, present for password-based authentication
public-key = “K:” *PKCHAR ; DER of ASN.1 SubjectPublicKeyInfo in compressed form and encoded in
“base64” as per [6], present when the network supports SAE-PK, else absent
printable = %x20-3a / %x3c-7e ; semi-colon excluded
PKCHAR = ALPHA / DIGIT / %x2b / %x2f / %x3d

---
</details>

- [guest.sh](https://github.com/site-u2023/config-software/blob/main/guest.sh)

```sh
#!/bin/sh

opkg update
opkg install bash
opkg install qrencode
opkg install at


cat << "EOF" > /etc/init.d/guest_wifi
#!/bin/bash /etc/rc.common

TYPE="WPA2"
TRDISABLE="1"
SSID_F="お客様"
SSID_B="_optout_nomap"
ENCRYPTION="psk-mixed"
TIMEOUT="60"
INTERFACE="lan"
BGCOLOR="0000FF"
echo "<body bgcolor=#${BGCOLOR}>" > /tmp/.guest_bgcolor

START=99
STOP=01

start() {
    DEL=`atq | awk '{ print $1 }' | sed -n 1p`
    if [ ${DEL} ]; then
    atrm ${DEL}
    fi
    echo ${TYPE} > /tmp/.guest_type
    echo "service guest_wifi stop" | at now +${TIMEOUT} minutes
    echo "<font color="yellow">Stops after "${TIMEOUT}" min.</font>" > /tmp/.guest_comment1
    TIMEOUT_SSID="${SSID_F}@`atq | awk '{ print $5 }' | cut -d':' -f1,2`${SSID_B}"
    echo ${TIMEOUT_SSID} > /tmp/.guest_ssid
    RANDOM_PASSWORD=`head /dev/urandom | env LC_CTYPE=C tr -cd 'a-fA-F0-9'| cut -b -8`
    echo ${RANDOM_PASSWORD} > /tmp/.guest_password
    qrencode --foreground=${RANDOM_PASSWORD:0:6} --inline --type=SVG --output=- --size 3 "WIFI:S:${TIMEOUT_SSID};T:${TYPE};R:${TRDISABLE};P:${RANDOM_PASSWORD};;" > /tmp/.guest_qr
    echo "Please disable the service don't use guest Wi-Fi." > /tmp/.guest_comment2
    WIFI_DEV="$(uci get wireless.@wifi-iface[0].device)"
    uci -q delete wireless.guest
    uci set wireless.guest="wifi-iface"
    uci set wireless.guest.device="${WIFI_DEV}"
    uci set wireless.guest.mode="ap"
    uci set wireless.guest.network="${INTERFACE}"
    uci set wireless.guest.ssid="${TIMEOUT_SSID}"
    uci set wireless.guest.encryption="${ENCRYPTION}"
    uci set wireless.guest.key="${RANDOM_PASSWORD}"
    uci set wireless.guest.macaddr="random"
    uci set wireless.guest.multicast_to_unicast_all='1'
    uci set wireless.guest.isolate='1'
    uci delete wireless.${WIFI_DEV}.disabled
    uci commit wireless
    wifi reload
    logger "perimeter Wi-Fi Guest ON"
    exit 0
}

restart() {
    exit 0
}
stop() {
    DEL=`atq | awk '{ print $1 }' | sed -n 1p`
    if [ ${DEL} ]; then
    atrm ${DEL}
    fi
    echo "<font color="red">Out of service.</font>"  > /tmp/.guest_comment1
    qrencode --foreground=${BGCOLOR} --background=808080 --inline --type=SVG --output=- --size 3 "WIFI:S:Out of service.;T:${TYPE};R:${TRDISABLE};P:Out of service.;;" > /tmp/.guest_qr
    echo "Please enable the service to use guest Wi-Fi." > /tmp/.guest_comment2
    echo > /tmp/.guest_type
    echo > /tmp/.guest_ssid
    echo > /tmp/.guest_password
    uci -q delete wireless.guest
    uci commit wireless
    wifi reload
    logger "perimeter Guest Wi-Fi OFF"
    exit 0
}
EOF
chmod +x /etc/init.d/guest_wifi


cat << "EOF" > /www/cgi-bin/guest
#!/bin/bash

SSID=$(</tmp/.guest_ssid )
QR=$(</tmp/.guest_qr)
PASSWORD=$(</tmp/.guest_password)
COMMENT1=$(</tmp/.guest_comment1)
COMMENT2=$(</tmp/.guest_comment2)
BGCOLOR=$(</tmp/.guest_bgcolor)

printf "%s\n" "Content-Type: text/html"
printf "%s\n" ""
printf "%s\n" "<?xml version="1.0" encoding="utf-8"?>"
printf "%s\n" "<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"
printf "%s\n" "<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">"
printf "%s\n" "<head>"
printf "%s\n" "<title>Guest Wi-Fi</title>"
printf "%s\n" "<meta charset="UTF-8" name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">"
printf "%s\n" "<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">"
printf "%s\n" "<meta http-equiv="Pragma" content="no-cache">"
printf "%s\n" "<meta http-equiv="Expires" content="0">"
printf "%s\n" "</head>"
printf "%s\n" "${BGCOLOR}"
printf "%s\n" "<div style='text-align:center;color:#fff;font-family:UnitRoundedOT,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:30px;font-weight:500;'>"
printf "%s\n" "<h1>Guest Wi-Fi</h1>"
printf "%s\n" "<h5>${COMMENT1}<br />${SSID}<br />${PASSWORD}</h5>"
printf "%s\n" "${QR}"
printf "%s\n" "<h5>${COMMENT2}</h5>"
printf "%s\n" "</div>"
printf "%s\n" "</body>"
printf "%s\n" "</html>"
EOF
chmod +x /www/cgi-bin/guest


cat << "EOF" > /www/guest.html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="refresh" content="0; URL=cgi-bin/guest" />
</head>
<body>
<a href="cgi-bin/guest/style.css?ver=240313" rel="stylesheet">Guest Wi-Fi</a>
</body>
</html>
EOF
chmod +r /www/guest.html

echo -e " \033[1;37mIf a white QR code appears, it's a miracle.\033[0;39m"

service guest_wifi start

```
以下仕様
- ucitのアラート
- atのアラート
- 再起動でatのタスクが消える (OpenWrt仕様)
- 強固なセキュリティが必要な場合は`lan`を別系統用意するのが良いだろう
[ゲスト Wi-Fi の基本](https://openwrt.org/docs/guide-user/network/wifi/guestwifi/guest-wlan)

<details><summary>旧版</summary>

```sh
#!/bin/sh

opkg update
opkg install bash
opkg install openssl-util
opkg install qrencode
opkg install at
opkg install iconv


cat << "EOF" > /etc/init.d/guest_wifi
#!/bin/bash /etc/rc.common

TYPE="WPA2"
TRDISABLE="1"
SSID_F="げすと"
SSID_B="_optout_nomap"
ENCRYPTION="psk-mixed"
TIMEOUT="60"
INTERFACE="lan"

START=99
STOP=01

start() {
    DEL=`atq | awk '{ print $1 }' | sed -n 1p`
    if [ ${DEL} ]; then
    atrm ${DEL}
    fi
    echo "Please disable the service don't use guest Wi-Fi." > /root/.guest_comment1
    echo ${TYPE} > /root/.guest_type
    echo "service guest_wifi stop" | at now +${TIMEOUT} minutes
    TIMEOUT_SSID=""${SSID_F}"@`atq | awk '{ print $5 }' | cut -d':' -f1,2`${SSID_B}"
    echo ${TIMEOUT_SSID} > /root/.guest_ssid
    RANDOM_PASSWORD=`openssl rand -base64 6`
    echo $RANDOM_PASSWORD > /root/.guest_password
    FOREGROUND=`openssl rand -hex 3`
    qrencode --foreground=${FOREGROUND} --inline --type=SVG --output=- --size 4 "WIFI:S:${TIMEOUT_SSID};T:${TYPE};R:${TRDISABLE};P:${RANDOM_PASSWORD};;" > /root/.guest_qr
    echo "<font color="yellow">Stops after "${TIMEOUT}" min.</font>" > /root/.guest_comment2
    WIFI_DEV="$(uci get wireless.@wifi-iface[0].device)"
    uci -q delete wireless.guest
    uci set wireless.guest="wifi-iface"
    uci set wireless.guest.device="${WIFI_DEV}"
    uci set wireless.guest.mode="ap"
    uci set wireless.guest.network="${INTERFACE}"
    uci set wireless.guest.ssid="${TIMEOUT_SSID}"
    uci set wireless.guest.encryption="${ENCRYPTION}"
    uci set wireless.guest.key="${RANDOM_PASSWORD}"
    uci set wireless.guest.macaddr="random"
    uci set wireless.guest.multicast_to_unicast_all='1'
    uci set wireless.guest.isolate='1'
    uci delete wireless.${WIFI_DEV}.disabled
    uci commit wireless
    wifi reload
    logger "perimeter Wi-Fi Guest ON"
    exit 0
}

restart() {
    exit 0
}
stop() {
    DEL=`atq | awk '{ print $1 }' | sed -n 1p`
    if [ ${DEL} ]; then
    atrm ${DEL}
    fi
    echo "Please enable the service to use guest Wi-Fi." > /root/.guest_comment1
    qrencode --foreground="808080" --background="0000FF" --inline --type=SVG --output=- --size 4 "WIFI:S:Out of service.;T:${TYPE};R:${TRDISABLE};P:Out of service.;;" > /root/.guest_qr
    echo "<font color="red">Out of service.</font>"  > /root/.guest_comment2
    echo > /root/.guest_type
    echo > /root/.guest_ssid
    echo > /root/.guest_password
    uci -q delete wireless.guest
    uci commit wireless
    wifi reload
    logger "perimeter Guest Wi-Fi OFF"
    exit 0
}

EOF
chmod +x /etc/init.d/guest_wifi


cat << "EOF" > /www/cgi-bin/guest
#!/bin/bash

#SSID=$(</root/.guest_ssid )
SSID=$(iconv -c -f CP932 -t SHIFT-JIS </root/.guest_ssid )
QR=$(</root/.guest_qr)
PASSWORD=$(</root/.guest_password)
COMMENT1=$(</root/.guest_comment1)
COMMENT2=$(</root/.guest_comment2)

echo "Content-Type: text/html"
echo ""
echo "<?xml version="1.0" encoding="utf-8"?>"
echo "<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"
echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">'
echo "<head>"
echo "<title>Guest Wi-Fi</title>"
echo '<meta charset="UTF-8" name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">'
echo '<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">'
echo '<meta http-equiv="Pragma" content="no-cache">'
echo '<meta http-equiv="Expires" content="0">'
echo "</head>"
echo '<body bgcolor="blue">'
echo "<div style='text-align:center;color:#fff;font-family:UnitRoundedOT,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:28px;font-weight:500;'>"
echo "<h1>Guest Wi-Fi</h1>"
echo "<p><font>${COMMENT1}</font></p>"
echo "<p>${QR}</p>"
echo "<p>${COMMENT2}</p>"
echo "<p>${SSID}</p>"
echo "<p>${PASSWORD}</p>"
echo "</div>"
echo "</body>"
echo "</html>"
EOF
chmod +x /www/cgi-bin/guest


cat << "EOF" > /www/guest.html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="refresh" content="0; URL=cgi-bin/guest" />
</head>
<body>
<a href="cgi-bin/guest/style.css?ver=240313" rel="stylesheet">Guest Wi-Fi</a>
</body>
</html>
EOF
chmod +r /www/guest.html
echo -e " \033[1;37mIf a white QR code appears, it's a miracle.\033[0;39m"

service guest_wifi start

```
以下仕様
- ucitのアラート
- atのアラート
- 再起動でatのタスクが消える (OpenWrt仕様)
- SSIDの日本語表示は文字コード変換サンプル 
※(文字化けする場合: iconv -c -f CP932 -t SHIFT-JIS を変更)
- 強固なセキュリティが必要な場合は`lan`を別系統用意するのが良いだろう
[ゲスト Wi-Fi の基本](https://openwrt.org/docs/guide-user/network/wifi/guestwifi/guest-wlan)

---
</details>

### サービス開始及び再起動、停止

**[192.168.1.1/cgi-bin/luci/admin/system/startup](http://192.168.1.1/cgi-bin/luci/admin/system/startup)**

```sh
# 有効
service guest_wifi enable
# 開始
service guest_wifi start
# 停止
service guest_wifi stop
# 無効
service guest_wifi disable
```

### at ジョブ確認
```sh
# 保留中ジョブ確認
atq
# 保留中ジョブ削除
JOB="番号"
atrm ${JOB}

```
※他でat commandを利用している場合、最後のジョブを削除してしまう仕様

### QRコード
- Webページ
**[192.168.1.1/guest.html](http://192.168.1.1/guest.html)**

※QRが薄く認識しない場合はサービスを再度スタートさせる

### QRコードスキャナー
Windows11用
- [バーコード マネージャー for Windows](https://apps.microsoft.com/detail/9n9pzsp6wc3k?launch=true&mode=full&hl=ja-jp&gl=jp&ocid=bingwebsearch)
※画面上のQRコードをクリップし接続可能

### 削除
```sh
service guest_wifi stop
service guest_wifi disable
rm -rf /etc/init.d/guest_wifi
rm -rf /www/cgi-bin/guest
rm -rf /www/guest.html

```

:::

# Target Wake Time (TWT)
::: note
### Target Wake Time (TWT) 
※Only WiFi6 (ax)
参考：Linux Hostpad
  - he_twt_required: Whether TWT is required
    0 = not required (default)
    1 = required
    he_twt_required=0 or 1
  - he_twt_responder: Whether TWT (HE) responder is enabled
    0 = disabled
    1 = enabled if supported by the driver (default)
    he_twt_responder=0 or 1

```sh:ON
sed -i -e "s/he_twt_required:0/he_twt_required:1/g" /lib/netifd/wireless/mac80211.sh
uci add_list wireless.radio0.hostapd_options='he_twt_responder=1'
uci add_list wireless.radio1.hostapd_options='he_twt_responder=1'
uci add_list wireless.radio2.hostapd_options='he_twt_responder=1'
uci commit wireless
wifi

```
```sh:OFF
sed -i -e "s/he_twt_required:1/he_twt_required:0/g" /lib/netifd/wireless/mac80211.sh
uci del_list wireless.radio0.hostapd_options='he_twt_responder=1'
uci del_list wireless.radio1.hostapd_options='he_twt_responder=1'
uci del_list wireless.radio2.hostapd_options='he_twt_responder=1'
uci commit wireless
wifi

```
:::

# 参考資料（感謝:relaxed:）

- [DFSレーダーにより5GHzが低下し回復しない](https://www.reddit.com/r/openwrt/comments/rs9pit/dfs_radar_causes_5ghz_to_drop_and_it_doesnt_come/)

- [ゲスト WIFIパスワードのランダム化](https://blog.tldnr.org/2019/11/11/Guest-Wifi/)

- [OpenWRT でゲスト Wi-Fi の QR コードを生成する](https://nwildner.com/posts/2022-02-24-openwrt-guest/)

- [ラジオチェック](https://github.com/NilsRo/Openwrt-radio-check)

- [QR コードハック](https://fukuchi.org/works/qrhack/index.html.ja)
面白いサイトだなと思ったら、この方が`qrencode`の製作者でした

# あとがき
DFSはなかなか調整が難しい
所有のデバイスは5Gで2つの帯域が使えるので、3バンド専用のDFS対策スクリプトを作ってみようかな
１つをW52で固定しておいてバンドステアリングして、DFSイネーブルのログを拾ったら初期値バンドに誘導復帰される感じ
これなら、途切れる事も無いし、再起動時もすぐ繋がる
２Gとのバンドステアリングでも良いかも、これなら汎用的だ