ルーターに USB を生やせ!

本記事はルーターハックAdvent Calendar 8日目の記事です。

わやくそ遅れていて申し訳ない。

さて。今日は もともと USB ポートのないルーターに USB を生やす 回である。SoC に USB PHY があるのに使わないというのはもったいない。ハードオフの青いかごで眠っていた324円のルーターと一緒に、次なる高みを目指そうじゃないか。

おことわり

技適 に関する筆者の配慮や考えについてはカレンダー1日目「技適とルーターハック」をご覧ください。本記事で紹介する内容は、法を遵守するための慎重な注意をもって書かれています。

www.zopfco.de

ひとまずはんだ付け

先日からハックの犠牲になってもらっている Buffalo WHR-G301N を改造する予定だったのだが、ミスってリアルに犠牲になってしまったので(苦笑)、スペックの近い代用品として改造済み WHR-HP-GN を利用する。利用できる遺産は利用していこう。

WHR-G301N にも WHR-HP-GN にも USB ポートはないが、SoC には USB PHY が搭載されている。

f:id:puhitaku:20181210231711p:plain
データシート。

USB は差動通信するので DP と逆相の DN がある。この2本を接続すれば原理的には通信できそうだ。というわけで接続したのが以下。

f:id:puhitaku:20181216001514j:plain

ファーム側でUSB有効化…のはずが

WHR-HP-GN や WHR-G301N を含む Atheros のチップを搭載した機種(アーキテクチャ名 ar71xx)は、OpenWrt において大きな転換点を迎えている。というのも、もともとはハードウェアの初期化のために機種ごとに異なるCのコードが用意されていたのだが、新しいアーキテクチャ名 ath79 として Device Tree による実装に置き換えられつつあるのだ。(情報をくださったmusashino_205さんに感謝

この流れに乗ろうと WHR-HP-GN も DTS 化を目指した。幸運にもハード的には WHR-HP-G300N とほぼ同じなので、実質的にそれの DTS を使えば WHR-HP-GN も初期化できる。もともとの初期化コードにも WHR-HP-G300N の隣に WHR-HP-GN の記述がなされていることが確認できる

各種記述を追加して早速やってみたのだが、USB を有効化してもprobeがうまくいかない。正確には probe というか、物理層が何かしらうまく行っていない感じだ。

[  431.775895] usb 1-1: new full-speed USB device number 2 using ohci-platform
[  432.065887] ohci-platform 1b000000.usb: frame counter not updating; disabled
[  432.072990] ohci-platform 1b000000.usb: HC died; cleaning up
[  436.836023] usb usb1-port1: attempt power cycle

USB は何かと闇が深いスタックで本業でも泣かされてきたので、今回はひとまず深堀りはやめて DTS ベースの初期化は諦めた。実を言うと ar71xx ベースでの USB 追加は以前やって発表したものと全く同じになるので避けたかったのだが。

初期化コードを加工する

openwrt/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c に以下のような加工を加える。見た目通りって感じ。

diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c
index 48f49ad0f7..84ee3c8a4c 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c
@@ -21,6 +21,7 @@
 #include "dev-gpio-buttons.h"
 #include "dev-leds-gpio.h"
 #include "dev-m25p80.h"
+#include "dev-usb.h"
 #include "machtypes.h"

 #define WHRHPG300N_GPIO_LED_SECURITY           0
@@ -123,6 +124,8 @@ static void __init whrhpg300n_setup(void)
                                    AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
                                    AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);

+       ath79_register_usb();
+
        ath79_register_leds_gpio(-1, ARRAY_SIZE(whrhpg300n_leds_gpio),
                                 whrhpg300n_leds_gpio);

カーネルモジュールを追加する

USB という物理層自体のドライバに加え、それ以上のレイヤーのドライバ、例えば USB storage を扱うドライバなどを追加しなければデバイスは利用できない。以前紹介した make menuconfig で追加していく。USB メモリを使うとして、主に必要なのは

  • Target System -> Atheros AR7xxx/AR9xxx
  • Kernel Modules -> USB Support -> kmod-usb-core
  • Kernel Modules -> USB Support -> kmod-usb-ohci
  • Kernel Modules -> USB Support -> kmod-usb-storage
  • Kernel Modules -> Filesystems -> kmod-fs-ext4
  • Kernel Modules -> Native Language Support -> kmod-nls-iso8859-1

