はじめに
シルバーウィーク中に何か作ろうと思い立ち、ちょっと気になっていたNanoPiを思い切って購入し、手始めにUSBの無線アダプターと繋いでSSH環境の無線化を行おうとしたのですが、いきなり躓いて思いのほか正常に動作するまでに時間がかかってしまいました。
具体的には、TP-LinkのUSB無線アダプターが Product: DISK として認識され、Wi-Fiとして使えませんでした。(最終的には、モード切り替えとファームウェアの導入で認識し、wpa_supplicant+systemd-networkdでWi-Fi通信まで確認できています。)
「Wi-Fiアダプターを挿したのに、なぜDISK……?」というところからのスタート。途中ではパッケージを入れようにもDNSが動かず、さらに再起動までタイムアウト。無線の設定を始めたはずが、思いのほか長い道のりになりました。
この記事では、正常なシステムでの最短手順を先に示し、途中で遭遇したDNS・systemdの問題を後半にまとめます。同じところで困った方が、必要な箇所から試せる構成にしました。
なお、今回のトラブルシュートと、この記事の構成・執筆・編集には、Codex上のGPT-6 Astraを使用しました。 コマンドの実行は筆者がNanoPi上で行い、その出力を共有しながら切り分けを進めています。記事では、実機で確認できた結果と、未確認・原因未特定の事項を分けて記載しています。
検証環境
| 項目 | 内容 |
|---|---|
| ボード | NanoPi NEO3 |
| OSイメージ | Armbian v26.05 rolling、DIY/custom image |
| ユーザーランド | Debian stable(trixie) |
| カーネル | 6.18.38-current-rockchip64 |
| アダプター | TP-Link製Wi-Fi/Bluetooth複合USBアダプター(TP-Link Archer TX10UB Nano(RTL8851BU)) |
| Wi-Fiドライバー | rtw89_8851bu |
| Bluetoothドライバー | btusb |
| ネットワーク管理 | systemd-networkd+wpa_supplicant |
以下は有線LANでSSH接続し、パッケージを取得できることを前提にしています。無線インターフェース名・SSID・アドレスは各環境に合わせて読み替えてください。記事中に実際のパスワードや固有のMACアドレスは記載していません。
1. 最短手順:無線アダプターとして認識させる
USB IDを確認する
lsusb
uname -r
今回、接続直後は次のように表示されました。
ID 0bda:1a2b Realtek Semiconductor Corp. RTL8188GU 802.11n WLAN Adapter (Driver CDROM Mode)
dmesg は次の状態でした。
Product: DISK
Manufacturer: Realtek
USB Mass Storage device detected
device ignored
最初は誤認識を疑いましたが、これはドライバー配布用の仮想CD-ROMモードです。lsusb の名称だけでRTL8188GU用ドライバーを選ばず、切り替え後のUSB IDで判断します。
必要なパッケージをまとめて導入する
sudo apt update
sudo apt install usbutils usb-modeswitch usb-modeswitch-data firmware-realtek
firmware-realtek はDebianの non-free-firmware コンポーネントにあります。候補が見つからない場合はAPTソースの設定を確認してください。Armbian独自パッケージとのファイル競合が出た場合は、強制上書きせず競合元を確認してください。
抜き差しし、自動切り替えを確認する
lsusb
lsusb -t
ip -br link
0bda:1a2b のままなら、今回のIDに対して次を実行します。
sudo usb_modeswitch -K -v 0x0bda -p 0x1a2b
数秒後に 3625:010b に変わることを確認してください。このコマンドは他のUSB IDへ無条件に流用しないでください。
ドライバーが自動で読み込まれない場合は次を試してください。
sudo modprobe rtw89_8851bu
sudo modprobe btusb
lsusb -t
ip -br link
sudo dmesg | tail -n 40
成功時には以下が確認できます。
- Bluetooth用インターフェースに
Driver=btusb - Wi-Fi用インターフェースに
Driver=rtw89_8851bu -
wlan0またはwlx...という無線インターフェース - Wi-Fi/Bluetoothファームウェアの読み込み成功
今回のカーネルには必要なドライバーが含まれており、外部ドライバーのビルドは不要でした。ソースからビルドすることも覚悟していたので、標準ドライバーで進められるのは助かりました。別のカーネルで Module not found が出る場合は、カーネルの構成やモジュールパッケージを別途確認してください。
2. 設定済みのwpa_supplicant.confでWi-Fiへ接続する
以下は /etc/wpa_supplicant/wpa_supplicant.conf に接続先を設定済みで、NetworkManagerは無効、systemd-networkdが有効な環境での手順です。
systemctl is-active systemd-networkd NetworkManager wpa_supplicant
ps -eo pid,args | grep '[w]pa_supplicant'
今回の通常サービスは、次の引数で動いていました。
/usr/sbin/wpa_supplicant -u -s -O DIR=/run/wpa_supplicant GROUP=netdev
このサービスが active でも、設定済みのconfで無線接続が開始されているとは限りません。別の管理ソフトが既に無線を管理している場合は、接続管理を重複させないようにしてください。
インターフェース名を指定する
以降のコマンドは同じシェルで実行します。WIFI_IF を ip -br link で確認した実際の名前へ置き換えてください。
WIFI_IF=wlx001122334455
インターフェース専用サービスへ設定を渡す
sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf
sudo ln -s /etc/wpa_supplicant/wpa_supplicant.conf \
"/etc/wpa_supplicant/wpa_supplicant-${WIFI_IF}.conf"
sudo systemctl start "wpa_supplicant@${WIFI_IF}.service"
リンク作成で File exists が出た場合は、既存ファイルの内容・リンク先を確認し、上書きしないでください。
sudo journalctl -u "wpa_supplicant@${WIFI_IF}.service" -n 20 --no-pager
networkctl status "$WIFI_IF" --no-pager
次のログが出れば認証・アクセスポイントへの接続に成功しています。
WPA: Key negotiation completed
CTRL-EVENT-CONNECTED
接続成功のログが出ると、ようやく一歩進んだ感じがします。ただし、アクセスポイントへの接続とIPアドレスの取得は別の段階です。
この時点で Network File: n/a、unmanaged、IPv6リンクローカルアドレスだけ、という場合はDHCP設定が必要です。
3. systemd-networkdでIPアドレスを取得する
今回のようにWi-Fiがまだnetworkdで管理されていない場合、専用ファイルを作成します。既存のWi-Fi設定ファイルがある環境では、先にその設定を確認してください。
sudo mkdir -p /etc/systemd/network
sudo tee /etc/systemd/network/25-usb-wifi.network >/dev/null <<EOF
[Match]
Name=${WIFI_IF}
[Link]
RequiredForOnline=no
[Network]
DHCP=ipv4
[DHCPv4]
RouteMetric=600
[IPv6AcceptRA]
RouteMetric=600
EOF
sudo networkctl reload
sudo networkctl reconfigure "$WIFI_IF"
sudo systemctl enable "wpa_supplicant@${WIFI_IF}.service"
RequiredForOnline=no は、このドングルの接続をオンライン待機の必須条件にしない指定です。今回、有線のIPv4経路のメトリックは100だったため、Wi-Fiを600にして有線を優先しました。IPv6の実際の優先順位は、有線側のIPv6経路も含めて確認してください。
ip -4 -br addr show "$WIFI_IF"
ip -4 route show dev "$WIFI_IF"
今回の取得結果は次のとおりです。
Wi-Fi IPv4: 192.168.0.32/24
default via 192.168.0.1 ... metric 600
DHCPのため、アドレスは将来変わる可能性があります。
4. 有線を残したままWi-Fi経由の通信を確認する
単に ping すると優先度の高い有線を使う可能性があるため、-I でWi-Fiを指定します。
# ルーターへ(アドレスは実環境に合わせる)
sudo ping -4 -I "$WIFI_IF" -c 3 -W 3 192.168.0.1
# インターネットへ
sudo ping -4 -I "$WIFI_IF" -c 3 -W 3 1.1.1.1
# Wi-Fi側のDNSで名前解決
resolvectl query -i "$WIFI_IF" deb.debian.org
今回、外部IPへのpingは3/3成功、DNSもWi-Fi経由で成功しました。ルーターへの追加確認は途中でCtrl+Cした時点で12/12成功、損失0%、平均約2msでした。ここまで来て、ようやく「Wi-Fi経由で通信できた」とひと安心です。これは基本通信の確認であり、長時間安定性や転送速度の測定ではありません。
ハマりポイント
device ignored は必ずしもエラーではない
LinuxにはRealtekの仮想CD-ROMをusb-storageから意図的に除外する処理があります。無線モードへ自動で切り替わる途中にもこのログは出ます。
正常化後の抜き差しでは、以下の流れを確認できました。
0bda:1a2b / DISK
→ device ignored
→ USB disconnect
→ 3625:010b / 802.11ax WLAN Adapter
→ Wi-Fi・Bluetoothドライバーの割り当て
独自udevルールは追加しなくても、自動切り替えできました。再起動だけではUSBの電源・モードが維持されることがあるため、抜き差しで確認してください。
usb_modeswitchの途中でエラーが出ても、切り替え後の状態を見る
今回、取り出し要求の途中に次の表示が出ました。
Sending the message returned error -1. Try to continue
Device seems to have vanished after reading. Good.
error の文字には身構えますが、直後には Good. とも表示されます。少し紛らわしいですね。
その後 3625:010b として再認識されたため、今回の切り替えは成功していました。エラー行だけで判断せず lsusb と dmesg を確認してください。
modprobe成功とデバイス初期化成功は別
モジュールを読み込めても、ファームウェアがないと初期化に失敗します。
Direct firmware load for rtw89/rtw8851b_fw.bin failed with error -2
Direct firmware load for rtl_bt/rtl8851bu_fw.bin failed with error -2
-2 はファイルが見つからないことを示します。今回必要だった以下のファイルは、trixieの firmware-realtek に含まれています。
rtw89/rtw8851b_fw.binrtl_bt/rtl8851bu_fw.binrtl_bt/rtl8851bu_config.bin
導入後にドングルを抜き差しして初期化をやり直しました。
wlan0 が wlx... に変わった
udev復旧後はMACアドレスに基づく名前になりました。設定には実際のインターフェース名を使ってください。また、DOWN だけでドライバー故障とは判断しないようにします。
一般ユーザーのpingが権限エラーになった
ping: socket: 許可されていない操作です
missing cap_net_raw+p capability or setuid?
これは通信失敗ではなくpingの実行権限の問題です。今回の確認では sudo ping を使用しました。
番外編:APTが使えないDNS・systemdの問題
これはアダプターの必要設定とは別の障害です。すべての環境で以下の対処が必要なわけではありません。
DNSだけが失敗しているか切り分ける
APTの 無視:1 http://deb.debian.org/debian ... だけでは原因は分かりません。最終エラーに加えて次を確認しました。
ip -br addr
ip route
sudo ping -c 3 -W 2 192.168.0.1
sudo ping -c 3 -W 2 1.1.1.1
getent hosts deb.debian.org
ls -l /etc/resolv.conf
cat /etc/resolv.conf
今回、有線LAN経由の外部IPへの通信は成功し、名前解決だけ失敗していました。/etc/resolv.conf は /run/systemd/resolve/stub-resolv.conf へのリンクで、DNS窓口は 127.0.0.53。この値自体は正常です。
ところが、以下もタイムアウトしました。
resolvectl status
systemctl is-active systemd-resolved
sudo resolvectl dns end0 1.1.1.1 8.8.8.8
systemd-resolvedとD-Busのプロセスは存在したが、存在するだけでは正常応答しているとは判断できませんでした。
応急処置として通常のresolv.confを使う
以下は元のファイルが上記のシンボリックリンクだった環境で実施した一時対処です。公開DNSが利用できるネットワークで行ってください。
sudo mv -i /etc/resolv.conf /etc/resolv.conf.before-dns-fix
退避先が既に存在する場合は上書きせず停止してください。退避成功後に実行します。
printf 'nameserver 1.1.1.1\nnameserver 8.8.8.8\n' | sudo tee /etc/resolv.conf
getent -s dns ahostsv4 deb.debian.org
getent ahostsv4 deb.debian.org
両方成功し、APTを実行できるようになりました。これはsystemd側の応答停止を修復するものではありません。
udevも応答していなかった
sudo timeout 10s systemctl is-active systemd-udevd
echo "終了コード=$?"
sudo timeout 10s udevadm control --timeout=5 --ping
systemctlは終了コード124(外側のtimeoutによる終了)、udevadmもタイムアウトしました。メモリー・ディスクには余裕があり、確認した範囲でOOMやI/Oエラーは見つかりませんでした。
SSH切断だけでは再起動した証拠にならない
通常の sudo reboot は以下のエラーで失敗していました。
Failed to set wall message, ignoring: 接続がタイムアウトしました
Call to Reboot failed: 接続がタイムアウトしました
ここは特にハマりました。SSHが切れて再接続できたので、すっかり再起動したつもりになっていました。ところが、boot IDとuptimeを確認すると再起動していませんでした。接続が切れたことと、本体が再起動したことは別なのですね。
cat /proc/sys/kernel/random/boot_id
cat /proc/uptime
systemctl reboot --force を1回指定した方法でも再起動できませんでした。
最終手段:管理プロセスを経由しない強制再起動
通常の再起動が失敗する場合の最終手段です。常用しないでください。 --force を2回指定すると、プロセス終了やファイルシステムのアンマウントを省略します。データ喪失・ファイルシステム破損のリスクがあるため、作業を保存し、書き込み処理を終了してから実行します。sync だけで安全が保証されるわけではありません。
sudo sync
sudo systemctl reboot --force --force
今回はこれで再起動できました。有線LANで再接続し、以下を確認しました。
cat /proc/sys/kernel/random/boot_id
uptime
sudo timeout 10s systemctl is-active systemd-udevd systemd-resolved
boot IDが変わり、uptimeは約1分、両サービスは active と応答しました。応答停止の根本原因は未特定であり、アダプターが原因だったとは断定できません。
DNSを元の管理方式へ戻す
復旧後、DHCPで渡されたDNS設定と名前解決を確認しました。
resolvectl status
resolvectl query deb.debian.org
続いて、退避したリンクを戻し、キャッシュを消して確認しました。
sudo mv -T /etc/resolv.conf.before-dns-fix /etc/resolv.conf
sudo resolvectl flush-caches
getent ahostsv4 deb.debian.org
元の設定でも名前解決でき、応急処置を解除できました。動いたところで終わらせず、一時的に変えた設定も戻せたので、ここもほっとしたポイントです。
最終的に確認できたこと・未確認のこと
- ドングルの抜き差し後、無線モードへ自動で切り替わります。
- Wi-Fi/Bluetooth双方のドライバー・ファームウェアが読み込まれます。
- Wi-Fi認証、DHCP、Wi-Fi指定の外部IP通信、Wi-Fi側のDNS名前解決が成功しています。
- Wi-Fi認証の自動起動設定は有効化済みです。ただしWi-Fi設定完了後の再起動・自動再接続は未検証です。
- Bluetoothのペアリング・実通信は未検証です。
- systemd関連の応答停止は再起動で復旧したが、根本原因は未特定です。
おわりに
振り返ると、アダプター側の要点はモード切り替えとファームウェアの導入でした。ただ、今回はシステム管理機能の応答停止が重なり、原因が一つに見えにくい状況でした。USBの認識、ドライバー、ファームウェア、Wi-Fi認証、IPアドレス取得と、一段ずつログを確認したことが解決につながりました。
GPT-6 Astraとのやり取りでも、コマンドが成功したように見えたら次の状態を実機で確かめる、という進め方が役立ちました。特にboot IDで再起動の有無を確認した経験は、今後も覚えておきたいと思います。同じように Product: DISK を見て戸惑った方の手がかりになればうれしいです。
ほぼほぼAstra先生の功績です。Astra先生、まじでありがとう!