といったところ。

挿してみる

手元にあった適当なUSBメモリを挿してみる。

[   86.223642] usb 1-1: new full-speed USB device number 3 using ohci-platform
[   87.638134] usb-storage 1-1:1.0: USB Mass Storage device detected
[   87.647383] scsi host0: usb-storage 1-1:1.0
[   88.680846] scsi 0:0:0:0: Direct-Access     UFD 3.0  Silicon-Power8G  PMAP PQ: 0 ANSI: 6
[   89.588758] sd 0:0:0:0: [sda] 15306752 512-byte logical blocks: (7.84 GB/7.30 GiB)
[   89.601729] sd 0:0:0:0: [sda] Write Protect is off
[   89.611736] sd 0:0:0:0: [sda] No Caching mode page found
[   89.617179] sd 0:0:0:0: [sda] Assuming drive cache: write through
[   89.680778] random: crng init done
[   89.690053]  sda: sda1
[   89.723805] sd 0:0:0:0: [sda] Attached SCSI removable disk

うん、いい感じ。見慣れたログが出る。マウントはどうか?中身のファイルシステムが何かも忘れてるけど。

root@OpenWrt:~# cd
root@OpenWrt:~# pwd
/root
root@OpenWrt:~# mkdir mnt
root@OpenWrt:~# mount /dev/sda1 mnt/
[  170.459769] FAT-fs (sda1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
root@OpenWrt:~# ls mnt/
System Volume Information  efi
boot                       keymap.pro
bootmgr                    reagent.xml
bootmgr.efi                sources

マウント成功。どうやら Windows のリカバリ USB のようだ。関係ないが keymap.pro は NiZ Plum のキーマップファイルだ。

USBは無限大

USBが挿さるということは、健康なギーク男子が想像するようなあんなものやこんなものが挿さってしまうということだ。さりとて、USB Storage こそ USB 機器の基本ともいえる。実際こいつが使えると rootfs の拡張がいとも簡単に成し遂げられてしまうし、ハックの幅を広げる第一歩ともいえるだろう。

次回は、USB メモリを実際に rootfs を広げる道具として使い、GCC を入れたりルーターの上で make をビルドしたりしてみたいと思う。なんだかLFSチックな話で胸が踊る。

蚊取りルーター・スマートノーマット

本記事はルーターハックAdvent Calendar 7日目の記事です。

さて、前回までに OpenWrt のインストールやカスタマイズまで軽く紹介したところで、7日目の今回は「イベントとかで発表したけど記事にしてなかった過去作」の紹介企画、【過去作供養】コーナー第1弾である。

第1弾のハックは、その名も「蚊取りルーター・スマートノーマット」だ!

おことわり

技適 に関する筆者の配慮や考えについてはカレンダー1日目「技適とルーターハック」をご覧ください。本記事で紹介する内容は、法を遵守するための慎重な注意をもって書かれています。

www.zopfco.de

当時

2016年は5月、まだ春の気温が続く頃、こんなツイートがバズっていた。

『Wi-Fi繋がりそうな勢い』…!!? ルーターにしちゃえばいいじゃん!!!

ツイート主にちゃんとDMで許可を取り、実際に小さなルーターを中に入れてマジのルーターにしてしまうことにした。

ノーマットの解剖

写真の商品は、蚊取り装置の代表とも言えるアース・ノーマットの電池式だった。薬液がしみこんでいるカートリッジに風を当て、まわりに蚊を忌避する成分を拡散させる仕組みだ。

www.earth.jp

買った。

f:id:puhitaku:20160523185257j:plain

即バラした。

f:id:puhitaku:20160523191313j:plain

部品を並べたのが以下。羽根の間からドライバーを差し込んでグリッとやらないと外れないパーツがあったりと案外複雑だった。

f:id:puhitaku:20160523191117j:plain

f:id:puhitaku:20160627222331j:plain

基板部を拡大してみると、TSOP8 と思われるパッケージの IC と、モーターが回るだけにしては案外複雑な周辺回路が見える。カートリッジ残量が減るとLEDで知らせる 仕組みがある(カートリッジにボタン電池がついていて、おそらくこれの電圧をADCしている)ことや、モーターの回転数を一定量に保つ必要もあるであろうことから、それなりに複雑になるのかもしれない。

…いやそれにしてももっと簡素になりそうなものだが。

ルーター選定

当時、上海問屋で売ってるやたら安くてコンパクトなルーターとして NEXX WT1520 が話題になっていた。見た感じだとノーマットに入りそうということで、早速買ってみた。

f:id:puhitaku:20160522233327j:plain

そしてバラす。

f:id:puhitaku:20160522231512j:plain
グリッと。

f:id:puhitaku:20160522231648j:plain

CPU に Ralink RT5350 @ 360MHz、Flash 8 MiB、RAM 32 MiB の構成。USBポートも元からあるのでコンパクトさに対してずいぶん遊びやすいルーターだ。

基板を取り出しノーマットの電池ボックスにあてがうと、これまたサイズがピッタリ。ノーマットに入れてくれと言わんばかりのピッタリさだ。

ノーマットの加工

そうと分かればあとはノーマットを加工してルーターを繋ぎこむだけだ。配線途中の画像がこちら。

f:id:puhitaku:20160628001432j:plain
LEDを交換し、ファン・LED・電源スイッチを配線。

f:id:puhitaku:20160628005451j:plain
ICはもう要らないので、ひっぺがしてランドにはんだ付け。

f:id:puhitaku:20160628005546j:plain
雑に配線。

今見てもかなり雑な配線である。モーターの消費電力がもともと小さくできているので、3.3V な GPIO の出力を 直接モーターに接続しても いい感じに回るのでこうした記憶がある。GPIO 番号と実際のテストポイントの対応については下記画像が参考になった。

f:id:puhitaku:20181208203358j:plain
from: https://tuxotronic.org/post/clone-wt1520/

そしてそして、電池ボックスのフタを削って組み付けたのが以下の画像である。

f:id:puhitaku:20160628221714j:plain

f:id:puhitaku:20181208205045j:plain

f:id:puhitaku:20181208205134j:plain
フタの固定はとりあえずマスキングテープw

うーんピッタリ!!

OpenWrt のインストールによって無線が使えないうえ、内蔵フラッシュが 8 MiB と遊ぶ幅がないので、rootfs を拡張するための USB メモリと、Wi-Fi ドングル(単体で技適認証を受けたもの)も配置した。

USB ハブは秋葉原で適当に買った小さいものだが、USBポートが横向きでそのままでは取り出せないので、USBハブも分解して体積を減らして詰め込んだ。

f:id:puhitaku:20181208204949j:plain
今思えば、ハブのコネクタは残す必要がなかったし直に繋げばよかったかも。

スマホから制御できるようにする

これだけではモーターは回らない。せめてスマホから操作できなければ「スマート」ノーマットとは呼べない。そこで API サーバーとフロントエンドを実装した。コードは GitHub に上げていた記憶があるのだが、実際に見てみると初手のコミットしかなくそのままになっている。めっちゃ頑張ってフロント書いたのに!過去の自分を呪いたい。

github.com

バックエンドは GPIO を書き換えるほかは静的ファイルをサーブするだけなので Flask でパパッと記述した。フロントエンドに関しては、当時社内ツールで React を使ったのでノリで React + JSX で書いた。

f:id:puhitaku:20181208205922p:plain
実際のスクショ。

上の画像では残量表示とか AUTOMATIC SWITCH なる項目が未実装で適当だが、実機にChromeでアクセスして得たスクショである。ボタンを押すと裏で XHR が走り、GPIO がスイッチされる。

ちなみに、ON にするときの API へのリクエストは DELETE 192.168.1.1/api/mosquitoes である。

当時公開しなかった理由

AUTOMATIC SWITCH が示唆するように、当時は窓を開けるとスイッチオンとか、GPS で自動でノーマットの電源を入れるみたいな機能を構想していた。だが、その自動制御を手前にしてやる気の灯火が消えてしまい、明治大学で開催された ABPro 2016 で発表した程度でお蔵入りになってしまった。結局長い不作の期間と共に夏も終わり、完全に発表するチャンスを逃してしまったのだ。

まあネタとしては面白かったし、今でもルーターハックの語り草としてよく登場させる印象的なハックだった。Advent Calendar として成仏させられてよかったと思う。

次回

さて、1日遅れで展開しているルーターハック Advent Calendar の次回は、ルーターのブートシークエンスについて書こうと思う。どっちかというと、U-Boot 〜 Login shell までの流れについて、個人の理解のために書く感じだ。乞うご期待。

ファームの礎『OpenWrt』 書き込み・カスタマイズ編

本記事はルーターハックAdvent Calendar 6日目の記事です。

1日遅れてしまった!なんとかして取り戻さないと…

昨日(というよりおととい)は番外編として PlayStation Classic の eMMC を吸い出したレポートに変更したが、PlayStation Classic の粗熱が取れてきたところで OpenWrt に戻ることにする。

www.zopfco.de

おことわり

技適 に関する筆者の配慮や考えについてはカレンダー1日目「技適とルーターハック」をご覧ください。本記事で紹介する内容は、法を遵守するための慎重な注意をもって書かれています。

www.zopfco.de

ビルド完了

前回は make を実行したところで一旦切った。ビルドはうまく行っただろうか?

f:id:puhitaku:20181206193727p:plain
このように、checksumのあと何も言わず終了していればビルドは成功だ。

リポジトリのrootで ./bin/targets/ar71xx/tiny/ls してみよう。

f:id:puhitaku:20181206194206p:plain

このうち、 openwrt-ar71xx-tiny-whr-g301n-squashfs-factory.bin をインストールに使用する。

ブラウザで流し込む

OpenWrt のインストール方法は、電源通電直後のブートローダーの間にTFTPクライアントでファームを送りつけるのが典型だ。だがこの機種 Buffalo WHR-G301N はことさら簡単で、上記の openwrt-ar71xx-tiny-whr-g301n-squashfs-factory.bin をルーターの設定画面から流し込むだけでインストールができる。

PC とルーターを Ethernet で接続し、PC 側 IP アドレスを 192.168.11.0/24 の適当なアドレスに設定する(DHCPでもいい)。次に 192.168.11.1 に接続して

  • ユーザー名: root
  • パスワード: (空白)

で設定画面のBASIC認証を通過。

f:id:puhitaku:20181207045108p:plain
いつもの設定画面。

あとはファーム更新画面でさっきのバイナリ openwrt-ar71xx-tiny-whr-g301n-squashfs-factory.bin を指定し雑にアップデートするだけだ。

f:id:puhitaku:20181207045339p:plain
禁断のバイナリを食してしまう様子。

アップロードが終わると本体は再起動する。完全に起動し切るまで本体のLEDが消えたりついたりするので、この隙に PC 側 IP アドレスを 192.168.1.0/24 なアドレス、例えば 192.168.1.2 にでも変えておこう。

ssh!!

あとは ssh で root@192.168.1.1 に接続すればパスワード無しでログインできるはずだ。ルーターに ssh!!ドキドキの瞬間である。

f:id:puhitaku:20181207095911p:plain
このような motd が見えれば成功。

WARNING とあるように root のパスワードは初期設定で空白になっている。このままでは言わずもがな危険なので passwd でパスワードを設定しておこう。

設定を変えてみる

いわゆる民生品のルーターは、利用者の障壁を下げるためすべてブラウザを通してグラフィカルに設定できる(OpenWrt でもグラフィカルな設定はできるのだが、後述)。一方でこちらは shell 越しが基本となる。

ちなみに、Wi-Fi は初期設定で disable1 になっているため安心だ。

例: IP アドレス

Interface ごとの IP アドレス、スイッチ、VLAN等の設定は /etc/config/network を編集する。初期設定はシンプルであり見た目にわかりやすい。

root@OpenWrt:~# cat /etc/config/network

config interface 'loopback'
        option ifname 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fdaf:7e24:c331::/48'

config interface 'lan'
        option type 'bridge'
        option ifname 'eth0.1'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

config interface 'wan'
        option ifname 'eth1'
        option proto 'dhcp'

config interface 'wan6'
        option ifname 'eth1'
        option proto 'dhcpv6'

config switch
        option name 'switch0'
        option reset '1'
        option enable_vlan '1'

config switch_vlan
        option device 'switch0'
        option vlan '1'
        option ports '1 2 3 4 0t'

設定を変えたら、 reload_config で設定を反映できる。

パッケージを増やしてみる

以前紹介したように、パッケージはかなりいろいろ追加できる。この追加は非常に簡単で、OpenWrt の Git リポジトリの root で make menuconfig を再び起動し、 Base system より下のジャンル別項目から欲しいソフトにチェックを入れることでいい感じにファームに追加される。

枚挙に暇がないので説明は LuCI だけに留めるが、Samba といった鉄板daemonに始まり、 mjpeg-streamer のようなおもしろパッケージまである。眺めてみると面白いだろう。

例: LuCI

初手としてよくインストールされるのは、ブラウザで各種設定ができる LuCI だ。容量も案外食わないため WHR-G301N でも追加することが可能。日本語の翻訳もあるので設定の障壁としては大きく下がるだろう。

f:id:puhitaku:20181207102031p:plain
menuconfig → LuCI → Collections 以下に大元のパッケージがある。

LuCI はネットワークにまつわる設定だけでなく、Module を追加することで他の daemon も設定できるようになるため便利である。

追加してビルドし、後述の sysupgrade でインストールすれば、再起動後に 192.168.1.1 に接続するだけでログイン画面を拝むことができる。ワクワク!

ファームをふたたび書き込むには

最初に OpenWrt をインストールする時は factory イメージを使用したが、以降は sysupgrade イメージを sysupgrade コマンドに渡すことでファームウェアのインストールができる。

$ scp ./bin/targets/ar71xx/tiny/openwrt-ar71xx-tiny-whr-g301n-squashfs-sysupgrade.bin root@192.168.1.1:/tmp
$ ssh root@192.168.1.1 sysupgrade /tmp/openwrt-ar71xx-tiny-whr-g301n-squashfs-sysupgrade.bin

通常であれば、 openwrt-ar71xx-tiny-whr-g301n-squashfs-factory.bin の横に openwrt-ar71xx-tiny-whr-g301n-squashfs-sysupgrade.bin も生成されるのだが、「ビルド完了」の節のスクショを見ると存在しないことがわかる。実は、 WHR-G301N は内蔵フラッシュがとりわけ小さいことが原因で初期 config では sysupgrade イメージが生成できない。 makeV=s という変数を設定して実行すると、データ量が大きすぎてイメージが生成できていない旨が表示される。

$ make V=s
...(中略)...
Warning: /home/takumi/dev/router/openwrt_stable/bin/targets/ar71xx/tiny/openwrt-ar71xx-tiny-whr-g301n-squashfs-sysupgrade.bin is too big (> 3538944 bytes)

生成されたrootfsの中身を見ると、pppd が比較的容量を食っていた。筆者の場合 pppd は必要ではないので、make menuconfig 以下より pppd を選択解除すると sysupgrade イメージが生成されるようになった。ここで LuCI を追加しても生成されたことから、pppd は結構容量を食っていたことがわかる。

無線ももちろん使えないので、wpa-supplicant のような無線関係のソフトウェアやドライバを選択解除するのもアリだろう。

次回

今回は OpenWrt をビルドして実機に流し込むところまで解説した。次回は過去作供養シリーズ第1弾として、以前イベント等では発表したものの記事にしていなかったものを文章にしたためようと思う。